Browse Source

Improved mesh support

Depending on mesh data, it can be loaded and default vertex attribute
location points are set, including colors, tangents and texcoords2
raysan5 9 years ago
parent
commit
0bcb873cbb
3 changed files with 171 additions and 45 deletions
  1. 94 26
      src/models.c
  2. 3 3
      src/raylib.h
  3. 74 16
      src/rlgl.c

+ 94 - 26
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);

+ 3 - 3
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

+ 74 - 16
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
 }