diff --git a/src/api/l_model.c b/src/api/l_model.c index 9622d4af..0a666490 100644 --- a/src/api/l_model.c +++ b/src/api/l_model.c @@ -74,20 +74,26 @@ static int l_lovrModelPose(lua_State* L) { static int l_lovrModelGetMaterial(lua_State* L) { Model* model = luax_checktype(L, 1, Model); - Material* material = lovrModelGetMaterial(model); - luax_pushtype(L, Material, material); - return 1; -} -static int l_lovrModelSetMaterial(lua_State* L) { - Model* model = luax_checktype(L, 1, Model); - if (lua_isnoneornil(L, 2)) { - lovrModelSetMaterial(model, NULL); - } else { - Material* material = luax_checktype(L, 2, Material); - lovrModelSetMaterial(model, material); + uint32_t material; + switch (lua_type(L, 2)) { + case LUA_TNUMBER: + material = lua_tointeger(L, 2) - 1; + break; + case LUA_TSTRING: { + const char* name = lua_tostring(L, 2); + ModelData* modelData = lovrModelGetModelData(model); + uint32_t* index = map_get(&modelData->materialMap, name); + lovrAssert(index, "Model has no material named '%s'", name); + material = *index; + break; + } + default: + return luaL_typerror(L, 2, "nil, number, or string"); } - return 0; + + luax_pushtype(L, Material, lovrModelGetMaterial(model, material)); + return 1; } static int l_lovrModelGetAABB(lua_State* L) { @@ -138,7 +144,6 @@ const luaL_Reg lovrModel[] = { { "animate", l_lovrModelAnimate }, { "pose", l_lovrModelPose }, { "getMaterial", l_lovrModelGetMaterial }, - { "setMaterial", l_lovrModelSetMaterial }, { "getAABB", l_lovrModelGetAABB }, { "getNodePose", l_lovrModelGetNodePose }, { NULL, NULL } diff --git a/src/modules/graphics/model.c b/src/modules/graphics/model.c index 58aeb198..5f580bd6 100644 --- a/src/modules/graphics/model.c +++ b/src/modules/graphics/model.c @@ -21,7 +21,6 @@ struct Model { struct Mesh** meshes; struct Texture** textures; struct Material** materials; - struct Material* userMaterial; NodeTransform* localTransforms; float* globalTransforms; bool transformsDirty; @@ -48,34 +47,27 @@ static void updateGlobalTransform(Model* model, uint32_t nodeIndex, mat4 parent) static void renderNode(Model* model, uint32_t nodeIndex, uint32_t instances) { ModelNode* node = &model->data->nodes[nodeIndex]; mat4 globalTransform = model->globalTransforms + 16 * nodeIndex; + float poseMatrix[16 * MAX_BONES]; + float* pose = NULL; - if (node->primitiveCount > 0) { - bool animated = node->skin != ~0u; - float pose[16 * MAX_BONES]; + if (node->skin != ~0u) { + ModelSkin* skin = &model->data->skins[node->skin]; + pose = poseMatrix; - if (animated) { - ModelSkin* skin = &model->data->skins[node->skin]; + for (uint32_t j = 0; j < skin->jointCount; j++) { + mat4 globalJointTransform = model->globalTransforms + 16 * skin->joints[j]; + mat4 inverseBindMatrix = skin->inverseBindMatrices + 16 * j; + mat4 jointPose = pose + 16 * j; - for (uint32_t j = 0; j < skin->jointCount; j++) { - mat4 globalJointTransform = model->globalTransforms + 16 * skin->joints[j]; - mat4 inverseBindMatrix = skin->inverseBindMatrices + 16 * j; - mat4 jointPose = pose + 16 * j; - - mat4_set(jointPose, globalTransform); - mat4_invert(jointPose); - mat4_multiply(jointPose, globalJointTransform); - mat4_multiply(jointPose, inverseBindMatrix); - } + mat4_set(jointPose, globalTransform); + mat4_invert(jointPose); + mat4_multiply(jointPose, globalJointTransform); + mat4_multiply(jointPose, inverseBindMatrix); } + } - for (uint32_t i = 0; i < node->primitiveCount; i++) { - ModelPrimitive* primitive = &model->data->primitives[node->primitiveIndex + i]; - Mesh* mesh = model->meshes[node->primitiveIndex + i]; - Material* material = primitive->material == ~0u ? NULL : model->materials[primitive->material]; - lovrMeshSetMaterial(mesh, model->userMaterial ? model->userMaterial : material); - lovrMeshSetDrawMode(mesh, primitive->mode); - lovrGraphicsDrawMesh(mesh, globalTransform, instances, animated ? pose : NULL); - } + for (uint32_t i = 0; i < node->primitiveCount; i++) { + lovrGraphicsDrawMesh(model->meshes[node->primitiveIndex + i], globalTransform, instances, pose); } for (uint32_t i = 0; i < node->childCount; i++) { @@ -88,6 +80,45 @@ Model* lovrModelCreate(ModelData* data) { model->data = data; lovrRetain(data); + // Materials + if (data->materialCount > 0) { + model->materials = malloc(data->materialCount * sizeof(Material*)); + + if (data->textureCount > 0) { + model->textures = calloc(data->textureCount, sizeof(Texture*)); + } + + for (uint32_t i = 0; i < data->materialCount; i++) { + Material* material = lovrMaterialCreate(); + + for (uint32_t j = 0; j < MAX_MATERIAL_SCALARS; j++) { + lovrMaterialSetScalar(material, j, data->materials[i].scalars[j]); + } + + for (uint32_t j = 0; j < MAX_MATERIAL_COLORS; j++) { + lovrMaterialSetColor(material, j, data->materials[i].colors[j]); + } + + for (uint32_t j = 0; j < MAX_MATERIAL_TEXTURES; j++) { + uint32_t index = data->materials[i].textures[j]; + + if (index != ~0u) { + if (!model->textures[index]) { + TextureData* textureData = data->textures[index]; + bool srgb = j == TEXTURE_DIFFUSE || j == TEXTURE_EMISSIVE; + 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]); + } + + lovrMaterialSetTexture(material, j, model->textures[index]); + } + } + + model->materials[i] = material; + } + } + // Geometry if (data->primitiveCount > 0) { if (data->bufferCount > 0) { @@ -99,6 +130,10 @@ Model* lovrModelCreate(ModelData* data) { ModelPrimitive* primitive = &data->primitives[i]; model->meshes[i] = lovrMeshCreate(primitive->mode, NULL, 0); + if (primitive->material != ~0u) { + lovrMeshSetMaterial(model->meshes[i], model->materials[primitive->material]); + } + bool setDrawRange = false; for (uint32_t j = 0; j < MAX_DEFAULT_ATTRIBUTES; j++) { if (primitive->attributes[j]) { @@ -149,45 +184,6 @@ Model* lovrModelCreate(ModelData* data) { } } - // Materials - if (data->materialCount > 0) { - model->materials = malloc(data->materialCount * sizeof(Material*)); - - if (data->textureCount > 0) { - model->textures = calloc(data->textureCount, sizeof(Texture*)); - } - - for (uint32_t i = 0; i < data->materialCount; i++) { - Material* material = lovrMaterialCreate(); - - for (uint32_t j = 0; j < MAX_MATERIAL_SCALARS; j++) { - lovrMaterialSetScalar(material, j, data->materials[i].scalars[j]); - } - - for (uint32_t j = 0; j < MAX_MATERIAL_COLORS; j++) { - lovrMaterialSetColor(material, j, data->materials[i].colors[j]); - } - - for (uint32_t j = 0; j < MAX_MATERIAL_TEXTURES; j++) { - uint32_t index = data->materials[i].textures[j]; - - if (index != ~0u) { - if (!model->textures[index]) { - TextureData* textureData = data->textures[index]; - bool srgb = j == TEXTURE_DIFFUSE || j == TEXTURE_EMISSIVE; - 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]); - } - - lovrMaterialSetTexture(material, j, model->textures[index]); - } - } - - model->materials[i] = material; - } - } - model->localTransforms = malloc(sizeof(NodeTransform) * data->nodeCount); model->globalTransforms = malloc(16 * sizeof(float) * data->nodeCount); lovrModelResetPose(model); @@ -208,7 +204,6 @@ void lovrModelDestroy(void* ref) { for (uint32_t i = 0; i < model->data->materialCount; i++) { lovrRelease(Material, model->materials[i]); } - lovrRelease(Material, model->userMaterial); lovrRelease(ModelData, model->data); free(model->globalTransforms); free(model->localTransforms); @@ -323,7 +318,7 @@ void lovrModelPose(Model* model, uint32_t nodeIndex, float position[4], float ro return; } - lovrAssert(nodeIndex < model->data->nodeCount, "Invalid node index '%d' (Model only has %d nodes)", nodeIndex, model->data->nodeCount); + lovrAssert(nodeIndex < model->data->nodeCount, "Invalid node index '%d' (Model only has %d node)", nodeIndex + 1, model->data->nodeCount, model->data->nodeCount == 1 ? "" : "s"); NodeTransform* transform = &model->localTransforms[nodeIndex]; if (alpha >= 1.f) { vec3_init(transform->properties[PROP_TRANSLATION], position); @@ -351,14 +346,9 @@ void lovrModelResetPose(Model* model) { model->transformsDirty = true; } -Material* lovrModelGetMaterial(Model* model) { - return model->userMaterial; -} - -void lovrModelSetMaterial(Model* model, Material* material) { - lovrRetain(material); - lovrRelease(Material, model->userMaterial); - model->userMaterial = material; +Material* lovrModelGetMaterial(Model* model, uint32_t material) { + lovrAssert(material < model->data->materialCount, "Invalid material index '%d' (Model only has %d material%s)", material + 1, model->data->materialCount, model->data->materialCount == 1 ? "" : "s"); + return model->materials[material]; } static void applyAABB(Model* model, uint32_t nodeIndex, float aabb[6]) { diff --git a/src/modules/graphics/model.h b/src/modules/graphics/model.h index e82caf90..6bff3354 100644 --- a/src/modules/graphics/model.h +++ b/src/modules/graphics/model.h @@ -20,6 +20,5 @@ void lovrModelAnimate(Model* model, uint32_t animationIndex, float time, float a void lovrModelGetNodePose(Model* model, uint32_t nodeIndex, float position[4], float rotation[4], CoordinateSpace space); void lovrModelPose(Model* model, uint32_t nodeIndex, float position[4], float rotation[4], float alpha); void lovrModelResetPose(Model* model); -struct Material* lovrModelGetMaterial(Model* model); -void lovrModelSetMaterial(Model* model, struct Material* material); +struct Material* lovrModelGetMaterial(Model* model, uint32_t material); void lovrModelGetAABB(Model* model, float aabb[6]);