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
|
||||
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[];
|
||||
|
|
|
@ -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 "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);
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "util.h"
|
||||
#include "lib/map/map.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
@ -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);
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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/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 <stdlib.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];
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -1,31 +1,17 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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]);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue