2016-11-19 09:28:01 +00:00
|
|
|
#include "graphics/model.h"
|
|
|
|
#include "graphics/graphics.h"
|
2017-01-21 03:55:54 +00:00
|
|
|
#include "math/mat4.h"
|
|
|
|
#include "math/vec3.h"
|
2016-10-04 04:54:27 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
2017-11-26 03:45:44 +00:00
|
|
|
static void renderNode(Model* model, int nodeIndex, int instances) {
|
2017-11-07 04:25:08 +00:00
|
|
|
ModelNode* node = &model->modelData->nodes[nodeIndex];
|
|
|
|
|
2017-11-21 02:19:39 +00:00
|
|
|
if (node->primitives.length > 0) {
|
|
|
|
lovrGraphicsPush();
|
2017-11-21 02:50:06 +00:00
|
|
|
lovrGraphicsMatrixTransform(MATRIX_MODEL, model->nodeTransforms[nodeIndex]);
|
2017-11-14 01:47:56 +00:00
|
|
|
|
2017-11-25 19:59:27 +00:00
|
|
|
float globalInverse[16];
|
2017-11-21 05:16:16 +00:00
|
|
|
if (model->animator) {
|
|
|
|
mat4_set(globalInverse, model->nodeTransforms[nodeIndex]);
|
|
|
|
mat4_invert(globalInverse);
|
2017-11-21 02:19:39 +00:00
|
|
|
}
|
2016-10-31 20:54:32 +00:00
|
|
|
|
2017-11-21 02:19:39 +00:00
|
|
|
for (int i = 0; i < node->primitives.length; i++) {
|
|
|
|
ModelPrimitive* primitive = &model->modelData->primitives[node->primitives.data[i]];
|
2017-11-25 19:59:27 +00:00
|
|
|
|
|
|
|
if (model->animator) {
|
|
|
|
for (int i = 0; i < primitive->boneCount; i++) {
|
|
|
|
Bone* bone = &primitive->bones[i];
|
|
|
|
int nodeIndex = *(int*) map_get(&model->modelData->nodeMap, bone->name);
|
|
|
|
|
|
|
|
mat4 bonePose = model->pose[i];
|
|
|
|
mat4_identity(bonePose);
|
|
|
|
mat4_set(bonePose, globalInverse);
|
|
|
|
mat4_multiply(bonePose, model->nodeTransforms[nodeIndex]);
|
|
|
|
mat4_multiply(bonePose, bone->offset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-30 05:44:32 +00:00
|
|
|
if (!model->material && model->materials) {
|
2017-11-26 03:02:28 +00:00
|
|
|
lovrMeshSetMaterial(model->mesh, model->materials[primitive->material]);
|
2017-11-21 02:19:39 +00:00
|
|
|
}
|
2017-11-25 19:59:27 +00:00
|
|
|
|
2017-11-21 02:19:39 +00:00
|
|
|
lovrMeshSetDrawRange(model->mesh, primitive->drawStart, primitive->drawCount);
|
2017-11-26 03:45:44 +00:00
|
|
|
lovrMeshDraw(model->mesh, NULL, (float*) model->pose, instances);
|
2017-10-21 22:20:16 +00:00
|
|
|
}
|
2016-10-31 20:54:32 +00:00
|
|
|
|
2017-11-21 02:19:39 +00:00
|
|
|
lovrGraphicsPop();
|
|
|
|
}
|
2017-11-21 02:17:06 +00:00
|
|
|
|
2017-10-15 01:01:00 +00:00
|
|
|
for (int i = 0; i < node->children.length; i++) {
|
2017-11-26 03:45:44 +00:00
|
|
|
renderNode(model, node->children.data[i], instances);
|
2016-10-31 20:54:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-25 08:49:19 +00:00
|
|
|
Model* lovrModelCreate(ModelData* modelData) {
|
2016-11-19 07:41:23 +00:00
|
|
|
Model* model = lovrAlloc(sizeof(Model), lovrModelDestroy);
|
2016-11-08 22:44:03 +00:00
|
|
|
if (!model) return NULL;
|
|
|
|
|
2018-01-23 02:24:39 +00:00
|
|
|
lovrRetain(&modelData->ref);
|
2016-11-25 08:49:19 +00:00
|
|
|
model->modelData = modelData;
|
2017-11-02 02:27:58 +00:00
|
|
|
model->aabbDirty = true;
|
2017-11-25 21:30:02 +00:00
|
|
|
model->animator = NULL;
|
2017-11-26 03:02:28 +00:00
|
|
|
model->material = NULL;
|
2016-10-31 20:54:32 +00:00
|
|
|
|
2018-02-11 01:27:29 +00:00
|
|
|
model->mesh = lovrMeshCreate(modelData->vertexData->count, &modelData->vertexData->format, MESH_TRIANGLES, MESH_STATIC);
|
|
|
|
VertexPointer vertices = lovrMeshMap(model->mesh, 0, modelData->vertexData->count, false, true);
|
|
|
|
memcpy(vertices.raw, modelData->vertexData->data.raw, modelData->vertexData->count * modelData->vertexData->format.stride);
|
2017-04-09 20:40:20 +00:00
|
|
|
lovrMeshUnmap(model->mesh);
|
2018-02-11 01:27:29 +00:00
|
|
|
lovrMeshSetVertexMap(model->mesh, modelData->indices.raw, modelData->indexCount);
|
2017-10-31 08:14:09 +00:00
|
|
|
lovrMeshSetRangeEnabled(model->mesh, true);
|
2016-10-31 20:54:32 +00:00
|
|
|
|
2018-01-30 05:44:32 +00:00
|
|
|
if (modelData->textures.length > 0) {
|
|
|
|
model->textures = malloc(modelData->textures.length * sizeof(Texture*));
|
|
|
|
for (int i = 0; i < modelData->textures.length; i++) {
|
|
|
|
if (modelData->textures.data[i]) {
|
|
|
|
model->textures[i] = lovrTextureCreate(TEXTURE_2D, (TextureData**) &modelData->textures.data[i], 1, true);
|
|
|
|
} else {
|
|
|
|
model->textures[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
model->textures = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (modelData->materialCount > 0) {
|
|
|
|
model->materials = malloc(modelData->materialCount * sizeof(Material*));
|
|
|
|
for (int i = 0; i < modelData->materialCount; i++) {
|
|
|
|
ModelMaterial* materialData = &modelData->materials[i];
|
|
|
|
Material* material = lovrMaterialCreate(false);
|
|
|
|
lovrMaterialSetColor(material, COLOR_DIFFUSE, materialData->diffuseColor);
|
|
|
|
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, model->textures[materialData->diffuseTexture]);
|
|
|
|
model->materials[i] = material;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
model->materials = NULL;
|
2017-10-21 22:20:16 +00:00
|
|
|
}
|
|
|
|
|
2017-11-07 04:25:08 +00:00
|
|
|
for (int i = 0; i < MAX_BONES; i++) {
|
2017-11-21 02:42:29 +00:00
|
|
|
mat4_identity(model->pose[i]);
|
2017-11-07 04:25:08 +00:00
|
|
|
}
|
|
|
|
|
2017-11-21 02:50:06 +00:00
|
|
|
model->nodeTransforms = malloc(16 * modelData->nodeCount * sizeof(float));
|
2017-11-20 00:45:00 +00:00
|
|
|
for (int i = 0; i < modelData->nodeCount; i++) {
|
2018-01-04 16:49:39 +00:00
|
|
|
ModelNode* node = &model->modelData->nodes[i];
|
2017-11-21 02:50:06 +00:00
|
|
|
mat4 transform = model->nodeTransforms[i];
|
2018-01-04 16:49:39 +00:00
|
|
|
|
|
|
|
if (node->parent >= 0) {
|
|
|
|
mat4_set(transform, model->nodeTransforms[node->parent]);
|
|
|
|
mat4_multiply(transform, node->transform);
|
|
|
|
} else {
|
|
|
|
mat4_set(transform, node->transform);
|
|
|
|
}
|
2017-11-14 01:47:56 +00:00
|
|
|
}
|
|
|
|
|
2016-10-04 04:54:27 +00:00
|
|
|
return model;
|
|
|
|
}
|
|
|
|
|
2016-11-19 07:41:23 +00:00
|
|
|
void lovrModelDestroy(const Ref* ref) {
|
|
|
|
Model* model = containerof(ref, Model);
|
2018-01-30 05:44:32 +00:00
|
|
|
for (int i = 0; i < model->modelData->textures.length; i++) {
|
|
|
|
if (model->textures[i]) {
|
|
|
|
lovrRelease(&model->textures[i]->ref);
|
|
|
|
}
|
|
|
|
}
|
2017-10-21 22:20:16 +00:00
|
|
|
for (int i = 0; i < model->modelData->materialCount; i++) {
|
|
|
|
lovrRelease(&model->materials[i]->ref);
|
|
|
|
}
|
2017-11-26 03:02:28 +00:00
|
|
|
if (model->animator) {
|
|
|
|
lovrRelease(&model->animator->ref);
|
|
|
|
}
|
|
|
|
if (model->material) {
|
|
|
|
lovrRelease(&model->material->ref);
|
|
|
|
}
|
2018-01-30 05:44:32 +00:00
|
|
|
free(model->textures);
|
2017-10-21 22:20:16 +00:00
|
|
|
free(model->materials);
|
2018-01-23 02:24:39 +00:00
|
|
|
lovrRelease(&model->modelData->ref);
|
2017-03-11 22:13:49 +00:00
|
|
|
lovrRelease(&model->mesh->ref);
|
2017-11-21 02:50:06 +00:00
|
|
|
free(model->nodeTransforms);
|
2016-10-04 04:54:27 +00:00
|
|
|
free(model);
|
|
|
|
}
|
2016-10-31 20:54:32 +00:00
|
|
|
|
2017-11-26 03:45:44 +00:00
|
|
|
void lovrModelDraw(Model* model, mat4 transform, int instances) {
|
2017-10-15 01:01:00 +00:00
|
|
|
if (model->modelData->nodeCount == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-11-07 04:25:08 +00:00
|
|
|
if (model->animator) {
|
2017-11-20 00:45:00 +00:00
|
|
|
for (int i = 0; i < model->modelData->nodeCount; i++) {
|
|
|
|
ModelNode* node = &model->modelData->nodes[i];
|
2017-11-21 02:50:06 +00:00
|
|
|
|
|
|
|
float localTransform[16];
|
|
|
|
mat4_identity(localTransform);
|
|
|
|
if (!lovrAnimatorEvaluate(model->animator, node->name, localTransform)) {
|
|
|
|
mat4_set(localTransform, node->transform);
|
2017-11-20 00:45:00 +00:00
|
|
|
}
|
|
|
|
|
2017-11-21 02:50:06 +00:00
|
|
|
mat4 globalTransform = model->nodeTransforms[i];
|
2017-11-20 00:45:00 +00:00
|
|
|
if (node->parent >= 0) {
|
2017-11-21 02:50:06 +00:00
|
|
|
mat4_set(globalTransform, model->nodeTransforms[node->parent]);
|
|
|
|
mat4_multiply(globalTransform, localTransform);
|
2017-11-20 00:45:00 +00:00
|
|
|
} else {
|
2017-11-21 02:50:06 +00:00
|
|
|
mat4_set(globalTransform, localTransform);
|
2017-11-20 00:45:00 +00:00
|
|
|
}
|
2017-11-07 04:25:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-26 03:02:28 +00:00
|
|
|
if (model->material) {
|
|
|
|
lovrMeshSetMaterial(model->mesh, model->material);
|
|
|
|
}
|
|
|
|
|
2017-10-15 01:01:00 +00:00
|
|
|
lovrGraphicsPush();
|
|
|
|
lovrGraphicsMatrixTransform(MATRIX_MODEL, transform);
|
2017-11-26 03:45:44 +00:00
|
|
|
renderNode(model, 0, instances);
|
2017-10-15 01:01:00 +00:00
|
|
|
lovrGraphicsPop();
|
2016-10-31 20:54:32 +00:00
|
|
|
}
|
2016-11-08 22:51:58 +00:00
|
|
|
|
2017-11-05 21:41:47 +00:00
|
|
|
Animator* lovrModelGetAnimator(Model* model) {
|
|
|
|
return model->animator;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrModelSetAnimator(Model* model, Animator* animator) {
|
2017-11-26 03:02:28 +00:00
|
|
|
if (model->animator != animator) {
|
|
|
|
if (model->animator) {
|
|
|
|
lovrRelease(&model->animator->ref);
|
|
|
|
}
|
|
|
|
|
|
|
|
model->animator = animator;
|
|
|
|
|
|
|
|
if (animator) {
|
|
|
|
lovrRetain(&animator->ref);
|
|
|
|
}
|
|
|
|
}
|
2017-11-05 21:41:47 +00:00
|
|
|
}
|
|
|
|
|
2017-11-21 02:15:10 +00:00
|
|
|
int lovrModelGetAnimationCount(Model* model) {
|
|
|
|
return model->modelData->animationCount;
|
|
|
|
}
|
|
|
|
|
2017-11-26 03:02:28 +00:00
|
|
|
Material* lovrModelGetMaterial(Model* model) {
|
|
|
|
return model->material;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrModelSetMaterial(Model* model, Material* material) {
|
|
|
|
if (model->material != material) {
|
|
|
|
if (model->material) {
|
|
|
|
lovrRelease(&model->material->ref);
|
|
|
|
}
|
|
|
|
|
|
|
|
model->material = material;
|
|
|
|
|
|
|
|
if (material) {
|
|
|
|
lovrRetain(&material->ref);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-15 17:26:33 +00:00
|
|
|
Mesh* lovrModelGetMesh(Model* model) {
|
|
|
|
return model->mesh;
|
|
|
|
}
|
2017-11-02 02:27:58 +00:00
|
|
|
|
|
|
|
const float* lovrModelGetAABB(Model* model) {
|
|
|
|
if (model->aabbDirty) {
|
|
|
|
lovrModelDataGetAABB(model->modelData, model->aabb);
|
|
|
|
model->aabbDirty = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return model->aabb;
|
|
|
|
}
|