/** * Copyright (c) 2021 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "vncharacter.h" void vnCharacterInit( vncharacter_t *character, texture_t *texture, int32_t baseWidth, int32_t baseHeight, int32_t faceX, int32_t faceY, int32_t faceWidth, int32_t faceHeight ) { character->x = 0; character->y = 0; character->z = 0; character->yaw = 0; character->pitch = 0; character->roll = 0; character->scaleX = 1; character->scaleY = 1; character->texture = texture; character->talking = false; character->blinkStart = 0; character->baseWidth = baseWidth; character->baseHeight = baseHeight; character->faceX = faceX; character->faceY = faceY; character->faceWidth = faceWidth; character->faceHeight = faceHeight; character->emotion = VN_CHARACTER_EMOTION_HAPPY; // Init the primitive. primitiveInit(&character->primitive, QUAD_VERTICE_COUNT * VN_CHARACTER_QUAD_COUNT, QUAD_INDICE_COUNT * VN_CHARACTER_QUAD_COUNT ); // Buffer the base quad, this never changes (currently) _vnCharacterBuffer(character, 0, 0, baseWidth, baseHeight, 0, 0, 0); _vnCharacterFaceBuffer(character, 0, VN_CHARACTER_QUAD_EYEBROWS); _vnCharacterFaceBuffer(character, 0, VN_CHARACTER_QUAD_EYES); _vnCharacterFaceBuffer(character, 0, VN_CHARACTER_QUAD_MOUTH); } void _vnCharacterBuffer(vncharacter_t *character, int32_t x, int32_t y, int32_t width, int32_t height, int32_t tx, int32_t ty, int32_t i ) { // Calc size for each pixel. float ps = 1.0f / (float)character->baseHeight;// Prefer Height float tpx = 1.0f / (float)character->texture->width; float tpy = 1.0f / (float)character->texture->height; // Center inside the character x -= (float)character->baseWidth / 2; y += (float)character->baseHeight / 2; quadBuffer(&character->primitive, 0.001f * (float)i, (float)x * ps, 1 - (float)y * ps, (float)tx * tpx, (float)ty * tpy, (float)(x + width) * ps, 1 - (float)(y + height) * ps, (float)(tx + width) * tpx, (float)(ty + height) * tpy, i * QUAD_VERTICE_COUNT, i * QUAD_INDICE_COUNT ); } void _vnCharacterFaceBuffer(vncharacter_t *character, int32_t col, int32_t i ) { _vnCharacterBuffer(character, character->faceX, character->faceY, character->faceWidth, character->faceHeight, character->baseWidth + (character->faceWidth * col), character->faceHeight * (i -1), i ); } void vnCharacterUpdate(vncharacter_t *character, engine_t *engine) { uint8_t eyes, mouth, eyebrows; float t; // Setup frames based on the emotion. mouth = character->emotion % 0x04; eyes = (character->emotion/0x04) % 0x04; eyebrows = ((character->emotion/0x04)/0x04) % 0x05; _vnCharacterFaceBuffer(character, eyebrows, VN_CHARACTER_QUAD_EYEBROWS); _vnCharacterFaceBuffer(character, eyes, VN_CHARACTER_QUAD_EYES); mouth *= VN_CHARACTER_TALKING_FRAME_COUNT; if(character->talking) { t = animForwardAndBackwardScaled(mathModFloat( engine->time.current * animTimeScaleFromFrameTime(3, 0.2f), 1.0f )); mouth += (uint8_t)(t * VN_CHARACTER_TALKING_FRAME_COUNT); } _vnCharacterFaceBuffer(character, mouth, VN_CHARACTER_QUAD_MOUTH); // float n; // // Update the blinking frames // n = (engine->time.current - character->blinkStart) * 3.0f; // if(n > 1.0f) { // character->blinkStart = engine->time.current + randFloatRange( // 1, VN_CHARACTER_BLINK_TIME_RANGE_MAX // ); // } else if(n > 0) { // n = easeInQuad(easeTimeToForwardAndBackward(n) * 4); // _vnCharacterFaceBuffer(character, // (int32_t)n, 1, VN_CHARACTER_QUAD_EYES // ); // } // if(character->talking) { // n = easeTimeToForwardAndBackward( // mathModFloat(engine->time.current * 1.6, 1) // ) * 6.0f; // _vnCharacterFaceBuffer(character, // (int32_t)n, 2, VN_CHARACTER_QUAD_MOUTH // ); // } else { // _vnCharacterFaceBuffer(character, // 0, 2, VN_CHARACTER_QUAD_MOUTH // ); // } // Update the scale frames for breathing / talk breathing float speed, amount; speed = 0.2f; amount = 90.0f; t = animForwardAndBackwardScaled( mathModFloat(engine->time.current, 1 / speed) * speed ); t = easeInOutQuad(t) / amount - (1/(amount*2)); character->scaleX = 1 + t; character->scaleY = 1 - t; } 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->texture); primitiveDraw(&character->primitive, 0, -1); } void vnCharacterDispose(vncharacter_t *character) { primitiveDispose(&character->primitive); }