// Copyright (c) 2022 Dominic Masters // // This software is released under the MIT License. // https://opensource.org/licenses/MIT #include "VisualNovelTextbox.hpp" #include "game/DawnGame.hpp" #include "visualnovel/VisualNovelManager.hpp" using namespace Dawn; VisualNovelTextbox::VisualNovelTextbox(UICanvas *canvas) : UIComponent(canvas), selfParent(canvas), border(canvas), label(canvas) { // Self Parent this->selfParent.setTransform( UI_COMPONENT_ALIGN_STRETCH, UI_COMPONENT_ALIGN_STRETCH, glm::vec4(0, 0, 0, 0), 0.0f ); // Border this->selfParent.addChild(&this->border); this->border.setTransform( UI_COMPONENT_ALIGN_STRETCH, UI_COMPONENT_ALIGN_STRETCH, glm::vec4(0, 0, 0, 0), 0.0f ); // Label this->selfParent.addChild(&this->label); this->label.startQuad = 0; this->label.quadCount = 0; this->canvas->getScene()->eventSceneUnpausedUpdate.addListener( this, &VisualNovelTextbox::textboxOnSceneUpdate ); } void VisualNovelTextbox::show() { if(this->isVisible()) return; this->visible = true; this->addChild(&this->selfParent); if(this->talkSound != nullptr) { auto vnManager = this->getVisualNovelManager(); assertNotNull(vnManager); assertNotNull(vnManager->audioCharacter); vnManager->audioCharacter->stop(); vnManager->audioCharacter->setAudioData(this->talkSound); vnManager->audioCharacter->loop = true; vnManager->audioCharacter->play(); } } void VisualNovelTextbox::hide() { if(!this->isVisible()) return; if(this->talkSound != nullptr) { auto vnManager = this->getVisualNovelManager(); assertNotNull(vnManager); assertNotNull(vnManager->audioCharacter); vnManager->audioCharacter->stop(); } this->visible = false; this->removeChild(&this->selfParent); this->eventHidden.invoke(); } bool_t VisualNovelTextbox::isVisible() { return this->visible; } VisualNovelManager * VisualNovelTextbox::getVisualNovelManager() { return this->getScene()->findComponent(); } void VisualNovelTextbox::updatePositions() { UIComponent::updatePositions(); this->lineCurrent = 0; this->timeCharacter = 0; this->label.setTransform( UI_COMPONENT_ALIGN_STRETCH, UI_COMPONENT_ALIGN_STRETCH, glm::vec4( this->border.getBorderSize() + this->labelPadding, this->border.getBorderSize() + this->labelPadding ), 1.0f ); this->label.startQuad = 0; this->label.quadCount = 0; } void VisualNovelTextbox::textboxOnSceneUpdate() { DawnGame *game = this->canvas->getGame(); if(this->hasRevealedAllCurrentCharacters()) { if(this->hasRevealedAllCharacters()) { if(game->inputManager.isPressed(INPUT_BIND_ACCEPT)) { this->hide(); } } else { if(game->inputManager.isPressed(INPUT_BIND_ACCEPT)) { this->lineCurrent += this->getCountOfVisibleLines(); this->label.startQuad = 0; for(int32_t i = 0; i < this->lineCurrent; i++) { this->label.startQuad += this->label.measure.getQuadsOnLine(i); } this->label.quadCount = 0; this->timeCharacter = 0.0f; this->label.setTransform( UI_COMPONENT_ALIGN_STRETCH, UI_COMPONENT_ALIGN_STRETCH, glm::vec4( glm::vec2( this->border.getBorderSize().x + this->labelPadding.x, this->border.getBorderSize().y + this->labelPadding.y - this->label.measure.getHeightOfLineCount(this->lineCurrent) ), this->border.getBorderSize() + this->labelPadding ), 5.0f ); this->eventNewPage.invoke(); } } if(this->talkSound != nullptr) { auto vnManager = this->getVisualNovelManager(); assertNotNull(vnManager); assertNotNull(vnManager->audioCharacter); vnManager->audioCharacter->stop(); } return; } auto lastTimeCharacter = mathFloor(this->timeCharacter); if(game->inputManager.isDown(INPUT_BIND_ACCEPT)) { this->timeCharacter += game->timeManager.delta * VISUAL_NOVEL_TEXTBOX_SPEED_FASTER; } else { this->timeCharacter += game->timeManager.delta * VISUAL_NOVEL_TEXTBOX_SPEED; } auto newTimeCharacter = mathFloor(this->timeCharacter); if(newTimeCharacter == lastTimeCharacter) return; this->label.quadCount = newTimeCharacter; this->eventCharacterRevealed.invoke(); } int32_t VisualNovelTextbox::getCountOfVisibleLines() { int32_t i = 1; glm::vec2 innerSize = this->border.getInnerSize() - this->labelPadding; for(i = this->label.measure.getLineCount(); i > 0; --i) { if(innerSize.y >= this->label.measure.getHeightOfLineCount(i)) { return i; } } return this->label.measure.getLineCount(); } std::vector VisualNovelTextbox::getSelfPassItems( glm::mat4 projection, glm::mat4 view, glm::mat4 transform ) { return std::vector(); } void VisualNovelTextbox::setFont(Font *font) { this->label.setFont(font); this->label.updateMesh(); } void VisualNovelTextbox::setText(std::string key, float_t fontSize) { this->label.setText(key); this->label.setFontSize(fontSize); this->label.updateMesh(); } void VisualNovelTextbox::setCharacter(VisualNovelCharacter *character) { this->character = character; this->talkSound = nullptr; } void VisualNovelTextbox::setTalkingSound(AudioAsset *asset) { this->talkSound = asset; } void VisualNovelTextbox::setText(std::string key) { this->label.setText(key); this->label.updateMesh(); } void VisualNovelTextbox::setFontSize(float_t fontSize) { this->label.setFontSize(fontSize); this->label.updateMesh(); } float_t VisualNovelTextbox::getFontSize() { return this->label.getFontSize(); } void VisualNovelTextbox::setLabelPadding(glm::vec2 padding) { this->labelPadding = padding; this->updatePositions(); } glm::vec2 VisualNovelTextbox::getLabelPadding() { return this->labelPadding; } bool_t VisualNovelTextbox::hasRevealedAllCurrentCharacters() { int32_t quadsTotal = 0; for( int32_t i = this->lineCurrent; i < mathMin( this->label.measure.getLineCount(), this->lineCurrent + this->getCountOfVisibleLines() ); i++ ) { quadsTotal += this->label.measure.getQuadsOnLine(i); } return mathFloor(this->timeCharacter) >= quadsTotal; } bool_t VisualNovelTextbox::hasRevealedAllCharacters() { return ( this->lineCurrent + this->getCountOfVisibleLines() >= this->label.measure.getLineCount() ); } VisualNovelTextbox::~VisualNovelTextbox() { this->canvas->getScene()->eventSceneUnpausedUpdate.removeListener( this, &VisualNovelTextbox::textboxOnSceneUpdate ); }