Still working on some VN elements, it's coming together slowly.

This commit is contained in:
2021-07-26 09:55:09 -07:00
parent f738f9b83d
commit 31f61cac69
14 changed files with 359 additions and 61 deletions

View File

@ -15,6 +15,16 @@
*/ */
#define easeTimeToEase(start, current, duration) ((current-start)/duration) #define easeTimeToEase(start, current, duration) ((current-start)/duration)
/**
* Animation tool for converting 0-1 space into a 0-0.5 back to zero space. This
* is intended to make a "Forward then backwards" effect for animation. This
* method will not scale t.
* @param t Time in space to back and fourth on between 0 and 1.
* @returns Forward and backwards time. 0 to 0.5 are as such, 0.5 to 1 are from
* 0.5 to 0.
*/
#define easeTimeToForwardAndBackward(t) (t < 0.5 ? t : 1 - t)
// Easing Functions, most were sourced from https://gist.github.com/gre/1650294 // Easing Functions, most were sourced from https://gist.github.com/gre/1650294
#define easeLinear(t) t #define easeLinear(t) t

View File

@ -9,7 +9,7 @@
#include "../../libs.h" #include "../../libs.h"
/** Maximum number of actions a timeline can support, smaller than 0xFF */ /** Maximum number of actions a timeline can support, smaller than 0xFF */
#define TIMELINE_ACTION_COUNT_MAX 32 #define TIMELINE_ACTION_COUNT_MAX 128
/** Type forwarders */ /** Type forwarders */
typedef struct _timeline_t timeline_t; typedef struct _timeline_t timeline_t;

View File

@ -7,22 +7,44 @@
#pragma once #pragma once
#include <dawn/dawn.h> #include <dawn/dawn.h>
#include "math.h"
/** /**
* Generate a number between 0 and max. (max exclusive) * Generates a random int32_t.
* * @returns A random int32_t number.
* @param max Max number to generate
* @return Number between 0 and max.
*/ */
#define u32rand(max) (rand()%max) #define randInt32() ((int32_t)rand())
#define u8rand(max) (uint8_t)u23rand(max)
/** /**
* Generate a number between min and max. (max exclusive, min inclusive) * Generates a random floating point number.
* * @returns A random floating point number.
* @param min Min number to generate.
* @param max Max number to generate.
* @return Number between min and max.
*/ */
#define u32randRange(min, max) (u32rand(max-min)+min) #define randFloat() (((float)randInt32()) * M_PI)
#define u8randRange(min, max) (uint8_t)u32randRange(min,max)
/**
* Generates a random uint32_t
* @returns A random uint32_t number.
*/
#define randUint32() (uint32_t)randInt32()
/**
* Generates a random uint8_t
* @returns A random uint8_t number.
*/
#define randUint8() (uint8_t)randInt32()
////////////////////////////////////////////////////////////////////////////////
/**
* Clamps a random number generation.
* @param n Number that has been generated from the random.
* @param min Minimum value to generate from. (Inclusive)
* @param max Maximum value to generate to. (Exclusive)
* @return Random number between min and max.
*/
#define randRange(n, min, max) (mathMod(n, max - min) + min)
#define randInt32Range(min, max) randRange(randInt32(), min, max)
#define randFloatRange(min, max) (fmod(randFloat(), max- min) + min)
#define randUint32Range(min, max) randRange(randUint32(), min, max)
#define randUint8Range(min, max) randRange(randUint8(), min, max)

View File

@ -11,21 +11,27 @@
#include "../display/primitive.h" #include "../display/primitive.h"
#include "../display/tileset.h" #include "../display/tileset.h"
#define VNCHARACTER_EMOTION_NEUTRAL 0x00 #define VN_CHARACTER_BLINK_TIME_RANGE_MAX 6
#define VN_CHARACTER_SIZE 0.5
typedef struct { typedef struct {
float x, y, z; float x, y, z;
float yaw, pitch, roll; float yaw, pitch, roll;
float scaleX, scaleY;
uint8_t emotion;
bool talking; bool talking;
float blinkStart;
float t; tileset_t tilesetEyes;
tileset_t tilesetMouth;
texture_t *textureEyes; texture_t *textureEyes;
texture_t *textureBody; texture_t *textureBody;
texture_t *textureMouth; texture_t *textureMouth;
texture_t *textureFace; texture_t *textureFace;
primitive_t primitive; primitive_t primitiveEyes;
primitive_t primitiveBody;
primitive_t primitiveMouth;
primitive_t primitiveFace;
} vncharacter_t; } vncharacter_t;

View File

