/** * Copyright (c) 2021 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "vntextbox.h" void vnTextBoxInit(vntextbox_t *box, font_t *font, texture_t *texture) { box->font = font; box->widthMax = 400; box->text = NULL; box->x = 0, box->y = 0; box->linesMax = 3; box->lineCurrent = 0; box->state = 0; frameInit(&box->frame); box->frame.texture = texture; } void vnTextBoxSetText(vntextbox_t *box, char *text) { box->text = text; box->lineCurrent = 0; box->state = 0; box->textScroll = 0; vnTextBoxRebuffer(box); } void vnTextBoxRebuffer(vntextbox_t *box) { if(box->primitive.indiceCount > 0) { primitiveDispose(&box->primitive); box->primitive.indiceCount = 0; } if(box->text == NULL) return; // Determine size of the textbox inside the frame. float textMaxWidth = box->widthMax - FRAME_BORDER_SIZE_FULL; box->width = box->widthMax; // Rebuffer the text. fontTextClamp( box->font, &box->textInfo, box->text, textMaxWidth, VN_TEXTBOX_FONT_SIZE ); fontTextInit(box->font, &box->primitive, &box->textInfo); // Resize the frame box->height = FONT_LINE_HEIGHT * box->linesMax; frameSetSize(&box->frame, box->width, box->height); } void vnTextBoxUpdate(vntextbox_t *box, engine_t *engine) { int32_t i; if(box->state & VN_TEXTBOX_STATE_CLOSED) return; // "Next text box" if(!vnTextBoxHasScrolled(box)) { i = inputIsDown(&engine->input, INPUT_ACCEPT) ? 2 : 1; box->textScroll += engine->time.delta * VN_TEXTBOX_SCROLL_SPEED * i; return; } if(!inputIsPressed(&engine->input, INPUT_ACCEPT)) return; if(vnTextBoxCanBeClosed(box)) { // Box can be closed. box->state |= VN_TEXTBOX_STATE_CLOSED; return; } // In theory this is always false if(box->linesMax < 1) return; // More lines to scroll box->lineCurrent += box->linesMax; } void vnTextBoxRender(vntextbox_t *box, shader_t *shader) { int32_t charStart, charCount; float yOffset; if(box->text == NULL || box->state & VN_TEXTBOX_STATE_CLOSED) return; // Render the debug box. box->frame.x = box->x; box->frame.y = box->y; frameRender(&box->frame, shader); // Determine where we're rendering the indices up to. charCount = (int32_t)box->textScroll; if(charCount == 0) return; // Clamp to lines if necessary. if(box->linesMax > 0) { if(box->lineCurrent >= box->textInfo.lineCount) return; charStart = box->textInfo.lines[box->lineCurrent].start; charCount -= charStart; yOffset = FONT_LINE_HEIGHT * box->lineCurrent; } else { charStart = 0; yOffset = 0; } // Convert characters into indices, don't render if we can't charStart *= QUAD_INDICE_COUNT; if(charStart >= box->primitive.indiceCount) return; // Clamp charCount = mathMin( charCount * QUAD_INDICE_COUNT, box->primitive.indiceCount - charStart ); if(charCount < 1) return; // Render the Text Box shaderUsePosition(shader, box->x + FRAME_BORDER_SIZE, box->y - yOffset + FRAME_BORDER_SIZE, 0, 0,0,0 ); shaderUseTexture(shader, &box->font->texture); primitiveDraw(&box->primitive, charStart, charCount); } void vnTextBoxDispose(vntextbox_t *box) { frameDispose(&box->frame); if(box->primitive.indiceCount > 0) { primitiveDispose(&box->primitive); box->primitive.indiceCount = 0; } } bool vnTextBoxHasScrolled(vntextbox_t *box) { int32_t currentChar; currentChar = (int32_t)box->textScroll; // Are we clamping lines? if(box->linesMax > 0) { return ( currentChar - box->textInfo.lines[box->lineCurrent].start// "Line" space ) >= fontGetLineCharCount( &box->textInfo, box->lineCurrent, box->linesMax ); } return currentChar > box->textInfo.realLength; } bool vnTextBoxCanBeClosed(vntextbox_t *box) { if(!vnTextBoxHasScrolled(box)) return false; if(box->linesMax < 1) return true; return box->lineCurrent + box->linesMax >= box->textInfo.lineCount; }