From 7ab008878afa202b4f2e579567be7a7d87242661 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 7 May 2016 18:07:15 +0200 Subject: Library redesign to accomodate materials system --- src/models.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 134 insertions(+), 30 deletions(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index 0bb2b8d6..9b139120 100644 --- a/src/models.c +++ b/src/models.c @@ -55,7 +55,9 @@ extern unsigned int whiteTexture; //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- -static Mesh LoadOBJ(const char *fileName); +static Mesh LoadOBJ(const char *fileName); // Load OBJ mesh data +static Material LoadMTL(const char *fileName); // Load MTL material data + static Mesh GenMeshHeightmap(Image image, Vector3 size); static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); @@ -542,24 +544,19 @@ void DrawGizmo(Vector3 position) Model LoadModel(const char *fileName) { Model model = { 0 }; - Mesh mesh = { 0 }; - // NOTE: Initialize default data for model in case loading fails, maybe a cube? + // TODO: Initialize default data for model in case loading fails, maybe a cube? - if (strcmp(GetExtension(fileName),"obj") == 0) mesh = LoadOBJ(fileName); + if (strcmp(GetExtension(fileName),"obj") == 0) model.mesh = LoadOBJ(fileName); else TraceLog(WARNING, "[%s] Model extension not recognized, it can't be loaded", fileName); - // NOTE: At this point we have all vertex, texcoord, normal data for the model in mesh struct - - if (mesh.vertexCount == 0) TraceLog(WARNING, "Model could not be loaded"); + if (model.mesh.vertexCount == 0) TraceLog(WARNING, "Model could not be loaded"); else { - // NOTE: model properties (transform, texture, shader) are initialized inside rlglLoadModel() - model = rlglLoadModel(mesh); // Upload vertex data to GPU - - // NOTE: Now that vertex data is uploaded to GPU VRAM, we can free arrays from CPU RAM - // We don't need CPU vertex data on OpenGL 3.3 or ES2... for static meshes... - // ...but we could keep CPU vertex data in case we need to update the mesh + rlglLoadMesh(&model.mesh); // Upload vertex data to GPU + + model.transform = MatrixIdentity(); + model.material = LoadDefaultMaterial(); } return model; @@ -568,12 +565,12 @@ Model LoadModel(const char *fileName) // Load a 3d model (from vertex data) Model LoadModelEx(Mesh data) { - Model model; + Model model = { 0 }; - // NOTE: model properties (transform, texture, shader) are initialized inside rlglLoadModel() - model = rlglLoadModel(data); // Upload vertex data to GPU + rlglLoadMesh(&data); // Upload vertex data to GPU - // NOTE: Vertex data is managed externally, must be deallocated manually + model.transform = MatrixIdentity(); + model.material = LoadDefaultMaterial(); return model; } @@ -582,8 +579,14 @@ Model LoadModelEx(Mesh data) // NOTE: model map size is defined in generic units Model LoadHeightmap(Image heightmap, Vector3 size) { - Mesh mesh = GenMeshHeightmap(heightmap, size); - Model model = rlglLoadModel(mesh); + Model model = { 0 }; + + model.mesh = GenMeshHeightmap(heightmap, size); + + rlglLoadMesh(&model.mesh); + + model.transform = MatrixIdentity(); + model.material = LoadDefaultMaterial(); return model; } @@ -591,8 +594,14 @@ Model LoadHeightmap(Image heightmap, Vector3 size) // Load a map image as a 3d model (cubes based) Model LoadCubicmap(Image cubicmap) { - Mesh mesh = GenMeshCubicmap(cubicmap, (Vector3){ 1.0, 1.0, 1.5f }); - Model model = rlglLoadModel(mesh); + Model model = { 0 }; + + model.mesh = GenMeshCubicmap(cubicmap, (Vector3){ 1.0, 1.0, 1.5f }); + + rlglLoadMesh(&model.mesh); + + model.transform = MatrixIdentity(); + model.material = LoadDefaultMaterial(); return model; } @@ -613,13 +622,44 @@ void UnloadModel(Model model) rlDeleteBuffers(model.mesh.vboId[0]); // vertex rlDeleteBuffers(model.mesh.vboId[1]); // texcoords rlDeleteBuffers(model.mesh.vboId[2]); // normals - //rlDeleteBuffers(model.mesh.vboId[3]); // texcoords2 (NOT USED) + //rlDeleteBuffers(model.mesh.vboId[3]); // colors (NOT USED) //rlDeleteBuffers(model.mesh.vboId[4]); // tangents (NOT USED) - //rlDeleteBuffers(model.mesh.vboId[5]); // colors (NOT USED) + //rlDeleteBuffers(model.mesh.vboId[5]); // texcoords2 (NOT USED) rlDeleteVertexArrays(model.mesh.vaoId); } +// Load material data (from file) +Material LoadMaterial(const char *fileName) +{ + Material material = { 0 }; + + if (strcmp(GetExtension(fileName),"mtl") == 0) material = LoadMTL(fileName); + else TraceLog(WARNING, "[%s] Material extension not recognized, it can't be loaded", fileName); + + return material; +} + +// Load default material (uses default models shader) +Material LoadDefaultMaterial(void) +{ + Material material = { 0 }; + + material.shader = GetDefaultShader(); + material.texDiffuse = GetDefaultTexture(); // White texture (1x1 pixel) + //material.texNormal; // NOTE: By default, not set + //material.texSpecular; // NOTE: By default, not set + + material.colDiffuse = WHITE; // Diffuse color + material.colAmbient = WHITE; // Ambient color + material.colSpecular = WHITE; // Specular color + + material.glossiness = 100.0f; // Glossiness level + material.normalDepth = 1.0f; // Normal map depth + + return material; +} + // Link a texture to a model void SetModelTexture(Model *model, Texture2D texture) { @@ -1100,31 +1140,59 @@ void DrawModel(Model model, Vector3 position, float scale, Color tint) { Vector3 vScale = { scale, scale, scale }; Vector3 rotationAxis = { 0.0f, 0.0f, 0.0f }; - + DrawModelEx(model, position, rotationAxis, 0.0f, vScale, tint); } // Draw a model with extended parameters void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint) { - // NOTE: Rotation must be provided in degrees, it's converted to radians inside rlglDrawModel() - rlglDrawModel(model, position, rotationAxis, rotationAngle, scale, tint, false); + // Calculate transformation matrix from function parameters + // Get transform matrix (rotation -> scale -> translation) + Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD); + Matrix matScale = MatrixScale(scale.x, scale.y, scale.z); + Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z); + + // Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform) + //Matrix matModel = MatrixMultiply(model.transform, matTransform); // Transform to world-space coordinates + + model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); + model.material.colDiffuse = tint; + + rlglDrawEx(model.mesh, model.material, model.transform, false); } // Draw a model wires (with texture if set) -void DrawModelWires(Model model, Vector3 position, float scale, Color color) +void DrawModelWires(Model model, Vector3 position, float scale, Color tint) { Vector3 vScale = { scale, scale, scale }; Vector3 rotationAxis = { 0.0f, 0.0f, 0.0f }; - rlglDrawModel(model, position, rotationAxis, 0.0f, vScale, color, true); + // Calculate transformation matrix from function parameters + // Get transform matrix (rotation -> scale -> translation) + Matrix matRotation = MatrixRotate(rotationAxis, 0.0f); + Matrix matScale = MatrixScale(vScale.x, vScale.y, vScale.z); + Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z); + + model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); + model.material.colDiffuse = tint; + + rlglDrawEx(model.mesh, model.material, model.transform, true); } // Draw a model wires (with texture if set) with extended parameters void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint) { - // NOTE: Rotation must be provided in degrees, it's converted to radians inside rlglDrawModel() - rlglDrawModel(model, position, rotationAxis, rotationAngle, scale, tint, true); + // Calculate transformation matrix from function parameters + // Get transform matrix (rotation -> scale -> translation) + Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD); + Matrix matScale = MatrixScale(scale.x, scale.y, scale.z); + Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z); + + model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); + model.material.colDiffuse = tint; + + rlglDrawEx(model.mesh, model.material, model.transform, true); } // Draw a billboard @@ -1856,3 +1924,39 @@ static Mesh LoadOBJ(const char *fileName) return mesh; } + +// Load MTL material data +static Material LoadMTL(const char *fileName) +{ + Material material = { 0 }; + + // TODO: Load mtl file + + char dataType; + char comments[200]; + + FILE *mtlFile; + + mtlFile = fopen(fileName, "rt"); + + if (mtlFile == NULL) + { + TraceLog(WARNING, "[%s] MTL file could not be opened", fileName); + return material; + } + + // First reading pass: Get numVertex, numNormals, numTexCoords, numTriangles + // NOTE: vertex, texcoords and normals could be optimized (to be used indexed on faces definition) + // NOTE: faces MUST be defined as TRIANGLES (3 vertex per face) + while(!feof(mtlFile)) + { + fscanf(mtlFile, "%c", &dataType); + } + + fclose(mtlFile); + + // NOTE: At this point we have all material data + TraceLog(INFO, "[%s] Material loaded successfully", fileName); + + return material; +} -- cgit v1.2.3 From 0bcb873cbb3758d67b1d263fafb6be818ddbf067 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 8 May 2016 15:24:02 +0200 Subject: Improved mesh support Depending on mesh data, it can be loaded and default vertex attribute location points are set, including colors, tangents and texcoords2 --- src/models.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++------------- src/raylib.h | 6 +-- src/rlgl.c | 90 ++++++++++++++++++++++++++++++++++++-------- 3 files changed, 171 insertions(+), 45 deletions(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index 9b139120..4aff7216 100644 --- a/src/models.c +++ b/src/models.c @@ -575,6 +575,89 @@ Model LoadModelEx(Mesh data) return model; } +// Load a 3d model from rRES file (raylib Resource) +Model LoadModelFromRES(const char *rresName, int resId) +{ + Model model = { 0 }; + bool found = false; + + char id[4]; // rRES file identifier + unsigned char version; // rRES file version and subversion + char useless; // rRES header reserved data + short numRes; + + ResInfoHeader infoHeader; + + FILE *rresFile = fopen(rresName, "rb"); + + if (rresFile == NULL) + { + TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", rresName); + } + else + { + // Read rres file (basic file check - id) + fread(&id[0], sizeof(char), 1, rresFile); + fread(&id[1], sizeof(char), 1, rresFile); + fread(&id[2], sizeof(char), 1, rresFile); + fread(&id[3], sizeof(char), 1, rresFile); + fread(&version, sizeof(char), 1, rresFile); + fread(&useless, sizeof(char), 1, rresFile); + + if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S')) + { + TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName); + } + else + { + // Read number of resources embedded + fread(&numRes, sizeof(short), 1, rresFile); + + for (int i = 0; i < numRes; i++) + { + fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile); + + if (infoHeader.id == resId) + { + found = true; + + // Check data is of valid MODEL type + if (infoHeader.type == 8) + { + // TODO: Load model data + } + else + { + TraceLog(WARNING, "[%s] Required resource do not seem to be a valid MODEL resource", rresName); + } + } + else + { + // Depending on type, skip the right amount of parameters + switch (infoHeader.type) + { + case 0: fseek(rresFile, 6, SEEK_CUR); break; // IMAGE: Jump 6 bytes of parameters + case 1: fseek(rresFile, 6, SEEK_CUR); break; // SOUND: Jump 6 bytes of parameters + case 2: fseek(rresFile, 5, SEEK_CUR); break; // MODEL: Jump 5 bytes of parameters (TODO: Review) + case 3: break; // TEXT: No parameters + case 4: break; // RAW: No parameters + default: break; + } + + // Jump DATA to read next infoHeader + fseek(rresFile, infoHeader.size, SEEK_CUR); + } + } + } + + fclose(rresFile); + } + + if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId); + + return model; +} + // Load a heightmap image as a 3d model // NOTE: model map size is defined in generic units Model LoadHeightmap(Image heightmap, Vector3 size) @@ -613,18 +696,18 @@ void UnloadModel(Model model) free(model.mesh.vertices); free(model.mesh.texcoords); free(model.mesh.normals); - free(model.mesh.colors); - //if (model.mesh.texcoords2 != NULL) free(model.mesh.texcoords2); // Not used - //if (model.mesh.tangents != NULL) free(model.mesh.tangents); // Not used + if (model.mesh.colors != NULL) free(model.mesh.colors); + if (model.mesh.tangents != NULL) free(model.mesh.tangents); + if (model.mesh.texcoords2 != NULL) free(model.mesh.texcoords2); TraceLog(INFO, "Unloaded model data from RAM (CPU)"); rlDeleteBuffers(model.mesh.vboId[0]); // vertex rlDeleteBuffers(model.mesh.vboId[1]); // texcoords rlDeleteBuffers(model.mesh.vboId[2]); // normals - //rlDeleteBuffers(model.mesh.vboId[3]); // colors (NOT USED) - //rlDeleteBuffers(model.mesh.vboId[4]); // tangents (NOT USED) - //rlDeleteBuffers(model.mesh.vboId[5]); // texcoords2 (NOT USED) + rlDeleteBuffers(model.mesh.vboId[3]); // colors + rlDeleteBuffers(model.mesh.vboId[4]); // tangents + rlDeleteBuffers(model.mesh.vboId[5]); // texcoords2 rlDeleteVertexArrays(model.mesh.vaoId); } @@ -672,7 +755,7 @@ static Mesh GenMeshHeightmap(Image heightmap, Vector3 size) { #define GRAY_VALUE(c) ((c.r+c.g+c.b)/3) - Mesh mesh; + Mesh mesh = { 0 }; int mapX = heightmap.width; int mapZ = heightmap.height; @@ -687,7 +770,7 @@ static Mesh GenMeshHeightmap(Image heightmap, Vector3 size) mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float)); - mesh.colors = (unsigned char *)malloc(mesh.vertexCount*4*sizeof(unsigned char)); // Not used... + mesh.colors = NULL; int vCounter = 0; // Used to count vertices float by float int tcCounter = 0; // Used to count texcoords float by float @@ -770,16 +853,12 @@ static Mesh GenMeshHeightmap(Image heightmap, Vector3 size) free(pixels); - // Fill color data - // NOTE: Not used any more... just one plain color defined at DrawModel() - for (int i = 0; i < (4*mesh.vertexCount); i++) mesh.colors[i] = 255; - return mesh; } static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) { - Mesh mesh; + Mesh mesh = { 0 }; Color *cubicmapPixels = GetImageData(cubicmap); @@ -1088,11 +1167,7 @@ static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float)); - mesh.colors = (unsigned char *)malloc(mesh.vertexCount*4*sizeof(unsigned char)); // Not used... - - // Fill color data - // NOTE: Not used any more... just one plain color defined at DrawModel() - for (int i = 0; i < (4*mesh.vertexCount); i++) mesh.colors[i] = 255; + mesh.colors = NULL; int fCounter = 0; @@ -1810,7 +1885,7 @@ static Mesh LoadOBJ(const char *fileName) mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float)); mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float)); - mesh.colors = (unsigned char *)malloc(mesh.vertexCount*4*sizeof(unsigned char)); + mesh.colors = NULL; int vCounter = 0; // Used to count vertices float by float int tcCounter = 0; // Used to count texcoords float by float @@ -1909,10 +1984,6 @@ static Mesh LoadOBJ(const char *fileName) // Security check, just in case no normals or no texcoords defined in OBJ if (numTexCoords == 0) for (int i = 0; i < (2*mesh.vertexCount); i++) mesh.texcoords[i] = 0.0f; - - // NOTE: We set all vertex colors to white - // NOTE: Not used any more... just one plain color defined at DrawModel() - for (int i = 0; i < (4*mesh.vertexCount); i++) mesh.colors[i] = 255; // Now we can free temp mid* arrays free(midVertices); @@ -1945,9 +2016,6 @@ static Material LoadMTL(const char *fileName) return material; } - // First reading pass: Get numVertex, numNormals, numTexCoords, numTriangles - // NOTE: vertex, texcoords and normals could be optimized (to be used indexed on faces definition) - // NOTE: faces MUST be defined as TRIANGLES (3 vertex per face) while(!feof(mtlFile)) { fscanf(mtlFile, "%c", &dataType); diff --git a/src/raylib.h b/src/raylib.h index c88a60f4..60384444 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -386,7 +386,7 @@ typedef struct Mesh { typedef struct Shader { unsigned int id; // Shader program id - // Variable attributes locations + // Vertex attributes locations (default locations) int vertexLoc; // Vertex attribute location point (default-location = 0) int texcoordLoc; // Texcoord attribute location point (default-location = 1) int normalLoc; // Normal attribute location point (default-location = 2) @@ -803,14 +803,14 @@ void DrawGizmo(Vector3 position); //------------------------------------------------------------------------------------ Model LoadModel(const char *fileName); // Load a 3d model (.OBJ) Model LoadModelEx(Mesh data); // Load a 3d model (from mesh data) -//Model LoadModelFromRES(const char *rresName, int resId); // TODO: Load a 3d model from rRES file (raylib Resource) +Model LoadModelFromRES(const char *rresName, int resId); // Load a 3d model from rRES file (raylib Resource) Model LoadHeightmap(Image heightmap, Vector3 size); // Load a heightmap image as a 3d model Model LoadCubicmap(Image cubicmap); // Load a map image as a 3d model (cubes based) void UnloadModel(Model model); // Unload 3d model from memory void SetModelTexture(Model *model, Texture2D texture); // Link a texture to a model Material LoadMaterial(const char *fileName); // Load material data (from file) -Material LoadDefaultMaterial(void); // Load default material (uses default models shader) +Material LoadDefaultMaterial(void); // Load default material (uses default models shader) void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters diff --git a/src/rlgl.c b/src/rlgl.c index 462ccdec..6ffcb8a5 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -811,9 +811,11 @@ void rlDeleteVertexArrays(unsigned int id) void rlDeleteBuffers(unsigned int id) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glDeleteBuffers(1, &id); - - if (!vaoSupported) TraceLog(INFO, "[VBO ID %i] Unloaded model vertex data from VRAM (GPU)", id); + if (id != 0) + { + glDeleteBuffers(1, &id); + if (!vaoSupported) TraceLog(INFO, "[VBO ID %i] Unloaded model vertex data from VRAM (GPU)", id); + } #endif } @@ -1638,6 +1640,7 @@ void rlglGenerateMipmaps(Texture2D texture) } // Upload vertex data into a VAO (if supported) and VBO +// TODO: Consider attributes: color, texcoords2, tangents (if available) void rlglLoadMesh(Mesh *mesh) { mesh->vaoId = 0; // Vertex Array Object @@ -1648,11 +1651,10 @@ void rlglLoadMesh(Mesh *mesh) mesh->vboId[4] = 0; // Vertex tangent VBO mesh->vboId[5] = 0; // Vertex texcoord2 VBO - // TODO: Consider attributes: color, texcoords2, tangents (if available) - + #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) GLuint vaoId = 0; // Vertex Array Objects (VAO) - GLuint vboId[3]; // Vertex Buffer Objects (VBOs) + GLuint vboId[6]; // Vertex Buffer Objects (VBOs) if (vaoSupported) { @@ -1661,36 +1663,92 @@ void rlglLoadMesh(Mesh *mesh) glBindVertexArray(vaoId); } - // Create buffers for our vertex data (positions, texcoords, normals) - glGenBuffers(3, vboId); - // NOTE: Attributes must be uploaded considering default locations points // Enable vertex attributes: position (shader-location = 0) + glGenBuffers(1, &vboId[0]); glBindBuffer(GL_ARRAY_BUFFER, vboId[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->vertices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, 0, 0, 0); glEnableVertexAttribArray(0); // Enable vertex attributes: texcoords (shader-location = 1) + glGenBuffers(1, &vboId[1]); glBindBuffer(GL_ARRAY_BUFFER, vboId[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords, GL_STATIC_DRAW); glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, 0); glEnableVertexAttribArray(1); // Enable vertex attributes: normals (shader-location = 2) - glBindBuffer(GL_ARRAY_BUFFER, vboId[2]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->normals, GL_STATIC_DRAW); - glVertexAttribPointer(2, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(2); + if (mesh->normals != NULL) + { + glGenBuffers(1, &vboId[2]); + glBindBuffer(GL_ARRAY_BUFFER, vboId[2]); + glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->normals, GL_STATIC_DRAW); + glVertexAttribPointer(2, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(2); + } + else + { + // Default color vertex attribute set to WHITE + glVertexAttrib3f(2, 1.0f, 1.0f, 1.0f); + glDisableVertexAttribArray(2); + } // Default color vertex attribute (shader-location = 3) - glVertexAttrib4f(3, 1.0f, 1.0f, 1.0f, 1.0f); // Color vertex attribute set to default: WHITE - glDisableVertexAttribArray(3); + if (mesh->colors != NULL) + { + glGenBuffers(1, &vboId[3]); + glBindBuffer(GL_ARRAY_BUFFER, vboId[3]); + glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*mesh->vertexCount, mesh->colors, GL_STATIC_DRAW); + glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(3); + } + else + { + // Default color vertex attribute set to WHITE + glVertexAttrib4f(3, 1.0f, 1.0f, 1.0f, 1.0f); + glDisableVertexAttribArray(3); + } + + // Default tangent vertex attribute (shader-location = 4) + if (mesh->tangents != NULL) + { + glGenBuffers(1, &vboId[4]); + glBindBuffer(GL_ARRAY_BUFFER, vboId[4]); + glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->tangents, GL_STATIC_DRAW); + glVertexAttribPointer(4, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(4); + } + else + { + // Default tangents vertex attribute + glVertexAttrib3f(4, 0.0f, 0.0f, 0.0f); + glDisableVertexAttribArray(4); + } + + // Default texcoord2 vertex attribute (shader-location = 5) + if (mesh->texcoords2 != NULL) + { + glGenBuffers(1, &vboId[5]); + glBindBuffer(GL_ARRAY_BUFFER, vboId[5]); + glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords2, GL_STATIC_DRAW); + glVertexAttribPointer(5, 2, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(5); + } + else + { + // Default tangents vertex attribute + glVertexAttrib2f(5, 0.0f, 0.0f); + glDisableVertexAttribArray(5); + } mesh->vboId[0] = vboId[0]; // Vertex position VBO mesh->vboId[1] = vboId[1]; // Texcoords VBO mesh->vboId[2] = vboId[2]; // Normals VBO + mesh->vboId[3] = vboId[3]; // Colors VBO + mesh->vboId[4] = vboId[4]; // Tangents VBO + mesh->vboId[5] = vboId[5]; // Texcoords2 VBO if (vaoSupported) { @@ -1703,7 +1761,7 @@ void rlglLoadMesh(Mesh *mesh) } else { - TraceLog(INFO, "[VBO ID %i][VBO ID %i][VBO ID %i] Mesh uploaded successfully to VRAM (GPU)", mesh->vboId[0], mesh->vboId[1], mesh->vboId[2]); + TraceLog(INFO, "[VBOs] Mesh uploaded successfully to VRAM (GPU)"); } #endif } -- cgit v1.2.3 From f7d4951165e8bece5ae58cd4c92b08e4f29cbef7 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 8 May 2016 23:50:35 +0200 Subject: Improved vertex attribs support for models --- src/models.c | 2 +- src/raylib.h | 14 ++++++++------ src/rlgl.c | 45 ++++++++++++++++++++++++++++++++++++--------- 3 files changed, 45 insertions(+), 16 deletions(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index 4aff7216..ee04b449 100644 --- a/src/models.c +++ b/src/models.c @@ -695,7 +695,7 @@ void UnloadModel(Model model) // Unload mesh data free(model.mesh.vertices); free(model.mesh.texcoords); - free(model.mesh.normals); + if (model.mesh.normals != NULL) free(model.mesh.normals); if (model.mesh.colors != NULL) free(model.mesh.colors); if (model.mesh.tangents != NULL) free(model.mesh.tangents); if (model.mesh.texcoords2 != NULL) free(model.mesh.texcoords2); diff --git a/src/raylib.h b/src/raylib.h index 60384444..1258bffc 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -369,12 +369,12 @@ typedef struct BoundingBox { // Vertex data definning a mesh typedef struct Mesh { int vertexCount; // num vertices - float *vertices; // vertex position (XYZ - 3 components per vertex) - float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) - float *texcoords2; // vertex second texture coordinates (useful for lightmaps) - float *normals; // vertex normals (XYZ - 3 components per vertex) - float *tangents; // vertex tangents (XYZ - 3 components per vertex) - unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) + float *vertices; // vertex position (XYZ - 3 components per vertex) (shader-location = 0) + float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) + float *texcoords2; // vertex second texture coordinates (useful for lightmaps) (shader-location = 5) + float *normals; // vertex normals (XYZ - 3 components per vertex) (shader-location = 2) + float *tangents; // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4) + unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3) BoundingBox bounds; // mesh limits defined by min and max points @@ -391,6 +391,8 @@ typedef struct Shader { int texcoordLoc; // Texcoord attribute location point (default-location = 1) int normalLoc; // Normal attribute location point (default-location = 2) int colorLoc; // Color attibute location point (default-location = 3) + int tangentLoc; // Tangent attribute location point (default-location = 4) + int texcoord2Loc; // Texcoord2 attribute location point (default-location = 5) // Uniform locations int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) diff --git a/src/rlgl.c b/src/rlgl.c index 6ffcb8a5..2e4601df 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1084,12 +1084,13 @@ void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires) // NOTE: On OpenGL 1.1 we use Vertex Arrays to draw model glEnableClientState(GL_VERTEX_ARRAY); // Enable vertex array glEnableClientState(GL_TEXTURE_COORD_ARRAY); // Enable texture coords array - glEnableClientState(GL_NORMAL_ARRAY); // Enable normals array + if (mesh.normals != NULL) glEnableClientState(GL_NORMAL_ARRAY); // Enable normals array + if (mesh.colors != NULL) glEnableClientState(GL_COLOR_ARRAY); // Enable colors array glVertexPointer(3, GL_FLOAT, 0, mesh.vertices); // Pointer to vertex coords array glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords); // Pointer to texture coords array - glNormalPointer(GL_FLOAT, 0, mesh.normals); // Pointer to normals array - //glColorPointer(4, GL_UNSIGNED_BYTE, 0, mesh.colors); // Pointer to colors array (NOT USED) + if (mesh.normals != NULL) glNormalPointer(GL_FLOAT, 0, mesh.normals); // Pointer to normals array + if (mesh.colors != NULL) glColorPointer(4, GL_UNSIGNED_BYTE, 0, mesh.colors); // Pointer to colors array rlPushMatrix(); rlMultMatrixf(MatrixToFloat(transform)); @@ -1099,7 +1100,8 @@ void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires) glDisableClientState(GL_VERTEX_ARRAY); // Disable vertex array glDisableClientState(GL_TEXTURE_COORD_ARRAY); // Disable texture coords array - glDisableClientState(GL_NORMAL_ARRAY); // Disable normals array + if (mesh.normals != NULL) glDisableClientState(GL_NORMAL_ARRAY); // Disable normals array + if (mesh.colors != NULL) glDisableClientState(GL_NORMAL_ARRAY); // Disable colors array glDisable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); @@ -1170,7 +1172,29 @@ void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires) glEnableVertexAttribArray(material.shader.normalLoc); } - // TODO: Bind mesh VBO data: colors, tangents, texcoords2 (if available) + // Bind mesh VBO data: vertex colors (shader-location = 3, if available) , tangents, texcoords2 (if available) + if (material.shader.colorLoc != -1) + { + glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[3]); + glVertexAttribPointer(material.shader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(material.shader.colorLoc); + } + + // Bind mesh VBO data: vertex tangents (shader-location = 4, if available) + if (material.shader.tangentLoc != -1) + { + glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[4]); + glVertexAttribPointer(material.shader.tangentLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(material.shader.tangentLoc); + } + + // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available) + if (material.shader.texcoord2Loc != -1) + { + glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[5]); + glVertexAttribPointer(material.shader.texcoord2Loc, 2, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(material.shader.texcoord2Loc); + } } // Draw call! @@ -1640,16 +1664,15 @@ void rlglGenerateMipmaps(Texture2D texture) } // Upload vertex data into a VAO (if supported) and VBO -// TODO: Consider attributes: color, texcoords2, tangents (if available) void rlglLoadMesh(Mesh *mesh) { mesh->vaoId = 0; // Vertex Array Object mesh->vboId[0] = 0; // Vertex positions VBO mesh->vboId[1] = 0; // Vertex texcoords VBO mesh->vboId[2] = 0; // Vertex normals VBO - mesh->vboId[3] = 0; // Vertex color VBO - mesh->vboId[4] = 0; // Vertex tangent VBO - mesh->vboId[5] = 0; // Vertex texcoord2 VBO + mesh->vboId[3] = 0; // Vertex colors VBO + mesh->vboId[4] = 0; // Vertex tangents VBO + mesh->vboId[5] = 0; // Vertex texcoords2 VBO #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -2314,12 +2337,16 @@ static void LoadDefaultShaderLocations(Shader *shader) // vertex texcoord location = 1 // vertex normal location = 2 // vertex color location = 3 + // vertex tangent location = 4 + // vertex texcoord2 location = 5 // Get handles to GLSL input attibute locations shader->vertexLoc = glGetAttribLocation(shader->id, "vertexPosition"); shader->texcoordLoc = glGetAttribLocation(shader->id, "vertexTexCoord"); shader->normalLoc = glGetAttribLocation(shader->id, "vertexNormal"); shader->colorLoc = glGetAttribLocation(shader->id, "vertexColor"); + shader->tangentLoc = glGetAttribLocation(shader->id, "vertexTangent"); + shader->texcoord2Loc = glGetAttribLocation(shader->id, "vertexTexCoord2"); // Get handles to GLSL uniform locations (vertex shader) shader->mvpLoc = glGetUniformLocation(shader->id, "mvpMatrix"); -- cgit v1.2.3 From dc4d5dabcdf8f35f32acb9c5b48a24b1141c460f Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 9 May 2016 01:18:46 +0200 Subject: Added MTL loading info --- src/models.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index ee04b449..7b6deb5c 100644 --- a/src/models.c +++ b/src/models.c @@ -2001,7 +2001,26 @@ static Material LoadMTL(const char *fileName) { Material material = { 0 }; - // TODO: Load mtl file + // TODO: Load mtl file (multiple variations of .mtl format) + /* + newmtl string Material newmtl (material name). Begins a new material description. + Ka float float float Ambient color Ka (red) (green) (blue) + Kd float float float Diffuse color Kd (red) (green) (blue) + Ks float float float Specular color Ks (red) (green) (blue) + Ke float float float Emmisive color + d float Tr float Dissolve factor. Transparency Tr (alpha). d is inverse of Tr + Ns int Shininess Ns (specular power). Ranges from 0 to 1000. Specular exponent. + Ni int Refraction index. + illum int Illumination model illum (1 / 2); 1 if specular disabled, 2 if specular enabled (lambertian model) + map_Kd string Texture map_Kd (filename) + map_Kd string Diffuse color texture map. + map_Ks string Specular color texture map. + map_Ka string Ambient color texture map. + map_Bump string Bump texture map. Alternative: bump string / map_bump string + map_d string Opacity texture map. + disp string Displacement map + refl Reflection type and map + */ char dataType; char comments[200]; -- cgit v1.2.3 From 3d0208223ad5b79cb4c3d6cd367d39f9d4e51662 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 9 May 2016 12:40:59 +0200 Subject: First implementation of MTL loading Not tested yet --- src/models.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 132 insertions(+), 24 deletions(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index 7b6deb5c..dff6b224 100644 --- a/src/models.c +++ b/src/models.c @@ -1997,33 +1997,16 @@ static Mesh LoadOBJ(const char *fileName) } // Load MTL material data +// NOTE: Texture map parameters are not supported static Material LoadMTL(const char *fileName) { - Material material = { 0 }; + #define MAX_BUFFER_SIZE 128 - // TODO: Load mtl file (multiple variations of .mtl format) - /* - newmtl string Material newmtl (material name). Begins a new material description. - Ka float float float Ambient color Ka (red) (green) (blue) - Kd float float float Diffuse color Kd (red) (green) (blue) - Ks float float float Specular color Ks (red) (green) (blue) - Ke float float float Emmisive color - d float Tr float Dissolve factor. Transparency Tr (alpha). d is inverse of Tr - Ns int Shininess Ns (specular power). Ranges from 0 to 1000. Specular exponent. - Ni int Refraction index. - illum int Illumination model illum (1 / 2); 1 if specular disabled, 2 if specular enabled (lambertian model) - map_Kd string Texture map_Kd (filename) - map_Kd string Diffuse color texture map. - map_Ks string Specular color texture map. - map_Ka string Ambient color texture map. - map_Bump string Bump texture map. Alternative: bump string / map_bump string - map_d string Opacity texture map. - disp string Displacement map - refl Reflection type and map - */ + Material material = { 0 }; // LoadDefaultMaterial(); - char dataType; - char comments[200]; + char buffer[MAX_BUFFER_SIZE]; + Vector3 color = { 1.0f, 1.0f, 1.0f }; + char *mapFileName; FILE *mtlFile; @@ -2037,7 +2020,132 @@ static Material LoadMTL(const char *fileName) while(!feof(mtlFile)) { - fscanf(mtlFile, "%c", &dataType); + fgets(buffer, MAX_BUFFER_SIZE, mtlFile); + + switch (buffer[0]) + { + case 'n': // newmtl string Material name. Begins a new material description. + { + // TODO: Support multiple materials in a single .mtl + sscanf(buffer, "newmtl %s", mapFileName); + + TraceLog(INFO, "[%s] Loading material...", mapFileName); + } + case 'i': // illum int Illumination model + { + // illum = 1 if specular disabled + // illum = 2 if specular enabled (lambertian model) + // ... + } + case 'K': // Ka, Kd, Ks, Ke + { + switch (buffer[1]) + { + case 'a': // Ka float float float Ambient color (RGB) + { + sscanf(buffer, "Ka %f %f %f", &color.x, &color.y, &color.z); + material.colAmbient.r = (unsigned char)(color.x*255); + material.colAmbient.g = (unsigned char)(color.y*255); + material.colAmbient.b = (unsigned char)(color.z*255); + } break; + case 'd': // Kd float float float Diffuse color (RGB) + { + sscanf(buffer, "Kd %f %f %f", &color.x, &color.y, &color.z); + material.colDiffuse.r = (unsigned char)(color.x*255); + material.colDiffuse.g = (unsigned char)(color.y*255); + material.colDiffuse.b = (unsigned char)(color.z*255); + } break; + case 's': // Ks float float float Specular color (RGB) + { + sscanf(buffer, "Ks %f %f %f", &color.x, &color.y, &color.z); + material.colSpecular.r = (unsigned char)(color.x*255); + material.colSpecular.g = (unsigned char)(color.y*255); + material.colSpecular.b = (unsigned char)(color.z*255); + } break; + case 'e': // Ke float float float Emmisive color (RGB) + { + // TODO: Support Ke ? + } break; + default: break; + } + } break; + case 'N': // Ns, Ni + { + if (buffer[1] == 's') // Ns int Shininess (specular exponent). Ranges from 0 to 1000. + { + sscanf(buffer, "Ns %i", &material.glossiness); + } + else if (buffer[1] == 'i') // Ni int Refraction index. + { + // Not supported... + } + } break; + case 'm': // map_Kd, map_Ks, map_Ka, map_Bump, map_d + { + switch (buffer[4]) + { + case 'K': // Color texture maps + { + if (buffer[5] == 'd') // map_Kd string Diffuse color texture map. + { + sscanf(buffer, "map_Kd %s", mapFileName); + if (mapFileName != NULL) material.texDiffuse = LoadTexture(mapFileName); + } + else if (buffer[5] == 's') // map_Ks string Specular color texture map. + { + sscanf(buffer, "map_Ks %s", mapFileName); + if (mapFileName != NULL) material.texSpecular = LoadTexture(mapFileName); + } + else if (buffer[5] == 'a') // map_Ka string Ambient color texture map. + { + // Not supported... + } + } break; + case 'B': // map_Bump string Bump texture map. + { + sscanf(buffer, "map_Bump %s", mapFileName); + if (mapFileName != NULL) material.texNormal = LoadTexture(mapFileName); + } break; + case 'b': // map_bump string Bump texture map. + { + sscanf(buffer, "map_bump %s", mapFileName); + if (mapFileName != NULL) material.texNormal = LoadTexture(mapFileName); + } break; + case 'd': // map_d string Opacity texture map. + { + // Not supported... + } break; + default: break; + } + } break; + case 'd': // d, disp + { + if (buffer[1] == ' ') // d float Dissolve factor. d is inverse of Tr + { + float alpha = 1.0f; + sscanf(buffer, "d %f", &alpha); + material.colDiffuse.a = (unsigned char)(alpha*255); + } + else if (buffer[1] == 'i') // disp string Displacement map + { + // Not supported... + } + } break; + case 'b': // bump string Bump texture map + { + sscanf(buffer, "bump %s", mapFileName); + if (mapFileName != NULL) material.texNormal = LoadTexture(mapFileName); + } break; + case 'T': // Tr float Transparency Tr (alpha). Tr is inverse of d + { + float ialpha = 0.0f; + sscanf(buffer, "Tr %f", &ialpha); + material.colDiffuse.a = (unsigned char)((1.0f - ialpha)*255); + + } break; + case 'r': // refl string Reflection texture map + default: break; + } } fclose(mtlFile); -- cgit v1.2.3 From ac44db26a2a2bed901c7e75d96e215fa09bd3705 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 9 May 2016 13:16:44 +0200 Subject: Added reference --- src/models.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/models.c') diff --git a/src/models.c b/src/models.c index dff6b224..7d24e383 100644 --- a/src/models.c +++ b/src/models.c @@ -1996,7 +1996,7 @@ static Mesh LoadOBJ(const char *fileName) return mesh; } -// Load MTL material data +// Load MTL material data (specs: http://paulbourke.net/dataformats/mtl/) // NOTE: Texture map parameters are not supported static Material LoadMTL(const char *fileName) { -- cgit v1.2.3