@ -11,10 +11,24 @@
#define VN_CONVERSATION_TEXT_COUNT_MAX 32 #define VN_CONVERSATION_TEXT_COUNT_MAX 32
#define VN_CONVERSATION_TYPE_DELAY 0x01 // Type Forwarders
#define VN_CONVERSATION_TYPE_TEXT 0x02
typedef struct _vnconversationtext_t vnconversationtext_t;
typedef struct _vnconversation_t vnconversation_t;
/**
* Callback for conversation text events.
* @param conversation Conversation this text is attached to.
* @param text Text item that is being used in the callback
*/
typedef void vnconversationcallback_t(vnconversation_t *conversation,
vnconversationtext_t *text
);
typedef struct _vnconversationtext_t {
/** Pointer to any custom user data for this text action. */
void *data;
typedef struct {
/** Conversation Type to decide what this data is used for */ /** Conversation Type to decide what this data is used for */
uint8_t type; uint8_t type;
@ -23,15 +37,32 @@ typedef struct {
/** Time in seconds to delay if type is delay */ /** Time in seconds to delay if type is delay */
float delay; float delay;
/** Callback to fire the moment the text is active in the conversation */
vnconversationcallback_t *onStart;
/** Callback to fire every update tick of this conversation element */
vnconversationcallback_t *onUpdate;
/** Callback to fire when this conversation element is ended */
vnconversationcallback_t *onEnd;
} vnconversationtext_t; } vnconversationtext_t;
typedef struct { /** Representation of a conversation, laid out similarly to a timeline. */
typedef struct _vnconversation_t {
/** Internal Textbox for text elements */
vntextbox_t textbox; vntextbox_t textbox;
vnconversationtext_t texts[VN_CONVERSATION_TEXT_COUNT_MAX];
/** Array of text elements */
vnconversationtext_t texts[VN_CONVERSATION_TEXT_COUNT_MAX];
uint8_t textCount;
/** Internal timeline tracking */
float timeline; float timeline;
/** When the current text was first attached */
float delayStart; float delayStart;
uint8_t textCount; /** Current index within the array of texts that is currently processing */
uint8_t textCurrent; uint8_t textCurrent;
} vnconversation_t; } vnconversation_t;

View File

@ -9,48 +9,88 @@
void testSceneInit(testscene_t *scene, game_t *game) { void testSceneInit(testscene_t *scene, game_t *game) {
vnconversationtext_t *text; vnconversationtext_t *text;
assetFontLoad(&scene->font, "fonts/opensans/OpenSans-Bold.ttf"); assetFontLoad(&scene->font, "fonts/opensans/OpenSans-Bold.ttf");
assetShaderLoad(&scene->shader, assetShaderLoad(&scene->shader,
"shaders/textured.vert", "shaders/textured.frag" "shaders/textured.vert", "shaders/textured.frag"
); );
assetTextureLoad(&scene->pennyEyes, "characters/penny/textures/eyes.png"); vnConversationInit(&scene->conversation, &scene->font);
assetTextureLoad(&scene->pennyBody, "characters/penny/textures/body.png"); scene->conversation.textbox.linesMax = 3;
assetTextureLoad(&scene->pennyFace, "characters/penny/textures/face.png"); scene->conversation.textbox.widthMax = game->engine.render.width;
assetTextureLoad(&scene->pennyMouth, "characters/penny/textures/mouth.png");
characterInit(&scene->character, text = vnCharacterConversationSetTalking(
&scene->character1, &scene->conversation, true
);
text = vnConversationAdd(&scene->conversation);
text->text = "Hello World";
// text = vnConversationAdd(&scene->conversation);
// text->text = "How are you today?";
text = vnCharacterConversationSetTalking(
&scene->character1, &scene->conversation, false
);
assetTextureLoad(&scene->pennyEyes, "characters/penny/textures/eyes_sm.png");
assetTextureLoad(&scene->pennyBody, "characters/penny/textures/body_sm.png");
assetTextureLoad(&scene->pennyMouth,"characters/penny/textures/mouth_sm.png");
assetTextureLoad(&scene->pennyFace, "characters/penny/textures/face_sm.png");
vnCharacterInit(&scene->character1,
&scene->pennyEyes, &scene->pennyEyes,
&scene->pennyBody, &scene->pennyBody,
&scene->pennyMouth, &scene->pennyMouth,
&scene->pennyFace &scene->pennyFace
); );
vnCharacterInit(&scene->character2,
&scene->pennyEyes,
&scene->pennyBody,
&scene->pennyMouth,
&scene->pennyFace
);
scene->character1.x = 0;
scene->character2.x = 1;
scene->character1.y = 0;
scene->character2.y = 0;
vnConversationNext(&scene->conversation);
} }
void testSceneRender(testscene_t *scene, game_t *game) { void testSceneRender(testscene_t *scene, game_t *game) {
if(false) { cameraLookAt(&scene->camera,
cameraLookAt(&scene->camera, 0.5, 0.5, 0.75,
300, 300, 300, 0.5, 0.5, -0.5
0, 0, 0 );
); cameraPerspective(&scene->camera, 75,
cameraPerspective(&scene->camera, 75, game->engine.render.width/game->engine.render.height, 0.01, 1000.0
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); shaderUse(&scene->shader);
shaderUseCamera(&scene->shader, &scene->camera); shaderUseCamera(&scene->shader, &scene->camera);
vnCharacterRender(&scene->character, &scene->shader);
// conversationUpdate(&scene->conv, &game->engine); vnCharacterUpdate(&scene->character1, &game->engine);
// conversationRender(&scene->conv, &scene->shader); vnCharacterUpdate(&scene->character2, &game->engine);
vnConversationUpdate(&scene->conversation, &game->engine);
vnCharacterRender(&scene->character1, &scene->shader);
vnCharacterRender(&scene->character2, &scene->shader);
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
);
shaderUseCamera(&scene->shader, &scene->camera);
vnConversationRender(&scene->conversation, &scene->shader);
} }

View File

@ -15,13 +15,18 @@
#include "../display/gui/font.h" #include "../display/gui/font.h"
#include "../display/texture.h" #include "../display/texture.h"
#include "../vn/vncharacter.h" #include "../vn/vncharacter.h"
#include "../vn/vnconversation.h"
#include "../vn/vncharacterconversation.h"
typedef struct { typedef struct {
shader_t shader; shader_t shader;
camera_t camera; camera_t camera;
font_t font; font_t font;
vncharacter_t character; vnconversation_t conversation;
vncharacter_t character1;
vncharacter_t character2;
texture_t pennyEyes; texture_t pennyEyes;
texture_t pennyBody; texture_t pennyBody;

View File

@ -18,7 +18,7 @@ void arrayShuffle(size_t size, void *array, int32_t arrayLength) {
for(x = 0; x < arrayLength-1; x++) { for(x = 0; x < arrayLength-1; x++) {
// Select random element from remaining elements. // Select random element from remaining elements.
y = u8randRange(x, arrayLength); y = randUint8Range(x, arrayLength);
itemDest = arrayGet(size, array, y); itemDest = arrayGet(size, array, y);
itemSource = arrayGet(size, array, x); itemSource = arrayGet(size, array, x);

View File

@ -7,12 +7,21 @@
#include "vncharacter.h" #include "vncharacter.h"
void _vnCharacterQuad(primitive_t *primitive, tilesetdiv_t *div) {
quadInit(primitive, 0,
-VN_CHARACTER_SIZE, 0, div->x0, div->y1,
VN_CHARACTER_SIZE, VN_CHARACTER_SIZE*2, div->x1, div->y0
);
}
void vnCharacterInit(vncharacter_t *character, void vnCharacterInit(vncharacter_t *character,
texture_t *textureEyes, texture_t *textureEyes,
texture_t *textureBody, texture_t *textureBody,
texture_t *textureMouth, texture_t *textureMouth,
texture_t *textureFace texture_t *textureFace
) { ) {
tilesetdiv_t div;
character->x = 0; character->x = 0;
character->y = 0; character->y = 0;
character->z = 0; character->z = 0;
@ -21,18 +30,109 @@ void vnCharacterInit(vncharacter_t *character,
character->pitch = 0; character->pitch = 0;
character->roll = 0; character->roll = 0;
character->scaleX = 1;
character->scaleY = 1;
character->talking = false;
character->blinkStart = randFloatRange(0, VN_CHARACTER_BLINK_TIME_RANGE_MAX);
// Setup Textures // Setup Textures
character->textureEyes = textureEyes; character->textureEyes = textureEyes;
character->textureBody = textureBody; character->textureBody = textureBody;
character->textureMouth = textureMouth; character->textureMouth = textureMouth;
character->textureFace = textureFace; character->textureFace = textureFace;
character->emotion = VNCHARACTER_EMOTION_NEUTRAL; // Tileset
character->talking = false; tilesetInit(&character->tilesetEyes, 1, 6,
textureEyes->width, textureEyes->height,
0, 0, 0, 0
);
tilesetInit(&character->tilesetMouth, 1, 11,
textureMouth->width, textureMouth->height,
0, 0, 0, 0
);
character->t = 0; vnCharacterSetEyes(character, 0);
vnCharacterSetMouth(character, 9);
div.x0 = 0, div.x1 = 1;
div.y0 = 0, div.y1 = 1;
_vnCharacterQuad(&character->primitiveBody, &div);
_vnCharacterQuad(&character->primitiveFace, &div);
}
void vnCharacterSetEyes(vncharacter_t *character, uint8_t eyes) {
tilesetdiv_t *div;
div = character->tilesetEyes.divisions + eyes;
_vnCharacterQuad(&character->primitiveEyes, div);
}
void vnCharacterSetMouth(vncharacter_t *character, uint8_t mouth) {
tilesetdiv_t *div;
div = character->tilesetMouth.divisions + mouth;
_vnCharacterQuad(&character->primitiveMouth, div);
}
void vnCharacterUpdate(vncharacter_t *character, engine_t *engine) {
float n;
// Update the blinking frames
n = (engine->time.current - character->blinkStart) * 1.5;
if(n >= 1) {
character->blinkStart = engine->time.current + randFloatRange(
1, VN_CHARACTER_BLINK_TIME_RANGE_MAX
);
} else if(n > 0) {
n = easeInQuad(easeTimeToForwardAndBackward(n) * 2);
vnCharacterSetEyes(character, n * character->tilesetEyes.count);
}
// Updating the talking frames
if(character->talking) {
vnCharacterSetMouth(character,
(int32_t)(engine->time.current*12) % character->tilesetMouth.count
);
} else {
vnCharacterSetMouth(character, 9);
}
// Update the scale frames
float speed, amount;
if(character->talking) {
speed = 2.5;
amount = 100;
n = easeTimeToForwardAndBackward(fmod(engine->time.current, 1 / speed) * speed) * 2;
n = easeInOutQuad(n) / amount - (1/(amount*2));
character->scaleX = 1 + n;
character->scaleY = 1 - n;
} else {
speed = 10;
amount = 50;
n = easeTimeToForwardAndBackward(fmod(engine->time.current, speed) / speed)*2;
n = easeInOutCubic(n) / amount - (1/(amount*2));
character->scaleX = 1 + n;
character->scaleY = 1 + n*2;
}
} }
void vnCharacterRender(vncharacter_t *character, shader_t *shader) { void vnCharacterRender(vncharacter_t *character, shader_t *shader) {
shaderUsePositionAndScale(shader,
character->x, character->y, character->z,
character->pitch, character->yaw, character->roll,
character->scaleX, character->scaleY, 1
);
shaderUseTexture(shader, character->textureBody);
primitiveDraw(&character->primitiveBody, 0, -1);
shaderUseTexture(shader, character->textureFace);
primitiveDraw(&character->primitiveFace, 0, -1);
shaderUseTexture(shader, character->textureEyes);
primitiveDraw(&character->primitiveEyes, 0, -1);
shaderUseTexture(shader, character->textureMouth);
primitiveDraw(&character->primitiveMouth, 0, -1);
} }

View File

@ -7,6 +7,12 @@
#pragma once #pragma once
#include <dawn/dawn.h> #include <dawn/dawn.h>
#include "../display/texture.h"
#include "../display/tileset.h"
#include "../display/primitive.h"
#include "../display/shader.h"
#include "../display/primitives/quad.h"
#include "vnconversation.h"
void vnCharacterInit(vncharacter_t *character, void vnCharacterInit(vncharacter_t *character,
texture_t *textureEyes, texture_t *textureEyes,
@ -15,4 +21,7 @@ void vnCharacterInit(vncharacter_t *character,
texture_t *textureFace texture_t *textureFace
); );
void vnCharacterSetEyes(vncharacter_t *character, uint8_t eyes);
void vnCharacterSetMouth(vncharacter_t *character, uint8_t mouth);
void vnCharacterUpdate(vncharacter_t *character, engine_t *engine);
void vnCharacterRender(vncharacter_t *character, shader_t *shader); void vnCharacterRender(vncharacter_t *character, shader_t *shader);

View File

@ -0,0 +1,35 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "vncharacterconversation.h"
void _vnCharacterConversationTalkingOn(
vnconversation_t *convo, vnconversationtext_t *text
) {
vncharacter_t *character = (vncharacter_t *)text->data;
character->talking = true;
vnConversationNext(convo);
}
void _vnCharacterConversationTalkingOff(
vnconversation_t *convo, vnconversationtext_t *text
) {
vncharacter_t *character = (vncharacter_t *)text->data;
character->talking = false;
vnConversationNext(convo);
}
vnconversationtext_t * vnCharacterConversationSetTalking(
vncharacter_t *character, vnconversation_t *conversation, bool talking
) {
vnconversationtext_t *text;
text = vnConversationAdd(conversation);
text->data = character;
text->onStart = talking ? (
&_vnCharacterConversationTalkingOn
) : &_vnCharacterConversationTalkingOff;
return text;
}

View File

@ -0,0 +1,15 @@
/**
* 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 "vncharacter.h"
#include "vnconversation.h"
vnconversationtext_t * vnCharacterConversationSetTalking(
vncharacter_t *character, vnconversation_t *conversation, bool talking
);

View File

@ -17,19 +17,31 @@ void vnConversationInit(vnconversation_t *convo, font_t *font) {
void vnConversationNext(vnconversation_t *convo) { void vnConversationNext(vnconversation_t *convo) {
vnconversationtext_t *text; vnconversationtext_t *text;
// Fire onend for current text
if(convo->textCurrent != 0xFF) {
text = convo->texts + convo->textCurrent;
if(text->onEnd != NULL) text->onEnd(convo, text);
}
// Next Text
convo->textCurrent++; convo->textCurrent++;
if(convo->textCurrent >= convo->textCount) return; if(convo->textCurrent >= convo->textCount) return;
convo->delayStart = convo->timeline; convo->delayStart = convo->timeline;
text = convo->texts + convo->textCurrent; text = convo->texts + convo->textCurrent;
if(text->text != NULL) {
vnTextBoxSetText(&convo->textbox, text->text); if(text->text != NULL) vnTextBoxSetText(&convo->textbox, text->text);
} if(text->onStart != NULL) text->onStart(convo, text);
} }
vnconversationtext_t * vnConversationAdd(vnconversation_t *conversation) { vnconversationtext_t * vnConversationAdd(vnconversation_t *conversation) {
vnconversationtext_t *text = conversation->texts + conversation->textCount; vnconversationtext_t *text = conversation->texts + conversation->textCount;
conversation->textCount++; conversation->textCount++;
text->data = NULL;
text->onStart = NULL;
text->onUpdate = NULL;
text->onEnd = NULL;
text->text = NULL; text->text = NULL;
return text; return text;
} }
@ -42,6 +54,8 @@ void vnConversationUpdate(vnconversation_t *convo, engine_t *engine) {
if(convo->textCurrent >= convo->textCount) return; if(convo->textCurrent >= convo->textCount) return;
text = convo->texts + convo->textCurrent; text = convo->texts + convo->textCurrent;
if(text->onUpdate) text->onUpdate(convo, text);
if(text->text != NULL) { if(text->text != NULL) {
vnTextBoxUpdate(&convo->textbox, engine); vnTextBoxUpdate(&convo->textbox, engine);
if(convo->textbox.state & VN_TEXTBOX_STATE_CLOSED) { if(convo->textbox.state & VN_TEXTBOX_STATE_CLOSED) {
@ -59,5 +73,8 @@ void vnConversationRender(vnconversation_t *convo, shader_t *shader) {
} }
void vnConversationDispose(vnconversation_t *convo) { void vnConversationDispose(vnconversation_t *convo) {
vnconversationtext_t *text;
text = convo->texts + convo->textCurrent;
if(text->onEnd != NULL) text->onEnd(convo, text);
vnTextBoxDispose(&convo->textbox); vnTextBoxDispose(&convo->textbox);
} }

View File

@ -13,12 +13,19 @@
/** /**
* Initialize the conversation set. After adding your first conversation element * Initialize the conversation set. After adding your first conversation element
* then ensure you call conversationNext to begin the first conversation piece. * then ensure you call vnConversationNext to begin the conversation.
* @param convo Conversation to initialize. * @param convo Conversation to initialize.
* @param font Font to initialize with. * @param font Font to initialize with.
*/ */
void vnConversationInit(vnconversation_t *convo, font_t *font); void vnConversationInit(vnconversation_t *convo, font_t *font);
/**
* Goes to the next conversation element, or start the conversation if this is
* the first element.
* @param convo Conversation to skip to the next text of.
*/
void vnConversationNext(vnconversation_t *convo);
/** /**
* Add a text element to the conversation. * Add a text element to the conversation.
* @param convo Conversation to add to. * @param convo Conversation to add to.
@ -26,6 +33,7 @@ void vnConversationInit(vnconversation_t *convo, font_t *font);
*/ */
vnconversationtext_t * vnConversationAdd(vnconversation_t *convo); vnconversationtext_t * vnConversationAdd(vnconversation_t *convo);
/** /**
* Updates the conversation logic and the wrapped textbox. * Updates the conversation logic and the wrapped textbox.
* @param convo Conversation to update. * @param convo Conversation to update.