diff options
| author | Joshua Reisenauer <kd7tck@msn.com> | 2016-05-10 02:00:42 -0700 |
|---|---|---|
| committer | Joshua Reisenauer <kd7tck@msn.com> | 2016-05-10 02:00:42 -0700 |
| commit | 9799856ad4864b808cbfb40b0b4398fcdf61c1c2 (patch) | |
| tree | 05e311a651b3c41d333810b7b9c9408cd5918eb7 /src | |
| parent | b7f8e97b0384ae37bff110a2ef42cc42cfa09228 (diff) | |
| parent | ac44db26a2a2bed901c7e75d96e215fa09bd3705 (diff) | |
| download | raylib-9799856ad4864b808cbfb40b0b4398fcdf61c1c2.tar.gz raylib-9799856ad4864b808cbfb40b0b4398fcdf61c1c2.zip | |
Merge remote-tracking branch 'refs/remotes/raysan5/develop' into develop
Diffstat (limited to 'src')
| -rw-r--r-- | src/core.c | 1 | ||||
| -rw-r--r-- | src/models.c | 403 | ||||
| -rw-r--r-- | src/raylib.h | 47 | ||||
| -rw-r--r-- | src/rlgl.c | 957 | ||||
| -rw-r--r-- | src/rlgl.h | 15 |
5 files changed, 903 insertions, 520 deletions
@@ -1448,6 +1448,7 @@ static void InitDisplay(int width, int height) glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Profiles Hint: Only 3.3 and above! // Other values: GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE); // Fordward Compatibility Hint: Only 3.3 and above! + //glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE); } if (fullscreen) diff --git a/src/models.c b/src/models.c index 0bb2b8d6..7d24e383 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,22 +565,111 @@ 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; } +// 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) { - 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 +677,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; } @@ -603,23 +695,54 @@ void UnloadModel(Model model) // Unload mesh data 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.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); 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]); // texcoords2 (NOT USED) - //rlDeleteBuffers(model.mesh.vboId[4]); // tangents (NOT USED) - //rlDeleteBuffers(model.mesh.vboId[5]); // colors (NOT USED) + rlDeleteBuffers(model.mesh.vboId[3]); // colors + rlDeleteBuffers(model.mesh.vboId[4]); // tangents + rlDeleteBuffers(model.mesh.vboId[5]); // texcoords2 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) { @@ -632,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; @@ -647,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 @@ -730,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); @@ -1048,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; @@ -1100,31 +1215,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 @@ -1742,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 @@ -1841,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); @@ -1856,3 +1995,163 @@ static Mesh LoadOBJ(const char *fileName) return mesh; } + +// Load MTL material data (specs: http://paulbourke.net/dataformats/mtl/) +// NOTE: Texture map parameters are not supported +static Material LoadMTL(const char *fileName) +{ + #define MAX_BUFFER_SIZE 128 + + Material material = { 0 }; // LoadDefaultMaterial(); + + char buffer[MAX_BUFFER_SIZE]; + Vector3 color = { 1.0f, 1.0f, 1.0f }; + char *mapFileName; + + FILE *mtlFile; + + mtlFile = fopen(fileName, "rt"); + + if (mtlFile == NULL) + { + TraceLog(WARNING, "[%s] MTL file could not be opened", fileName); + return material; + } + + while(!feof(mtlFile)) + { + 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); + + // NOTE: At this point we have all material data + TraceLog(INFO, "[%s] Material loaded successfully", fileName); + + return material; +} diff --git a/src/raylib.h b/src/raylib.h index 63ab0a5c..d464c8e9 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 @@ -386,11 +386,13 @@ typedef struct Mesh { typedef struct Shader { unsigned int id; // Shader program id - // Variable attributes locations - int vertexLoc; // Vertex attribute location point (vertex shader) - int texcoordLoc; // Texcoord attribute location point (vertex shader) - int normalLoc; // Normal attribute location point (vertex shader) - int colorLoc; // Color attibute location point (vertex shader) + // 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) + 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) @@ -801,17 +803,20 @@ void DrawGizmo(Vector3 position); //------------------------------------------------------------------------------------ // Model 3d Loading and Drawing Functions (Module: models) //------------------------------------------------------------------------------------ -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 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 +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); // 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) 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 -void DrawModelWires(Model model, Vector3 position, float scale, Color color); // Draw a model wires (with texture if set) +void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set) void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) @@ -832,11 +837,11 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p // NOTE: This functions are useless when using OpenGL 1.1 //------------------------------------------------------------------------------------ Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations -unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr); // Load custom shaders strings and return program id void UnloadShader(Shader shader); // Unload a custom shader from memory void SetDefaultShader(void); // Set default shader to be used in batch draw void SetCustomShader(Shader shader); // Set custom shader to be used in batch draw -void SetModelShader(Model *model, Shader shader); // Link a shader to a model +Shader GetDefaultShader(void); // Get default shader +Texture2D GetDefaultTexture(void); // Get default texture int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float) @@ -115,6 +115,15 @@ #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #endif + +// Default vertex attribute names on shader to set location points +#define DEFAULT_ATTRIB_POSITION_NAME "vertexPosition" // shader-location = 0 +#define DEFAULT_ATTRIB_TEXCOORD_NAME "vertexTexCoord" // shader-location = 1 +#define DEFAULT_ATTRIB_NORMAL_NAME "vertexNormal" // shader-location = 2 +#define DEFAULT_ATTRIB_COLOR_NAME "vertexColor" // shader-location = 3 +#define DEFAULT_ATTRIB_TANGENT_NAME "vertexTangent" // shader-location = 4 +#define DEFAULT_ATTRIB_TEXCOORD2_NAME "vertexTexCoord2" // shader-location = 5 + //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- @@ -255,14 +264,16 @@ unsigned int whiteTexture; //---------------------------------------------------------------------------------- #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) static void LoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int compressedFormat); +static unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr); // Load custom shader strings and return program id -static Shader LoadDefaultShader(void); -static void LoadDefaultShaderLocations(Shader *shader); -static void UnloadDefaultShader(void); +static Shader LoadDefaultShader(void); // Load default shader (just vertex positioning and texture coloring) +static void LoadDefaultShaderLocations(Shader *shader); // Bind default shader locations (attributes and uniforms) +static void UnloadDefaultShader(void); // Unload default shader -static void LoadDefaultBuffers(void); -static void UpdateDefaultBuffers(void); -static void UnloadDefaultBuffers(void); +static void LoadDefaultBuffers(void); // Load default internal buffers (lines, triangles, quads) +static void UpdateDefaultBuffers(void); // Update default internal buffers (VAOs/VBOs) with vertex data +static void DrawDefaultBuffers(void); // Draw default internal buffers vertex data +static void UnloadDefaultBuffers(void); // Unload default internal buffers vertex data from CPU and GPU static char *ReadTextFile(const char *fileName); #endif @@ -809,9 +820,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 } @@ -1061,167 +1074,12 @@ void rlglDraw(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) UpdateDefaultBuffers(); - - if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0)) - { - glUseProgram(currentShader.id); - - Matrix matMVP = MatrixMultiply(modelview, projection); // Create modelview-projection matrix - - glUniformMatrix4fv(currentShader.mvpLoc, 1, false, MatrixToFloat(matMVP)); - glUniform1i(currentShader.mapDiffuseLoc, 0); - glUniform4f(currentShader.tintColorLoc, 1.0f, 1.0f, 1.0f, 1.0f); - } - - // NOTE: We draw in this order: lines, triangles, quads - - if (lines.vCounter > 0) - { - glBindTexture(GL_TEXTURE_2D, whiteTexture); - - if (vaoSupported) - { - glBindVertexArray(vaoLines); - } - else - { - glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[0]); - glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.vertexLoc); - - if (currentShader.colorLoc != -1) - { - glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]); - glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(currentShader.colorLoc); - } - } - - glDrawArrays(GL_LINES, 0, lines.vCounter); - - if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - } - - if (triangles.vCounter > 0) - { - glBindTexture(GL_TEXTURE_2D, whiteTexture); - - if (vaoSupported) - { - glBindVertexArray(vaoTriangles); - } - else - { - glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[0]); - glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.vertexLoc); - - if (currentShader.colorLoc != -1) - { - glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[1]); - glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(currentShader.colorLoc); - } - } - - glDrawArrays(GL_TRIANGLES, 0, triangles.vCounter); - - if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - } - - if (quads.vCounter > 0) - { - int quadsCount = 0; - int numIndicesToProcess = 0; - int indicesOffset = 0; - - if (vaoSupported) - { - glBindVertexArray(vaoQuads); - } - else - { - // Enable vertex attributes - glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]); - glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.vertexLoc); - - glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[1]); - glVertexAttribPointer(currentShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.texcoordLoc); - - if (currentShader.colorLoc != -1) - { - glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]); - glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(currentShader.colorLoc); - } - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]); - } - - //TraceLog(DEBUG, "Draws required per frame: %i", drawsCounter); - - for (int i = 0; i < drawsCounter; i++) - { - quadsCount = draws[i].vertexCount/4; - numIndicesToProcess = quadsCount*6; // Get number of Quads * 6 index by Quad - - //TraceLog(DEBUG, "Quads to render: %i - Vertex Count: %i", quadsCount, draws[i].vertexCount); - - glBindTexture(GL_TEXTURE_2D, draws[i].textureId); - - // NOTE: The final parameter tells the GPU the offset in bytes from the start of the index buffer to the location of the first index to process -#if defined(GRAPHICS_API_OPENGL_33) - glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid*) (sizeof(GLuint) * indicesOffset)); -#elif defined(GRAPHICS_API_OPENGL_ES2) - glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_SHORT, (GLvoid*) (sizeof(GLushort) * indicesOffset)); -#endif - //GLenum err; - //if ((err = glGetError()) != GL_NO_ERROR) TraceLog(INFO, "OpenGL error: %i", (int)err); //GL_INVALID_ENUM! - - indicesOffset += draws[i].vertexCount/4*6; - } - - if (!vaoSupported) - { - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures - } - - if (vaoSupported) glBindVertexArray(0); // Unbind VAO - - glUseProgram(0); // Unbind shader program - - // Reset draws counter - drawsCounter = 1; - draws[0].textureId = whiteTexture; - draws[0].vertexCount = 0; - - // Reset vertex counters for next frame - lines.vCounter = 0; - lines.cCounter = 0; - - triangles.vCounter = 0; - triangles.cCounter = 0; - - quads.vCounter = 0; - quads.tcCounter = 0; - quads.cCounter = 0; - - // Reset depth for next draw - currentDepth = -1.0f; + DrawDefaultBuffers(); #endif } -// Draw a 3d model -// NOTE: Model transform can come within model struct -void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color color, bool wires) +// Draw a 3d mesh with material and transform +void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires) { #if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) // NOTE: glPolygonMode() not available on OpenGL ES @@ -1230,128 +1088,134 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float ro #if defined(GRAPHICS_API_OPENGL_11) glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, model.material.texDiffuse.id); + glBindTexture(GL_TEXTURE_2D, material.texDiffuse.id); // 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 + glEnableClientState(GL_VERTEX_ARRAY); // Enable vertex array + glEnableClientState(GL_TEXTURE_COORD_ARRAY); // Enable texture coords 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, model.mesh.vertices); // Pointer to vertex coords array - glTexCoordPointer(2, GL_FLOAT, 0, model.mesh.texcoords); // Pointer to texture coords array - glNormalPointer(GL_FLOAT, 0, model.mesh.normals); // Pointer to normals array - //glColorPointer(4, GL_UNSIGNED_BYTE, 0, model.mesh.colors); // Pointer to colors array (NOT USED) + glVertexPointer(3, GL_FLOAT, 0, mesh.vertices); // Pointer to vertex coords array + glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords); // Pointer to texture coords array + 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(); - rlTranslatef(position.x, position.y, position.z); - rlScalef(scale.x, scale.y, scale.z); - rlRotatef(rotationAngle, rotationAxis.x, rotationAxis.y, rotationAxis.z); - - rlColor4ub(color.r, color.g, color.b, color.a); - - glDrawArrays(GL_TRIANGLES, 0, model.mesh.vertexCount); + rlMultMatrixf(MatrixToFloat(transform)); + rlColor4ub(material.colDiffuse.r, material.colDiffuse.g, material.colDiffuse.b, material.colDiffuse.a); + glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount); rlPopMatrix(); - glDisableClientState(GL_VERTEX_ARRAY); // Disable vertex array - glDisableClientState(GL_TEXTURE_COORD_ARRAY); // Disable texture coords array - glDisableClientState(GL_NORMAL_ARRAY); // Disable normals array + glDisableClientState(GL_VERTEX_ARRAY); // Disable vertex array + glDisableClientState(GL_TEXTURE_COORD_ARRAY); // Disable texture coords 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); #endif #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glUseProgram(model.material.shader.id); + glUseProgram(material.shader.id); // At this point the modelview matrix just contains the view matrix (camera) // That's because Begin3dMode() sets it an no model-drawing function modifies it, all use rlPushMatrix() and rlPopMatrix() Matrix matView = modelview; // View matrix (camera) Matrix matProjection = projection; // Projection matrix (perspective) - - // 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); - Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); - - // Combine model internal transformation matrix (model.transform) with matrix generated by function parameters (matTransform) - Matrix matModel = MatrixMultiply(model.transform, matTransform); // Transform to world-space coordinates - + // Calculate model-view matrix combining matModel and matView - Matrix matModelView = MatrixMultiply(matModel, matView); // Transform to camera-space coordinates + Matrix matModelView = MatrixMultiply(transform, matView); // Transform to camera-space coordinates // Calculate model-view-projection matrix (MVP) Matrix matMVP = MatrixMultiply(matModelView, matProjection); // Transform to screen-space coordinates // Send combined model-view-projection matrix to shader - glUniformMatrix4fv(model.material.shader.mvpLoc, 1, false, MatrixToFloat(matMVP)); + glUniformMatrix4fv(material.shader.mvpLoc, 1, false, MatrixToFloat(matMVP)); - // Apply color tinting to model + // Apply color tinting (material.colDiffuse) // NOTE: Just update one uniform on fragment shader - float vColor[4] = { (float)color.r/255, (float)color.g/255, (float)color.b/255, (float)color.a/255 }; - glUniform4fv(model.material.shader.tintColorLoc, 1, vColor); + float vColor[4] = { (float)material.colDiffuse.r/255, (float)material.colDiffuse.g/255, (float)material.colDiffuse.b/255, (float)material.colDiffuse.a/255 }; + glUniform4fv(material.shader.tintColorLoc, 1, vColor); // Set shader textures (diffuse, normal, specular) glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, model.material.texDiffuse.id); - glUniform1i(model.material.shader.mapDiffuseLoc, 0); // Texture fits in active texture unit 0 + glBindTexture(GL_TEXTURE_2D, material.texDiffuse.id); + glUniform1i(material.shader.mapDiffuseLoc, 0); // Texture fits in active texture unit 0 - if ((model.material.texNormal.id != 0) && (model.material.shader.mapNormalLoc != -1)) + if ((material.texNormal.id != 0) && (material.shader.mapNormalLoc != -1)) { glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, model.material.texNormal.id); - glUniform1i(model.material.shader.mapNormalLoc, 1); // Texture fits in active texture unit 1 + glBindTexture(GL_TEXTURE_2D, material.texNormal.id); + glUniform1i(material.shader.mapNormalLoc, 1); // Texture fits in active texture unit 1 } - if ((model.material.texSpecular.id != 0) && (model.material.shader.mapSpecularLoc != -1)) + if ((material.texSpecular.id != 0) && (material.shader.mapSpecularLoc != -1)) { glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, model.material.texSpecular.id); - glUniform1i(model.material.shader.mapSpecularLoc, 2); // Texture fits in active texture unit 2 + glBindTexture(GL_TEXTURE_2D, material.texSpecular.id); + glUniform1i(material.shader.mapSpecularLoc, 2); // Texture fits in active texture unit 2 } if (vaoSupported) { - glBindVertexArray(model.mesh.vaoId); + glBindVertexArray(mesh.vaoId); } else { - // Bind model VBO data: vertex position - glBindBuffer(GL_ARRAY_BUFFER, model.mesh.vboId[0]); - glVertexAttribPointer(model.material.shader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.material.shader.vertexLoc); + // Bind mesh VBO data: vertex position (shader-location = 0) + glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]); + glVertexAttribPointer(material.shader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(material.shader.vertexLoc); - // Bind model VBO data: vertex texcoords - glBindBuffer(GL_ARRAY_BUFFER, model.mesh.vboId[1]); - glVertexAttribPointer(model.material.shader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.material.shader.texcoordLoc); + // Bind mesh VBO data: vertex texcoords (shader-location = 1) + glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]); + glVertexAttribPointer(material.shader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(material.shader.texcoordLoc); - // Bind model VBO data: vertex normals (if available) - if (model.material.shader.normalLoc != -1) + // Bind mesh VBO data: vertex normals (shader-location = 2, if available) + if (material.shader.normalLoc != -1) + { + glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[2]); + glVertexAttribPointer(material.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(material.shader.normalLoc); + } + + // Bind mesh VBO data: vertex colors (shader-location = 3, if available) , tangents, texcoords2 (if available) + if (material.shader.colorLoc != -1) { - glBindBuffer(GL_ARRAY_BUFFER, model.mesh.vboId[2]); - glVertexAttribPointer(model.material.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.material.shader.normalLoc); + glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[3]); + glVertexAttribPointer(material.shader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(material.shader.colorLoc); } - // TODO: Bind model VBO data: colors, tangents, texcoords2 (if available) + // 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! - glDrawArrays(GL_TRIANGLES, 0, model.mesh.vertexCount); - - //glDisableVertexAttribArray(model.shader.vertexLoc); - //glDisableVertexAttribArray(model.shader.texcoordLoc); - //if (model.shader.normalLoc != -1) glDisableVertexAttribArray(model.shader.normalLoc); + glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount); - if (model.material.texNormal.id != 0) + if (material.texNormal.id != 0) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); } - if (model.material.texSpecular.id != 0) + if (material.texSpecular.id != 0) { glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, 0); @@ -1808,95 +1672,130 @@ void rlglGenerateMipmaps(Texture2D texture) glBindTexture(GL_TEXTURE_2D, 0); } -// Load vertex data into a VAO (if supported) and VBO -Model rlglLoadModel(Mesh mesh) +// Upload vertex data into a VAO (if supported) and VBO +void rlglLoadMesh(Mesh *mesh) { - Model model; - - model.mesh = mesh; - model.mesh.vaoId = 0; // Vertex Array Object - model.mesh.vboId[0] = 0; // Vertex positions VBO - model.mesh.vboId[1] = 0; // Vertex texcoords VBO - model.mesh.vboId[2] = 0; // Vertex normals VBO - - // TODO: Consider attributes: color, texcoords2, tangents (if available) + 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 colors VBO + mesh->vboId[4] = 0; // Vertex tangents VBO + mesh->vboId[5] = 0; // Vertex texcoords2 VBO - model.transform = MatrixIdentity(); -#if defined(GRAPHICS_API_OPENGL_11) - model.material.texDiffuse.id = 0; // No texture required - model.material.shader.id = 0; // No shader used - -#elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - model.material.shader = defaultShader; // Default model shader - - model.material.texDiffuse.id = whiteTexture; // Default whiteTexture - model.material.texDiffuse.width = 1; // Default whiteTexture width - model.material.texDiffuse.height = 1; // Default whiteTexture height - model.material.texDiffuse.format = UNCOMPRESSED_R8G8B8A8; // Default whiteTexture format - - model.material.texNormal.id = 0; // By default, no normal texture - model.material.texSpecular.id = 0; // By default, no specular texture - - // TODO: Fill default material properties (color, glossiness...) - - GLuint vaoModel = 0; // Vertex Array Objects (VAO) - GLuint vertexBuffer[3]; // Vertex Buffer Objects (VBO) +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + GLuint vaoId = 0; // Vertex Array Objects (VAO) + GLuint vboId[6]; // Vertex Buffer Objects (VBOs) if (vaoSupported) { // Initialize Quads VAO (Buffer A) - glGenVertexArrays(1, &vaoModel); - glBindVertexArray(vaoModel); + glGenVertexArrays(1, &vaoId); + glBindVertexArray(vaoId); } - // Create buffers for our vertex data (positions, texcoords, normals) - glGenBuffers(3, vertexBuffer); + // NOTE: Attributes must be uploaded considering default locations points - // NOTE: Default shader is assigned to model, so vbo buffers are properly linked to vertex attribs - // If model shader is changed, vbo buffers must be re-assigned to new location points (previously loaded) + // 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: position - glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.vertices, GL_STATIC_DRAW); - glVertexAttribPointer(model.material.shader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.material.shader.vertexLoc); + // 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: texcoords - glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh.vertexCount, mesh.texcoords, GL_STATIC_DRAW); - glVertexAttribPointer(model.material.shader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.material.shader.texcoordLoc); - - // Enable vertex attributes: normals - glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.normals, GL_STATIC_DRAW); - glVertexAttribPointer(model.material.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.material.shader.normalLoc); + // Enable vertex attributes: normals (shader-location = 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) + 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); + } - glVertexAttrib4f(model.material.shader.colorLoc, 1.0f, 1.0f, 1.0f, 1.0f); // Color vertex attribute set to default: WHITE - glDisableVertexAttribArray(model.material.shader.colorLoc); + // 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); + } - model.mesh.vboId[0] = vertexBuffer[0]; // Vertex position VBO - model.mesh.vboId[1] = vertexBuffer[1]; // Texcoords VBO - model.mesh.vboId[2] = vertexBuffer[2]; // Normals VBO + 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) { - if (vaoModel > 0) + if (vaoId > 0) { - model.mesh.vaoId = vaoModel; - TraceLog(INFO, "[VAO ID %i] Model uploaded successfully to VRAM (GPU)", vaoModel); + mesh->vaoId = vaoId; + TraceLog(INFO, "[VAO ID %i] Mesh uploaded successfully to VRAM (GPU)", mesh->vaoId); } - else TraceLog(WARNING, "Model could not be uploaded to VRAM (GPU)"); + else TraceLog(WARNING, "Mesh could not be uploaded to VRAM (GPU)"); } else { - TraceLog(INFO, "[VBO ID %i][VBO ID %i][VBO ID %i] Model uploaded successfully to VRAM (GPU)", model.mesh.vboId[0], model.mesh.vboId[1], model.mesh.vboId[2]); + TraceLog(INFO, "[VBOs] Mesh uploaded successfully to VRAM (GPU)"); } #endif - - return model; } // Read screen pixel data (color buffer) @@ -2058,6 +1957,20 @@ void *rlglReadTexturePixels(Texture2D texture) // NOTE: Those functions are exposed directly to the user in raylib.h //---------------------------------------------------------------------------------- +// Get default internal texture (white texture) +Texture2D GetDefaultTexture(void) +{ + Texture2D texture; + + texture.id = whiteTexture; + texture.width = 1; + texture.height = 1; + texture.mipmaps = 1; + texture.format = UNCOMPRESSED_R8G8B8A8; + + return texture; +} + // Load a custom shader and bind default locations Shader LoadShader(char *vsFileName, char *fsFileName) { @@ -2090,106 +2003,6 @@ Shader LoadShader(char *vsFileName, char *fsFileName) return shader; } -// Load custom shader strings and return program id -unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr) -{ - unsigned int program = 0; - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - GLuint vertexShader; - GLuint fragmentShader; - - vertexShader = glCreateShader(GL_VERTEX_SHADER); - fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - - const char *pvs = vShaderStr; - const char *pfs = fShaderStr; - - glShaderSource(vertexShader, 1, &pvs, NULL); - glShaderSource(fragmentShader, 1, &pfs, NULL); - - GLint success = 0; - - glCompileShader(vertexShader); - - glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); - - if (success != GL_TRUE) - { - TraceLog(WARNING, "[VSHDR ID %i] Failed to compile vertex shader...", vertexShader); - - int maxLength = 0; - int length; - - glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &maxLength); - - char log[maxLength]; - - glGetShaderInfoLog(vertexShader, maxLength, &length, log); - - TraceLog(INFO, "%s", log); - } - else TraceLog(INFO, "[VSHDR ID %i] Vertex shader compiled successfully", vertexShader); - - glCompileShader(fragmentShader); - - glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); - - if (success != GL_TRUE) - { - TraceLog(WARNING, "[FSHDR ID %i] Failed to compile fragment shader...", fragmentShader); - - int maxLength = 0; - int length; - - glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &maxLength); - - char log[maxLength]; - - glGetShaderInfoLog(fragmentShader, maxLength, &length, log); - - TraceLog(INFO, "%s", log); - } - else TraceLog(INFO, "[FSHDR ID %i] Fragment shader compiled successfully", fragmentShader); - - program = glCreateProgram(); - - glAttachShader(program, vertexShader); - glAttachShader(program, fragmentShader); - - glLinkProgram(program); - - // NOTE: All uniform variables are intitialised to 0 when a program links - - glGetProgramiv(program, GL_LINK_STATUS, &success); - - if (success == GL_FALSE) - { - TraceLog(WARNING, "[SHDR ID %i] Failed to link shader program...", program); - - int maxLength = 0; - int length; - - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); - - char log[maxLength]; - - glGetProgramInfoLog(program, maxLength, &length, log); - - TraceLog(INFO, "%s", log); - - glDeleteProgram(program); - - program = 0; - } - else TraceLog(INFO, "[SHDR ID %i] Shader program loaded successfully", program); - - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); -#endif - return program; -} - // Unload a custom shader from memory void UnloadShader(Shader shader) { @@ -2220,33 +2033,14 @@ void SetDefaultShader(void) #endif } -// Link shader to model -void SetModelShader(Model *model, Shader shader) +// Get default shader +Shader GetDefaultShader(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - model->material.shader = shader; - - if (vaoSupported) glBindVertexArray(model->mesh.vaoId); - - // Enable vertex attributes: position - glBindBuffer(GL_ARRAY_BUFFER, model->mesh.vboId[0]); - glEnableVertexAttribArray(shader.vertexLoc); - glVertexAttribPointer(shader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - - // Enable vertex attributes: texcoords - glBindBuffer(GL_ARRAY_BUFFER, model->mesh.vboId[1]); - glEnableVertexAttribArray(shader.texcoordLoc); - glVertexAttribPointer(shader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); - - // Enable vertex attributes: normals - glBindBuffer(GL_ARRAY_BUFFER, model->mesh.vboId[2]); - glEnableVertexAttribArray(shader.normalLoc); - glVertexAttribPointer(shader.normalLoc, 3, GL_FLOAT, 0, 0, 0); - - if (vaoSupported) glBindVertexArray(0); // Unbind VAO - -#elif (GRAPHICS_API_OPENGL_11) - TraceLog(WARNING, "Shaders not supported on OpenGL 1.1"); + return defaultShader; +#else + Shader shader = { 0 }; + return shader; #endif } @@ -2367,7 +2161,118 @@ static void LoadCompressedTexture(unsigned char *data, int width, int height, in } } -// Load default shader (Vertex and Fragment) +// Load custom shader strings and return program id +static unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr) +{ + unsigned int program = 0; + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + GLuint vertexShader; + GLuint fragmentShader; + + vertexShader = glCreateShader(GL_VERTEX_SHADER); + fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + + const char *pvs = vShaderStr; + const char *pfs = fShaderStr; + + glShaderSource(vertexShader, 1, &pvs, NULL); + glShaderSource(fragmentShader, 1, &pfs, NULL); + + GLint success = 0; + + glCompileShader(vertexShader); + + glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); + + if (success != GL_TRUE) + { + TraceLog(WARNING, "[VSHDR ID %i] Failed to compile vertex shader...", vertexShader); + + int maxLength = 0; + int length; + + glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &maxLength); + + char log[maxLength]; + + glGetShaderInfoLog(vertexShader, maxLength, &length, log); + + TraceLog(INFO, "%s", log); + } + else TraceLog(INFO, "[VSHDR ID %i] Vertex shader compiled successfully", vertexShader); + + glCompileShader(fragmentShader); + + glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); + + if (success != GL_TRUE) + { + TraceLog(WARNING, "[FSHDR ID %i] Failed to compile fragment shader...", fragmentShader); + + int maxLength = 0; + int length; + + glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &maxLength); + + char log[maxLength]; + + glGetShaderInfoLog(fragmentShader, maxLength, &length, log); + + TraceLog(INFO, "%s", log); + } + else TraceLog(INFO, "[FSHDR ID %i] Fragment shader compiled successfully", fragmentShader); + + program = glCreateProgram(); + + glAttachShader(program, vertexShader); + glAttachShader(program, fragmentShader); + + // NOTE: Default attribute shader locations must be binded before linking + glBindAttribLocation(program, 0, DEFAULT_ATTRIB_POSITION_NAME); + glBindAttribLocation(program, 1, DEFAULT_ATTRIB_TEXCOORD_NAME); + glBindAttribLocation(program, 2, DEFAULT_ATTRIB_NORMAL_NAME); + glBindAttribLocation(program, 3, DEFAULT_ATTRIB_COLOR_NAME); + glBindAttribLocation(program, 4, DEFAULT_ATTRIB_TANGENT_NAME); + glBindAttribLocation(program, 5, DEFAULT_ATTRIB_TEXCOORD2_NAME); + + // NOTE: If some attrib name is no found on the shader, it locations becomes -1 + + glLinkProgram(program); + + // NOTE: All uniform variables are intitialised to 0 when a program links + + glGetProgramiv(program, GL_LINK_STATUS, &success); + + if (success == GL_FALSE) + { + TraceLog(WARNING, "[SHDR ID %i] Failed to link shader program...", program); + + int maxLength = 0; + int length; + + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); + + char log[maxLength]; + + glGetProgramInfoLog(program, maxLength, &length, log); + + TraceLog(INFO, "%s", log); + + glDeleteProgram(program); + + program = 0; + } + else TraceLog(INFO, "[SHDR ID %i] Shader program loaded successfully", program); + + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); +#endif + return program; +} + + +// Load default shader (just vertex positioning and texture coloring) // NOTE: This shader program is used for batch buffers (lines, triangles, quads) static Shader LoadDefaultShader(void) { @@ -2436,11 +2341,21 @@ static Shader LoadDefaultShader(void) // NOTE: If any location is not found, loc point becomes -1 static void LoadDefaultShaderLocations(Shader *shader) { + // NOTE: Default shader attrib locations have been fixed before linking: + // vertex position location = 0 + // 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"); @@ -2470,7 +2385,7 @@ static void LoadDefaultBuffers(void) // [CPU] Allocate and initialize float array buffers to store vertex data (lines, triangles, quads) //-------------------------------------------------------------------------------------------- - // Initialize lines arrays (vertex position and color data) + // Lines - Initialize arrays (vertex position and color data) lines.vertices = (float *)malloc(sizeof(float)*3*2*MAX_LINES_BATCH); // 3 float by vertex, 2 vertex by line lines.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*2*MAX_LINES_BATCH); // 4 float by color, 2 colors by line @@ -2480,7 +2395,7 @@ static void LoadDefaultBuffers(void) lines.vCounter = 0; lines.cCounter = 0; - // Initialize triangles arrays (vertex position and color data) + // Triangles - Initialize arrays (vertex position and color data) triangles.vertices = (float *)malloc(sizeof(float)*3*3*MAX_TRIANGLES_BATCH); // 3 float by vertex, 3 vertex by triangle triangles.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*3*MAX_TRIANGLES_BATCH); // 4 float by color, 3 colors by triangle @@ -2490,7 +2405,7 @@ static void LoadDefaultBuffers(void) triangles.vCounter = 0; triangles.cCounter = 0; - // Initialize quads arrays (vertex position, texcoord and color data... and indexes) + // Quads - Initialize arrays (vertex position, texcoord, color data and indexes) quads.vertices = (float *)malloc(sizeof(float)*3*4*MAX_QUADS_BATCH); // 3 float by vertex, 4 vertex by quad quads.texcoords = (float *)malloc(sizeof(float)*2*4*MAX_QUADS_BATCH); // 2 float by texcoord, 4 texcoord by quad quads.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*4*MAX_QUADS_BATCH); // 4 float by color, 4 colors by quad @@ -2523,7 +2438,7 @@ static void LoadDefaultBuffers(void) quads.tcCounter = 0; quads.cCounter = 0; - TraceLog(INFO, "Default buffers initialized successfully in CPU (lines, triangles, quads)"); + TraceLog(INFO, "[CPU] Default buffers initialized successfully (lines, triangles, quads)"); //-------------------------------------------------------------------------------------------- // [GPU] Upload vertex data and initialize VAOs/VBOs (lines, triangles, quads) @@ -2541,20 +2456,21 @@ static void LoadDefaultBuffers(void) // Create buffers for our vertex data glGenBuffers(2, linesBuffer); - // Lines - Vertex positions buffer binding and attributes enable + // Lines - Vertex buffers binding and attributes enable + // Vertex position buffer (shader-location = 0) glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*2*MAX_LINES_BATCH, lines.vertices, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.vertexLoc); glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - // Lines - colors buffer + // Vertex color buffer (shader-location = 3) glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.colorLoc); glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers (lines) VAO initialized successfully", vaoLines); - else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Default buffers (lines) VBOs initialized successfully", linesBuffer[0], linesBuffer[1]); + if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers VAO initialized successfully (lines)", vaoLines); + else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (lines)", linesBuffer[0], linesBuffer[1]); // Upload and link triangles vertex buffers if (vaoSupported) @@ -2567,19 +2483,21 @@ static void LoadDefaultBuffers(void) // Create buffers for our vertex data glGenBuffers(2, trianglesBuffer); - // Enable vertex attributes + // Triangles - Vertex buffers binding and attributes enable + // Vertex position buffer (shader-location = 0) glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*3*MAX_TRIANGLES_BATCH, triangles.vertices, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.vertexLoc); glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + // Vertex color buffer (shader-location = 3) glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.colorLoc); glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers (triangles) VAO initialized successfully", vaoTriangles); - else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Default buffers (triangles) VBOs initialized successfully", trianglesBuffer[0], trianglesBuffer[1]); + if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers VAO initialized successfully (triangles)", vaoTriangles); + else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully(triangles)", trianglesBuffer[0], trianglesBuffer[1]); // Upload and link quads vertex buffers if (vaoSupported) @@ -2592,17 +2510,20 @@ static void LoadDefaultBuffers(void) // Create buffers for our vertex data glGenBuffers(4, quadsBuffer); - // Enable vertex attributes + // Quads - Vertex buffers binding and attributes enable + // Vertex position buffer (shader-location = 0) glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_QUADS_BATCH, quads.vertices, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.vertexLoc); glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + // Vertex texcoord buffer (shader-location = 1) glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_QUADS_BATCH, quads.texcoords, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.texcoordLoc); glVertexAttribPointer(currentShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); + // Vertex color buffer (shader-location = 3) glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]); glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.colorLoc); @@ -2616,15 +2537,15 @@ static void LoadDefaultBuffers(void) glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW); #endif - if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers (quads) VAO initialized successfully", vaoQuads); - else TraceLog(INFO, "[VBO ID %i][VBO ID %i][VBO ID %i][VBO ID %i] Default buffers (quads) VBOs initialized successfully", quadsBuffer[0], quadsBuffer[1], quadsBuffer[2], quadsBuffer[3]); + if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers VAO initialized successfully (quads)", vaoQuads); + else TraceLog(INFO, "[VBO ID %i][VBO ID %i][VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (quads)", quadsBuffer[0], quadsBuffer[1], quadsBuffer[2], quadsBuffer[3]); // Unbind the current VAO if (vaoSupported) glBindVertexArray(0); //-------------------------------------------------------------------------------------------- } -// Update default buffers (VAOs/VBOs) with vertex array data +// Update default internal buffers (VAOs/VBOs) with vertex array data // NOTE: If there is not vertex data, buffers doesn't need to be updated (vertexCount > 0) // TODO: If no data changed on the CPU arrays --> No need to re-update GPU arrays (change flag required) static void UpdateDefaultBuffers(void) @@ -2695,7 +2616,165 @@ static void UpdateDefaultBuffers(void) if (vaoSupported) glBindVertexArray(0); } -// Unload default buffers vertex data from CPU and GPU +// Draw default internal buffers vertex data +// NOTE: We draw in this order: lines, triangles, quads +static void DrawDefaultBuffers(void) +{ + // Set current shader and upload current MVP matrix + if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0)) + { + glUseProgram(currentShader.id); + + // Create modelview-projection matrix + Matrix matMVP = MatrixMultiply(modelview, projection); + + glUniformMatrix4fv(currentShader.mvpLoc, 1, false, MatrixToFloat(matMVP)); + glUniform1i(currentShader.mapDiffuseLoc, 0); + glUniform4f(currentShader.tintColorLoc, 1.0f, 1.0f, 1.0f, 1.0f); + } + + // Draw lines buffers + if (lines.vCounter > 0) + { + glBindTexture(GL_TEXTURE_2D, whiteTexture); + + if (vaoSupported) + { + glBindVertexArray(vaoLines); + } + else + { + // Bind vertex attrib: position (shader-location = 0) + glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[0]); + glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(currentShader.vertexLoc); + + // Bind vertex attrib: color (shader-location = 3) + glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]); + glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(currentShader.colorLoc); + } + + glDrawArrays(GL_LINES, 0, lines.vCounter); + + if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + } + + // Draw triangles buffers + if (triangles.vCounter > 0) + { + glBindTexture(GL_TEXTURE_2D, whiteTexture); + + if (vaoSupported) + { + glBindVertexArray(vaoTriangles); + } + else + { + // Bind vertex attrib: position (shader-location = 0) + glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[0]); + glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(currentShader.vertexLoc); + + // Bind vertex attrib: color (shader-location = 3) + glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[1]); + glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(currentShader.colorLoc); + } + + glDrawArrays(GL_TRIANGLES, 0, triangles.vCounter); + + if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + } + + // Draw quads buffers + if (quads.vCounter > 0) + { + int quadsCount = 0; + int numIndicesToProcess = 0; + int indicesOffset = 0; + + if (vaoSupported) + { + glBindVertexArray(vaoQuads); + } + else + { + // Bind vertex attrib: position (shader-location = 0) + glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]); + glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(currentShader.vertexLoc); + + // Bind vertex attrib: texcoord (shader-location = 1) + glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[1]); + glVertexAttribPointer(currentShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(currentShader.texcoordLoc); + + // Bind vertex attrib: color (shader-location = 3) + glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]); + glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(currentShader.colorLoc); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]); + } + + //TraceLog(DEBUG, "Draws required per frame: %i", drawsCounter); + + for (int i = 0; i < drawsCounter; i++) + { + quadsCount = draws[i].vertexCount/4; + numIndicesToProcess = quadsCount*6; // Get number of Quads * 6 index by Quad + + //TraceLog(DEBUG, "Quads to render: %i - Vertex Count: %i", quadsCount, draws[i].vertexCount); + + glBindTexture(GL_TEXTURE_2D, draws[i].textureId); + + // NOTE: The final parameter tells the GPU the offset in bytes from the start of the index buffer to the location of the first index to process +#if defined(GRAPHICS_API_OPENGL_33) + glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid*) (sizeof(GLuint) * indicesOffset)); +#elif defined(GRAPHICS_API_OPENGL_ES2) + glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_SHORT, (GLvoid*) (sizeof(GLushort) * indicesOffset)); +#endif + //GLenum err; + //if ((err = glGetError()) != GL_NO_ERROR) TraceLog(INFO, "OpenGL error: %i", (int)err); //GL_INVALID_ENUM! + + indicesOffset += draws[i].vertexCount/4*6; + } + + if (!vaoSupported) + { + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + + glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures + } + + if (vaoSupported) glBindVertexArray(0); // Unbind VAO + + glUseProgram(0); // Unbind shader program + + // Reset draws counter + drawsCounter = 1; + draws[0].textureId = whiteTexture; + draws[0].vertexCount = 0; + + // Reset vertex counters for next frame + lines.vCounter = 0; + lines.cCounter = 0; + triangles.vCounter = 0; + triangles.cCounter = 0; + quads.vCounter = 0; + quads.tcCounter = 0; + quads.cCounter = 0; + + // Reset depth for next draw + currentDepth = -1.0f; +} + +// Unload default internal buffers vertex data from CPU and GPU static void UnloadDefaultBuffers(void) { // Unbind everything @@ -280,29 +280,28 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma RenderTexture2D rlglLoadRenderTexture(int width, int height); // Load a texture to be used for rendering (fbo with color and depth attachments) void rlglUpdateTexture(unsigned int id, int width, int height, int format, void *data); // Update GPU texture with new data void rlglGenerateMipmaps(Texture2D texture); // Generate mipmap data for selected texture - -// NOTE: There is a set of shader related functions that are available to end user, -// to avoid creating function wrappers through core module, they have been directly declared in raylib.h - -Model rlglLoadModel(Mesh mesh); // Upload vertex data into GPU and provided VAO/VBO ids -void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color color, bool wires); +void rlglLoadMesh(Mesh *mesh); // Upload vertex data into GPU and provided VAO/VBO ids +void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires); Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates unsigned char *rlglReadScreenPixels(int width, int height); // Read screen pixel data (color buffer) void *rlglReadTexturePixels(Texture2D texture); // Read texture pixel data +// NOTE: There is a set of shader related functions that are available to end user, +// to avoid creating function wrappers through core module, they have been directly declared in raylib.h + #if defined(RLGL_STANDALONE) //------------------------------------------------------------------------------------ // Shaders System Functions (Module: rlgl) // NOTE: This functions are useless when using OpenGL 1.1 //------------------------------------------------------------------------------------ Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations -unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr); // Load custom shader strings and return program id void UnloadShader(Shader shader); // Unload a custom shader from memory void SetCustomShader(Shader shader); // Set custom shader to be used in batch draw void SetDefaultShader(void); // Set default shader to be used in batch draw -void SetModelShader(Model *model, Shader shader); // Link a shader to a model +Shader GetDefaultShader(void); // Get default shader +Texture2D GetDefaultTexture(void); // Get default texture int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float) |
