/** * 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) { 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->layerCount = 0; character->texture = texture; character->layerEyes = 0xFF; character->layerMouth = 0xFF; character->layerEyebrows = 0xFF; character->breathing = true; character->blinkStart = 0; // Init the primitive. primitiveInit(&character->primitive, QUAD_VERTICE_COUNT * VN_CHARACTER_LAYERS_MAX, QUAD_INDICE_COUNT * VN_CHARACTER_LAYERS_MAX ); } void vnCharacterUpdate(vncharacter_t *character, engine_t *engine) { float t, n; float speed, amount; // Setup frames based on the emotion. if(character->layerEyes != 0xFF) { n = (engine->time.current-character->blinkStart)*VN_CHARACTER_BLINK_SPEED; if(n > 1.0f) { character->blinkStart = engine->time.current + randFloatRange( 1, VN_CHARACTER_BLINK_TIME_RANGE_MAX ); } else if(n > 0) { n = ( easeInQuad(animForwardAndBackwardScaled(n)) * character->layers[character->layerEyes].frames ); vnCharacterLayerSetFrame(character, character->layerEyes, (int32_t)n); } } // 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 if(character->breathing) { 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; } else { character->scaleX = 1; character->scaleY = 1; } } uint8_t vnCharacterLayerAdd(vncharacter_t *character, uint8_t frames, int16_t lx, int16_t ly, int16_t x, int16_t y, int16_t width, int16_t height ) { uint8_t i; vncharacterlayer_t *layer; i = character->layerCount++; layer = character->layers + i; layer->frames = frames; layer->lx = lx; layer->ly = ly; layer->x = x; layer->y =y; layer->width = width; layer->height = height; vnCharacterLayerSetFrame(character, i, 0); return i; } void vnCharacterLayerSetFrame(vncharacter_t *character, uint8_t l, uint8_t f) { vncharacterlayer_t *layer; vncharacterlayer_t *base; layer = character->layers + l; base = character->layers; f = f % layer->frames; float ps = 1.0f / (float)base->height; float tpx = 1.0f / (float)character->texture->width; float tpy = 1.0f / (float)character->texture->height; int32_t x = layer->x - (base->width / 2); int32_t y = layer->y + (base->height / 2); int32_t tx = layer->lx + (layer->width * f); quadBuffer(&character->primitive, 0.001f * (float)l, (float)x * ps, 1 - (float)y * ps, (float)tx * tpx, (float)layer->ly * tpy, (float)(x + layer->width) * ps, 1 - (float)(y + layer->height) * ps, (float)(tx + layer->width) * tpx, (float)(layer->ly + layer->height) * tpy, l * QUAD_VERTICE_COUNT, l * QUAD_INDICE_COUNT ); } void vnCharacterRender( vncharacter_t *character, shader_t *shader, shaderuniform_t uniformModel, shaderuniform_t uniformTexture ) { shaderUsePositionAndScale(shader, uniformModel, character->x, character->y, character->z, character->pitch, character->yaw, character->roll, character->scaleX, character->scaleY, 1 ); shaderUseTexture(shader, uniformTexture, character->texture); primitiveDraw( &character->primitive, 0, character->layerCount * QUAD_INDICE_COUNT ); } void vnCharacterDispose(vncharacter_t *character) { primitiveDispose(&character->primitive); }