1
0
Fork 0
mirror of https://github.com/bjornbytes/lovr.git synced 2024-07-03 04:53:35 +00:00
lovr/src/graphics/model.c

210 lines
6.9 KiB
C
Raw Normal View History

2016-11-19 09:28:01 +00:00
#include "graphics/model.h"
#include "graphics/graphics.h"
2018-09-26 00:10:09 +00:00
#include "resources/shaders.h"
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-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-01-17 20:58:25 +00:00
.transform = globalTransform,
.material = model->materials[primitive->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];
model->meshes[i] = lovrMeshCreateEmpty(primitive->mode);
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-15 16:22:21 +00:00
.integer = j == ATTR_BONES,
2018-09-26 00:10:09 +00:00
.enabled = true
});
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,
.integer = true,
.enabled = true
});
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*));
if (data->imageCount > 0) {
model->textures = calloc(data->imageCount, sizeof(Texture*));
}
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]) {
ModelTexture* texture = &data->textures[index];
TextureData* image = data->images[texture->imageIndex];
bool srgb = j == TEXTURE_DIFFUSE || j == TEXTURE_EMISSIVE;
model->textures[index] = lovrTextureCreate(TEXTURE_2D, &image, 1, srgb, texture->mipmaps, 0);
lovrTextureSetFilter(model->textures[index], texture->filter);
lovrTextureSetWrap(model->textures[index], texture->wrap);
}
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++) {
2018-09-26 00:10:09 +00:00
lovrRelease(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++) {
lovrRelease(model->meshes[i]);
}
2018-09-26 00:10:09 +00:00
lovrRelease(model->data);
2016-10-04 04:54:27 +00:00
}
2016-10-31 20:54:32 +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);
lovrRelease(model->animator);
model->animator = animator;
}
}