From 3c07ad6b0b841202836fe72904f3607fd038bf3f Mon Sep 17 00:00:00 2001 From: bjorn Date: Fri, 24 May 2019 15:14:09 -0700 Subject: [PATCH] Replace Animator with Model:animate; --- src/api/api.h | 1 - src/api/l_animator.c | 217 ------------------------ src/api/l_graphics.c | 13 +- src/api/l_model.c | 36 ++-- src/modules/data/modelData.c | 7 +- src/modules/data/modelData.h | 8 +- src/modules/data/modelData_gltf.c | 26 ++- src/modules/data/modelData_obj.c | 4 +- src/modules/graphics/animator.c | 269 ------------------------------ src/modules/graphics/animator.h | 50 ------ src/modules/graphics/model.c | 160 ++++++++++++++---- src/modules/graphics/model.h | 24 +-- src/modules/headset/openvr.c | 4 +- 13 files changed, 181 insertions(+), 638 deletions(-) delete mode 100644 src/api/l_animator.c delete mode 100644 src/modules/graphics/animator.c delete mode 100644 src/modules/graphics/animator.h diff --git a/src/api/api.h b/src/api/api.h index 8b51bb74..3935d63d 100644 --- a/src/api/api.h +++ b/src/api/api.h @@ -17,7 +17,6 @@ extern const luaL_Reg lovrModules[]; // Objects extern const luaL_Reg lovrLightUserdata[]; -extern const luaL_Reg lovrAnimator[]; extern const luaL_Reg lovrAudioStream[]; extern const luaL_Reg lovrBallJoint[]; extern const luaL_Reg lovrBlob[]; diff --git a/src/api/l_animator.c b/src/api/l_animator.c deleted file mode 100644 index 674e6fd8..00000000 --- a/src/api/l_animator.c +++ /dev/null @@ -1,217 +0,0 @@ -#include "api.h" -#include "graphics/animator.h" - -static uint32_t luax_checkanimation(lua_State* L, int index, Animator* animator) { - switch (lua_type(L, index)) { - case LUA_TNUMBER: { - uint32_t i = lua_tointeger(L, index); - lovrAssert(i >= 1 && i <= lovrAnimatorGetAnimationCount(animator), "Invalid animation '%d'", i); - return i - 1; - } - case LUA_TSTRING: { - const char* name = lua_tostring(L, index); - uint32_t* i = lovrAnimatorGetAnimationIndex(animator, name); - lovrAssert(i, "Unknown animation '%s'", name); - return *i; - } - default: - luaL_typerror(L, index, "number or string"); - return ~0u; - } -} - -static int l_lovrAnimatorReset(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - lovrAnimatorReset(animator); - return 0; -} - -static int l_lovrAnimatorUpdate(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - float dt = luax_checkfloat(L, 2); - lovrAnimatorUpdate(animator, dt); - return 0; -} - -static int l_lovrAnimatorGetAnimationCount(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - lua_pushnumber(L, lovrAnimatorGetAnimationCount(animator)); - return 1; -} - -static int l_lovrAnimatorGetAnimationNames(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - int animationCount = lovrAnimatorGetAnimationCount(animator); - - if (lua_istable(L, 2)) { - lua_settop(L, 2); - } else { - lua_settop(L, 1); - lua_createtable(L, animationCount, 0); - } - - for (int i = 0; i < animationCount; i++) { - lua_pushstring(L, lovrAnimatorGetAnimationName(animator, i)); - lua_rawseti(L, -2, i + 1); - } - - return 1; -} - -static int l_lovrAnimatorPlay(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - int animation = luax_checkanimation(L, 2, animator); - lovrAnimatorPlay(animator, animation); - return 0; -} - -static int l_lovrAnimatorStop(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - int animation = luax_checkanimation(L, 2, animator); - lovrAnimatorStop(animator, animation); - return 0; -} - -static int l_lovrAnimatorPause(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - int animation = luax_checkanimation(L, 2, animator); - lovrAnimatorPause(animator, animation); - return 0; -} - -static int l_lovrAnimatorResume(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - int animation = luax_checkanimation(L, 2, animator); - lovrAnimatorResume(animator, animation); - return 0; -} - -static int l_lovrAnimatorSeek(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - int animation = luax_checkanimation(L, 2, animator); - float time = luax_checkfloat(L, 3); - lovrAnimatorSeek(animator, animation, time); - return 0; -} - -static int l_lovrAnimatorTell(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - int animation = luax_checkanimation(L, 2, animator); - float time = lovrAnimatorTell(animator, animation); - lua_pushnumber(L, time); - return 1; -} - -static int l_lovrAnimatorGetAlpha(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - int animation = luax_checkanimation(L, 2, animator); - float alpha = lovrAnimatorGetAlpha(animator, animation); - lua_pushnumber(L, alpha); - return 1; -} - -static int l_lovrAnimatorSetAlpha(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - int animation = luax_checkanimation(L, 2, animator); - float alpha = luax_checkfloat(L, 3); - lovrAnimatorSetAlpha(animator, animation, alpha); - return 0; -} - -static int l_lovrAnimatorGetDuration(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - int animation = luax_checkanimation(L, 2, animator); - float duration = lovrAnimatorGetDuration(animator, animation); - lua_pushnumber(L, duration); - return 1; -} - -static int l_lovrAnimatorIsPlaying(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - int animation = luax_checkanimation(L, 2, animator); - bool playing = lovrAnimatorIsPlaying(animator, animation); - lua_pushboolean(L, playing); - return 1; -} - -static int l_lovrAnimatorIsLooping(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - int animation = luax_checkanimation(L, 2, animator); - bool looping = lovrAnimatorIsLooping(animator, animation); - lua_pushboolean(L, looping); - return 1; -} - -static int l_lovrAnimatorSetLooping(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - int animation = luax_checkanimation(L, 2, animator); - bool looping = lua_toboolean(L, 3); - lovrAnimatorSetLooping(animator, animation, looping); - return 0; -} - -static int l_lovrAnimatorGetPriority(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - int animation = luax_checkanimation(L, 2, animator); - int priority = lovrAnimatorGetPriority(animator, animation); - lua_pushinteger(L, priority); - return 1; -} - -static int l_lovrAnimatorSetPriority(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - int animation = luax_checkanimation(L, 2, animator); - int priority = luaL_checkinteger(L, 3); - lovrAnimatorSetPriority(animator, animation, priority); - return 0; -} - -static int l_lovrAnimatorGetSpeed(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - if (lua_isnoneornil(L, 2)) { - float speed = lovrAnimatorGetSpeed(animator, -1); - lua_pushnumber(L, speed); - } else { - int animation = luax_checkanimation(L, 2, animator); - float speed = lovrAnimatorGetSpeed(animator, animation); - lua_pushnumber(L, speed); - } - return 1; -} - -static int l_lovrAnimatorSetSpeed(lua_State* L) { - Animator* animator = luax_checktype(L, 1, Animator); - if (lua_isnoneornil(L, 2)) { - float speed = luax_checkfloat(L, 2); - lovrAnimatorSetSpeed(animator, -1, speed); - } else { - int animation = luax_checkanimation(L, 2, animator); - float speed = luax_checkfloat(L, 3); - lovrAnimatorSetSpeed(animator, animation, speed); - } - return 0; -} - -const luaL_Reg lovrAnimator[] = { - { "reset", l_lovrAnimatorReset }, - { "update", l_lovrAnimatorUpdate }, - { "getAnimationCount", l_lovrAnimatorGetAnimationCount }, - { "getAnimationNames", l_lovrAnimatorGetAnimationNames }, - { "play", l_lovrAnimatorPlay }, - { "stop", l_lovrAnimatorStop }, - { "pause", l_lovrAnimatorPause }, - { "resume", l_lovrAnimatorResume }, - { "seek", l_lovrAnimatorSeek }, - { "tell", l_lovrAnimatorTell }, - { "getAlpha", l_lovrAnimatorGetAlpha }, - { "setAlpha", l_lovrAnimatorSetAlpha }, - { "getDuration", l_lovrAnimatorGetDuration }, - { "isPlaying", l_lovrAnimatorIsPlaying }, - { "isLooping", l_lovrAnimatorIsLooping }, - { "setLooping", l_lovrAnimatorSetLooping }, - { "getPriority", l_lovrAnimatorGetPriority }, - { "setPriority", l_lovrAnimatorSetPriority }, - { "getSpeed", l_lovrAnimatorGetSpeed }, - { "setSpeed", l_lovrAnimatorSetSpeed }, - { NULL, NULL } -}; diff --git a/src/api/l_graphics.c b/src/api/l_graphics.c index 25c7ac62..7b25e0ac 100644 --- a/src/api/l_graphics.c +++ b/src/api/l_graphics.c @@ -1,6 +1,5 @@ #include "api.h" #include "graphics/graphics.h" -#include "graphics/animator.h" #include "graphics/buffer.h" #include "graphics/canvas.h" #include "graphics/material.h" @@ -973,14 +972,6 @@ static int l_lovrGraphicsCompute(lua_State* L) { // Types -static int l_lovrGraphicsNewAnimator(lua_State* L) { - Model* model = luax_checktype(L, 1, Model); - Animator* animator = lovrAnimatorCreate(model->data); - luax_pushtype(L, Animator, animator); - lovrRelease(Animator, animator); - return 1; -} - static void luax_checkuniformtype(lua_State* L, int index, UniformType* baseType, int* components) { size_t length; lovrAssert(lua_type(L, index) == LUA_TSTRING, "Uniform types must be strings, got %s", lua_typename(L, index)); @@ -1674,7 +1665,6 @@ static const luaL_Reg lovrGraphics[] = { { "compute", l_lovrGraphicsCompute }, // Types - { "newAnimator", l_lovrGraphicsNewAnimator }, { "newCanvas", l_lovrGraphicsNewCanvas }, { "newFont", l_lovrGraphicsNewFont }, { "newMaterial", l_lovrGraphicsNewMaterial }, @@ -1691,7 +1681,7 @@ static const luaL_Reg lovrGraphics[] = { int luaopen_lovr_graphics(lua_State* L) { lua_newtable(L); luaL_register(L, NULL, lovrGraphics); - luax_registertype(L, Animator); + luax_registertype(L, Canvas); luax_registertype(L, Font); luax_registertype(L, Material); luax_registertype(L, Mesh); @@ -1699,7 +1689,6 @@ int luaopen_lovr_graphics(lua_State* L) { luax_registertype(L, Shader); luax_registertype(L, ShaderBlock); luax_registertype(L, Texture); - luax_registertype(L, Canvas); lovrGraphicsInit(); luax_pushconf(L); diff --git a/src/api/l_model.c b/src/api/l_model.c index 5a661e64..2258c518 100644 --- a/src/api/l_model.c +++ b/src/api/l_model.c @@ -1,7 +1,7 @@ #include "api.h" -#include "graphics/animator.h" #include "graphics/material.h" #include "graphics/model.h" +#include "data/modelData.h" static int l_lovrModelDraw(lua_State* L) { Model* model = luax_checktype(L, 1, Model); @@ -12,20 +12,29 @@ static int l_lovrModelDraw(lua_State* L) { return 0; } -static int l_lovrModelGetAnimator(lua_State* L) { +static int l_lovrModelAnimate(lua_State* L) { Model* model = luax_checktype(L, 1, Model); - luax_pushtype(L, Aniamtor, lovrModelGetAnimator(model)); - return 1; -} -static int l_lovrModelSetAnimator(lua_State* L) { - Model* model = luax_checktype(L, 1, Model); - if (lua_isnoneornil(L, 2)) { - lovrModelSetAnimator(model, NULL); - } else { - Animator* animator = luax_checktype(L, 2, Animator); - lovrModelSetAnimator(model, animator); + uint32_t animation = ~0u; + switch (lua_type(L, 2)) { + case LUA_TSTRING: { + const char* name = lua_tostring(L, 2); + ModelData* modelData = lovrModelGetModelData(model); + uint32_t* index = map_get(&modelData->animationMap, name); + lovrAssert(index, "Model has no animation named '%s'", name); + animation = *index; + break; + } + case LUA_TNUMBER: + animation = lua_tointeger(L, 2) - 1; + break; + default: + return luaL_typerror(L, 2, "number or string"); } + + float time = luaL_checknumber(L, 3); + float alpha = luax_optfloat(L, 4, 1.f); + lovrModelAnimate(model, animation, time, alpha); return 0; } @@ -59,8 +68,7 @@ static int l_lovrModelGetAABB(lua_State* L) { const luaL_Reg lovrModel[] = { { "draw", l_lovrModelDraw }, - { "getAnimator", l_lovrModelGetAnimator }, - { "setAnimator", l_lovrModelSetAnimator }, + { "animate", l_lovrModelAnimate }, { "getMaterial", l_lovrModelGetMaterial }, { "setMaterial", l_lovrModelSetMaterial }, { "getAABB", l_lovrModelGetAABB }, diff --git a/src/modules/data/modelData.c b/src/modules/data/modelData.c index d68d967f..5e652a87 100644 --- a/src/modules/data/modelData.c +++ b/src/modules/data/modelData.c @@ -23,6 +23,8 @@ void lovrModelDataDestroy(void* ref) { for (uint32_t i = 0; i < model->textureCount; i++) { lovrRelease(TextureData, model->textures[i]); } + map_deinit(&model->animationMap); + map_deinit(&model->nodeMap); free(model->data); } @@ -42,7 +44,6 @@ void lovrModelDataAllocate(ModelData* model) { totalSize += sizes[9] = model->channelCount * sizeof(ModelAnimationChannel); totalSize += sizes[10] = model->childCount * sizeof(uint32_t); totalSize += sizes[11] = model->jointCount * sizeof(uint32_t); - totalSize += sizes[12] = model->charCount * sizeof(char); size_t offset = 0; char* p = model->data = calloc(1, totalSize); @@ -59,5 +60,7 @@ void lovrModelDataAllocate(ModelData* model) { model->channels = (ModelAnimationChannel*) (p + offset), offset += sizes[9]; model->children = (uint32_t*) (p + offset), offset += sizes[10]; model->joints = (uint32_t*) (p + offset), offset += sizes[11]; - model->chars = (char*) (p + offset), offset += sizes[12]; + + map_init(&model->animationMap); + map_init(&model->nodeMap); } diff --git a/src/modules/data/modelData.h b/src/modules/data/modelData.h index 68161575..ce636df2 100644 --- a/src/modules/data/modelData.h +++ b/src/modules/data/modelData.h @@ -1,4 +1,5 @@ #include "util.h" +#include "lib/map/map.h" #include #include #include @@ -133,7 +134,6 @@ typedef struct { } ModelAnimationChannel; typedef struct { - const char* name; ModelAnimationChannel* channels; uint32_t channelCount; float duration; @@ -164,6 +164,7 @@ typedef struct { uint32_t primitiveIndex; uint32_t primitiveCount; uint32_t skin; + bool matrix; } ModelNode; typedef struct { @@ -198,11 +199,12 @@ typedef struct ModelData { ModelAnimationChannel* channels; uint32_t* children; uint32_t* joints; - char* chars; uint32_t channelCount; uint32_t childCount; uint32_t jointCount; - uint32_t charCount; + + map_t(uint32_t) animationMap; + map_t(uint32_t) nodeMap; } ModelData; ModelData* lovrModelDataInit(ModelData* model, struct Blob* blob); diff --git a/src/modules/data/modelData_gltf.c b/src/modules/data/modelData_gltf.c index 7fd8d53d..977e3904 100644 --- a/src/modules/data/modelData_gltf.c +++ b/src/modules/data/modelData_gltf.c @@ -271,7 +271,6 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source) { gltfString key = NOM_STR(json, t); if (STR_EQ(key, "channels")) { model->channelCount += t->size; } else if (STR_EQ(key, "samplers")) { samplerCount += t->size; } - else if (STR_EQ(key, "name")) { model->charCount += t->end - t->start + 1; } t += NOM_VALUE(json, t); } } @@ -576,7 +575,6 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source) { ModelAnimation* animation = model->animations; for (int i = (token++)->size; i > 0; i--, animation++) { int samplerCount = 0; - animation->name = NULL; for (int k = (token++)->size; k > 0; k--) { gltfString key = NOM_STR(json, token); if (STR_EQ(key, "channels")) { @@ -635,10 +633,9 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source) { token += NOM_VALUE(json, token); } else if (STR_EQ(key, "name")) { gltfString name = NOM_STR(json, token); - memcpy(model->chars, name.data, name.length); - model->chars[name.length] = '\0'; - animation->name = model->chars; - model->chars += name.length; + name.data[name.length] = '\0'; + map_set(&model->animationMap, name.data, model->animationCount - i); + name.data[name.length] = '"'; } else { token += NOM_VALUE(json, token); } @@ -802,7 +799,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source) { vec3 translation = vec3_set(node->translation, 0.f, 0.f, 0.f); quat rotation = quat_set(node->rotation, 0.f, 0.f, 0.f, 1.f); vec3 scale = vec3_set(node->scale, 1.f, 1.f, 1.f); - bool matrix = false; + node->matrix = false; node->primitiveCount = 0; node->skin = ~0u; @@ -822,7 +819,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source) { } } else if (STR_EQ(key, "matrix")) { lovrAssert((token++)->size == 16, "Node matrix needs 16 elements"); - matrix = true; + node->matrix = true; for (int j = 0; j < 16; j++) { node->transform[j] = NOM_FLOAT(json, token); } @@ -842,18 +839,15 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source) { scale[0] = NOM_FLOAT(json, token); scale[1] = NOM_FLOAT(json, token); scale[2] = NOM_FLOAT(json, token); + } else if (STR_EQ(key, "name")) { + gltfString name = NOM_STR(json, token); + name.data[name.length] = '\0'; + map_set(&model->nodeMap, name.data, model->nodeCount - i); + name.data[name.length] = '"'; } else { token += NOM_VALUE(json, token); } } - - // Fix it in post - if (!matrix) { - mat4_identity(node->transform); - mat4_translate(node->transform, translation[0], translation[1], translation[2]); - mat4_rotateQuat(node->transform, rotation); - mat4_scale(node->transform, scale[0], scale[1], scale[2]); - } } } diff --git a/src/modules/data/modelData_obj.c b/src/modules/data/modelData_obj.c index 3fb343d6..01a9de73 100644 --- a/src/modules/data/modelData_obj.c +++ b/src/modules/data/modelData_obj.c @@ -304,7 +304,9 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) { model->nodes[0] = (ModelNode) { .transform = MAT4_IDENTITY, .primitiveIndex = 0, - .primitiveCount = groups.length + .primitiveCount = groups.length, + .skin = ~0u, + .matrix = true }; arr_free(&groups); diff --git a/src/modules/graphics/animator.c b/src/modules/graphics/animator.c deleted file mode 100644 index c27b3959..00000000 --- a/src/modules/graphics/animator.c +++ /dev/null @@ -1,269 +0,0 @@ -#include "graphics/animator.h" -#include "data/modelData.h" -#include "core/maf.h" -#include "core/ref.h" -#include -#include - -static int trackSortCallback(const void* a, const void* b) { - return ((Track*) a)->priority < ((Track*) b)->priority; -} - -Animator* lovrAnimatorInit(Animator* animator, ModelData* data) { - lovrRetain(data); - animator->data = data; - map_init(&animator->animations); - arr_init(&animator->tracks); - arr_reserve(&animator->tracks, data->animationCount); - animator->speed = 1.f; - - for (uint32_t i = 0; i < data->animationCount; i++) { - arr_push(&animator->tracks, ((Track) { - .time = 0.f, - .speed = 1.f, - .alpha = 1.f, - .priority = 0, - .playing = false, - .looping = false - })); - - if (data->animations[i].name) { - map_set(&animator->animations, data->animations[i].name, i); - } - } - - return animator; -} - -void lovrAnimatorDestroy(void* ref) { - Animator* animator = ref; - lovrRelease(ModelData, animator->data); - arr_free(&animator->tracks); -} - -void lovrAnimatorReset(Animator* animator) { - for (size_t i = 0; i < animator->tracks.length; i++) { - Track* track = &animator->tracks.data[i]; - track->time = 0.f; - track->speed = 1.f; - track->playing = false; - track->looping = false; - } - animator->speed = 1.f; -} - -void lovrAnimatorUpdate(Animator* animator, float dt) { - for (size_t i = 0; i < animator->tracks.length; i++) { - Track* track = &animator->tracks.data[i]; - if (track->playing) { - track->time += dt * track->speed * animator->speed; - float duration = animator->data->animations[i].duration; - - if (track->looping) { - track->time = fmodf(track->time, duration); - } else if (track->time > duration || track->time < 0) { - track->time = 0; - track->playing = false; - } - } - } -} - -bool lovrAnimatorEvaluate(Animator* animator, uint32_t nodeIndex, mat4 transform) { - float properties[3][4]; - ModelNode* node = &animator->data->nodes[nodeIndex]; - vec3_init(properties[PROP_TRANSLATION], node->translation); - quat_init(properties[PROP_ROTATION], node->rotation); - vec3_init(properties[PROP_SCALE], node->scale); - bool touched = false; - - for (uint32_t i = 0; i < animator->data->animationCount; i++) { - ModelAnimation* animation = &animator->data->animations[i]; - - for (uint32_t j = 0; j < animation->channelCount; j++) { - ModelAnimationChannel* channel = &animation->channels[j]; - if (channel->nodeIndex != nodeIndex) { - continue; - } - - Track* track = &animator->tracks.data[i]; - if (!track->playing || track->alpha == 0.f) { - continue; - } - - float duration = animator->data->animations[i].duration; - float time = fmodf(track->time, duration); - uint32_t k = 0; - - while (k < channel->keyframeCount && channel->times[k] < time) { - k++; - } - - float value[4]; - bool rotate = channel->property == PROP_ROTATION; - size_t n = 3 + rotate; - float* (*lerp)(float* a, float* b, float t) = rotate ? quat_slerp : vec3_lerp; - - if (k < channel->keyframeCount) { - float t1 = channel->times[k - 1]; - float t2 = channel->times[k]; - float z = (time - t1) / (t2 - t1); - float next[4]; - - memcpy(value, channel->data + (k - 1) * n, n * sizeof(float)); - memcpy(next, channel->data + k * n, n * sizeof(float)); - - switch (channel->smoothing) { - case SMOOTH_STEP: - if (z >= .5f) { - memcpy(value, next, n * sizeof(float)); - } - break; - case SMOOTH_LINEAR: lerp(value, next, z); break; - case SMOOTH_CUBIC: lovrThrow("Cubic spline interpolation is not supported yet"); break; - default: break; - } - } else { - memcpy(value, channel->data + CLAMP(k, 0, channel->keyframeCount - 1) * n, n * sizeof(float)); - } - - if (track->alpha == 1.f) { - memcpy(properties[channel->property], value, n * sizeof(float)); - } else { - lerp(properties[channel->property], value, track->alpha); - } - - touched = true; - } - } - - if (touched) { - vec3 T = properties[PROP_TRANSLATION]; - quat R = properties[PROP_ROTATION]; - vec3 S = properties[PROP_SCALE]; - mat4_translate(transform, T[0], T[1], T[2]); - mat4_rotateQuat(transform, R); - mat4_scale(transform, S[0], S[1], S[2]); - } else { - mat4_multiply(transform, node->transform); - } - - return touched; -} - -uint32_t lovrAnimatorGetAnimationCount(Animator* animator) { - return animator->data->animationCount; -} - -uint32_t* lovrAnimatorGetAnimationIndex(Animator* animator, const char* name) { - return map_get(&animator->animations, name); -} - -const char* lovrAnimatorGetAnimationName(Animator* animator, uint32_t index) { - return animator->data->animations[index].name; -} - -void lovrAnimatorPlay(Animator* animator, uint32_t animation) { - Track* track = &animator->tracks.data[animation]; - track->playing = true; - track->time = 0.f; -} - -void lovrAnimatorStop(Animator* animator, uint32_t animation) { - Track* track = &animator->tracks.data[animation]; - track->playing = false; - track->time = 0.f; -} - -void lovrAnimatorPause(Animator* animator, uint32_t animation) { - Track* track = &animator->tracks.data[animation]; - track->playing = false; -} - -void lovrAnimatorResume(Animator* animator, uint32_t animation) { - Track* track = &animator->tracks.data[animation]; - track->playing = true; -} - -void lovrAnimatorSeek(Animator* animator, uint32_t animation, float time) { - Track* track = &animator->tracks.data[animation]; - float duration = animator->data->animations[animation].duration; - - while (time > duration) { - time -= duration; - } - - while (time < 0.f) { - time += duration; - } - - track->time = time; - - if (!track->looping) { - track->time = MIN(track->time, duration); - track->time = MAX(track->time, 0); - } -} - -float lovrAnimatorTell(Animator* animator, uint32_t animation) { - Track* track = &animator->tracks.data[animation]; - return track->time; -} - -float lovrAnimatorGetAlpha(Animator* animator, uint32_t animation) { - Track* track = &animator->tracks.data[animation]; - return track->alpha; -} - -void lovrAnimatorSetAlpha(Animator* animator, uint32_t animation, float alpha) { - Track* track = &animator->tracks.data[animation]; - track->alpha = alpha; -} - -float lovrAnimatorGetDuration(Animator* animator, uint32_t animation) { - return animator->data->animations[animation].duration; -} - -bool lovrAnimatorIsPlaying(Animator* animator, uint32_t animation) { - Track* track = &animator->tracks.data[animation]; - return track->playing; -} - -bool lovrAnimatorIsLooping(Animator* animator, uint32_t animation) { - Track* track = &animator->tracks.data[animation]; - return track->looping; -} - -void lovrAnimatorSetLooping(Animator* animator, uint32_t animation, bool loop) { - Track* track = &animator->tracks.data[animation]; - track->looping = loop; -} - -int32_t lovrAnimatorGetPriority(Animator* animator, uint32_t animation) { - Track* track = &animator->tracks.data[animation]; - return track->priority; -} - -void lovrAnimatorSetPriority(Animator* animator, uint32_t animation, int32_t priority) { - Track* track = &animator->tracks.data[animation]; - track->priority = priority; - qsort(animator->tracks.data, animator->tracks.length, sizeof(Track), trackSortCallback); -} - -float lovrAnimatorGetSpeed(Animator* animator, uint32_t animation) { - if (animation == ~0u) { - return animator->speed; - } - - Track* track = &animator->tracks.data[animation]; - return track->speed; -} - -void lovrAnimatorSetSpeed(Animator* animator, uint32_t animation, float speed) { - if (animation == ~0u) { - animator->speed = speed; - } - - Track* track = &animator->tracks.data[animation]; - track->speed = speed; -} diff --git a/src/modules/graphics/animator.h b/src/modules/graphics/animator.h deleted file mode 100644 index 0a333099..00000000 --- a/src/modules/graphics/animator.h +++ /dev/null @@ -1,50 +0,0 @@ -#include "core/arr.h" -#include "lib/map/map.h" -#include -#include - -#pragma once - -struct ModelData; - -typedef struct { - float time; - float speed; - float alpha; - int32_t priority; - bool playing; - bool looping; -} Track; - -typedef struct Animator { - struct ModelData* data; - map_t(uint32_t) animations; - arr_t(Track, 1) tracks; - float speed; -} Animator; - -Animator* lovrAnimatorInit(Animator* animator, struct ModelData* modelData); -#define lovrAnimatorCreate(...) lovrAnimatorInit(lovrAlloc(Animator), __VA_ARGS__) -void lovrAnimatorDestroy(void* ref); -void lovrAnimatorReset(Animator* animator); -void lovrAnimatorUpdate(Animator* animator, float dt); -bool lovrAnimatorEvaluate(Animator* animator, uint32_t nodeIndex, float* transform); -uint32_t lovrAnimatorGetAnimationCount(Animator* animator); -uint32_t* lovrAnimatorGetAnimationIndex(Animator* animator, const char* name); -const char* lovrAnimatorGetAnimationName(Animator* animator, uint32_t index); -void lovrAnimatorPlay(Animator* animator, uint32_t animation); -void lovrAnimatorStop(Animator* animator, uint32_t animation); -void lovrAnimatorPause(Animator* animator, uint32_t animation); -void lovrAnimatorResume(Animator* animator, uint32_t animation); -void lovrAnimatorSeek(Animator* animator, uint32_t animation, float time); -float lovrAnimatorTell(Animator* animator, uint32_t animation); -float lovrAnimatorGetAlpha(Animator* animator, uint32_t animation); -void lovrAnimatorSetAlpha(Animator* animator, uint32_t animation, float alpha); -float lovrAnimatorGetDuration(Animator* animator, uint32_t animation); -bool lovrAnimatorIsPlaying(Animator* animator, uint32_t animation); -bool lovrAnimatorIsLooping(Animator* animator, uint32_t animation); -void lovrAnimatorSetLooping(Animator* animator, uint32_t animation, bool loop); -int32_t lovrAnimatorGetPriority(Animator* animator, uint32_t animation); -void lovrAnimatorSetPriority(Animator* animator, uint32_t animation, int32_t priority); -float lovrAnimatorGetSpeed(Animator* animator, uint32_t animation); -void lovrAnimatorSetSpeed(Animator* animator, uint32_t animation, float speed); diff --git a/src/modules/graphics/model.c b/src/modules/graphics/model.c index 65437387..e1b94344 100644 --- a/src/modules/graphics/model.c +++ b/src/modules/graphics/model.c @@ -1,45 +1,67 @@ #include "graphics/model.h" -#include "graphics/animator.h" #include "graphics/buffer.h" #include "graphics/graphics.h" #include "graphics/material.h" #include "graphics/mesh.h" #include "graphics/texture.h" #include "resources/shaders.h" +#include "core/maf.h" #include "core/ref.h" #include #include +#include -static void updateGlobalNodeTransform(Model* model, uint32_t nodeIndex, mat4 transform) { +typedef struct { + float properties[3][4]; +} NodeTransform; + +struct Model { + struct ModelData* data; + struct Buffer** buffers; + struct Mesh** meshes; + struct Texture** textures; + struct Material** materials; + struct Material* userMaterial; + NodeTransform* localTransforms; + float* globalTransforms; + bool transformsDirty; +}; + +static void updateGlobalTransform(Model* model, uint32_t nodeIndex, mat4 parent) { ModelNode* node = &model->data->nodes[nodeIndex]; + mat4 global = model->globalTransforms + 16 * nodeIndex; + mat4_init(global, parent); - mat4 globalTransform = model->globalNodeTransforms + 16 * nodeIndex; - mat4_set(globalTransform, transform); - - if (model->animator) { - lovrAnimatorEvaluate(model->animator, nodeIndex, globalTransform); + if (node->matrix) { + mat4_multiply(global, node->transform); } else { - mat4_multiply(globalTransform, node->transform); + NodeTransform* local = &model->localTransforms[nodeIndex]; + vec3 T = local->properties[PROP_TRANSLATION]; + quat R = local->properties[PROP_ROTATION]; + vec3 S = local->properties[PROP_SCALE]; + mat4_translate(global, T[0], T[1], T[2]); + mat4_rotateQuat(global, R); + mat4_scale(global, S[0], S[1], S[2]); } for (uint32_t i = 0; i < node->childCount; i++) { - updateGlobalNodeTransform(model, node->children[i], globalTransform); + updateGlobalTransform(model, node->children[i], global); } } static void renderNode(Model* model, uint32_t nodeIndex, uint32_t instances) { ModelNode* node = &model->data->nodes[nodeIndex]; - mat4 globalTransform = model->globalNodeTransforms + 16 * nodeIndex; + mat4 globalTransform = model->globalTransforms + 16 * nodeIndex; if (node->primitiveCount > 0) { - bool animated = node->skin != ~0u && model->animator; + bool animated = node->skin != ~0u; float pose[16 * MAX_BONES]; if (animated) { ModelSkin* skin = &model->data->skins[node->skin]; for (uint32_t j = 0; j < skin->jointCount; j++) { - mat4 globalJointTransform = model->globalNodeTransforms + 16 * skin->joints[j]; + mat4 globalJointTransform = model->globalTransforms + 16 * skin->joints[j]; mat4 inverseBindMatrix = skin->inverseBindMatrices + 16 * j; mat4 jointPose = pose + 16 * j; @@ -65,7 +87,8 @@ static void renderNode(Model* model, uint32_t nodeIndex, uint32_t instances) { } } -Model* lovrModelInit(Model* model, ModelData* data) { +Model* lovrModelCreate(ModelData* data) { + Model* model = lovrAlloc(Model); model->data = data; lovrRetain(data); @@ -169,9 +192,20 @@ Model* lovrModelInit(Model* model, ModelData* data) { } } - model->globalNodeTransforms = malloc(16 * sizeof(float) * model->data->nodeCount); - for (uint32_t i = 0; i < model->data->nodeCount; i++) { - mat4_identity(model->globalNodeTransforms + 16 * i); + model->localTransforms = malloc(sizeof(NodeTransform) * data->nodeCount); + model->globalTransforms = malloc(16 * sizeof(float) * data->nodeCount); + model->transformsDirty = true; + + for (uint32_t i = 0; i < data->nodeCount; i++) { + if (data->nodes[i].matrix) { + vec3_set(model->localTransforms[i].properties[PROP_TRANSLATION], 0.f, 0.f, 0.f); + quat_set(model->localTransforms[i].properties[PROP_ROTATION], 0.f, 0.f, 0.f, 1.f); + vec3_set(model->localTransforms[i].properties[PROP_SCALE], 1.f, 1.f, 1.f); + } else { + vec3_init(model->localTransforms[i].properties[PROP_TRANSLATION], data->nodes[i].translation); + quat_init(model->localTransforms[i].properties[PROP_ROTATION], data->nodes[i].rotation); + vec3_init(model->localTransforms[i].properties[PROP_SCALE], data->nodes[i].scale); + } } return model; @@ -192,26 +226,82 @@ void lovrModelDestroy(void* ref) { lovrRelease(Material, model->materials[i]); } lovrRelease(Material, model->userMaterial); - lovrRelease(Animator, model->animator); lovrRelease(ModelData, model->data); - free(model->globalNodeTransforms); + free(model->globalTransforms); + free(model->localTransforms); +} + +ModelData* lovrModelGetModelData(Model* model) { + return model->data; } void lovrModelDraw(Model* model, mat4 transform, uint32_t instances) { - updateGlobalNodeTransform(model, model->data->rootNode, transform); - renderNode(model, model->data->rootNode, instances); -} - -Animator* lovrModelGetAnimator(Model* model) { - return model->animator; -} - -void lovrModelSetAnimator(Model* model, Animator* animator) { - if (model->animator != animator) { - lovrRetain(animator); - lovrRelease(Animator, model->animator); - model->animator = animator; + if (model->transformsDirty) { + updateGlobalTransform(model, model->data->rootNode, (float[]) MAT4_IDENTITY); + model->transformsDirty = false; } + + lovrGraphicsPush(); + lovrGraphicsMatrixTransform(transform); + renderNode(model, model->data->rootNode, instances); + lovrGraphicsPop(); +} + +void lovrModelAnimate(Model* model, uint32_t animationIndex, float time, float alpha) { + if (alpha == 0.f) { + return; + } + + lovrAssert(animationIndex < model->data->animationCount, "Invalid animation index #%d (Model only has %d animations)", animationIndex, model->data->animationCount); + ModelAnimation* animation = &model->data->animations[animationIndex]; + time = fmodf(time, animation->duration); + + for (uint32_t i = 0; i < animation->channelCount; i++) { + ModelAnimationChannel* channel = &animation->channels[i]; + uint32_t nodeIndex = channel->nodeIndex; + NodeTransform* transform = &model->localTransforms[nodeIndex]; + + uint32_t keyframe = 0; + while (keyframe < channel->keyframeCount && channel->times[keyframe] < time) { + keyframe++; + } + + float property[4]; + bool rotate = channel->property == PROP_ROTATION; + size_t n = 3 + rotate; + float* (*lerp)(float* a, float* b, float t) = rotate ? quat_slerp : vec3_lerp; + + if (keyframe >= channel->keyframeCount) { + memcpy(property, channel->data + CLAMP(keyframe, 0, channel->keyframeCount - 1) * n, n * sizeof(float)); + } else { + float t1 = channel->times[keyframe - 1]; + float t2 = channel->times[keyframe]; + float z = (time - t1) / (t2 - t1); + float next[4]; + + memcpy(property, channel->data + (keyframe - 1) * n, n * sizeof(float)); + memcpy(next, channel->data + keyframe * n, n * sizeof(float)); + + switch (channel->smoothing) { + case SMOOTH_STEP: + if (z >= .5f) { + memcpy(property, next, n * sizeof(float)); + } + break; + case SMOOTH_LINEAR: lerp(property, next, z); break; + case SMOOTH_CUBIC: lovrThrow("Cubic spline interpolation is not supported yet"); break; + default: break; + } + } + + if (alpha == 1.f) { + memcpy(transform->properties[channel->property], property, n * sizeof(float)); + } else { + lerp(transform->properties[channel->property], property, alpha); + } + } + + model->transformsDirty = true; } Material* lovrModelGetMaterial(Model* model) { @@ -230,7 +320,7 @@ static void applyAABB(Model* model, uint32_t nodeIndex, float aabb[6]) { for (uint32_t i = 0; i < node->primitiveCount; i++) { ModelAttribute* position = model->data->primitives[node->primitiveIndex + i].attributes[ATTR_POSITION]; if (position && position->hasMin && position->hasMax) { - mat4 m = model->globalNodeTransforms + 16 * nodeIndex; + mat4 m = model->globalTransforms + 16 * nodeIndex; float xa[3] = { position->min[0] * m[0], position->min[0] * m[1], position->min[0] * m[2] }; float xb[3] = { position->max[0] * m[0], position->max[0] * m[1], position->max[0] * m[2] }; @@ -268,8 +358,12 @@ static void applyAABB(Model* model, uint32_t nodeIndex, float aabb[6]) { } void lovrModelGetAABB(Model* model, float aabb[6]) { + if (model->transformsDirty) { + updateGlobalTransform(model, model->data->rootNode, (float[]) MAT4_IDENTITY); + model->transformsDirty = false; + } + aabb[0] = aabb[2] = aabb[4] = FLT_MAX; aabb[1] = aabb[3] = aabb[5] = -FLT_MAX; - updateGlobalNodeTransform(model, model->data->rootNode, (float[]) MAT4_IDENTITY); applyAABB(model, model->data->rootNode, aabb); } diff --git a/src/modules/graphics/model.h b/src/modules/graphics/model.h index 57a08fe9..386cd4d0 100644 --- a/src/modules/graphics/model.h +++ b/src/modules/graphics/model.h @@ -1,31 +1,17 @@ #include +#include #pragma once -struct Animator; -struct Buffer; struct Material; -struct Mesh; struct ModelData; -struct Texture; -typedef struct { - struct ModelData* data; - struct Animator* animator; - struct Buffer** buffers; - struct Mesh** meshes; - struct Texture** textures; - struct Material** materials; - struct Material* userMaterial; - float* globalNodeTransforms; -} Model; - -Model* lovrModelInit(Model* model, struct ModelData* data); -#define lovrModelCreate(...) lovrModelInit(lovrAlloc(Model), __VA_ARGS__) +typedef struct Model Model; +Model* lovrModelCreate(struct ModelData* data); void lovrModelDestroy(void* ref); +struct ModelData* lovrModelGetModelData(Model* model); void lovrModelDraw(Model* model, float* transform, uint32_t instances); -struct Animator* lovrModelGetAnimator(Model* model); -void lovrModelSetAnimator(Model* model, struct Animator* animator); +void lovrModelAnimate(Model* model, uint32_t animationIndex, float time, float alpha); struct Material* lovrModelGetMaterial(Model* model); void lovrModelSetMaterial(Model* model, struct Material* material); void lovrModelGetAABB(Model* model, float aabb[6]); diff --git a/src/modules/headset/openvr.c b/src/modules/headset/openvr.c index fce1147b..5469850e 100644 --- a/src/modules/headset/openvr.c +++ b/src/modules/headset/openvr.c @@ -543,7 +543,9 @@ static ModelData* openvr_newModelData(Device device) { model->nodes[0] = (ModelNode) { .transform = MAT4_IDENTITY, .primitiveIndex = 0, - .primitiveCount = 1 + .primitiveCount = 1, + .skin = ~0u, + .matrix = true }; return model;