2016-11-19 09:28:01 +00:00
|
|
|
#include "graphics/model.h"
|
2019-04-05 11:58:29 +00:00
|
|
|
#include "graphics/animator.h"
|
|
|
|
#include "graphics/buffer.h"
|
2016-11-19 09:28:01 +00:00
|
|
|
#include "graphics/graphics.h"
|
2019-04-05 11:58:29 +00:00
|
|
|
#include "graphics/material.h"
|
|
|
|
#include "graphics/mesh.h"
|
2018-09-26 00:10:09 +00:00
|
|
|
#include "resources/shaders.h"
|
2019-01-23 18:24:08 +00:00
|
|
|
#include <float.h>
|
2018-09-26 00:10:09 +00:00
|
|
|
|
2019-01-14 20:10:41 +00:00
|
|
|
static void updateGlobalNodeTransform(Model* model, uint32_t nodeIndex, mat4 transform) {
|
2019-01-10 19:34:00 +00:00
|
|
|
ModelNode* node = &model->data->nodes[nodeIndex];
|
|
|
|
|
2019-01-14 20:10:41 +00:00
|
|
|
mat4 globalTransform = model->globalNodeTransforms + 16 * nodeIndex;
|
|
|
|
mat4_set(globalTransform, transform);
|
2019-01-13 16:41:18 +00:00
|
|
|
|
2019-01-14 20:10:41 +00:00
|
|
|
if (!model->animator || !lovrAnimatorEvaluate(model->animator, nodeIndex, globalTransform)) {
|
|
|
|
mat4_multiply(globalTransform, node->transform);
|
|
|
|
}
|
2019-01-13 19:08:06 +00:00
|
|
|
|
2019-01-14 20:10:41 +00:00
|
|
|
for (uint32_t i = 0; i < node->childCount; i++) {
|
|
|
|
updateGlobalNodeTransform(model, node->children[i], globalTransform);
|
2019-01-13 16:41:18 +00:00
|
|
|
}
|
2019-01-14 20:10:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void renderNode(Model* model, uint32_t nodeIndex, int instances) {
|
|
|
|
ModelNode* node = &model->data->nodes[nodeIndex];
|
|
|
|
mat4 globalTransform = model->globalNodeTransforms + 16 * nodeIndex;
|
2019-01-10 19:34:00 +00:00
|
|
|
|
2019-01-16 03:25:51 +00:00
|
|
|
if (node->primitiveCount > 0) {
|
2019-01-14 20:10:41 +00:00
|
|
|
float pose[16 * MAX_BONES];
|
|
|
|
if (node->skin >= 0 && model->animator) {
|
|
|
|
ModelSkin* skin = &model->data->skins[node->skin];
|
|
|
|
|
|
|
|
for (uint32_t j = 0; j < skin->jointCount; j++) {
|
|
|
|
mat4 globalJointTransform = model->globalNodeTransforms + 16 * skin->joints[j];
|
2019-01-16 03:25:51 +00:00
|
|
|
mat4 inverseBindMatrix = skin->inverseBindMatrices + 16 * j;
|
2019-01-14 20:10:41 +00:00
|
|
|
mat4 jointPose = pose + 16 * j;
|
2019-01-16 03:25:51 +00:00
|
|
|
|
2019-01-14 20:10:41 +00:00
|
|
|
mat4_set(jointPose, globalTransform);
|
|
|
|
mat4_invert(jointPose);
|
|
|
|
mat4_multiply(jointPose, globalJointTransform);
|
|
|
|
mat4_multiply(jointPose, inverseBindMatrix);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-16 03:25:51 +00:00
|
|
|
for (uint32_t i = 0; i < node->primitiveCount; i++) {
|
|
|
|
ModelPrimitive* primitive = &model->data->primitives[node->primitiveIndex + i];
|
|
|
|
Mesh* mesh = model->meshes[node->primitiveIndex + i];
|
2019-02-14 07:55:47 +00:00
|
|
|
Material* material = primitive->material >= 0 ? model->materials[primitive->material] : NULL;
|
|
|
|
|
|
|
|
if (model->userMaterial) {
|
|
|
|
material = model->userMaterial;
|
|
|
|
}
|
2019-01-10 19:34:00 +00:00
|
|
|
|
|
|
|
uint32_t rangeStart, rangeCount;
|
|
|
|
lovrMeshGetDrawRange(mesh, &rangeStart, &rangeCount);
|
|
|
|
|
|
|
|
lovrGraphicsBatch(&(BatchRequest) {
|
|
|
|
.type = BATCH_MESH,
|
|
|
|
.params.mesh = {
|
|
|
|
.object = mesh,
|
|
|
|
.mode = primitive->mode,
|
|
|
|
.rangeStart = rangeStart,
|
|
|
|
.rangeCount = rangeCount,
|
2019-01-13 16:41:18 +00:00
|
|
|
.instances = instances,
|
2019-01-13 19:08:06 +00:00
|
|
|
.pose = node->skin >= 0 ? pose : NULL
|
2019-01-10 19:34:00 +00:00
|
|
|
},
|
2019-04-05 08:23:48 +00:00
|
|
|
.drawMode = primitive->mode,
|
2019-01-17 20:58:25 +00:00
|
|
|
.transform = globalTransform,
|
2019-02-14 07:55:47 +00:00
|
|
|
.material = material
|
2019-01-10 19:34:00 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < node->childCount; i++) {
|
2019-01-14 20:10:41 +00:00
|
|
|
renderNode(model, node->children[i], instances);
|
2019-01-10 19:34:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-26 00:10:09 +00:00
|
|
|
Model* lovrModelInit(Model* model, ModelData* data) {
|
|
|
|
model->data = data;
|
|
|
|
lovrRetain(data);
|
|
|
|
|
2019-01-17 20:58:25 +00:00
|
|
|
// Geometry
|
2018-09-26 00:10:09 +00:00
|
|
|
if (data->primitiveCount > 0) {
|
2019-01-17 20:58:25 +00:00
|
|
|
if (data->bufferCount > 0) {
|
|
|
|
model->buffers = calloc(data->bufferCount, sizeof(Buffer*));
|
|
|
|
}
|
|
|
|
|
2018-09-26 00:10:09 +00:00
|
|
|
model->meshes = calloc(data->primitiveCount, sizeof(Mesh*));
|
|
|
|
for (int i = 0; i < data->primitiveCount; i++) {
|
|
|
|
ModelPrimitive* primitive = &data->primitives[i];
|
2019-01-27 22:29:06 +00:00
|
|
|
model->meshes[i] = lovrMeshCreate(primitive->mode, NULL, 0);
|
2018-09-26 00:10:09 +00:00
|
|
|
|
|
|
|
bool setDrawRange = false;
|
|
|
|
for (int j = 0; j < MAX_DEFAULT_ATTRIBUTES; j++) {
|
2019-01-16 03:25:51 +00:00
|
|
|
if (primitive->attributes[j]) {
|
|
|
|
ModelAttribute* attribute = primitive->attributes[j];
|
|
|
|
|
|
|
|
if (!model->buffers[attribute->buffer]) {
|
|
|
|
ModelBuffer* buffer = &data->buffers[attribute->buffer];
|
|
|
|
model->buffers[attribute->buffer] = lovrBufferCreate(buffer->size, buffer->data, BUFFER_VERTEX, USAGE_STATIC, false);
|
|
|
|
}
|
2018-09-26 00:10:09 +00:00
|
|
|
|
|
|
|
lovrMeshAttachAttribute(model->meshes[i], lovrShaderAttributeNames[j], &(MeshAttribute) {
|
2019-01-16 03:25:51 +00:00
|
|
|
.buffer = model->buffers[attribute->buffer],
|
|
|
|
.offset = attribute->offset,
|
|
|
|
.stride = data->buffers[attribute->buffer].stride,
|
|
|
|
.type = attribute->type,
|
|
|
|
.components = attribute->components,
|
2019-01-27 22:29:06 +00:00
|
|
|
.integer = j == ATTR_BONES
|
2018-09-26 00:10:09 +00:00
|
|
|
});
|
|
|
|
|
2019-01-16 03:25:51 +00:00
|
|
|
if (!setDrawRange && !primitive->indices) {
|
|
|
|
lovrMeshSetDrawRange(model->meshes[i], 0, attribute->count);
|
2018-09-26 00:10:09 +00:00
|
|
|
setDrawRange = true;
|
2018-09-01 13:27:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-26 00:10:09 +00:00
|
|
|
lovrMeshAttachAttribute(model->meshes[i], "lovrDrawID", &(MeshAttribute) {
|
|
|
|
.buffer = lovrGraphicsGetIdentityBuffer(),
|
|
|
|
.type = U8,
|
|
|
|
.components = 1,
|
|
|
|
.divisor = 1,
|
2019-01-27 22:29:06 +00:00
|
|
|
.integer = true
|
2018-09-26 00:10:09 +00:00
|
|
|
});
|
2018-01-04 16:49:39 +00:00
|
|
|
|
2019-01-16 03:25:51 +00:00
|
|
|
if (primitive->indices) {
|
|
|
|
ModelAttribute* attribute = primitive->indices;
|
|
|
|
|
|
|
|
if (!model->buffers[attribute->buffer]) {
|
|
|
|
ModelBuffer* buffer = &data->buffers[attribute->buffer];
|
|
|
|
model->buffers[attribute->buffer] = lovrBufferCreate(buffer->size, buffer->data, BUFFER_INDEX, USAGE_STATIC, false);
|
|
|
|
}
|
|
|
|
|
2019-01-17 22:14:13 +00:00
|
|
|
size_t indexSize = attribute->type == U16 ? 2 : 4;
|
|
|
|
lovrMeshSetIndexBuffer(model->meshes[i], model->buffers[attribute->buffer], attribute->count, indexSize, attribute->offset);
|
2019-01-16 03:25:51 +00:00
|
|
|
lovrMeshSetDrawRange(model->meshes[i], 0, attribute->count);
|
2018-09-26 00:10:09 +00:00
|
|
|
}
|
2018-01-04 16:49:39 +00:00
|
|
|
}
|
2017-11-14 01:47:56 +00:00
|
|
|
}
|
|
|
|
|
2019-01-17 20:58:25 +00:00
|
|
|
// Materials
|
|
|
|
if (data->materialCount > 0) {
|
|
|
|
model->materials = malloc(data->materialCount * sizeof(Material*));
|
|
|
|
|
2019-01-31 02:56:17 +00:00
|
|
|
if (data->textureCount > 0) {
|
2019-01-23 06:40:34 +00:00
|
|
|
model->textures = calloc(data->textureCount, sizeof(Texture*));
|
2019-01-17 20:58:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < data->materialCount; i++) {
|
|
|
|
Material* material = lovrMaterialCreate();
|
|
|
|
|
|
|
|
for (int j = 0; j < MAX_MATERIAL_SCALARS; j++) {
|
|
|
|
lovrMaterialSetScalar(material, j, data->materials[i].scalars[j]);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int j = 0; j < MAX_MATERIAL_COLORS; j++) {
|
|
|
|
lovrMaterialSetColor(material, j, data->materials[i].colors[j]);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int j = 0; j < MAX_MATERIAL_TEXTURES; j++) {
|
|
|
|
int index = data->materials[i].textures[j];
|
|
|
|
|
2019-01-18 21:28:17 +00:00
|
|
|
if (index != -1) {
|
|
|
|
if (!model->textures[index]) {
|
2019-01-31 02:56:17 +00:00
|
|
|
TextureData* textureData = data->textures[index];
|
2019-01-18 21:28:17 +00:00
|
|
|
bool srgb = j == TEXTURE_DIFFUSE || j == TEXTURE_EMISSIVE;
|
2019-01-31 02:56:17 +00:00
|
|
|
model->textures[index] = lovrTextureCreate(TEXTURE_2D, &textureData, 1, srgb, true, 0);
|
|
|
|
lovrTextureSetFilter(model->textures[index], data->materials[i].filters[j]);
|
|
|
|
lovrTextureSetWrap(model->textures[index], data->materials[i].wraps[j]);
|
2019-01-18 21:28:17 +00:00
|
|
|
}
|
2019-01-17 20:58:25 +00:00
|
|
|
|
2019-01-18 21:28:17 +00:00
|
|
|
lovrMaterialSetTexture(material, j, model->textures[index]);
|
|
|
|
}
|
2019-01-17 20:58:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
model->materials[i] = material;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-14 20:10:41 +00:00
|
|
|
model->globalNodeTransforms = malloc(16 * sizeof(float) * model->data->nodeCount);
|
|
|
|
for (int i = 0; i < model->data->nodeCount; i++) {
|
|
|
|
mat4_identity(model->globalNodeTransforms + 16 * i);
|
|
|
|
}
|
|
|
|
|
2016-10-04 04:54:27 +00:00
|
|
|
return model;
|
|
|
|
}
|
|
|
|
|
2018-02-26 08:59:03 +00:00
|
|
|
void lovrModelDestroy(void* ref) {
|
|
|
|
Model* model = ref;
|
2019-01-16 03:25:51 +00:00
|
|
|
for (int i = 0; i < model->data->bufferCount; i++) {
|
2019-04-05 10:41:03 +00:00
|
|
|
lovrRelease(Buffer, model->buffers[i]);
|
2018-01-30 05:44:32 +00:00
|
|
|
}
|
2018-09-26 00:10:09 +00:00
|
|
|
for (int i = 0; i < model->data->primitiveCount; i++) {
|
2019-04-05 10:41:03 +00:00
|
|
|
lovrRelease(Mesh, model->meshes[i]);
|
2017-11-26 03:02:28 +00:00
|
|
|
}
|
2019-04-05 10:41:03 +00:00
|
|
|
lovrRelease(ModelData, model->data);
|
2016-10-04 04:54:27 +00:00
|
|
|
}
|
2016-10-31 20:54:32 +00:00
|
|
|
|
2017-11-26 03:45:44 +00:00
|
|
|
void lovrModelDraw(Model* model, mat4 transform, int instances) {
|
2019-01-20 05:46:42 +00:00
|
|
|
updateGlobalNodeTransform(model, model->data->rootNode, transform);
|
|
|
|
renderNode(model, model->data->rootNode, instances);
|
2017-11-02 02:27:58 +00:00
|
|
|
}
|
2019-01-13 19:08:06 +00:00
|
|
|
|
|
|
|
Animator* lovrModelGetAnimator(Model* model) {
|
|
|
|
return model->animator;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrModelSetAnimator(Model* model, Animator* animator) {
|
|
|
|
if (model->animator != animator) {
|
|
|
|
lovrRetain(animator);
|
2019-04-05 10:41:03 +00:00
|
|
|
lovrRelease(Animator, model->animator);
|
2019-01-13 19:08:06 +00:00
|
|
|
model->animator = animator;
|
|
|
|
}
|
|
|
|
}
|
2019-01-23 18:24:08 +00:00
|
|
|
|
2019-02-14 07:55:47 +00:00
|
|
|
Material* lovrModelGetMaterial(Model* model) {
|
|
|
|
return model->userMaterial;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrModelSetMaterial(Model* model, Material* material) {
|
|
|
|
lovrRetain(material);
|
2019-04-05 10:41:03 +00:00
|
|
|
lovrRelease(Material, model->userMaterial);
|
2019-02-14 07:55:47 +00:00
|
|
|
model->userMaterial = material;
|
|
|
|
}
|
|
|
|
|
2019-01-23 18:24:08 +00:00
|
|
|
static void applyAABB(Model* model, int nodeIndex, float aabb[6]) {
|
|
|
|
ModelNode* node = &model->data->nodes[nodeIndex];
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
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 ya[3] = { position->min[1] * m[4], position->min[1] * m[5], position->min[1] * m[6] };
|
|
|
|
float yb[3] = { position->max[1] * m[4], position->max[1] * m[5], position->max[1] * m[6] };
|
|
|
|
|
|
|
|
float za[3] = { position->min[2] * m[8], position->min[2] * m[9], position->min[2] * m[10] };
|
|
|
|
float zb[3] = { position->max[2] * m[8], position->max[2] * m[9], position->max[2] * m[10] };
|
|
|
|
|
|
|
|
float min[3] = {
|
|
|
|
MIN(xa[0], xb[0]) + MIN(ya[0], yb[0]) + MIN(za[0], zb[0]) + m[12],
|
|
|
|
MIN(xa[1], xb[1]) + MIN(ya[1], yb[1]) + MIN(za[1], zb[1]) + m[13],
|
|
|
|
MIN(xa[2], xb[2]) + MIN(ya[2], yb[2]) + MIN(za[2], zb[2]) + m[14]
|
|
|
|
};
|
|
|
|
|
|
|
|
float max[3] = {
|
|
|
|
MAX(xa[0], xb[0]) + MAX(ya[0], yb[0]) + MAX(za[0], zb[0]) + m[12],
|
|
|
|
MAX(xa[1], xb[1]) + MAX(ya[1], yb[1]) + MAX(za[1], zb[1]) + m[13],
|
|
|
|
MAX(xa[2], xb[2]) + MAX(ya[2], yb[2]) + MAX(za[2], zb[2]) + m[14]
|
|
|
|
};
|
|
|
|
|
|
|
|
aabb[0] = MIN(aabb[0], min[0]);
|
|
|
|
aabb[1] = MAX(aabb[1], max[0]);
|
|
|
|
aabb[2] = MIN(aabb[2], min[1]);
|
|
|
|
aabb[3] = MAX(aabb[3], max[1]);
|
|
|
|
aabb[4] = MIN(aabb[4], min[2]);
|
|
|
|
aabb[5] = MAX(aabb[5], max[2]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < node->childCount; i++) {
|
|
|
|
applyAABB(model, node->children[i], aabb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrModelGetAABB(Model* model, float aabb[6]) {
|
|
|
|
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);
|
|
|
|
}
|