lovr/src/data/modelData.c

601 lines
21 KiB
C
Raw Normal View History

2018-02-11 23:22:04 +00:00
#include "data/modelData.h"
2017-10-21 07:19:05 +00:00
#include "filesystem/filesystem.h"
2017-10-22 00:35:50 +00:00
#include "filesystem/file.h"
#include "lib/math.h"
2017-12-01 05:17:54 +00:00
#include <float.h>
#include <limits.h>
2016-10-29 06:40:31 +00:00
#include <stdlib.h>
#include <stdio.h>
2018-10-02 04:07:29 +00:00
#include <string.h>
#ifdef LOVR_USE_ASSIMP
2017-10-21 07:19:05 +00:00
#include <assimp/cfileio.h>
2016-10-04 04:54:27 +00:00
#include <assimp/cimport.h>
#include <assimp/config.h>
2017-09-20 06:49:10 +00:00
#include <assimp/scene.h>
#include <assimp/mesh.h>
#include <assimp/matrix4x4.h>
#include <assimp/vector3.h>
2016-10-04 04:54:27 +00:00
#include <assimp/postprocess.h>
2016-10-29 22:18:10 +00:00
2018-01-30 05:44:32 +00:00
static void normalizePath(char* path, char* dst, size_t size) {
char* slash = path;
while ((slash = strchr(path, '\\')) != NULL) { *slash++ = '/'; }
if (path[0] == '/') {
strncpy(dst, path, size);
return;
}
memset(dst, 0, size);
while (*path != '\0') {
if (*path == '/') {
path++;
continue;
}
if (*path == '.') {
if (path[1] == '\0' || path[1] == '/') {
path++;
continue;
}
if (path[1] == '.' && (path[2] == '\0' || path[2] == '/')) {
path += 2;
while ((--dst)[-1] != '/');
continue;
}
}
while (*path != '\0' && *path != '/') {
*dst++ = *path++;
}
*dst++ = '/';
}
*--dst = '\0';
}
static void assimpSumChildren(struct aiNode* assimpNode, int* totalChildren) {
(*totalChildren)++;
for (unsigned int i = 0; i < assimpNode->mNumChildren; i++) {
assimpSumChildren(assimpNode->mChildren[i], totalChildren);
}
}
static void assimpNodeTraversal(ModelData* modelData, struct aiNode* assimpNode, int* nodeId) {
int currentIndex = *nodeId;
ModelNode* node = &modelData->nodes[currentIndex];
node->name = strdup(assimpNode->mName.data);
map_set(&modelData->nodeMap, node->name, currentIndex);
// Transform
struct aiMatrix4x4 m = assimpNode->mTransformation;
aiTransposeMatrix4(&m);
mat4_set(node->transform, (float*) &m);
if (node->parent == -1) {
mat4_set(node->globalTransform, node->transform);
} else {
mat4_set(node->globalTransform, modelData->nodes[node->parent].globalTransform);
mat4_multiply(node->globalTransform, node->transform);
}
// Primitives
vec_init(&node->primitives);
vec_pusharr(&node->primitives, assimpNode->mMeshes, assimpNode->mNumMeshes);
// Children
vec_init(&node->children);
for (unsigned int n = 0; n < assimpNode->mNumChildren; n++) {
(*nodeId)++;
vec_push(&node->children, *nodeId);
ModelNode* child = &modelData->nodes[*nodeId];
child->parent = currentIndex;
assimpNodeTraversal(modelData, assimpNode->mChildren[n], nodeId);
}
}
static void aabbIterator(ModelData* modelData, ModelNode* node, float aabb[6]) {
for (int i = 0; i < node->primitives.length; i++) {
ModelPrimitive* primitive = &modelData->primitives[node->primitives.data[i]];
for (int j = 0; j < primitive->drawCount; j++) {
uint32_t index;
if (modelData->indexSize == sizeof(uint16_t)) {
index = modelData->indices.shorts[primitive->drawStart + j];
} else {
index = modelData->indices.ints[primitive->drawStart + j];
}
float vertex[3];
VertexPointer vertices = { .raw = modelData->vertexData->blob.data };
vec3_init(vertex, (float*) (vertices.bytes + index * modelData->vertexData->format.stride));
mat4_transform(node->globalTransform, &vertex[0], &vertex[1], &vertex[2]);
aabb[0] = MIN(aabb[0], vertex[0]);
aabb[1] = MAX(aabb[1], vertex[0]);
aabb[2] = MIN(aabb[2], vertex[1]);
aabb[3] = MAX(aabb[3], vertex[1]);
aabb[4] = MIN(aabb[4], vertex[2]);
aabb[5] = MAX(aabb[5], vertex[2]);
}
}
for (int i = 0; i < node->children.length; i++) {
ModelNode* child = &modelData->nodes[node->children.data[i]];
aabbIterator(modelData, child, aabb);
}
}
2018-02-12 03:16:40 +00:00
static float readMaterialScalar(struct aiMaterial* assimpMaterial, const char* key, unsigned int type, unsigned int index) {
float scalar;
if (aiGetMaterialFloatArray(assimpMaterial, key, type, index, &scalar, NULL) == aiReturn_SUCCESS) {
return scalar;
} else {
return 1.f;
}
}
static Color readMaterialColor(struct aiMaterial* assimpMaterial, const char* key, unsigned int type, unsigned int index, Color fallback) {
2018-01-30 05:44:32 +00:00
struct aiColor4D assimpColor;
if (aiGetMaterialColor(assimpMaterial, key, type, index, &assimpColor) == aiReturn_SUCCESS) {
return (Color) { .r = assimpColor.r, .g = assimpColor.g, .b = assimpColor.b, .a = assimpColor.a };
2018-01-30 05:44:32 +00:00
} else {
return fallback;
2017-10-22 00:35:50 +00:00
}
2018-01-30 05:44:32 +00:00
}
2017-10-22 00:35:50 +00:00
2018-02-16 03:59:31 +00:00
static int readMaterialTexture(struct aiMaterial* assimpMaterial, enum aiTextureType type, ModelData* modelData, map_int_t* textureCache, const char* dirname) {
2018-01-30 05:44:32 +00:00
struct aiString str;
2017-10-22 00:35:50 +00:00
2018-02-14 05:24:18 +00:00
if (aiGetMaterialTexture(assimpMaterial, type, 0, &str, NULL, NULL, NULL, NULL, NULL, NULL) != aiReturn_SUCCESS) {
return 0;
}
2018-01-30 05:44:32 +00:00
2018-02-14 05:24:18 +00:00
char* path = str.data;
2018-01-30 05:44:32 +00:00
2018-02-16 03:59:31 +00:00
int* cachedTexture = map_get(textureCache, path);
2018-02-14 05:24:18 +00:00
if (cachedTexture) {
return *cachedTexture;
}
2017-10-22 00:35:50 +00:00
2018-02-14 05:24:18 +00:00
char fullPath[LOVR_PATH_MAX];
char normalizedPath[LOVR_PATH_MAX];
strncpy(fullPath, dirname, LOVR_PATH_MAX);
char* lastSlash = strrchr(fullPath, '/');
if (lastSlash) lastSlash[1] = '\0';
else fullPath[0] = '\0';
strncat(fullPath, path, LOVR_PATH_MAX - 1);
2018-02-14 05:24:18 +00:00
normalizePath(fullPath, normalizedPath, LOVR_PATH_MAX);
size_t size;
void* data = lovrFilesystemRead(normalizedPath, &size);
if (!data) {
return 0;
2018-01-30 05:44:32 +00:00
}
2018-02-14 05:24:18 +00:00
Blob* blob = lovrBlobCreate(data, size, path);
2018-09-04 03:59:12 +00:00
TextureData* textureData = lovrTextureDataCreateFromBlob(blob, true);
2018-08-02 10:04:13 +00:00
lovrRelease(blob);
2018-02-14 05:24:18 +00:00
int textureIndex = modelData->textures.length;
vec_push(&modelData->textures, textureData);
map_set(textureCache, path, textureIndex);
return textureIndex;
2017-10-22 00:35:50 +00:00
}
2017-10-21 07:19:05 +00:00
// Blob IO (to avoid reading data twice)
2017-11-25 10:26:45 +00:00
static size_t assimpBlobRead(struct aiFile* assimpFile, char* buffer, size_t size, size_t count) {
2017-10-22 00:35:50 +00:00
Blob* blob = (Blob*) assimpFile->UserData;
2017-10-21 07:19:05 +00:00
char* data = blob->data;
2017-10-22 00:35:50 +00:00
size_t bytes = MIN(count * size * sizeof(char), blob->size - blob->seek);
memcpy(buffer, data + blob->seek, bytes);
2017-11-30 03:06:04 +00:00
blob->seek += bytes;
return bytes / size;
2017-10-21 07:19:05 +00:00
}
2017-10-22 00:35:50 +00:00
static size_t assimpBlobGetSize(struct aiFile* assimpFile) {
Blob* blob = (Blob*) assimpFile->UserData;
2017-10-21 07:19:05 +00:00
return blob->size;
}
2017-11-25 10:26:45 +00:00
static aiReturn assimpBlobSeek(struct aiFile* assimpFile, size_t position, enum aiOrigin origin) {
2017-10-22 00:35:50 +00:00
Blob* blob = (Blob*) assimpFile->UserData;
switch (origin) {
case aiOrigin_SET: blob->seek = position; break;
case aiOrigin_CUR: blob->seek += position; break;
case aiOrigin_END: blob->seek = blob->size - position; break;
default: return aiReturn_FAILURE;
}
return blob->seek < blob->size ? aiReturn_SUCCESS : aiReturn_FAILURE;
2017-10-21 07:19:05 +00:00
}
2017-11-25 10:26:45 +00:00
static size_t assimpBlobTell(struct aiFile* assimpFile) {
2017-10-22 00:35:50 +00:00
Blob* blob = (Blob*) assimpFile->UserData;
return blob->seek;
2017-10-21 07:19:05 +00:00
}
// File IO (for reading referenced materials/textures)
2017-11-25 10:26:45 +00:00
static size_t assimpFileRead(struct aiFile* assimpFile, char* buffer, size_t size, size_t count) {
2017-10-22 00:35:50 +00:00
File* file = (File*) assimpFile->UserData;
unsigned long bytes = lovrFileRead(file, buffer, size * count);
2017-11-30 03:06:04 +00:00
return bytes / size;
2017-10-21 07:19:05 +00:00
}
2017-10-22 00:35:50 +00:00
static size_t assimpFileGetSize(struct aiFile* assimpFile) {
File* file = (File*) assimpFile->UserData;
return lovrFileGetSize(file);
2017-10-21 07:19:05 +00:00
}
2017-11-25 10:26:45 +00:00
static aiReturn assimpFileSeek(struct aiFile* assimpFile, size_t position, enum aiOrigin origin) {
2017-10-22 00:35:50 +00:00
File* file = (File*) assimpFile->UserData;
return lovrFileSeek(file, position) ? aiReturn_FAILURE : aiReturn_SUCCESS;
2017-10-21 07:19:05 +00:00
}
static size_t assimpFileTell(struct aiFile* assimpFile) {
2017-10-22 00:35:50 +00:00
File* file = (File*) assimpFile->UserData;
return lovrFileTell(file);
2017-10-21 07:19:05 +00:00
}
static struct aiFile* assimpFileOpen(struct aiFileIO* io, const char* path, const char* mode) {
2017-10-22 00:35:50 +00:00
struct aiFile* assimpFile = malloc(sizeof(struct aiFile));
2017-10-21 07:19:05 +00:00
Blob* blob = (Blob*) io->UserData;
if (!strcmp(blob->name, path)) {
2017-11-30 03:06:04 +00:00
blob->seek = 0;
2017-10-22 00:35:50 +00:00
assimpFile->ReadProc = assimpBlobRead;
assimpFile->FileSizeProc = assimpBlobGetSize;
assimpFile->SeekProc = assimpBlobSeek;
assimpFile->TellProc = assimpBlobTell;
assimpFile->UserData = (void*) blob;
2017-10-21 07:19:05 +00:00
} else {
char tempPath[LOVR_PATH_MAX];
2017-10-22 00:35:50 +00:00
char normalizedPath[LOVR_PATH_MAX];
strncpy(tempPath, path, LOVR_PATH_MAX);
normalizePath(tempPath, normalizedPath, LOVR_PATH_MAX);
2017-10-22 00:35:50 +00:00
File* file = lovrFileCreate(normalizedPath);
2017-10-22 00:35:50 +00:00
if (lovrFileOpen(file, OPEN_READ)) {
2018-08-02 10:04:13 +00:00
lovrRelease(file);
2017-10-22 00:35:50 +00:00
return NULL;
}
assimpFile->ReadProc = assimpFileRead;
assimpFile->FileSizeProc = assimpFileGetSize;
assimpFile->SeekProc = assimpFileSeek;
assimpFile->TellProc = assimpFileTell;
assimpFile->UserData = (void*) file;
2017-10-21 07:19:05 +00:00
}
2017-10-22 00:35:50 +00:00
return assimpFile;
2017-10-21 07:19:05 +00:00
}
2017-10-22 00:35:50 +00:00
static void assimpFileClose(struct aiFileIO* io, struct aiFile* assimpFile) {
2017-10-21 07:19:05 +00:00
void* blob = io->UserData;
2017-10-22 00:35:50 +00:00
if (assimpFile->UserData != blob) {
File* file = (File*) assimpFile->UserData;
lovrFileClose(file);
2018-02-26 08:59:03 +00:00
lovrRelease(file);
2017-10-21 07:19:05 +00:00
}
2017-10-22 00:35:50 +00:00
free(assimpFile);
2017-10-21 07:19:05 +00:00
}
ModelData* lovrModelDataInit(ModelData* modelData, Blob* blob) {
2017-10-21 07:19:05 +00:00
struct aiFileIO assimpIO;
assimpIO.OpenProc = assimpFileOpen;
assimpIO.CloseProc = assimpFileClose;
assimpIO.UserData = (void*) blob;
struct aiPropertyStore* propertyStore = aiCreatePropertyStore();
aiSetImportPropertyInteger(propertyStore, AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_POINT | aiPrimitiveType_LINE);
2017-11-25 20:29:40 +00:00
aiSetImportPropertyInteger(propertyStore, AI_CONFIG_PP_SBBC_MAX_BONES, 48);
2017-12-10 03:11:53 +00:00
unsigned int flags = aiProcessPreset_TargetRealtime_MaxQuality | aiProcess_OptimizeGraph | aiProcess_SplitByBoneCount;
2017-10-21 07:19:05 +00:00
const struct aiScene* scene = aiImportFileExWithProperties(blob->name, flags, &assimpIO, propertyStore);
aiReleasePropertyStore(propertyStore);
lovrAssert(scene, "Unable to load model from '%s': %s", blob->name, aiGetErrorString());
2017-10-22 00:35:50 +00:00
2018-02-11 01:27:29 +00:00
uint32_t vertexCount = 0;
2018-01-27 02:58:36 +00:00
bool hasNormals = false;
bool hasUVs = false;
bool hasVertexColors = false;
2018-02-26 10:54:35 +00:00
bool hasTangents = false;
2018-01-27 02:58:36 +00:00
bool isSkinned = false;
2016-11-27 02:58:58 +00:00
for (unsigned int m = 0; m < scene->mNumMeshes; m++) {
struct aiMesh* assimpMesh = scene->mMeshes[m];
2018-02-11 01:27:29 +00:00
vertexCount += assimpMesh->mNumVertices;
modelData->indexCount += assimpMesh->mNumFaces * 3;
2018-01-27 02:58:36 +00:00
hasNormals |= assimpMesh->mNormals != NULL;
hasUVs |= assimpMesh->mTextureCoords[0] != NULL;
hasVertexColors |= assimpMesh->mColors[0] != NULL;
2018-02-26 10:54:35 +00:00
hasTangents |= assimpMesh->mTangents != NULL;
2018-01-27 02:58:36 +00:00
isSkinned |= assimpMesh->mNumBones > 0;
}
2016-10-29 22:18:10 +00:00
2018-02-11 01:27:29 +00:00
VertexFormat format;
vertexFormatInit(&format);
vertexFormatAppend(&format, "lovrPosition", ATTR_FLOAT, 3);
2018-01-27 02:58:36 +00:00
2018-02-11 01:27:29 +00:00
if (hasNormals) vertexFormatAppend(&format, "lovrNormal", ATTR_FLOAT, 3);
if (hasUVs) vertexFormatAppend(&format, "lovrTexCoord", ATTR_FLOAT, 2);
if (hasVertexColors) vertexFormatAppend(&format, "lovrVertexColor", ATTR_BYTE, 4);
2018-02-26 10:54:35 +00:00
if (hasTangents) vertexFormatAppend(&format, "lovrTangent", ATTR_FLOAT, 3);
2018-02-11 01:27:29 +00:00
size_t boneByteOffset = format.stride;
if (isSkinned) vertexFormatAppend(&format, "lovrBones", ATTR_INT, 4);
if (isSkinned) vertexFormatAppend(&format, "lovrBoneWeights", ATTR_FLOAT, 4);
2018-01-27 02:58:36 +00:00
// Allocate
2018-03-21 21:48:46 +00:00
modelData->vertexData = lovrVertexDataCreate(vertexCount, &format);
2018-02-11 01:27:29 +00:00
modelData->indexSize = vertexCount > USHRT_MAX ? sizeof(uint32_t) : sizeof(uint16_t);
modelData->indices.raw = malloc(modelData->indexCount * modelData->indexSize);
modelData->primitiveCount = scene->mNumMeshes;
modelData->primitives = malloc(modelData->primitiveCount * sizeof(ModelPrimitive));
2017-11-02 06:10:21 +00:00
2017-10-24 02:24:23 +00:00
// Load vertices
2018-02-11 01:27:29 +00:00
IndexPointer indices = modelData->indices;
2017-11-02 06:10:21 +00:00
uint32_t vertex = 0;
uint32_t index = 0;
2016-11-12 09:19:47 +00:00
for (unsigned int m = 0; m < scene->mNumMeshes; m++) {
2016-10-29 22:18:10 +00:00
struct aiMesh* assimpMesh = scene->mMeshes[m];
ModelPrimitive* primitive = &modelData->primitives[m];
primitive->material = assimpMesh->mMaterialIndex;
primitive->drawStart = index;
primitive->drawCount = 0;
2017-11-02 06:10:21 +00:00
uint32_t baseVertex = vertex;
2016-10-29 22:18:10 +00:00
// Indices
2016-11-12 09:19:47 +00:00
for (unsigned int f = 0; f < assimpMesh->mNumFaces; f++) {
2016-10-29 22:18:10 +00:00
struct aiFace assimpFace = assimpMesh->mFaces[f];
lovrAssert(assimpFace.mNumIndices == 3, "Only triangular faces are supported");
2016-10-31 20:54:32 +00:00
primitive->drawCount += assimpFace.mNumIndices;
2016-10-31 20:54:32 +00:00
2017-11-02 02:27:58 +00:00
if (modelData->indexSize == sizeof(uint16_t)) {
for (unsigned int i = 0; i < assimpFace.mNumIndices; i++) {
2017-11-02 06:10:21 +00:00
indices.shorts[index++] = baseVertex + assimpFace.mIndices[i];
}
2017-11-02 02:27:58 +00:00
} else {
for (unsigned int i = 0; i < assimpFace.mNumIndices; i++) {
2017-11-02 06:10:21 +00:00
indices.ints[index++] = baseVertex + assimpFace.mIndices[i];
}
2016-10-29 22:18:10 +00:00
}
}
2017-11-02 06:10:21 +00:00
// Vertices
2016-11-12 09:19:47 +00:00
for (unsigned int v = 0; v < assimpMesh->mNumVertices; v++) {
VertexPointer vertices = { .raw = modelData->vertexData->blob.data };
2018-02-11 01:27:29 +00:00
vertices.bytes += vertex * modelData->vertexData->format.stride;
2017-11-02 06:10:21 +00:00
2017-10-24 02:24:23 +00:00
*vertices.floats++ = assimpMesh->mVertices[v].x;
*vertices.floats++ = assimpMesh->mVertices[v].y;
*vertices.floats++ = assimpMesh->mVertices[v].z;
2018-01-27 02:58:36 +00:00
if (hasNormals) {
if (assimpMesh->mNormals) {
2017-10-24 02:24:23 +00:00
*vertices.floats++ = assimpMesh->mNormals[v].x;
*vertices.floats++ = assimpMesh->mNormals[v].y;
*vertices.floats++ = assimpMesh->mNormals[v].z;
} else {
2017-10-24 02:24:23 +00:00
*vertices.floats++ = 0;
*vertices.floats++ = 0;
*vertices.floats++ = 0;
}
}
2016-11-23 08:02:19 +00:00
2018-01-27 02:58:36 +00:00
if (hasUVs) {
if (assimpMesh->mTextureCoords[0]) {
2017-10-24 02:24:23 +00:00
*vertices.floats++ = assimpMesh->mTextureCoords[0][v].x;
*vertices.floats++ = assimpMesh->mTextureCoords[0][v].y;
} else {
2017-10-24 02:24:23 +00:00
*vertices.floats++ = 0;
*vertices.floats++ = 0;
}
2016-11-23 08:02:19 +00:00
}
2017-10-24 02:24:23 +00:00
2018-01-27 02:58:36 +00:00
if (hasVertexColors) {
2017-10-24 02:24:23 +00:00
if (assimpMesh->mColors[0]) {
*vertices.bytes++ = assimpMesh->mColors[0][v].r * 255;
*vertices.bytes++ = assimpMesh->mColors[0][v].g * 255;
*vertices.bytes++ = assimpMesh->mColors[0][v].b * 255;
*vertices.bytes++ = assimpMesh->mColors[0][v].a * 255;
} else {
*vertices.bytes++ = 255;
*vertices.bytes++ = 255;
*vertices.bytes++ = 255;
*vertices.bytes++ = 255;
}
}
2018-02-26 10:54:35 +00:00
if (hasTangents) {
if (assimpMesh->mTangents) {
*vertices.floats++ = assimpMesh->mTangents[v].x;
*vertices.floats++ = assimpMesh->mTangents[v].y;
*vertices.floats++ = assimpMesh->mTangents[v].z;
} else {
*vertices.floats++ = 0;
*vertices.floats++ = 0;
*vertices.floats++ = 0;
}
}
2017-10-24 02:24:23 +00:00
vertex++;
2016-11-23 08:02:19 +00:00
}
2017-11-02 06:10:21 +00:00
// Bones
primitive->boneCount = assimpMesh->mNumBones;
map_init(&primitive->boneMap);
2017-11-02 06:10:21 +00:00
for (unsigned int b = 0; b < assimpMesh->mNumBones; b++) {
struct aiBone* assimpBone = assimpMesh->mBones[b];
Bone* bone = &primitive->bones[b];
2017-11-02 06:10:21 +00:00
bone->name = strdup(assimpBone->mName.data);
aiTransposeMatrix4(&assimpBone->mOffsetMatrix);
mat4_set(bone->offset, (float*) &assimpBone->mOffsetMatrix);
map_set(&primitive->boneMap, bone->name, b);
2017-11-02 06:10:21 +00:00
for (unsigned int w = 0; w < assimpBone->mNumWeights; w++) {
uint32_t vertexIndex = baseVertex + assimpBone->mWeights[w].mVertexId;
float weight = assimpBone->mWeights[w].mWeight;
VertexPointer vertices = { .raw = modelData->vertexData->blob.data };
2018-02-11 01:27:29 +00:00
vertices.bytes += vertexIndex * modelData->vertexData->format.stride;
uint32_t* bones = (uint32_t*) (vertices.bytes + boneByteOffset);
2017-11-02 06:10:21 +00:00
float* weights = (float*) (bones + MAX_BONES_PER_VERTEX);
int boneSlot = 0;
while (weights[boneSlot] > 0) {
boneSlot++;
lovrAssert(boneSlot < MAX_BONES_PER_VERTEX, "Too many bones for vertex %d", vertexIndex);
}
bones[boneSlot] = b;
2017-11-02 06:10:21 +00:00
weights[boneSlot] = weight;
}
}
2016-10-09 04:52:58 +00:00
}
2016-10-29 22:18:10 +00:00
2017-10-21 22:20:16 +00:00
// Materials
2018-01-30 05:44:32 +00:00
map_int_t textureCache;
map_init(&textureCache);
vec_init(&modelData->textures);
2018-02-14 05:24:18 +00:00
vec_push(&modelData->textures, NULL);
2017-10-21 22:20:16 +00:00
modelData->materialCount = scene->mNumMaterials;
2018-01-30 05:44:32 +00:00
modelData->materials = malloc(modelData->materialCount * sizeof(ModelMaterial));
2017-10-21 22:20:16 +00:00
for (unsigned int m = 0; m < scene->mNumMaterials; m++) {
2018-01-30 05:44:32 +00:00
ModelMaterial* material = &modelData->materials[m];
struct aiMaterial* assimpMaterial = scene->mMaterials[m];
2017-10-21 22:20:16 +00:00
material->diffuseColor = readMaterialColor(assimpMaterial, AI_MATKEY_COLOR_DIFFUSE, (Color) { 1., 1., 1., 1. });
material->emissiveColor = readMaterialColor(assimpMaterial, AI_MATKEY_COLOR_EMISSIVE, (Color) { 0., 0., 0., 0. });
2018-01-30 05:44:32 +00:00
material->diffuseTexture = readMaterialTexture(assimpMaterial, aiTextureType_DIFFUSE, modelData, &textureCache, blob->name);
2018-02-12 03:16:40 +00:00
material->emissiveTexture = readMaterialTexture(assimpMaterial, aiTextureType_EMISSIVE, modelData, &textureCache, blob->name);
material->metalnessTexture = readMaterialTexture(assimpMaterial, aiTextureType_UNKNOWN, modelData, &textureCache, blob->name);
material->roughnessTexture = material->metalnessTexture;
material->occlusionTexture = readMaterialTexture(assimpMaterial, aiTextureType_LIGHTMAP, modelData, &textureCache, blob->name);
material->normalTexture = readMaterialTexture(assimpMaterial, aiTextureType_NORMALS, modelData, &textureCache, blob->name);
material->metalness = readMaterialScalar(assimpMaterial, "$mat.gltf.pbrMetallicRoughness.metallicFactor", 0, 0);
material->roughness = readMaterialScalar(assimpMaterial, "$mat.gltf.pbrMetallicRoughness.roughnessFactor", 0, 0);
2017-10-21 22:20:16 +00:00
}
2018-01-30 05:44:32 +00:00
map_deinit(&textureCache);
2017-10-21 22:20:16 +00:00
2016-10-29 22:18:10 +00:00
// Nodes
modelData->nodeCount = 0;
assimpSumChildren(scene->mRootNode, &modelData->nodeCount);
modelData->nodes = malloc(modelData->nodeCount * sizeof(ModelNode));
modelData->nodes[0].parent = -1;
map_init(&modelData->nodeMap);
int nodeIndex = 0;
assimpNodeTraversal(modelData, scene->mRootNode, &nodeIndex);
2016-10-29 22:18:10 +00:00
2017-11-02 06:10:21 +00:00
// Animations
2018-01-30 04:30:13 +00:00
modelData->animationCount = scene->mNumAnimations;
modelData->animations = malloc(modelData->animationCount * sizeof(Animation));
for (int i = 0; i < modelData->animationCount; i++) {
2017-11-02 06:10:21 +00:00
struct aiAnimation* assimpAnimation = scene->mAnimations[i];
float ticksPerSecond = assimpAnimation->mTicksPerSecond;
2017-11-02 06:10:21 +00:00
2018-01-30 04:30:13 +00:00
Animation* animation = &modelData->animations[i];
animation->name = strdup(assimpAnimation->mName.data);
animation->duration = assimpAnimation->mDuration / ticksPerSecond;
animation->channelCount = assimpAnimation->mNumChannels;
map_init(&animation->channels);
2017-11-03 06:47:13 +00:00
2018-01-30 04:30:13 +00:00
for (int j = 0; j < animation->channelCount; j++) {
2017-11-02 06:10:21 +00:00
struct aiNodeAnim* assimpChannel = assimpAnimation->mChannels[j];
AnimationChannel channel;
channel.node = strdup(assimpChannel->mNodeName.data);
2017-11-02 06:10:21 +00:00
vec_init(&channel.positionKeyframes);
vec_init(&channel.rotationKeyframes);
vec_init(&channel.scaleKeyframes);
for (unsigned int k = 0; k < assimpChannel->mNumPositionKeys; k++) {
struct aiVectorKey assimpKeyframe = assimpChannel->mPositionKeys[k];
struct aiVector3D position = assimpKeyframe.mValue;
2018-07-04 21:46:52 +00:00
vec_push(&channel.positionKeyframes, ((Keyframe) {
.time = assimpKeyframe.mTime / ticksPerSecond,
.data = { position.x, position.y, position.z }
}));
2017-11-02 06:10:21 +00:00
}
for (unsigned int k = 0; k < assimpChannel->mNumRotationKeys; k++) {
struct aiQuatKey assimpKeyframe = assimpChannel->mRotationKeys[k];
struct aiQuaternion quaternion = assimpKeyframe.mValue;
2018-07-04 21:46:52 +00:00
vec_push(&channel.rotationKeyframes, ((Keyframe) {
.time = assimpKeyframe.mTime / ticksPerSecond,
.data = { quaternion.x, quaternion.y, quaternion.z, quaternion.w }
}));
2017-11-02 06:10:21 +00:00
}
for (unsigned int k = 0; k < assimpChannel->mNumScalingKeys; k++) {
struct aiVectorKey assimpKeyframe = assimpChannel->mScalingKeys[k];
struct aiVector3D scale = assimpKeyframe.mValue;
2018-07-04 21:46:52 +00:00
vec_push(&channel.scaleKeyframes, ((Keyframe) {
.time = assimpKeyframe.mTime / ticksPerSecond,
.data = { scale.x, scale.y, scale.z }
}));
2017-11-02 06:10:21 +00:00
}
2018-01-30 04:30:13 +00:00
map_set(&animation->channels, channel.node, channel);
2017-11-02 06:10:21 +00:00
}
}
2016-10-09 04:52:58 +00:00
aiReleaseImport(scene);
2016-10-04 04:54:27 +00:00
return modelData;
}
#else
static void aabbIterator(ModelData* modelData, ModelNode* node, float aabb[6]) {}
ModelData* lovrModelDataInit(ModelData* modelData, Blob* blob) {
return NULL;
}
#endif
2016-10-04 04:54:27 +00:00
2018-02-26 08:59:03 +00:00
void lovrModelDataDestroy(void* ref) {
ModelData* modelData = ref;
2018-01-23 02:24:39 +00:00
2017-10-21 22:20:16 +00:00
for (int i = 0; i < modelData->nodeCount; i++) {
vec_deinit(&modelData->nodes[i].children);
vec_deinit(&modelData->nodes[i].primitives);
free((char*) modelData->nodes[i].name);
2017-02-19 09:54:58 +00:00
}
for (int i = 0; i < modelData->primitiveCount; i++) {
ModelPrimitive* primitive = &modelData->primitives[i];
for (int j = 0; j < primitive->boneCount; j++) {
free((char*) primitive->bones[j].name);
}
map_deinit(&primitive->boneMap);
}
2018-01-30 04:30:13 +00:00
for (int i = 0; i < modelData->animationCount; i++) {
Animation* animation = &modelData->animations[i];
const char* key;
map_iter_t iter = map_iter(&animation->channels);
while ((key = map_next(&animation->channels, &iter)) != NULL) {
AnimationChannel* channel = map_get(&animation->channels, key);
vec_deinit(&channel->positionKeyframes);
vec_deinit(&channel->rotationKeyframes);
vec_deinit(&channel->scaleKeyframes);
}
map_deinit(&animation->channels);
free((char*) animation->name);
2018-01-06 05:09:16 +00:00
}
2017-11-02 06:10:21 +00:00
2018-01-30 05:44:32 +00:00
for (int i = 0; i < modelData->textures.length; i++) {
2018-02-26 08:59:03 +00:00
lovrRelease(modelData->textures.data[i]);
2017-10-21 22:20:16 +00:00
}
2018-01-30 05:44:32 +00:00
vec_deinit(&modelData->textures);
map_deinit(&modelData->nodeMap);
2018-02-26 08:59:03 +00:00
lovrRelease(modelData->vertexData);
2018-02-11 01:27:29 +00:00
free(modelData->nodes);
free(modelData->primitives);
2018-01-30 04:30:13 +00:00
free(modelData->animations);
2017-10-21 22:20:16 +00:00
free(modelData->materials);
2018-02-11 01:27:29 +00:00
free(modelData->indices.raw);
2017-02-19 09:54:58 +00:00
}
2017-11-02 02:27:58 +00:00
void lovrModelDataGetAABB(ModelData* modelData, float aabb[6]) {
2017-12-01 05:17:54 +00:00
aabb[0] = FLT_MAX;
aabb[1] = -FLT_MAX;
aabb[2] = FLT_MAX;
aabb[3] = -FLT_MAX;
aabb[4] = FLT_MAX;
aabb[5] = -FLT_MAX;
2018-03-02 04:51:57 +00:00
aabbIterator(modelData, &modelData->nodes[0], aabb);
2017-11-02 02:27:58 +00:00
}