Still working on my scrolling text and bug fixing.

This commit is contained in:
2021-07-16 22:26:04 -07:00
parent 06202f6f7e
commit f619b7c9d2
26 changed files with 495 additions and 115 deletions

View File

@ -7,17 +7,12 @@
#include "timeline.h"
void onDone(timeline_t *test) {
}
void timelineInit(timeline_t *timeline) {
timeline->current = 0;
timeline->diff = 0;
timeline->previous = 0;
timeline->user = 0;
timeline->actionCount = 0;
timeline->actions[0].onStart = &onDone;
}
void timelineUpdate(timeline_t *timeline, float delta) {
@ -38,7 +33,7 @@ void timelineUpdate(timeline_t *timeline, float delta) {
// Did we start this frame?
if(action->start > timeline->previous && action->onStart != NULL) {
action->onStart(timeline);
action->onStart(timeline, action, i);
}
// Durations of 0 only fire starts, never ends or durations.
@ -47,9 +42,10 @@ void timelineUpdate(timeline_t *timeline, float delta) {
// Is the end still in the future? Durations in negatives go forever
full = action->start+action->duration;
if(action->duration < 0 || full > timeline->current) {
if(action->onDuration != NULL) action->onDuration(timeline);
if(action->onDuration != NULL) action->onDuration(timeline, action, i);
} else if(full > timeline->previous) {// Did we end this frame?
if(action->onEnd != NULL) action->onEnd(timeline);
if(action->onEnd != NULL) action->onEnd(timeline, action, i);
if(action->loop) action->start = timeline->current;
}
}
}
@ -74,6 +70,7 @@ timelineaction_t * timelineAddAction(timeline_t *timeline, float start,
) {
if(timeline->actionCount == TIMELINE_ACTION_COUNT_MAX) return NULL;
timelineaction_t *action = timeline->actions + (timeline->actionCount++);
action->loop = false;
action->start = start, action->duration = duration;
action->onStart = action->onEnd = action->onDuration = NULL;
return action;

View File

@ -44,17 +44,6 @@ void fontDispose(font_t *font) {
textureDispose(&font->texture);
}
fonttextinfo_t * fontGetTextInfo(font_t *font, char *text) {
return fontTextClamp(font, text, 999999);
}
void fontTextInfoDispose(fonttextinfo_t *info) {
free(info->quads);
free(info);
}
void fontTextBuffer(font_t *font,primitive_t *primitive,fonttextinfo_t *info) {
stbtt_aligned_quad *quad;
int32_t i;
@ -76,29 +65,27 @@ void fontTextInit(font_t *font, primitive_t *primitive, fonttextinfo_t *info) {
fontTextBuffer(font, primitive, info);
}
fonttextinfo_t * fontTextClamp(font_t *font, char *text, float maxWidth) {
// This method is similar to fontGetTextInfo, but will modify the text.
void fontTextClamp(font_t *font, fonttextinfo_t *info, char *text,
float maxWidth
) {
int32_t i, j, wordIndex;
char c;
float x, y, wordX;
stbtt_aligned_quad *quad;
fonttextinfo_t *info = malloc(sizeof(fonttextinfo_t));
/** Which index in the original text var is the current word from */
int32_t wordStart = 0;
/** Buffer of the quads for the word (currently) */
int32_t bufferTextSize = 64;
info->quads = malloc(sizeof(stbtt_aligned_quad) * bufferTextSize);
// Setup Scales
info->length = 0;
info->realLength = 0;
info->lines = 1;
info->lineCount = 0;
// Prepare the line counters
info->lines[0].start = 0;
info->lines[0].length = 0;
// Unlike GetTextInfo we can actually calculate the quads at the same time
// that we determine the string length.
// Setup the initial loop state, and X/Y coords for the quad.
i = 0;
x = 0;
y = FONT_INITIAL_LINE;
@ -112,12 +99,13 @@ fonttextinfo_t * fontTextClamp(font_t *font, char *text, float maxWidth) {
// Did this space cause a newline?
if(x > maxWidth) {
info->lines++;
info->lineCount++;
info->lines[info->lineCount].start = info->realLength;
info->lines[info->lineCount].length = 0;
y += FONT_LINE_HEIGHT;
x = 0;
}
// info->width = mathMax(info->width, x);
// info->height = mathMax(info->height, y);
wordX = x;
wordStart = info->realLength;
continue;
@ -125,21 +113,16 @@ fonttextinfo_t * fontTextClamp(font_t *font, char *text, float maxWidth) {
// New line.
if(c == FONT_NEWLINE) {
info->lines++;
info->lineCount++;
info->lines[info->lineCount].start = info->realLength;
info->lines[info->lineCount].length = 0;
wordStart = info->realLength;
y += FONT_LINE_HEIGHT;
x = 0;
continue;
}
// Actual letter. We need to start by resizing the buffer
if(info->realLength+1 >= bufferTextSize) {
info->quads = memBufferResize(info->quads,
bufferTextSize, bufferTextSize * 2, sizeof(stbtt_aligned_quad)
);
bufferTextSize *= 2;
}
// Generate the quad.
quad = info->quads + info->realLength;
stbtt_GetBakedQuad(font->characterData,
@ -156,20 +139,28 @@ fonttextinfo_t * fontTextClamp(font_t *font, char *text, float maxWidth) {
quad->x0 -= wordX, quad->x1 -= wordX;
quad->y0 += FONT_LINE_HEIGHT, quad->y1 += FONT_LINE_HEIGHT;
}
// Go back to the previous (still current) line and remove the chars
info->lines[info->lineCount].length -= info->realLength - wordStart;
// Next line begins with this word
info->lineCount++;
info->lines[info->lineCount].start = wordStart;
info->lines[info->lineCount].length = info->realLength - wordStart;
y += FONT_LINE_HEIGHT;
info->lines++;
wordX = 0;
}
info->lines[info->lineCount].length++;
info->realLength++;
}
info->lineCount++;
for(j = 0; j < info->realLength; j++) {
quad = info->quads + j;
info->width = mathMax(info->width, quad->x1);
info->height = mathMax(info->height, quad->y1);
}
return info;
}

View File

@ -26,23 +26,6 @@ void fontInit(font_t *font, char *data);
*/
void fontDispose(font_t *Font);
/**
* Measures (and calculates the quads for) a text prior to rendering it.
*
* @param font Font to use for rendering and measuring
* @param text Text to measure/render.
* @returns Font info calculated.
*/
fonttextinfo_t * fontGetTextInfo(font_t *font, char *text);
/**
* Disposes a previously calculated font info struct..
* @param info Info to dispose.
*/
void fontTextInfoDispose(fonttextinfo_t *info);
/**
* Buffers the vertices of a font text onto a primitive. Requires some info
* about how the font is meant to render from the text info section.
@ -67,8 +50,10 @@ void fontTextInit(font_t *font, primitive_t *primitive, fonttextinfo_t *info);
* Clamps text to a max width, inserting newlines where possible.
*
* @param font Font to use
* @param text Text to clamp
* @param info Font text info to clamp into.
* @param text Text to clamp.
* @param maxWidth Max width (in pixels) to clamp the text to.
* @returns The calculated text information.
*/
fonttextinfo_t * fontTextClamp(font_t *font,char *text, float maxWidth);
void fontTextClamp(font_t *font, fonttextinfo_t *info, char *text,
float maxWidth
);

View File

@ -9,6 +9,7 @@
#define QUAD_VERTICE_COUNT 4
#define QUAD_INDICE_COUNT 6
#define QUAD_INDICE_PER_QUAD 2
/**
* Buffers the vertices of a quad onto a primitive.

View File

@ -7,6 +7,8 @@
#include "game.h"
testscene_t testScene;
bool gameInit(game_t *game) {
// Init the game
game->name = GAME_NAME;
@ -15,7 +17,8 @@ bool gameInit(game_t *game) {
engineInit(&game->engine, game);
// Hand off to the poker logic.
pokerInit(&game->poker, &game->engine);
testSceneInit(&testScene, game);
// pokerInit(&game->poker, &game->engine);
return true;
}
@ -25,7 +28,9 @@ bool gameUpdate(game_t *game, float platformDelta) {
engineUpdateStart(&game->engine, game, platformDelta);
// Hand off to the poker logic
pokerUpdate(&game->poker, &game->engine);
testSceneRender(&testScene, game);
// pokerUpdate(&game->poker, &game->engine);
// Hand back to the engine.
return engineUpdateEnd(&game->engine, game);

View File

@ -7,9 +7,7 @@
#include <dawn/dawn.h>
#include "../engine/engine.h"
#include "../poker/poker.h"
#include "../poker/card.h"
#include "../display/animation/timeline.h"
#include "../test/testscene.h"
/**
* Initialize the game context.

View File

@ -40,6 +40,11 @@ int32_t main() {
game_t *game = malloc(sizeof(game_t));
GAME_STATE = game;
input_t *input = &game->engine.input;
// Init the render resolution
renderSetResolution(&game->engine.render,
WINDOW_WIDTH_DEFAULT, WINDOW_HEIGHT_DEFAULT
);
// Init the game
if(gameInit(game)) {
@ -67,11 +72,6 @@ int32_t main() {
inputBind(input, INPUT_ACCEPT, (inputsource_t)GLFW_KEY_ENTER);
inputBind(input, INPUT_ACCEPT, (inputsource_t)GLFW_KEY_SPACE);
// Init the render resolution
renderSetResolution(&game->engine.render,
WINDOW_WIDTH_DEFAULT, WINDOW_HEIGHT_DEFAULT
);
// Update the window title.
glfwSetWindowTitle(window, GAME_STATE->name);

View File

@ -13,15 +13,12 @@ void pokerInit(poker_t *poker, engine_t *engine) {
"shaders/textured.vert", "shaders/textured.frag"
);
// Load the main font
assetFontLoad(&poker->font, "fonts/opensans/OpenSans-Bold.ttf");
// Initialize the render stuffs.
pokerFrameInit(poker, &engine->render);
pokerWorldInit(poker);
pokerCardInit(poker);
pokerPlayerInit(poker);
pokerTalkInit(poker);
// pokerTalkInit(poker);
// Hand over to the deal for the first time.
pokerMatchInit(poker, engine);
@ -53,13 +50,11 @@ void pokerUpdate(poker_t *poker, engine_t *engine) {
}
pokerFrameGui(poker, &engine->render);
pokerTalkRender(poker, &engine->input);
poker->textLastWidth = poker->guiWidth;
// pokerTalkRender(poker, &engine->input);
}
void pokerDispose(poker_t * poker) {
pokerTalkDispose(poker);
// pokerTalkDispose(poker);
pokerWorldDispose(poker);
shaderDispose(&poker->shader);
}

View File

@ -14,7 +14,6 @@
#include "render/card.h"
#include "render/player.h"
#include "render/look.h"
#include "render/talk.h"
#include "../file/asset.h"
#include "../display/shader.h"

View File

@ -1,63 +0,0 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "talk.h"
void pokerTalkInit(poker_t *poker) {
poker->talkText = NULL;
poker->talkTextInfo = NULL;
poker->textLastWidth = 0;
}
void pokerTalkDispose(poker_t *poker) {
if(poker->talkTextInfo == NULL) return;
fontTextInfoDispose(poker->talkTextInfo);
primitiveDispose(&poker->talkPrimitive);
}
void pokerTalkTextRebuffer(poker_t *poker) {
// Check if we need to force a redraw or not.
if(poker->talkText == NULL || poker->textLastWidth != poker->guiWidth) {
if(poker->talkTextInfo != NULL) {
fontTextInfoDispose(poker->talkTextInfo);
primitiveDispose(&poker->talkPrimitive);
poker->talkTextInfo = NULL;
}
}
if(poker->talkText == NULL) return;
// Rebuffer
poker->talkTextInfo = fontTextClamp(&poker->font, poker->talkText, poker->guiWidth);
fontTextInit(&poker->font, &poker->talkPrimitive, poker->talkTextInfo);
}
void pokerTalkRender(poker_t *poker, input_t *input) {
pokerTalkTextRebuffer(poker);
if(poker->talkTextInfo == NULL) return;
// Render text
shaderUsePosition(&poker->shader,
0,POKER_GUI_HEIGHT-poker->talkTextInfo->height,0,
0,0,0
);
shaderUseTexture(&poker->shader, &poker->font.texture);
primitiveDraw(&poker->talkPrimitive, 0, -1);
if(inputIsPressed(input, INPUT_ACCEPT)) {
poker->talkText = NULL;
}
}
void pokerTalk(poker_t *poker, char *text) {
poker->talkText = text;
poker->roundTextCounter++;
}
bool pokerTalkIsTalking(poker_t *poker) {
return poker->talkText != NULL || poker->talkTextInfo != NULL;
}

View File

@ -1,53 +0,0 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include <dawn/dawn.h>
#include "../../display/gui/font.h"
#include "../../display/primitive.h"
#include "../../display/shader.h"
#include "../../input/input.h"
/**
* Initializes the talk manager.
* @param poker The poker game context.
*/
void pokerTalkInit(poker_t *poker);
/**
* Disposes and cleans the talk manager context.
* @param poker Poker instance.
*/
void pokerTalkDispose(poker_t *poker);
/**
* Internal method. Checks for changes and rebuffers the talk text information
* when scene changes occur.
* @param poker Poker game context to buffer for.
*/
void pokerTalkTextRebuffer(poker_t *poker);
/**
* Tick render method for the poker talk manager.
* @param poker Poker manager context.
* @param input Input manager to listen to.
*/
void pokerTalkRender(poker_t *poker, input_t *input);
/**
* Requests the talk manager to begin speaking some text.
* @param poker Poker game context
* @param text Text to speak. Please ensure this is kept alive during talk.
*/
void pokerTalk(poker_t *poker, char *text);
/**
* Returns true if the poker text manager is still running the talk.
* @param poker Poker manager.
* @returns True while the game is still running active text.
*/
bool pokerTalkIsTalking(poker_t *poker);

View File

@ -32,8 +32,4 @@ void pokerMatchUpdate(poker_t *poker, engine_t *engine) {
pokerLookAtPlayer(&poker->cameraWorld, POKER_SEAT_PLAYER0, (
t < 1 ? 1 - easeOutQuart(t) : 0
));
if(t > 0.75) {
pokerTalk(poker, "Hello World");
}
}

View File

@ -9,7 +9,6 @@
#include <dawn/dawn.h>
#include "start.h"
#include "../render/look.h"
#include "../render/talk.h"
/**
* Init the poker match round.

50
src/test/testscene.c Normal file
View File

@ -0,0 +1,50 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "testscene.h"
void testSceneInit(testscene_t *scene, game_t *game) {
assetFontLoad(&scene->font, "fonts/opensans/OpenSans-Bold.ttf");
assetShaderLoad(&scene->shader,
"shaders/textured.vert", "shaders/textured.frag"
);
vnTextBoxInit(&scene->box, &scene->font);
scene->box.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent aliquam volutpat libero, vitae laoreet neque egestas et. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce dui leo, molestie et consectetur quis, blandit eu velit. Suspendisse at dolor sed ligula consectetur luctus. Donec mollis semper lacus id pretium. Maecenas et magna lorem. Nullam non viverra dui. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Pellentesque dapibus facilisis ipsum, eu placerat justo pretium tempus. Quisque vehicula sapien vel sem ullamcorper vestibulum. Mauris pellentesque sapien vel volutpat imperdiet.";
scene->box.widthMax = game->engine.render.width;
vnTextBoxRebuffer(&scene->box);
}
void testSceneRender(testscene_t *scene, game_t *game) {
if(false) {
cameraLookAt(&scene->camera,
300, 300, 300,
0, 0, 0
);
cameraPerspective(&scene->camera, 75,
game->engine.render.width/game->engine.render.height, 0.01, 1000.0
);
} else {
cameraLookAt(&scene->camera,
0, 0, 10,
0, 0, 0
);
cameraOrtho(&scene->camera,
0, game->engine.render.width,
game->engine.render.height, 0,
0.01, 1000.0
);
}
shaderUse(&scene->shader);
shaderUseCamera(&scene->shader, &scene->camera);
vnTextBoxUpdate(&scene->box, &game->engine);
vnTextBoxRender(&scene->box, &scene->shader);
}

26
src/test/testscene.h Normal file
View File

@ -0,0 +1,26 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include <dawn/dawn.h>
#include "../display/shader.h"
#include "../display/camera.h"
#include "../display/gui/font.h"
#include "../file/asset.h"
#include "../vn/gui/vntextbox.h"
#include "../display/gui/font.h"
typedef struct {
shader_t shader;
camera_t camera;
font_t font;
vntextbox_t box;
} testscene_t;
void testSceneInit(testscene_t *scene, game_t *game);
void testSceneRender(testscene_t *scene, game_t *game);

26
src/vn/conversation.c Normal file
View File

@ -0,0 +1,26 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "conversation.h"
void conversationInit(conversation_t *convo) {
convo->textCount = 0x00;
convo->textCurrent = 0x00;
}
void conversationNext(conversation_t *convo) {
convo->textCurrent++;
}
conversationtext_t * conversationAdd(conversation_t *convo, uint8_t speaker,
char *text
) {
conversationtext_t *txt = convo->texts + (convo->textCount++);
txt->text = text;
txt->speaker = speaker;
return txt;
}

35
src/vn/conversation.h Normal file
View File

@ -0,0 +1,35 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include <dawn/dawn.h>
#include "../util/array.h"
#include "../display/animation/timeline.h"
/**
* Initialize the conversation set.
* @param convo Conversation to initialize.
*/
void conversationInit(conversation_t *convo);
/**
* Proceed to the next conversation element.
* @param convo Conversation to advance.
*/
void conversationNext(conversation_t *convo);
/**
* Add a text element to the conversation.
*
* @param convo Conversation to add to.
* @param speaker Speaker that said this thing.
* @param text Text to speak
* @return The pointer to the text element.
*/
conversationtext_t * conversationAdd(conversation_t *convo, uint8_t speaker,
char *text
);

124
src/vn/gui/vntextbox.c Normal file
View File

@ -0,0 +1,124 @@
/**
* 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) {
box->font = font;
box->widthMax = 400;
box->text = NULL;
box->x = 0, box->y = 0;
box->linesMax = 1;
box->lineCurrent = 0;
}
void vnTextBoxRebuffer(vntextbox_t *box) {
if(box->primitive.indiceCount > 0) {
vnTextBoxDispose(box);
}
if(box->text == NULL) return;
// Rebuffer the text.
fontTextClamp(box->font, &box->textInfo, box->text, box->widthMax);
fontTextInit(box->font, &box->primitive, &box->textInfo);
quadInit(&box->testPrimitive, 0,
0, 0, 0.3, 0.3,
box->textInfo.width, box->textInfo.height, 0.6, 0.6
);
pixel_t pixels[25];
for(uint8_t i = 0; i < 25; i++) {
pixels[i].r = pixels[i].a = 0xFF;
pixels[i].g = pixels[i].b = 0x00;
}
textureInit(&box->testTexture, 5, 5, pixels);
}
void vnTextBoxUpdate(vntextbox_t *box, engine_t *engine) {
if(vnTextBoxHasScrolled(box)) {
if(!inputIsPressed(&engine->input, INPUT_ACCEPT)) return;
// "Next text box"
printf("Next");
box->lineCurrent++;
return;
}
bool speedup = inputIsDown(&engine->input, INPUT_ACCEPT);
timelineUpdate(&box->animTimeline, engine->time.delta * (speedup ? 1 : 2));
}
void vnTextBoxRender(vntextbox_t *box, shader_t *shader) {
int32_t charStart, charCount, i;
if(box->text == NULL) return;
// Determine where we're rendering the indices up to.
charCount = box->animTimeline.current * VN_TEXTBOX_SCROLL_SPEED;
if(charCount == 0) return;
// Clamp to lines if necessary.
if(box->linesMax > 0) {
if(box->lineCurrent >= box->textInfo.lineCount) return;
// From lineCurrent to lineCurrent+lineMax (or max lines in text).
i = box->lineCurrent;
charStart = 0;// Misusing variable for now.
while(i < mathMin(box->lineCurrent+box->linesMax, box->textInfo.lineCount)){
charStart += box->textInfo.lines[i].length;// Sum char counts for lines.
i++;
}
i = box->textInfo.lines[box->lineCurrent].start;//i=the starting indice now
if(charCount >= charStart) {
int32_t brhva;
brhva = 32;
}
// Select either the scroll position or the total chars for the lowest.
charCount = mathMin(charCount - i, charStart);
charStart = box->lineCurrent;
} else {
charStart = 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 debug box.
shaderUsePosition(shader, box->x,box->y,0, 0,0,0);
shaderUseTexture(shader, &box->testTexture);
primitiveDraw(&box->testPrimitive, 0, -1);
// Render the Text Box
shaderUseTexture(shader, &box->font->texture);
primitiveDraw(&box->primitive, charStart, charCount);
}
void vnTextBoxDispose(vntextbox_t *box) {
primitiveDispose(&box->primitive);
primitiveDispose(&box->testPrimitive);
textureDispose(&box->testTexture);
box->primitive.indiceCount = 0;
}
bool vnTextBoxHasScrolled(vntextbox_t *box) {
if(box->text == NULL) return true;
return (box->animTimeline.current * (
VN_TEXTBOX_SCROLL_SPEED * QUAD_INDICE_COUNT
)) >= box->primitive.indiceCount;
}

61
src/vn/gui/vntextbox.h Normal file
View File

@ -0,0 +1,61 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include <dawn/dawn.h>
#include "../../display/primitive.h"
#include "../../display/shader.h"
#include "../../display/animation/timeline.h"
#include "../../display/gui/font.h"
#include "../../display/primitives/quad.h"
#include "../../input/input.h"
/**
* Initializes the Visual Novel Text Box to its initial state.
*
* @param box The box to initialize.
* @param font Font for the text box to use by default.
*/
void vnTextBoxInit(vntextbox_t *box, font_t *font);
/**
* Method required to be called when changing anything within the textbox. This
* will recalculate the text widths, fonts, etc.
* @param box Box to recalculate for.
*/
void vnTextBoxRebuffer(vntextbox_t *box);
/**
* Updates the Visual Novel Text Box. This includes handling logic for both,
* the animation and the input controlling for the textbox.
* @param box Box to update.
* @param engine Engine that the box is being updated by.
*/
void vnTextBoxUpdate(vntextbox_t *box, engine_t *engine);
/**
* Renders the Visual Novel Text Box. No logic occurs, just renders. Animations
* will not be ticked, use update to do this.
* @param box Box to render.
* @param shader Shader to render to.
*/
void vnTextBoxRender(vntextbox_t *box, shader_t *shader);
/**
* Disposes a previously created Visual Novel Text Box.
* @param box Text Box to dispose.
*/
void vnTextBoxDispose(vntextbox_t *box);
/**
* Checks the current buffer position of a vn text box and returns true if it has finished
* scrolling.
*
* @param box Box to check.
* @return True if the text box has finished scrolling.
*/
bool vnTextBoxHasScrolled(vntextbox_t *box);