mirror of https://github.com/bjornbytes/lovr.git
OBJ groups/materials;
This commit is contained in:
parent
6857b01ac0
commit
4373e29bea
|
@ -16,8 +16,8 @@ void lovrModelDataDestroy(void* ref) {
|
|||
for (int i = 0; i < model->blobCount; i++) {
|
||||
lovrRelease(model->blobs[i]);
|
||||
}
|
||||
for (int i = 0; i < model->imageCount; i++) {
|
||||
lovrRelease(model->images[i]);
|
||||
for (int i = 0; i < model->textureCount; i++) {
|
||||
lovrRelease(model->textures[i]);
|
||||
}
|
||||
free(model->data);
|
||||
}
|
||||
|
@ -25,37 +25,35 @@ void lovrModelDataDestroy(void* ref) {
|
|||
// Note: this code is a scary optimization
|
||||
void lovrModelDataAllocate(ModelData* model) {
|
||||
size_t totalSize = 0;
|
||||
size_t sizes[14];
|
||||
size_t sizes[13];
|
||||
totalSize += sizes[0] = model->blobCount * sizeof(Blob*);
|
||||
totalSize += sizes[1] = model->imageCount * sizeof(TextureData*);
|
||||
totalSize += sizes[2] = model->animationCount * sizeof(ModelAnimation);
|
||||
totalSize += sizes[3] = model->attributeCount * sizeof(ModelAttribute);
|
||||
totalSize += sizes[4] = model->bufferCount * sizeof(ModelBuffer);
|
||||
totalSize += sizes[5] = model->textureCount * sizeof(ModelTexture);
|
||||
totalSize += sizes[6] = model->materialCount * sizeof(ModelMaterial);
|
||||
totalSize += sizes[7] = model->primitiveCount * sizeof(ModelPrimitive);
|
||||
totalSize += sizes[1] = model->bufferCount * sizeof(ModelBuffer);
|
||||
totalSize += sizes[2] = model->textureCount * sizeof(TextureData*);
|
||||
totalSize += sizes[3] = model->materialCount * sizeof(ModelMaterial);
|
||||
totalSize += sizes[4] = model->attributeCount * sizeof(ModelAttribute);
|
||||
totalSize += sizes[5] = model->primitiveCount * sizeof(ModelPrimitive);
|
||||
totalSize += sizes[6] = model->animationCount * sizeof(ModelAnimation);
|
||||
totalSize += sizes[7] = model->skinCount * sizeof(ModelSkin);
|
||||
totalSize += sizes[8] = model->nodeCount * sizeof(ModelNode);
|
||||
totalSize += sizes[9] = model->skinCount * sizeof(ModelSkin);
|
||||
totalSize += sizes[10] = model->channelCount * sizeof(ModelAnimationChannel);
|
||||
totalSize += sizes[11] = model->childCount * sizeof(uint32_t);
|
||||
totalSize += sizes[12] = model->jointCount * sizeof(uint32_t);
|
||||
totalSize += sizes[13] = model->charCount * sizeof(char);
|
||||
totalSize += sizes[9] = model->channelCount * sizeof(ModelAnimationChannel);
|
||||
totalSize += sizes[10] = model->childCount * sizeof(uint32_t);
|
||||
totalSize += sizes[11] = model->jointCount * sizeof(uint32_t);
|
||||
totalSize += sizes[12] = model->charCount * sizeof(char);
|
||||
|
||||
size_t offset = 0;
|
||||
char* p = model->data = calloc(1, totalSize);
|
||||
lovrAssert(model->data, "Out of memory");
|
||||
model->blobs = (Blob**) (p + offset), offset += sizes[0];
|
||||
model->images = (TextureData**) (p + offset), offset += sizes[1];
|
||||
model->animations = (ModelAnimation*) (p + offset), offset += sizes[2];
|
||||
model->attributes = (ModelAttribute*) (p + offset), offset += sizes[3];
|
||||
model->buffers = (ModelBuffer*) (p + offset), offset += sizes[4];
|
||||
model->textures = (ModelTexture*) (p + offset), offset += sizes[5];
|
||||
model->materials = (ModelMaterial*) (p + offset), offset += sizes[6];
|
||||
model->primitives = (ModelPrimitive*) (p + offset), offset += sizes[7];
|
||||
model->buffers = (ModelBuffer*) (p + offset), offset += sizes[1];
|
||||
model->textures = (TextureData**) (p + offset), offset += sizes[2];
|
||||
model->materials = (ModelMaterial*) (p + offset), offset += sizes[3];
|
||||
model->attributes = (ModelAttribute*) (p + offset), offset += sizes[4];
|
||||
model->primitives = (ModelPrimitive*) (p + offset), offset += sizes[5];
|
||||
model->animations = (ModelAnimation*) (p + offset), offset += sizes[6];
|
||||
model->skins = (ModelSkin*) (p + offset), offset += sizes[7];
|
||||
model->nodes = (ModelNode*) (p + offset), offset += sizes[8];
|
||||
model->skins = (ModelSkin*) (p + offset), offset += sizes[9];
|
||||
model->channels = (ModelAnimationChannel*) (p + offset), offset += sizes[10];
|
||||
model->children = (uint32_t*) (p + offset), offset += sizes[11];
|
||||
model->joints = (uint32_t*) (p + offset), offset += sizes[12];
|
||||
model->chars = (char*) (p + offset), offset += sizes[13];
|
||||
model->channels = (ModelAnimationChannel*) (p + offset), offset += sizes[9];
|
||||
model->children = (uint32_t*) (p + offset), offset += sizes[10];
|
||||
model->joints = (uint32_t*) (p + offset), offset += sizes[11];
|
||||
model->chars = (char*) (p + offset), offset += sizes[12];
|
||||
}
|
||||
|
|
|
@ -136,6 +136,8 @@ typedef struct {
|
|||
float scalars[MAX_MATERIAL_SCALARS];
|
||||
Color colors[MAX_MATERIAL_COLORS];
|
||||
int textures[MAX_MATERIAL_TEXTURES];
|
||||
TextureFilter filters[MAX_MATERIAL_TEXTURES];
|
||||
TextureWrap wraps[MAX_MATERIAL_TEXTURES];
|
||||
} ModelMaterial;
|
||||
|
||||
typedef struct {
|
||||
|
@ -164,26 +166,25 @@ typedef struct {
|
|||
Ref ref;
|
||||
void* data;
|
||||
Blob** blobs;
|
||||
TextureData** images;
|
||||
ModelAnimation* animations;
|
||||
ModelAttribute* attributes;
|
||||
ModelBuffer* buffers;
|
||||
ModelTexture* textures;
|
||||
TextureData** textures;
|
||||
ModelMaterial* materials;
|
||||
ModelAttribute* attributes;
|
||||
ModelPrimitive* primitives;
|
||||
ModelNode* nodes;
|
||||
ModelAnimation* animations;
|
||||
ModelSkin* skins;
|
||||
ModelNode* nodes;
|
||||
int rootNode;
|
||||
|
||||
int blobCount;
|
||||
int imageCount;
|
||||
int animationCount;
|
||||
int attributeCount;
|
||||
int bufferCount;
|
||||
int textureCount;
|
||||
int materialCount;
|
||||
int attributeCount;
|
||||
int primitiveCount;
|
||||
int nodeCount;
|
||||
int animationCount;
|
||||
int skinCount;
|
||||
int rootNode;
|
||||
int nodeCount;
|
||||
|
||||
ModelAnimationChannel* channels;
|
||||
uint32_t* children;
|
||||
|
|
|
@ -51,6 +51,11 @@ typedef struct {
|
|||
TextureWrap wrap;
|
||||
} gltfSampler;
|
||||
|
||||
typedef struct {
|
||||
int image;
|
||||
int sampler;
|
||||
} gltfTexture;
|
||||
|
||||
typedef struct {
|
||||
uint32_t node;
|
||||
uint32_t nodeCount;
|
||||
|
@ -89,11 +94,14 @@ static jsmntok_t* aggregate(const char* json, jsmntok_t* token, const char* targ
|
|||
return token;
|
||||
}
|
||||
|
||||
static jsmntok_t* parseTextureInfo(const char* json, jsmntok_t* token, int* dest) {
|
||||
static jsmntok_t* resolveTexture(const char* json, jsmntok_t* token, ModelMaterial* material, MaterialTexture type, gltfTexture* textures, gltfSampler* samplers) {
|
||||
for (int k = (token++)->size; k > 0; k--) {
|
||||
gltfString key = NOM_STR(json, token);
|
||||
if (STR_EQ(key, "index")) {
|
||||
*dest = NOM_INT(json, token);
|
||||
int index = NOM_INT(json, token);
|
||||
material->textures[type] = textures[index].image;
|
||||
material->filters[type] = samplers[textures[index].sampler].filter;
|
||||
material->wraps[type] = samplers[textures[index].sampler].wrap;
|
||||
} else if (STR_EQ(key, "texCoord")) {
|
||||
lovrAssert(NOM_INT(json, token) == 0, "Only one set of texture coordinates is supported");
|
||||
} else {
|
||||
|
@ -148,10 +156,12 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO io)
|
|||
|
||||
if ((tokenCount = jsmn_parse(&parser, json, jsonLength, stackTokens, MAX_STACK_TOKENS)) == JSMN_ERROR_NOMEM) {
|
||||
size_t capacity = MAX_STACK_TOKENS;
|
||||
jsmn_init(&parser); // This shouldn't be necessary but not doing it caused an infinite loop?
|
||||
|
||||
do {
|
||||
capacity *= 2;
|
||||
lovrAssert(heapTokens = realloc(heapTokens, capacity), "Out of memory");
|
||||
heapTokens = realloc(heapTokens, capacity * sizeof(jsmntok_t));
|
||||
lovrAssert(heapTokens, "Out of memory");
|
||||
tokenCount = jsmn_parse(&parser, json, jsonLength, heapTokens, capacity);
|
||||
} while (tokenCount == JSMN_ERROR_NOMEM);
|
||||
|
||||
|
@ -172,7 +182,6 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO io)
|
|||
jsmntok_t* buffers;
|
||||
jsmntok_t* bufferViews;
|
||||
jsmntok_t* images;
|
||||
jsmntok_t* textures;
|
||||
jsmntok_t* materials;
|
||||
jsmntok_t* meshes;
|
||||
jsmntok_t* nodes;
|
||||
|
@ -184,6 +193,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO io)
|
|||
gltfAnimationSampler* animationSamplers = NULL;
|
||||
gltfMesh* meshes = NULL;
|
||||
gltfSampler* samplers = NULL;
|
||||
gltfTexture* textures = NULL;
|
||||
gltfScene* scenes = NULL;
|
||||
int rootScene = 0;
|
||||
|
||||
|
@ -256,7 +266,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO io)
|
|||
|
||||
} else if (STR_EQ(key, "images")) {
|
||||
info.images = token;
|
||||
model->imageCount = token->size;
|
||||
model->textureCount = token->size;
|
||||
token += NOM_VALUE(json, token);
|
||||
|
||||
} else if (STR_EQ(key, "samplers")) {
|
||||
|
@ -304,9 +314,21 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO io)
|
|||
}
|
||||
|
||||
} else if (STR_EQ(key, "textures")) {
|
||||
info.textures = token;
|
||||
model->textureCount = token->size;
|
||||
token += NOM_VALUE(json, token);
|
||||
textures = malloc(token->size * sizeof(gltfTexture));
|
||||
lovrAssert(textures, "Out of memory");
|
||||
gltfTexture* texture = textures;
|
||||
for (int i = (token++)->size; i > 0; i--, texture++) {
|
||||
for (int k = (token++)->size; k > 0; k--) {
|
||||
gltfString key = NOM_STR(json, token);
|
||||
if (STR_EQ(key, "source")) {
|
||||
texture->image = NOM_INT(json, token);
|
||||
} else if (STR_EQ(key, "sampler")) {
|
||||
texture->sampler = NOM_INT(json, token);
|
||||
} else {
|
||||
token += NOM_VALUE(json, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (STR_EQ(key, "materials")) {
|
||||
info.materials = token;
|
||||
|
@ -561,17 +583,17 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO io)
|
|||
}
|
||||
}
|
||||
|
||||
// Images
|
||||
if (model->imageCount > 0) {
|
||||
// Textures (glTF images)
|
||||
if (model->textureCount > 0) {
|
||||
jsmntok_t* token = info.images;
|
||||
TextureData** image = model->images;
|
||||
for (int i = (token++)->size; i > 0; i--, image++) {
|
||||
TextureData** texture = model->textures;
|
||||
for (int i = (token++)->size; i > 0; i--, texture++) {
|
||||
for (int k = (token++)->size; k > 0; k--) {
|
||||
gltfString key = NOM_STR(json, token);
|
||||
if (STR_EQ(key, "bufferView")) {
|
||||
ModelBuffer* buffer = &model->buffers[NOM_INT(json, token)];
|
||||
Blob* blob = lovrBlobCreate(buffer->data, buffer->size, NULL);
|
||||
*image = lovrTextureDataCreateFromBlob(blob, false);
|
||||
*texture = lovrTextureDataCreateFromBlob(blob, false);
|
||||
blob->data = NULL; // FIXME
|
||||
lovrRelease(blob);
|
||||
} else if (STR_EQ(key, "uri")) {
|
||||
|
@ -580,10 +602,10 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO io)
|
|||
gltfString uri = NOM_STR(json, token);
|
||||
lovrAssert(strncmp("data:", uri.data, strlen("data:")), "Base64 URIs aren't supported yet");
|
||||
snprintf(filename, 1024, "%s/%.*s%c", basePath, (int) uri.length, uri.data, 0);
|
||||
void* data = io.read(filename, &size);
|
||||
lovrAssert(data && size > 0, "Unable to read image from '%s'", filename);
|
||||
void* data = lovrFilesystemRead(filename, &size);
|
||||
lovrAssert(data && size > 0, "Unable to read texture from '%s'", filename);
|
||||
Blob* blob = lovrBlobCreate(data, size, NULL);
|
||||
*image = lovrTextureDataCreateFromBlob(blob, false);
|
||||
*texture = lovrTextureDataCreateFromBlob(blob, false);
|
||||
lovrRelease(blob);
|
||||
} else {
|
||||
token += NOM_VALUE(json, token);
|
||||
|
@ -592,27 +614,6 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO io)
|
|||
}
|
||||
}
|
||||
|
||||
// Textures
|
||||
if (model->textureCount > 0) {
|
||||
jsmntok_t* token = info.textures;
|
||||
ModelTexture* texture = model->textures;
|
||||
for (int i = (token++)->size; i > 0; i--, texture++) {
|
||||
texture->filter.mode = FILTER_TRILINEAR;
|
||||
texture->wrap.s = texture->wrap.t = WRAP_REPEAT;
|
||||
for (int k = (token++)->size; k > 0; k--) {
|
||||
gltfString key = NOM_STR(json, token);
|
||||
if (STR_EQ(key, "source")) {
|
||||
texture->imageIndex = NOM_INT(json, token);
|
||||
} else if (STR_EQ(key, "sampler")) {
|
||||
gltfSampler* sampler = &samplers[NOM_INT(json, token)];
|
||||
texture->filter = sampler->filter;
|
||||
texture->wrap = sampler->wrap;
|
||||
}
|
||||
else { token += NOM_VALUE(json, token); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Materials
|
||||
if (model->materialCount > 0) {
|
||||
jsmntok_t* token = info.materials;
|
||||
|
@ -636,24 +637,26 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO io)
|
|||
material->colors[COLOR_DIFFUSE].b = NOM_FLOAT(json, token);
|
||||
material->colors[COLOR_DIFFUSE].a = NOM_FLOAT(json, token);
|
||||
} else if (STR_EQ(key, "baseColorTexture")) {
|
||||
token = parseTextureInfo(json, token, &material->textures[TEXTURE_DIFFUSE]);
|
||||
token = resolveTexture(json, token, material, TEXTURE_DIFFUSE, textures, samplers);
|
||||
} else if (STR_EQ(key, "metallicFactor")) {
|
||||
material->scalars[SCALAR_METALNESS] = NOM_FLOAT(json, token);
|
||||
} else if (STR_EQ(key, "roughnessFactor")) {
|
||||
material->scalars[SCALAR_ROUGHNESS] = NOM_FLOAT(json, token);
|
||||
} else if (STR_EQ(key, "metallicRoughnessTexture")) {
|
||||
token = parseTextureInfo(json, token, &material->textures[TEXTURE_METALNESS]);
|
||||
token = resolveTexture(json, token, material, TEXTURE_METALNESS, textures, samplers);
|
||||
material->textures[TEXTURE_ROUGHNESS] = material->textures[TEXTURE_METALNESS];
|
||||
material->filters[TEXTURE_ROUGHNESS] = material->filters[TEXTURE_METALNESS];
|
||||
material->wraps[TEXTURE_ROUGHNESS] = material->wraps[TEXTURE_METALNESS];
|
||||
} else {
|
||||
token += NOM_VALUE(json, token);
|
||||
}
|
||||
}
|
||||
} else if (STR_EQ(key, "normalTexture")) {
|
||||
token = parseTextureInfo(json, token, &material->textures[TEXTURE_NORMAL]);
|
||||
token = resolveTexture(json, token, material, TEXTURE_NORMAL, textures, samplers);
|
||||
} else if (STR_EQ(key, "occlusionTexture")) {
|
||||
token = parseTextureInfo(json, token, &material->textures[TEXTURE_OCCLUSION]);
|
||||
token = resolveTexture(json, token, material, TEXTURE_OCCLUSION, textures, samplers);
|
||||
} else if (STR_EQ(key, "emissiveTexture")) {
|
||||
token = parseTextureInfo(json, token, &material->textures[TEXTURE_EMISSIVE]);
|
||||
token = resolveTexture(json, token, material, TEXTURE_EMISSIVE, textures, samplers);
|
||||
} else if (STR_EQ(key, "emissiveFactor")) {
|
||||
token++; // Enter array
|
||||
material->colors[COLOR_EMISSIVE].r = NOM_FLOAT(json, token);
|
||||
|
@ -852,6 +855,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO io)
|
|||
free(animationSamplers);
|
||||
free(meshes);
|
||||
free(samplers);
|
||||
free(textures);
|
||||
free(scenes);
|
||||
free(heapTokens);
|
||||
return model;
|
||||
|
|
|
@ -1,27 +1,116 @@
|
|||
#include "data/modelData.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "lib/math.h"
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
typedef vec_t(ModelMaterial) vec_material_t;
|
||||
|
||||
typedef struct {
|
||||
int material;
|
||||
int start;
|
||||
int count;
|
||||
} objGroup;
|
||||
|
||||
typedef vec_t(objGroup) vec_group_t;
|
||||
|
||||
#define STARTS_WITH(a, b) !strncmp(a, b, strlen(b))
|
||||
|
||||
ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO io) {
|
||||
static void parseMtl(char* path, vec_void_t* textures, vec_material_t* materials, map_int_t* names, char* base) {
|
||||
size_t length = 0;
|
||||
char* data = lovrFilesystemRead(path, &length);
|
||||
lovrAssert(data && length > 0, "Unable to read mtl from '%s'", path);
|
||||
char* s = data;
|
||||
|
||||
while (length > 0) {
|
||||
int lineLength = 0;
|
||||
|
||||
if (STARTS_WITH(s, "newmtl ")) {
|
||||
char name[128];
|
||||
bool hasName = sscanf(s + 7, "%s\n%n", name, &lineLength);
|
||||
lovrAssert(hasName, "Bad OBJ: Expected a material name");
|
||||
map_set(names, name, materials->length);
|
||||
vec_push(materials, ((ModelMaterial) {
|
||||
.scalars[SCALAR_METALNESS] = 1.f,
|
||||
.scalars[SCALAR_ROUGHNESS] = 1.f,
|
||||
.colors[COLOR_DIFFUSE] = { 1.f, 1.f, 1.f, 1.f },
|
||||
.colors[COLOR_EMISSIVE] = { 0.f, 0.f, 0.f, 0.f }
|
||||
}));
|
||||
memset(&vec_last(materials).textures, 0xff, MAX_MATERIAL_TEXTURES * sizeof(int));
|
||||
} else if (STARTS_WITH(s, "Kd")) {
|
||||
float r, g, b;
|
||||
int count = sscanf(s + 2, "%f %f %f\n%n", &r, &g, &b, &lineLength);
|
||||
lovrAssert(count == 3, "Bad OBJ: Expected 3 components for diffuse color");
|
||||
ModelMaterial* material = &vec_last(materials);
|
||||
material->colors[COLOR_DIFFUSE] = (Color) { r, g, b, 1.f };
|
||||
} else if (STARTS_WITH(s, "map_Kd")) {
|
||||
|
||||
// Read file
|
||||
char filename[128];
|
||||
bool hasFilename = sscanf(s + 7, "%s\n%n", filename, &lineLength);
|
||||
lovrAssert(hasFilename, "Bad OBJ: Expected a texture filename");
|
||||
char path[1024];
|
||||
snprintf(path, 1023, "%s/%s", base, filename);
|
||||
size_t size = 0;
|
||||
void* data = lovrFilesystemRead(path, &size);
|
||||
lovrAssert(data && size > 0, "Unable to read texture from %s", path);
|
||||
Blob* blob = lovrBlobCreate(data, size, NULL);
|
||||
|
||||
// Load texture, assign to material
|
||||
TextureData* texture = lovrTextureDataCreateFromBlob(blob, true);
|
||||
lovrAssert(materials->length > 0, "Tried to set a material property without declaring a material first");
|
||||
ModelMaterial* material = &vec_last(materials);
|
||||
material->textures[TEXTURE_DIFFUSE] = textures->length;
|
||||
material->filters[TEXTURE_DIFFUSE].mode = FILTER_TRILINEAR;
|
||||
material->wraps[TEXTURE_DIFFUSE] = (TextureWrap) { .s = WRAP_REPEAT, .t = WRAP_REPEAT };
|
||||
vec_push(textures, texture);
|
||||
lovrRelease(blob);
|
||||
} else {
|
||||
char* newline = memchr(s, '\n', length);
|
||||
lineLength = newline - s + 1;
|
||||
}
|
||||
|
||||
s += lineLength;
|
||||
length -= lineLength;
|
||||
while (length && isspace(*s)) length--, s++;
|
||||
}
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
|
||||
char* data = (char*) source->data;
|
||||
size_t length = source->size;
|
||||
|
||||
vec_float_t vertexBuffer;
|
||||
vec_int_t indexBuffer;
|
||||
vec_group_t groups;
|
||||
vec_void_t textures;
|
||||
vec_material_t materials;
|
||||
map_int_t materialNames;
|
||||
vec_float_t vertexBlob;
|
||||
vec_int_t indexBlob;
|
||||
map_int_t vertexMap;
|
||||
vec_float_t vertices;
|
||||
vec_float_t positions;
|
||||
vec_float_t normals;
|
||||
vec_float_t uvs;
|
||||
|
||||
vec_init(&vertexBuffer);
|
||||
vec_init(&indexBuffer);
|
||||
vec_init(&groups);
|
||||
vec_init(&textures);
|
||||
vec_init(&materials);
|
||||
map_init(&materialNames);
|
||||
vec_init(&vertexBlob);
|
||||
vec_init(&indexBlob);
|
||||
map_init(&vertexMap);
|
||||
vec_init(&vertices);
|
||||
vec_init(&positions);
|
||||
vec_init(&normals);
|
||||
vec_init(&uvs);
|
||||
|
||||
vec_push(&groups, ((objGroup) { .material = -1 }));
|
||||
|
||||
char base[1024];
|
||||
strncpy(base, source->name, 1023);
|
||||
char* slash = strrchr(base, '/');
|
||||
if (slash) *slash = 0;
|
||||
|
||||
while (length > 0) {
|
||||
int lineLength = 0;
|
||||
|
||||
|
@ -29,7 +118,7 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO io)
|
|||
float x, y, z;
|
||||
int count = sscanf(data + 2, "%f %f %f\n%n", &x, &y, &z, &lineLength);
|
||||
lovrAssert(count == 3, "Bad OBJ: Expected 3 coordinates for vertex position");
|
||||
vec_pusharr(&vertices, ((float[3]) { x, y, z }), 3);
|
||||
vec_pusharr(&positions, ((float[3]) { x, y, z }), 3);
|
||||
} else if (STARTS_WITH(data, "vn ")) {
|
||||
float x, y, z;
|
||||
int count = sscanf(data + 3, "%f %f %f\n%n", &x, &y, &z, &lineLength);
|
||||
|
@ -49,25 +138,29 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO io)
|
|||
*space = '\0'; // I'll be back
|
||||
int* index = map_get(&vertexMap, s);
|
||||
if (index) {
|
||||
vec_push(&indexBuffer, *index);
|
||||
vec_push(&indexBlob, *index);
|
||||
} else {
|
||||
int v, vt, vn;
|
||||
int newIndex = vertexBuffer.length / 8;
|
||||
vec_push(&indexBuffer, newIndex);
|
||||
int newIndex = vertexBlob.length / 8;
|
||||
vec_push(&indexBlob, newIndex);
|
||||
map_set(&vertexMap, s, newIndex);
|
||||
|
||||
// Can be improved
|
||||
if (sscanf(s, "%d/%d/%d", &v, &vt, &vn) == 3) {
|
||||
vec_pusharr(&vertexBuffer, vertices.data + 3 * (v - 1), 3);
|
||||
vec_pusharr(&vertexBuffer, normals.data + 3 * (vn - 1), 3);
|
||||
vec_pusharr(&vertexBuffer, uvs.data + 2 * (vt - 1), 2);
|
||||
vec_pusharr(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
||||
vec_pusharr(&vertexBlob, normals.data + 3 * (vn - 1), 3);
|
||||
vec_pusharr(&vertexBlob, uvs.data + 2 * (vt - 1), 2);
|
||||
} else if (sscanf(s, "%d//%d", &v, &vn) == 2) {
|
||||
vec_pusharr(&vertexBuffer, vertices.data + 3 * (v - 1), 3);
|
||||
vec_pusharr(&vertexBuffer, normals.data + 3 * (vn - 1), 3);
|
||||
vec_pusharr(&vertexBuffer, ((float[2]) { 0 }), 2);
|
||||
vec_pusharr(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
||||
vec_pusharr(&vertexBlob, normals.data + 3 * (vn - 1), 3);
|
||||
vec_pusharr(&vertexBlob, ((float[2]) { 0 }), 2);
|
||||
} else if (sscanf(s, "%d/%d", &v, &vt) == 2) {
|
||||
vec_pusharr(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
||||
vec_pusharr(&vertexBlob, ((float[3]) { 0 }), 3);
|
||||
vec_pusharr(&vertexBlob, uvs.data + 2 * (vt - 1), 2);
|
||||
} else if (sscanf(s, "%d", &v) == 1) {
|
||||
vec_pusharr(&vertexBuffer, vertices.data + 3 * (v - 1), 3);
|
||||
vec_pusharr(&vertexBuffer, ((float[5]) { 0 }), 5);
|
||||
vec_pusharr(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
||||
vec_pusharr(&vertexBlob, ((float[5]) { 0 }), 5);
|
||||
} else {
|
||||
lovrThrow("Bad OBJ: Unknown face format");
|
||||
}
|
||||
|
@ -76,7 +169,33 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO io)
|
|||
s = space + 1;
|
||||
}
|
||||
}
|
||||
vec_last(&groups).count += 3;
|
||||
lineLength = s - data;
|
||||
} else if (STARTS_WITH(data, "mtllib ")) {
|
||||
char filename[1024];
|
||||
bool hasName = sscanf(data + 7, "%1024s\n%n", filename, &lineLength);
|
||||
lovrAssert(hasName, "Bad OBJ: Expected filename after mtllib");
|
||||
char path[1024];
|
||||
snprintf(path, 1023, "%s/%s", base, filename);
|
||||
parseMtl(path, &textures, &materials, &materialNames, base);
|
||||
} else if (STARTS_WITH(data, "usemtl ")) {
|
||||
char name[128];
|
||||
bool hasName = sscanf(data + 7, "%s\n%n", name, &lineLength);
|
||||
int* material = map_get(&materialNames, name);
|
||||
lovrAssert(hasName && material, "Bad OBJ: Expected a material name");
|
||||
|
||||
// If the last group didn't have any faces, just reuse it, otherwise make a new group
|
||||
objGroup* group = &vec_last(&groups);
|
||||
if (group->count > 0) {
|
||||
int start = group->start + group->count; // Don't put this in the compound literal (realloc)
|
||||
vec_push(&groups, ((objGroup) {
|
||||
.material = *material,
|
||||
.start = start,
|
||||
.count = 0
|
||||
}));
|
||||
} else {
|
||||
group->material = *material;
|
||||
}
|
||||
} else {
|
||||
char* newline = memchr(data, '\n', length);
|
||||
lineLength = newline - data + 1;
|
||||
|
@ -84,17 +203,20 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO io)
|
|||
|
||||
data += lineLength;
|
||||
length -= lineLength;
|
||||
while (length && isspace(*data)) length--, data++;
|
||||
}
|
||||
|
||||
model->blobCount = 2;
|
||||
model->bufferCount = 2;
|
||||
model->attributeCount = 4;
|
||||
model->primitiveCount = 1;
|
||||
model->attributeCount = 3 + groups.length;
|
||||
model->primitiveCount = groups.length;
|
||||
model->nodeCount = 1;
|
||||
model->textureCount = textures.length;
|
||||
model->materialCount = materials.length;
|
||||
lovrModelDataAllocate(model);
|
||||
|
||||
model->blobs[0] = lovrBlobCreate(vertexBuffer.data, vertexBuffer.length * sizeof(float), "obj vertex data");
|
||||
model->blobs[1] = lovrBlobCreate(indexBuffer.data, indexBuffer.length * sizeof(int), "obj index data");
|
||||
model->blobs[0] = lovrBlobCreate(vertexBlob.data, vertexBlob.length * sizeof(float), "obj vertex data");
|
||||
model->blobs[1] = lovrBlobCreate(indexBlob.data, indexBlob.length * sizeof(int), "obj index data");
|
||||
|
||||
model->buffers[0] = (ModelBuffer) {
|
||||
.data = model->blobs[0]->data,
|
||||
|
@ -108,10 +230,13 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO io)
|
|||
.stride = sizeof(int)
|
||||
};
|
||||
|
||||
memcpy(model->textures, textures.data, model->textureCount * sizeof(TextureData*));
|
||||
memcpy(model->materials, materials.data, model->materialCount * sizeof(ModelMaterial));
|
||||
|
||||
model->attributes[0] = (ModelAttribute) {
|
||||
.buffer = 0,
|
||||
.offset = 0,
|
||||
.count = vertexBuffer.length / 8,
|
||||
.count = vertexBlob.length / 8,
|
||||
.type = F32,
|
||||
.components = 3
|
||||
};
|
||||
|
@ -119,7 +244,7 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO io)
|
|||
model->attributes[1] = (ModelAttribute) {
|
||||
.buffer = 0,
|
||||
.offset = 3 * sizeof(float),
|
||||
.count = vertexBuffer.length / 8,
|
||||
.count = vertexBlob.length / 8,
|
||||
.type = F32,
|
||||
.components = 3
|
||||
};
|
||||
|
@ -127,38 +252,48 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO io)
|
|||
model->attributes[2] = (ModelAttribute) {
|
||||
.buffer = 0,
|
||||
.offset = 6 * sizeof(float),
|
||||
.count = vertexBuffer.length / 8,
|
||||
.count = vertexBlob.length / 8,
|
||||
.type = F32,
|
||||
.components = 2
|
||||
};
|
||||
|
||||
model->attributes[3] = (ModelAttribute) {
|
||||
.buffer = 1,
|
||||
.offset = 0,
|
||||
.count = indexBuffer.length,
|
||||
.type = U32,
|
||||
.components = 1
|
||||
};
|
||||
for (int i = 0; i < groups.length; i++) {
|
||||
objGroup* group = &groups.data[i];
|
||||
model->attributes[3 + i] = (ModelAttribute) {
|
||||
.buffer = 1,
|
||||
.offset = group->start * sizeof(int),
|
||||
.count = group->count,
|
||||
.type = U32,
|
||||
.components = 1
|
||||
};
|
||||
}
|
||||
|
||||
model->primitives[0] = (ModelPrimitive) {
|
||||
.mode = DRAW_TRIANGLES,
|
||||
.attributes = {
|
||||
[ATTR_POSITION] = &model->attributes[0],
|
||||
[ATTR_NORMAL] = &model->attributes[1],
|
||||
[ATTR_TEXCOORD] = &model->attributes[2]
|
||||
},
|
||||
.indices = &model->attributes[3],
|
||||
.material = -1
|
||||
};
|
||||
for (int i = 0; i < groups.length; i++) {
|
||||
objGroup* group = &groups.data[i];
|
||||
model->primitives[i] = (ModelPrimitive) {
|
||||
.mode = DRAW_TRIANGLES,
|
||||
.attributes = {
|
||||
[ATTR_POSITION] = &model->attributes[0],
|
||||
[ATTR_NORMAL] = &model->attributes[1],
|
||||
[ATTR_TEXCOORD] = &model->attributes[2]
|
||||
},
|
||||
.indices = &model->attributes[3 + i],
|
||||
.material = group->material
|
||||
};
|
||||
}
|
||||
|
||||
model->nodes[0] = (ModelNode) {
|
||||
.transform = MAT4_IDENTITY,
|
||||
.primitiveIndex = 0,
|
||||
.primitiveCount = 1
|
||||
.primitiveCount = groups.length
|
||||
};
|
||||
|
||||
vec_deinit(&groups);
|
||||
vec_deinit(&textures);
|
||||
vec_deinit(&materials);
|
||||
map_deinit(&materialNames);
|
||||
map_deinit(&vertexMap);
|
||||
vec_deinit(&vertices);
|
||||
vec_deinit(&positions);
|
||||
vec_deinit(&normals);
|
||||
vec_deinit(&uvs);
|
||||
return model;
|
||||
|
|
|
@ -137,7 +137,7 @@ Model* lovrModelInit(Model* model, ModelData* data) {
|
|||
if (data->materialCount > 0) {
|
||||
model->materials = malloc(data->materialCount * sizeof(Material*));
|
||||
|
||||
if (data->imageCount > 0) {
|
||||
if (data->textureCount > 0) {
|
||||
model->textures = calloc(data->textureCount, sizeof(Texture*));
|
||||
}
|
||||
|
||||
|
@ -157,12 +157,11 @@ Model* lovrModelInit(Model* model, ModelData* data) {
|
|||
|
||||
if (index != -1) {
|
||||
if (!model->textures[index]) {
|
||||
ModelTexture* texture = &data->textures[index];
|
||||
TextureData* image = data->images[texture->imageIndex];
|
||||
TextureData* textureData = data->textures[index];
|
||||
bool srgb = j == TEXTURE_DIFFUSE || j == TEXTURE_EMISSIVE;
|
||||
model->textures[index] = lovrTextureCreate(TEXTURE_2D, &image, 1, srgb, true, 0);
|
||||
lovrTextureSetFilter(model->textures[index], texture->filter);
|
||||
lovrTextureSetWrap(model->textures[index], texture->wrap);
|
||||
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]);
|
||||
|
|
|
@ -405,7 +405,6 @@ static ModelData* openvrControllerNewModelData(Controller* controller) {
|
|||
|
||||
model->bufferCount = 2;
|
||||
model->attributeCount = 4;
|
||||
model->imageCount = 1;
|
||||
model->textureCount = 1;
|
||||
model->materialCount = 1;
|
||||
model->primitiveCount = 1;
|
||||
|
@ -457,17 +456,13 @@ static ModelData* openvrControllerNewModelData(Controller* controller) {
|
|||
};
|
||||
|
||||
RenderModel_TextureMap_t* vrTexture = state.deviceTextures[id];
|
||||
model->images[0] = lovrTextureDataCreate(vrTexture->unWidth, vrTexture->unHeight, 0, FORMAT_RGBA);
|
||||
memcpy(model->images[0]->blob.data, vrTexture->rubTextureMapData, vrTexture->unWidth * vrTexture->unHeight * 4);
|
||||
|
||||
model->textures[0] = (ModelTexture) {
|
||||
.imageIndex = 0,
|
||||
.filter = lovrGraphicsGetDefaultFilter()
|
||||
};
|
||||
model->textures[0] = lovrTextureDataCreate(vrTexture->unWidth, vrTexture->unHeight, 0, FORMAT_RGBA);
|
||||
memcpy(model->textures[0]->blob.data, vrTexture->rubTextureMapData, vrTexture->unWidth * vrTexture->unHeight * 4);
|
||||
|
||||
model->materials[0] = (ModelMaterial) {
|
||||
.colors[COLOR_DIFFUSE] = { 1.f, 1.f, 1.f, 1.f },
|
||||
.textures[TEXTURE_DIFFUSE] = 0
|
||||
.textures[TEXTURE_DIFFUSE] = 0,
|
||||
.filters[TEXTURE_DIFFUSE] = lovrGraphicsGetDefaultFilter()
|
||||
};
|
||||
|
||||
model->primitives[0] = (ModelPrimitive) {
|
||||
|
|
Loading…
Reference in New Issue