VN Textbox Scroll initial version

This commit is contained in:
2023-05-20 22:13:22 -07:00
parent d3ac3b688b
commit f8ca5f2e17
16 changed files with 347 additions and 72 deletions

View File

@ -19,7 +19,7 @@ int32_t FontMeasure::getQuadCount() {
return this->realLength;
}
float_t FontMeasure::getHeightOfLineCount(int32_t lineCount) {
float_t FontMeasure::getHeightOfLineCount(size_t lineCount) {
assertTrue(lineCount > 0);
return this->lineHeight * lineCount;
}
@ -28,13 +28,13 @@ size_t FontMeasure::getLineCount() {
return this->lines.size();
}
int32_t FontMeasure::getQuadsOnLine(int32_t line) {
int32_t FontMeasure::getQuadsOnLine(size_t line) {
assertTrue(line >= 0);
assertTrue(line < this->lines.size());
return this->lines[line].length;
}
int32_t FontMeasure::getQuadIndexOnLine(int32_t line) {
int32_t FontMeasure::getQuadIndexOnLine(size_t line) {
assertTrue(line >= 0);
assertTrue(line < this->lines.size());
return this->lines[line].start;

View File

@ -60,7 +60,7 @@ namespace Dawn {
* @param line Which line to get the count of quads for.
* @return Count of quads on that line.
*/
int32_t getQuadsOnLine(int32_t line);
int32_t getQuadsOnLine(size_t line);
/**
* Returns the index, of which quad is the first quad on the given line.
@ -68,7 +68,7 @@ namespace Dawn {
* @param line Line to get the quad index of.
* @return The quad index of that line.
*/
int32_t getQuadIndexOnLine(int32_t line);
int32_t getQuadIndexOnLine(size_t line);
/**
* Returns the height of the count of lines provided.
@ -76,7 +76,7 @@ namespace Dawn {
* @param lineCount Count of lines to get the height of.
* @return Height of the given count of lines.
*/
float_t getHeightOfLineCount(int32_t lineCount);
float_t getHeightOfLineCount(size_t lineCount);
/**
* Returns the count of lines in this string.

View File

@ -7,4 +7,5 @@
target_sources(${DAWN_TARGET_NAME}
PRIVATE
VNManager.cpp
VNTextboxScroller.cpp
)

View File

@ -0,0 +1,110 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "VNTextboxScroller.hpp"
#include "game/DawnGame.hpp"
using namespace Dawn;
VNTextboxScroller::VNTextboxScroller(SceneItem *item) :
SceneItemComponent(item),
label(nullptr)
{
}
void VNTextboxScroller::onStart() {
assertNotNull(label);
std::function<void()> x = [&]{
this->lineCurrent = 0;
this->timeCharacter = 0;
this->label->startQuad = 0;
this->label->quadCount = 0;
};
x();
useEvent([&](float_t delta){
auto game = this->getGame();
this->timeCharacter += delta;
if(this->hasRevealedAllCurrentCharacters()) {
if(this->hasRevealedAllCharacters()) {
if(game->inputManager.isPressed(INPUT_BIND_ACCEPT)) {
std::cout << "HIDE" << std::endl;
}
} 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();
}
}
return;
}
auto lastTimeCharacter = mathFloor<int32_t>(this->timeCharacter);
if(game->inputManager.isDown(INPUT_BIND_ACCEPT)) {
this->timeCharacter += game->timeManager.delta * VN_TEXTBOX_SPEED_FASTER;
} else {
this->timeCharacter += game->timeManager.delta * VN_TEXTBOX_SPEED;
}
this->label->quadCount = mathFloor<int32_t>(this->timeCharacter);
// this->eventCharacterRevealed.invoke();
}, getScene()->eventSceneUpdate);
}
size_t VNTextboxScroller::getCountOfVisibleLines() {
float_t y = this->label->getHeight();
size_t i = 1;
for(i = this->label->measure.getLineCount(); i > 0; --i) {
if(y >= this->label->measure.getHeightOfLineCount(i)) {
return i;
}
}
return this->label->measure.getLineCount();
}
bool_t VNTextboxScroller::hasRevealedAllCurrentCharacters() {
int32_t quadsTotal = 0;
for(
size_t i = this->lineCurrent;
i < mathMin<size_t>(
this->label->measure.getLineCount(),
this->lineCurrent + this->getCountOfVisibleLines()
);
i++
) {
quadsTotal += this->label->measure.getQuadsOnLine(i);
}
return mathFloor<int32_t>(this->timeCharacter) >= quadsTotal;
}
bool_t VNTextboxScroller::hasRevealedAllCharacters() {
return (
this->lineCurrent + this->getCountOfVisibleLines() >=
this->label->measure.getLineCount()
);
}

View File

@ -0,0 +1,53 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "scene/SceneItemComponent.hpp"
#include "scene/components/ui/UILabel.hpp"
#include "input/InputManager.hpp"
#define VN_TEXTBOX_SPEED 25.0f
#define VN_TEXTBOX_SPEED_FASTER 40.0f
namespace Dawn {
class VNTextboxScroller : public SceneItemComponent {
protected:
public:
// @optional
StateProperty<UILabel*> label;
size_t lineCurrent = 0;
float_t timeCharacter = 0.0f;
VNTextboxScroller(SceneItem *item);
virtual void onStart() override;
/**
* Returns the count of visible lines within the textbox. Mostly used for
* when we need to decide how to wrap.
*
* @return The count of visible lines.
*/
size_t getCountOfVisibleLines();
/**
* Returns true if all of the characters that can be made visible for the
* current textbox size have finished revealing, or false if not.
*
* @return True if above statement is met.
*/
bool_t hasRevealedAllCurrentCharacters();
/**
* Returns true only when every character passed previously in setText
* has been revealed by scrolling.
*
* @return True if above statement is true.
*/
bool_t hasRevealedAllCharacters();
};
}

View File

@ -14,13 +14,6 @@ namespace Dawn {
protected:
void onStart() override {
std::cout << "TEXT: " << text << std::endl;
useEvent([&](float_t delta) {
if(getScene()->game->inputManager.isPressed(INPUT_BIND_ACCEPT)) {
std::cout << "Text Advance" << std::endl;
this->next();
}
}, getScene()->eventSceneUpdate);
}
};
}

View File

@ -13,7 +13,9 @@ UILabel::UILabel(SceneItem *item) :
text(""),
fontSize(10.0f),
font(&item->scene->game->renderManager.defaultFont),
maxWidth(UI_LABEL_MAX_WIDTH_ALIGN)
maxWidth(UI_LABEL_MAX_WIDTH_ALIGN),
startQuad(0),
quadCount(-1)
{
}
@ -30,7 +32,12 @@ void UILabel::updateMesh() {
if(!this->hasText()) return;
float_t width = this->maxWidth;
assertTrue(width == UI_LABEL_MAX_WIDTH_NONE || width == UI_LABEL_MAX_WIDTH_ALIGN || width > 0);
assertTrue(
width == UI_LABEL_MAX_WIDTH_NONE ||
width == UI_LABEL_MAX_WIDTH_ALIGN ||
width > 0
);
if(width == UI_LABEL_MAX_WIDTH_ALIGN) {
auto dimensional = this->getParentDimensional();
auto align = (glm::vec4)this->alignment;
@ -56,6 +63,8 @@ void UILabel::updateMesh() {
);
this->needsRebuffering = false;
this->eventFontRebuffered.invoke();
}
std::vector<struct ShaderPassItem> UILabel::getPassItems(
@ -100,7 +109,7 @@ void UILabel::onStart() {
useEffect([&]{
alignmentNeedsUpdating = true;
}, { &fontSize, &font, &text, &maxWidth });
}, { &fontSize, &font, &text, &maxWidth, &startQuad, &quadCount });
useEffect([&]{
needsRebuffering = true;

View File

@ -39,10 +39,14 @@ namespace Dawn {
StateProperty<float_t> maxWidth;
/* @optional */
struct Color textColor = COLOR_WHITE;
// @optional
StateProperty<int32_t> startQuad;
// @optional
StateProperty<int32_t> quadCount;
StateEvent<> eventFontRebuffered;
struct FontMeasure measure;
int32_t startQuad = 0;
int32_t quadCount = -1;
UILabel(SceneItem *item);

View File

@ -35,7 +35,6 @@ int32_t SceneTool::start() {
struct SceneItemComponentRegistry registry;
registry.sources = File::normalizeSlashes(flags["sources"]);
scene.registry = &registry;
auto result = ((SceneParser()).parse(&xml, &scene, &error));
if(result != 0) {
std::cout << "Failed to parse scene " << input.filename << "::" << error << std::endl;

View File

@ -13,6 +13,8 @@ void SceneGenerator::generate(
struct MethodGenInfo &methodAssets,
struct MethodGenInfo &methodInit
) {
assertNotNull(scene);
classInfo.clazz = scene->name;
classInfo.constructorArgs = "DawnGame *game";
classInfo.extendArgs = "game";
@ -54,10 +56,12 @@ void SceneGenerator::generate(
int32_t childNumber = 0;
int32_t componentNumber = 0;
std::map<std::string, std::string> assetMap;
std::vector<struct SceneItemComponent> componentsUnused;
auto sceneItems = scene->items.begin();
while(sceneItems != scene->items.end()) {
SceneItemGenerator::generate(
auto itDeps = scene->dependencies.begin();
while(itDeps != scene->dependencies.end()) {
auto dep = *itDeps;
SceneItemGenerator::generateDependency(
assetNumber,
componentNumber,
childNumber,
@ -68,24 +72,15 @@ void SceneGenerator::generate(
&methodAssets.body,
"",
"this",
&(*sceneItems),
""
componentsUnused,
scene->items,
scene->code,
dep
);
++sceneItems;
++itDeps;
}
// Seal methods
line(&methodAssets.body, "return assets;", "");
// Code
auto itCode = scene->code.begin();
while(itCode != scene->code.end()) {
SceneCodeGenerator::generate(
&classInfo.publicProperties,
&methodInit.body,
&(*itCode),
""
);
++itCode;
}
}

View File

@ -7,6 +7,76 @@
using namespace Dawn;
void SceneItemGenerator::generateDependency(
int32_t &assetNumber,
int32_t &componentNumber,
int32_t &childNumber,
std::map<std::string, std::string> &assetMap,
std::vector<std::string> &includes,
std::vector<std::string> *publicProperties,
std::vector<std::string> *initBody,
std::vector<std::string> *assetBody,
std::string name,
std::string sceneRef,
std::vector<struct SceneItemComponent> &components,
std::vector<struct SceneItem> &children,
std::vector<struct SceneCode> &code,
struct SceneItemDependency dep
) {
switch(dep.type) {
case SCENE_ITEM_DEPENDENCY_TYPE_CODE: {
auto i = &code[dep.position];
SceneCodeGenerator::generate(
publicProperties,
initBody,
i,
""
);
line(initBody, "", "");
break;
}
case SCENE_ITEM_DEPENDENCY_TYPE_COMPONENT: {
auto i = &components[dep.position];
SceneItemComponentGenerator::generate(
assetMap,
componentNumber,
includes,
name,
publicProperties,
initBody,
i,
""
);
line(initBody, "", "");
break;
}
case SCENE_ITEM_DEPENDENCY_TYPE_ITEM: {
auto i = &children[dep.position];
SceneItemGenerator::generate(
assetNumber,
componentNumber,
childNumber,
assetMap,
includes,
publicProperties,
initBody,
assetBody,
name,
sceneRef,
i,
""
);
line(initBody, "", "");
break;
}
default:
assertUnreachable();
}
}
void SceneItemGenerator::generate(
int32_t &assetNumber,
int32_t &componentNumber,
@ -21,6 +91,11 @@ void SceneItemGenerator::generate(
struct SceneItem *item,
std::string tabs
) {
assertNotNull(publicProperties);
assertNotNull(initBody);
assertNotNull(assetBody);
assertNotNull(item);
// Determine interface
std::string name = "itm" + std::to_string(childNumber++);
std::string itemType = "SceneItem";
@ -82,26 +157,11 @@ void SceneItemGenerator::generate(
++itAssets;
}
// Add components for children
auto itComponents = item->components.begin();
while(itComponents != item->components.end()) {
SceneItemComponentGenerator::generate(
assetMap,
componentNumber,
includes,
name,
publicProperties,
initBody,
&(*itComponents),
""
);
++itComponents;
}
// Process sub children
auto itChildren = item->children.begin();
while(itChildren != item->children.end()) {
SceneItemGenerator::generate(
// Add the dependencies
auto itDeps = item->dependencies.begin();
while(itDeps != item->dependencies.end()) {
auto dep = *itDeps;
SceneItemGenerator::generateDependency(
assetNumber,
componentNumber,
childNumber,
@ -112,26 +172,16 @@ void SceneItemGenerator::generate(
assetBody,
name,
sceneRef,
&(*itChildren),
""
item->components,
item->children,
item->code,
dep
);
++itChildren;
++itDeps;
}
// Set parent
if(!parentRef.empty()) {
line(initBody, name + "->transform.setParent(&"+parentRef+"->transform);", "");
}
// Code
auto itCode = item->code.begin();
while(itCode != item->code.end()) {
SceneCodeGenerator::generate(
publicProperties,
initBody,
&(*itCode),
""
);
++itCode;
}
}

View File

@ -12,6 +12,23 @@
namespace Dawn {
class SceneItemGenerator : public CodeGen {
public:
static void generateDependency(
int32_t &assetNumber,
int32_t &componentNumber,
int32_t &childNumber,
std::map<std::string, std::string> &assetMap,
std::vector<std::string> &includes,
std::vector<std::string> *publicProperties,
std::vector<std::string> *initBody,
std::vector<std::string> *assetBody,
std::string name,
std::string sceneRef,
std::vector<struct SceneItemComponent> &components,
std::vector<struct SceneItem> &children,
std::vector<struct SceneCode> &code,
struct SceneItemDependency dep
);
static void generate(
int32_t &assetNumber,
int32_t &componentNumber,

View File

@ -54,6 +54,8 @@ int32_t SceneItemParser::onParse(
out->prefab = values["prefab"];
struct SceneItemDependency dep;
auto itChildren = node->children.begin();
while(itChildren != node->children.end()) {
// Parse child nodes, they may be components or not
@ -65,6 +67,12 @@ int32_t SceneItemParser::onParse(
auto ret = (SceneItemParser()).parse(c, &child, error);
if(ret != 0) return ret;
out->children.push_back(child);
// Add a dependency. This solves the reference order problem.
struct SceneItemDependency dep;
dep.type = SCENE_ITEM_DEPENDENCY_TYPE_ITEM;
dep.position = out->children.size() - 1;
out->dependencies.push_back(dep);
} else if(c->node == "asset") {
struct SceneAsset asset;
@ -77,6 +85,11 @@ int32_t SceneItemParser::onParse(
auto ret = (SceneCodeParser()).parse(c, &code, error);
if(ret != 0) return ret;
out->code.push_back(code);
// Add Dep
dep.type = SCENE_ITEM_DEPENDENCY_TYPE_CODE;
dep.position = out->code.size() - 1;
out->dependencies.push_back(dep);
} else {
struct SceneItemComponent component;
@ -84,6 +97,12 @@ int32_t SceneItemParser::onParse(
auto ret = (SceneItemComponentParser()).parse(c, &component, error);
if(ret != 0) return ret;
out->components.push_back(component);
// Add dep
struct SceneItemDependency dep;
dep.type = SCENE_ITEM_DEPENDENCY_TYPE_COMPONENT;
dep.position = out->components.size() - 1;
out->dependencies.push_back(dep);
}
++itChildren;
}

View File

@ -9,6 +9,17 @@
#include "util/parser/SceneCodeParser.hpp"
namespace Dawn {
enum SceneItemDependencyType {
SCENE_ITEM_DEPENDENCY_TYPE_ITEM,
SCENE_ITEM_DEPENDENCY_TYPE_COMPONENT,
SCENE_ITEM_DEPENDENCY_TYPE_CODE,
};
struct SceneItemDependency {
enum SceneItemDependencyType type;
size_t position;
};
struct SceneItem {
struct SceneItemComponentRegistry *registry;
std::string ref;
@ -21,6 +32,7 @@ namespace Dawn {
std::vector<struct SceneItem> children;
std::vector<struct SceneAsset> assets;
std::vector<struct SceneCode> code;
std::vector<struct SceneItemDependency> dependencies;
};
class SceneItemParser : public XmlParser<struct SceneItem> {

View File

@ -29,6 +29,8 @@ int32_t SceneParser::onParse(
out->name = values["name"];
out->extend = values["extend"];
struct SceneItemDependency dep;
//Parse the children
auto itChildren = node->children.begin();
while(itChildren != node->children.end()) {
@ -40,12 +42,22 @@ int32_t SceneParser::onParse(
ret = (SceneItemParser()).parse(child, &item, error);
if(ret != 0) return 1;
out->items.push_back(item);
//Add the dependency
dep.type = SCENE_ITEM_DEPENDENCY_TYPE_ITEM;
dep.position = out->items.size() - 1;
out->dependencies.push_back(dep);
} else if(child->node == "code") {
struct SceneCode code;
ret = (SceneCodeParser()).parse(child, &code, error);
if(ret != 0) return ret;
out->code.push_back(code);
//Add the dependency
dep.type = SCENE_ITEM_DEPENDENCY_TYPE_CODE;
dep.position = out->code.size() - 1;
out->dependencies.push_back(dep);
}
++itChildren;

View File

@ -14,6 +14,7 @@ namespace Dawn {
std::vector<struct SceneItem> items;
std::vector<struct SceneCode> code;
struct SceneItemComponentRegistry *registry;
std::vector<struct SceneItemDependency> dependencies;
};
class SceneParser : public XmlParser<struct Scene> {