mirror of https://github.com/bjornbytes/lovr.git
Replace Animator with Model:animate;
This commit is contained in:
parent
4372eb293e
commit
3c07ad6b0b
|
@ -17,7 +17,6 @@ extern const luaL_Reg lovrModules[];
|
||||||
|
|
||||||
// Objects
|
// Objects
|
||||||
extern const luaL_Reg lovrLightUserdata[];
|
extern const luaL_Reg lovrLightUserdata[];
|
||||||
extern const luaL_Reg lovrAnimator[];
|
|
||||||
extern const luaL_Reg lovrAudioStream[];
|
extern const luaL_Reg lovrAudioStream[];
|
||||||
extern const luaL_Reg lovrBallJoint[];
|
extern const luaL_Reg lovrBallJoint[];
|
||||||
extern const luaL_Reg lovrBlob[];
|
extern const luaL_Reg lovrBlob[];
|
||||||
|
|
|
@ -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 }
|
|
||||||
};
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "api.h"
|
#include "api.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
#include "graphics/animator.h"
|
|
||||||
#include "graphics/buffer.h"
|
#include "graphics/buffer.h"
|
||||||
#include "graphics/canvas.h"
|
#include "graphics/canvas.h"
|
||||||
#include "graphics/material.h"
|
#include "graphics/material.h"
|
||||||
|
@ -973,14 +972,6 @@ static int l_lovrGraphicsCompute(lua_State* L) {
|
||||||
|
|
||||||
// Types
|
// 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) {
|
static void luax_checkuniformtype(lua_State* L, int index, UniformType* baseType, int* components) {
|
||||||
size_t length;
|
size_t length;
|
||||||
lovrAssert(lua_type(L, index) == LUA_TSTRING, "Uniform types must be strings, got %s", lua_typename(L, index));
|
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 },
|
{ "compute", l_lovrGraphicsCompute },
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
{ "newAnimator", l_lovrGraphicsNewAnimator },
|
|
||||||
{ "newCanvas", l_lovrGraphicsNewCanvas },
|
{ "newCanvas", l_lovrGraphicsNewCanvas },
|
||||||
{ "newFont", l_lovrGraphicsNewFont },
|
{ "newFont", l_lovrGraphicsNewFont },
|
||||||
{ "newMaterial", l_lovrGraphicsNewMaterial },
|
{ "newMaterial", l_lovrGraphicsNewMaterial },
|
||||||
|
@ -1691,7 +1681,7 @@ static const luaL_Reg lovrGraphics[] = {
|
||||||
int luaopen_lovr_graphics(lua_State* L) {
|
int luaopen_lovr_graphics(lua_State* L) {
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
luaL_register(L, NULL, lovrGraphics);
|
luaL_register(L, NULL, lovrGraphics);
|
||||||
luax_registertype(L, Animator);
|
luax_registertype(L, Canvas);
|
||||||
luax_registertype(L, Font);
|
luax_registertype(L, Font);
|
||||||
luax_registertype(L, Material);
|
luax_registertype(L, Material);
|
||||||
luax_registertype(L, Mesh);
|
luax_registertype(L, Mesh);
|
||||||
|
@ -1699,7 +1689,6 @@ int luaopen_lovr_graphics(lua_State* L) {
|
||||||
luax_registertype(L, Shader);
|
luax_registertype(L, Shader);
|
||||||
luax_registertype(L, ShaderBlock);
|
luax_registertype(L, ShaderBlock);
|
||||||
luax_registertype(L, Texture);
|
luax_registertype(L, Texture);
|
||||||
luax_registertype(L, Canvas);
|
|
||||||
lovrGraphicsInit();
|
lovrGraphicsInit();
|
||||||
|
|
||||||
luax_pushconf(L);
|
luax_pushconf(L);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "api.h"
|
#include "api.h"
|
||||||
#include "graphics/animator.h"
|
|
||||||
#include "graphics/material.h"
|
#include "graphics/material.h"
|
||||||
#include "graphics/model.h"
|
#include "graphics/model.h"
|
||||||
|
#include "data/modelData.h"
|
||||||
|
|
||||||
static int l_lovrModelDraw(lua_State* L) {
|
static int l_lovrModelDraw(lua_State* L) {
|
||||||
Model* model = luax_checktype(L, 1, Model);
|
Model* model = luax_checktype(L, 1, Model);
|
||||||
|
@ -12,20 +12,29 @@ static int l_lovrModelDraw(lua_State* L) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_lovrModelGetAnimator(lua_State* L) {
|
static int l_lovrModelAnimate(lua_State* L) {
|
||||||
Model* model = luax_checktype(L, 1, Model);
|
Model* model = luax_checktype(L, 1, Model);
|
||||||
luax_pushtype(L, Aniamtor, lovrModelGetAnimator(model));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int l_lovrModelSetAnimator(lua_State* L) {
|
uint32_t animation = ~0u;
|
||||||
Model* model = luax_checktype(L, 1, Model);
|
switch (lua_type(L, 2)) {
|
||||||
if (lua_isnoneornil(L, 2)) {
|
case LUA_TSTRING: {
|
||||||
lovrModelSetAnimator(model, NULL);
|
const char* name = lua_tostring(L, 2);
|
||||||
} else {
|
ModelData* modelData = lovrModelGetModelData(model);
|
||||||
Animator* animator = luax_checktype(L, 2, Animator);
|
uint32_t* index = map_get(&modelData->animationMap, name);
|
||||||
lovrModelSetAnimator(model, animator);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,8 +68,7 @@ static int l_lovrModelGetAABB(lua_State* L) {
|
||||||
|
|
||||||
const luaL_Reg lovrModel[] = {
|
const luaL_Reg lovrModel[] = {
|
||||||
{ "draw", l_lovrModelDraw },
|
{ "draw", l_lovrModelDraw },
|
||||||
{ "getAnimator", l_lovrModelGetAnimator },
|
{ "animate", l_lovrModelAnimate },
|
||||||
{ "setAnimator", l_lovrModelSetAnimator },
|
|
||||||
{ "getMaterial", l_lovrModelGetMaterial },
|
{ "getMaterial", l_lovrModelGetMaterial },
|
||||||
{ "setMaterial", l_lovrModelSetMaterial },
|
{ "setMaterial", l_lovrModelSetMaterial },
|
||||||
{ "getAABB", l_lovrModelGetAABB },
|
{ "getAABB", l_lovrModelGetAABB },
|
||||||
|
|
|
@ -23,6 +23,8 @@ void lovrModelDataDestroy(void* ref) {
|
||||||
for (uint32_t i = 0; i < model->textureCount; i++) {
|
for (uint32_t i = 0; i < model->textureCount; i++) {
|
||||||
lovrRelease(TextureData, model->textures[i]);
|
lovrRelease(TextureData, model->textures[i]);
|
||||||
}
|
}
|
||||||
|
map_deinit(&model->animationMap);
|
||||||
|
map_deinit(&model->nodeMap);
|
||||||
free(model->data);
|
free(model->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +44,6 @@ void lovrModelDataAllocate(ModelData* model) {
|
||||||
totalSize += sizes[9] = model->channelCount * sizeof(ModelAnimationChannel);
|
totalSize += sizes[9] = model->channelCount * sizeof(ModelAnimationChannel);
|
||||||
totalSize += sizes[10] = model->childCount * sizeof(uint32_t);
|
totalSize += sizes[10] = model->childCount * sizeof(uint32_t);
|
||||||
totalSize += sizes[11] = model->jointCount * sizeof(uint32_t);
|
totalSize += sizes[11] = model->jointCount * sizeof(uint32_t);
|
||||||
totalSize += sizes[12] = model->charCount * sizeof(char);
|
|
||||||
|
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
char* p = model->data = calloc(1, totalSize);
|
char* p = model->data = calloc(1, totalSize);
|
||||||
|
@ -59,5 +60,7 @@ void lovrModelDataAllocate(ModelData* model) {
|
||||||
model->channels = (ModelAnimationChannel*) (p + offset), offset += sizes[9];
|
model->channels = (ModelAnimationChannel*) (p + offset), offset += sizes[9];
|
||||||
model->children = (uint32_t*) (p + offset), offset += sizes[10];
|
model->children = (uint32_t*) (p + offset), offset += sizes[10];
|
||||||
model->joints = (uint32_t*) (p + offset), offset += sizes[11];
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "lib/map/map.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
@ -133,7 +134,6 @@ typedef struct {
|
||||||
} ModelAnimationChannel;
|
} ModelAnimationChannel;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char* name;
|
|
||||||
ModelAnimationChannel* channels;
|
ModelAnimationChannel* channels;
|
||||||
uint32_t channelCount;
|
uint32_t channelCount;
|
||||||
float duration;
|
float duration;
|
||||||
|
@ -164,6 +164,7 @@ typedef struct {
|
||||||
uint32_t primitiveIndex;
|
uint32_t primitiveIndex;
|
||||||
uint32_t primitiveCount;
|
uint32_t primitiveCount;
|
||||||
uint32_t skin;
|
uint32_t skin;
|
||||||
|
bool matrix;
|
||||||
} ModelNode;
|
} ModelNode;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -198,11 +199,12 @@ typedef struct ModelData {
|
||||||
ModelAnimationChannel* channels;
|
ModelAnimationChannel* channels;
|
||||||
uint32_t* children;
|
uint32_t* children;
|
||||||
uint32_t* joints;
|
uint32_t* joints;
|
||||||
char* chars;
|
|
||||||
uint32_t channelCount;
|
uint32_t channelCount;
|
||||||
uint32_t childCount;
|
uint32_t childCount;
|
||||||
uint32_t jointCount;
|
uint32_t jointCount;
|
||||||
uint32_t charCount;
|
|
||||||
|
map_t(uint32_t) animationMap;
|
||||||
|
map_t(uint32_t) nodeMap;
|
||||||
} ModelData;
|
} ModelData;
|
||||||
|
|
||||||
ModelData* lovrModelDataInit(ModelData* model, struct Blob* blob);
|
ModelData* lovrModelDataInit(ModelData* model, struct Blob* blob);
|
||||||
|
|
|
@ -271,7 +271,6 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source) {
|
||||||
gltfString key = NOM_STR(json, t);
|
gltfString key = NOM_STR(json, t);
|
||||||
if (STR_EQ(key, "channels")) { model->channelCount += t->size; }
|
if (STR_EQ(key, "channels")) { model->channelCount += t->size; }
|
||||||
else if (STR_EQ(key, "samplers")) { samplerCount += 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);
|
t += NOM_VALUE(json, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -576,7 +575,6 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source) {
|
||||||
ModelAnimation* animation = model->animations;
|
ModelAnimation* animation = model->animations;
|
||||||
for (int i = (token++)->size; i > 0; i--, animation++) {
|
for (int i = (token++)->size; i > 0; i--, animation++) {
|
||||||
int samplerCount = 0;
|
int samplerCount = 0;
|
||||||
animation->name = NULL;
|
|
||||||
for (int k = (token++)->size; k > 0; k--) {
|
for (int k = (token++)->size; k > 0; k--) {
|
||||||
gltfString key = NOM_STR(json, token);
|
gltfString key = NOM_STR(json, token);
|
||||||
if (STR_EQ(key, "channels")) {
|
if (STR_EQ(key, "channels")) {
|
||||||
|
@ -635,10 +633,9 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source) {
|
||||||
token += NOM_VALUE(json, token);
|
token += NOM_VALUE(json, token);
|
||||||
} else if (STR_EQ(key, "name")) {
|
} else if (STR_EQ(key, "name")) {
|
||||||
gltfString name = NOM_STR(json, token);
|
gltfString name = NOM_STR(json, token);
|
||||||
memcpy(model->chars, name.data, name.length);
|
name.data[name.length] = '\0';
|
||||||
model->chars[name.length] = '\0';
|
map_set(&model->animationMap, name.data, model->animationCount - i);
|
||||||
animation->name = model->chars;
|
name.data[name.length] = '"';
|
||||||
model->chars += name.length;
|
|
||||||
} else {
|
} else {
|
||||||
token += NOM_VALUE(json, token);
|
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);
|
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);
|
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);
|
vec3 scale = vec3_set(node->scale, 1.f, 1.f, 1.f);
|
||||||
bool matrix = false;
|
node->matrix = false;
|
||||||
node->primitiveCount = 0;
|
node->primitiveCount = 0;
|
||||||
node->skin = ~0u;
|
node->skin = ~0u;
|
||||||
|
|
||||||
|
@ -822,7 +819,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source) {
|
||||||
}
|
}
|
||||||
} else if (STR_EQ(key, "matrix")) {
|
} else if (STR_EQ(key, "matrix")) {
|
||||||
lovrAssert((token++)->size == 16, "Node matrix needs 16 elements");
|
lovrAssert((token++)->size == 16, "Node matrix needs 16 elements");
|
||||||
matrix = true;
|
node->matrix = true;
|
||||||
for (int j = 0; j < 16; j++) {
|
for (int j = 0; j < 16; j++) {
|
||||||
node->transform[j] = NOM_FLOAT(json, token);
|
node->transform[j] = NOM_FLOAT(json, token);
|
||||||
}
|
}
|
||||||
|
@ -842,18 +839,15 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source) {
|
||||||
scale[0] = NOM_FLOAT(json, token);
|
scale[0] = NOM_FLOAT(json, token);
|
||||||
scale[1] = NOM_FLOAT(json, token);
|
scale[1] = NOM_FLOAT(json, token);
|
||||||
scale[2] = 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 {
|
} else {
|
||||||
token += NOM_VALUE(json, token);
|
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]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -304,7 +304,9 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
|
||||||
model->nodes[0] = (ModelNode) {
|
model->nodes[0] = (ModelNode) {
|
||||||
.transform = MAT4_IDENTITY,
|
.transform = MAT4_IDENTITY,
|
||||||
.primitiveIndex = 0,
|
.primitiveIndex = 0,
|
||||||
.primitiveCount = groups.length
|
.primitiveCount = groups.length,
|
||||||
|
.skin = ~0u,
|
||||||
|
.matrix = true
|
||||||
};
|
};
|
||||||
|
|
||||||
arr_free(&groups);
|
arr_free(&groups);
|
||||||
|
|
|
@ -1,269 +0,0 @@
|
||||||
#include "graphics/animator.h"
|
|
||||||
#include "data/modelData.h"
|
|
||||||
#include "core/maf.h"
|
|
||||||
#include "core/ref.h"
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
#include "core/arr.h"
|
|
||||||
#include "lib/map/map.h"
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#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);
|
|
|
@ -1,45 +1,67 @@
|
||||||
#include "graphics/model.h"
|
#include "graphics/model.h"
|
||||||
#include "graphics/animator.h"
|
|
||||||
#include "graphics/buffer.h"
|
#include "graphics/buffer.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
#include "graphics/material.h"
|
#include "graphics/material.h"
|
||||||
#include "graphics/mesh.h"
|
#include "graphics/mesh.h"
|
||||||
#include "graphics/texture.h"
|
#include "graphics/texture.h"
|
||||||
#include "resources/shaders.h"
|
#include "resources/shaders.h"
|
||||||
|
#include "core/maf.h"
|
||||||
#include "core/ref.h"
|
#include "core/ref.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
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];
|
ModelNode* node = &model->data->nodes[nodeIndex];
|
||||||
|
mat4 global = model->globalTransforms + 16 * nodeIndex;
|
||||||
|
mat4_init(global, parent);
|
||||||
|
|
||||||
mat4 globalTransform = model->globalNodeTransforms + 16 * nodeIndex;
|
if (node->matrix) {
|
||||||
mat4_set(globalTransform, transform);
|
mat4_multiply(global, node->transform);
|
||||||
|
|
||||||
if (model->animator) {
|
|
||||||
lovrAnimatorEvaluate(model->animator, nodeIndex, globalTransform);
|
|
||||||
} else {
|
} 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++) {
|
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) {
|
static void renderNode(Model* model, uint32_t nodeIndex, uint32_t instances) {
|
||||||
ModelNode* node = &model->data->nodes[nodeIndex];
|
ModelNode* node = &model->data->nodes[nodeIndex];
|
||||||
mat4 globalTransform = model->globalNodeTransforms + 16 * nodeIndex;
|
mat4 globalTransform = model->globalTransforms + 16 * nodeIndex;
|
||||||
|
|
||||||
if (node->primitiveCount > 0) {
|
if (node->primitiveCount > 0) {
|
||||||
bool animated = node->skin != ~0u && model->animator;
|
bool animated = node->skin != ~0u;
|
||||||
float pose[16 * MAX_BONES];
|
float pose[16 * MAX_BONES];
|
||||||
|
|
||||||
if (animated) {
|
if (animated) {
|
||||||
ModelSkin* skin = &model->data->skins[node->skin];
|
ModelSkin* skin = &model->data->skins[node->skin];
|
||||||
|
|
||||||
for (uint32_t j = 0; j < skin->jointCount; j++) {
|
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 inverseBindMatrix = skin->inverseBindMatrices + 16 * j;
|
||||||
mat4 jointPose = pose + 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;
|
model->data = data;
|
||||||
lovrRetain(data);
|
lovrRetain(data);
|
||||||
|
|
||||||
|
@ -169,9 +192,20 @@ Model* lovrModelInit(Model* model, ModelData* data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
model->globalNodeTransforms = malloc(16 * sizeof(float) * model->data->nodeCount);
|
model->localTransforms = malloc(sizeof(NodeTransform) * data->nodeCount);
|
||||||
for (uint32_t i = 0; i < model->data->nodeCount; i++) {
|
model->globalTransforms = malloc(16 * sizeof(float) * data->nodeCount);
|
||||||
mat4_identity(model->globalNodeTransforms + 16 * i);
|
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;
|
return model;
|
||||||
|
@ -192,26 +226,82 @@ void lovrModelDestroy(void* ref) {
|
||||||
lovrRelease(Material, model->materials[i]);
|
lovrRelease(Material, model->materials[i]);
|
||||||
}
|
}
|
||||||
lovrRelease(Material, model->userMaterial);
|
lovrRelease(Material, model->userMaterial);
|
||||||
lovrRelease(Animator, model->animator);
|
|
||||||
lovrRelease(ModelData, model->data);
|
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) {
|
void lovrModelDraw(Model* model, mat4 transform, uint32_t instances) {
|
||||||
updateGlobalNodeTransform(model, model->data->rootNode, transform);
|
if (model->transformsDirty) {
|
||||||
renderNode(model, model->data->rootNode, instances);
|
updateGlobalTransform(model, model->data->rootNode, (float[]) MAT4_IDENTITY);
|
||||||
}
|
model->transformsDirty = false;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
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++) {
|
for (uint32_t i = 0; i < node->primitiveCount; i++) {
|
||||||
ModelAttribute* position = model->data->primitives[node->primitiveIndex + i].attributes[ATTR_POSITION];
|
ModelAttribute* position = model->data->primitives[node->primitiveIndex + i].attributes[ATTR_POSITION];
|
||||||
if (position && position->hasMin && position->hasMax) {
|
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 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] };
|
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]) {
|
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[0] = aabb[2] = aabb[4] = FLT_MAX;
|
||||||
aabb[1] = aabb[3] = aabb[5] = -FLT_MAX;
|
aabb[1] = aabb[3] = aabb[5] = -FLT_MAX;
|
||||||
updateGlobalNodeTransform(model, model->data->rootNode, (float[]) MAT4_IDENTITY);
|
|
||||||
applyAABB(model, model->data->rootNode, aabb);
|
applyAABB(model, model->data->rootNode, aabb);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,17 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
struct Animator;
|
|
||||||
struct Buffer;
|
|
||||||
struct Material;
|
struct Material;
|
||||||
struct Mesh;
|
|
||||||
struct ModelData;
|
struct ModelData;
|
||||||
struct Texture;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct Model Model;
|
||||||
struct ModelData* data;
|
Model* lovrModelCreate(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__)
|
|
||||||
void lovrModelDestroy(void* ref);
|
void lovrModelDestroy(void* ref);
|
||||||
|
struct ModelData* lovrModelGetModelData(Model* model);
|
||||||
void lovrModelDraw(Model* model, float* transform, uint32_t instances);
|
void lovrModelDraw(Model* model, float* transform, uint32_t instances);
|
||||||
struct Animator* lovrModelGetAnimator(Model* model);
|
void lovrModelAnimate(Model* model, uint32_t animationIndex, float time, float alpha);
|
||||||
void lovrModelSetAnimator(Model* model, struct Animator* animator);
|
|
||||||
struct Material* lovrModelGetMaterial(Model* model);
|
struct Material* lovrModelGetMaterial(Model* model);
|
||||||
void lovrModelSetMaterial(Model* model, struct Material* material);
|
void lovrModelSetMaterial(Model* model, struct Material* material);
|
||||||
void lovrModelGetAABB(Model* model, float aabb[6]);
|
void lovrModelGetAABB(Model* model, float aabb[6]);
|
||||||
|
|
|
@ -543,7 +543,9 @@ static ModelData* openvr_newModelData(Device device) {
|
||||||
model->nodes[0] = (ModelNode) {
|
model->nodes[0] = (ModelNode) {
|
||||||
.transform = MAT4_IDENTITY,
|
.transform = MAT4_IDENTITY,
|
||||||
.primitiveIndex = 0,
|
.primitiveIndex = 0,
|
||||||
.primitiveCount = 1
|
.primitiveCount = 1,
|
||||||
|
.skin = ~0u,
|
||||||
|
.matrix = true
|
||||||
};
|
};
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
|
|
Loading…
Reference in New Issue