diff --git a/src/raylib.h b/src/raylib.h index d86b17452..dff69705e 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -427,7 +427,9 @@ typedef struct Shader { // Uniform locations int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) - int tintColorLoc; // Diffuse color uniform location point (fragment shader) + int colDiffuseLoc; // Diffuse color uniform location point (fragment shader) + int colAmbientLoc; // Ambient color uniform location point (fragment shader) + int colSpecularLoc; // Specular color uniform location point (fragment shader) // Texture map locations (generic for any kind of map) int mapTexture0Loc; // Map texture uniform location point (default-texture-unit = 0) @@ -464,7 +466,7 @@ typedef struct LightData { int type; // Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT Vector3 position; // Light position - Vector3 target; // Light target: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) + Vector3 target; // Light direction: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) float radius; // Light attenuation radius light intensity reduced with distance (world distance) Color diffuse; // Light diffuse color diff --git a/src/rlgl.c b/src/rlgl.c index 68d562c76..1b3d98982 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -337,6 +337,8 @@ static int screenHeight; // Default framebuffer height // Lighting data static Light lights[MAX_LIGHTS]; // Lights pool static int lightsCount = 0; // Enabled lights counter +static int lightsLocs[MAX_LIGHTS][8]; // 8 possible location points per light: + // enabled, type, position, target, radius, diffuse, intensity, coneAngle //---------------------------------------------------------------------------------- // Module specific Functions Declaration @@ -362,9 +364,10 @@ static void SetStereoConfig(VrDeviceInfo info); // Set internal projection and modelview matrix depending on eyes tracking data static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView); -static void SetShaderLights(Shader shader); // Sets shader uniform values for lights array +static void GetShaderLightsLocations(Shader shader); // Get shader locations for lights (up to MAX_LIGHTS) +static void SetShaderLightsValues(Shader shader); // Set shader uniform values for lights -static char *ReadTextFile(const char *fileName); // Read chars array from text file +static char *ReadTextFile(const char *fileName); // Read chars array from text file #endif #if defined(RLGL_OCULUS_SUPPORT) @@ -1939,9 +1942,14 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) glUseProgram(material.shader.id); // Upload to shader material.colDiffuse - float vColorDiffuse[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, vColorDiffuse); + glUniform4f(material.shader.colDiffuseLoc, (float)material.colDiffuse.r/255, (float)material.colDiffuse.g/255, (float)material.colDiffuse.b/255, (float)material.colDiffuse.a/255); + // Upload to shader material.colAmbient (if available) + if (material.shader.colAmbientLoc != -1) glUniform4f(material.shader.colAmbientLoc, (float)material.colAmbient.r/255, (float)material.colAmbient.g/255, (float)material.colAmbient.b/255, (float)material.colAmbient.a/255); + + // Upload to shader material.colSpecular (if available) + if (material.shader.colSpecularLoc != -1) glUniform4f(material.shader.colSpecularLoc, (float)material.colSpecular.r/255, (float)material.colSpecular.g/255, (float)material.colSpecular.b/255, (float)material.colSpecular.a/255); + // 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) @@ -1950,32 +1958,35 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) // Calculate model-view matrix combining matModel and matView Matrix matModelView = MatrixMultiply(transform, matView); // Transform to camera-space coordinates - // Check if using standard shader to get location points - // NOTE: standard shader specific locations are got at render time to keep Shader struct as simple as possible (with just default shader locations) - if (material.shader.id == standardShader.id) + // If not using default shader, we check for some additional location points + // NOTE: This method is quite inefficient... it's a temporal solution while looking for a better one + if (material.shader.id != defaultShader.id) { - // Transpose and inverse model transformations matrix for fragment normal calculations - Matrix transInvTransform = transform; - MatrixTranspose(&transInvTransform); - MatrixInvert(&transInvTransform); - - // Send model transformations matrix to shader - glUniformMatrix4fv(glGetUniformLocation(material.shader.id, "modelMatrix"), 1, false, MatrixToFloat(transInvTransform)); - - // Send view transformation matrix to shader. View matrix 8, 9 and 10 are view direction vector axis values (target - position) - glUniform3f(glGetUniformLocation(material.shader.id, "viewDir"), matView.m8, matView.m9, matView.m10); - - // Setup shader uniforms for lights - SetShaderLights(material.shader); - - // Upload to shader material.colAmbient - glUniform4f(glGetUniformLocation(material.shader.id, "colAmbient"), (float)material.colAmbient.r/255, (float)material.colAmbient.g/255, (float)material.colAmbient.b/255, (float)material.colAmbient.a/255); - - // Upload to shader material.colSpecular - glUniform4f(glGetUniformLocation(material.shader.id, "colSpecular"), (float)material.colSpecular.r/255, (float)material.colSpecular.g/255, (float)material.colSpecular.b/255, (float)material.colSpecular.a/255); - - // Upload to shader glossiness - glUniform1f(glGetUniformLocation(material.shader.id, "glossiness"), material.glossiness); + // Check if model matrix is located in shader and upload value + int modelMatrixLoc = glGetUniformLocation(material.shader.id, "modelMatrix"); + if (modelMatrixLoc != -1) + { + // Transpose and inverse model transformations matrix for fragment normal calculations + Matrix transInvTransform = transform; + MatrixTranspose(&transInvTransform); + MatrixInvert(&transInvTransform); + + // Send model transformations matrix to shader + glUniformMatrix4fv(modelMatrixLoc, 1, false, MatrixToFloat(transInvTransform)); + } + + // Check if view direction is located in shader and upload value + // NOTE: View matrix values m8, m9 and m10 are view direction vector axis (target - position) + int viewDirLoc = glGetUniformLocation(material.shader.id, "viewDir"); + if (viewDirLoc != -1) glUniform3f(viewDirLoc, matView.m8, matView.m9, matView.m10); + + // Check if glossiness is located in shader and upload value + int glossinessLoc = glGetUniformLocation(material.shader.id, "glossiness"); + if (glossinessLoc != -1) glUniform1f(glossinessLoc, material.glossiness); + + // Set shader lights values for enabled lights + // NOTE: Lights array location points are obtained on shader loading (if available) + if (lightsCount > 0) SetShaderLightsValues(material.shader); } // Set shader textures (diffuse, normal, specular) @@ -3100,7 +3111,7 @@ static Shader LoadStandardShader(void) shader = GetDefaultShader(); } #else - shader = defaultShader; + shader = GetDefaultShader(); TraceLog(WARNING, "[SHDR ID %i] Standard shader not available, using default shader", shader.id); #endif @@ -3112,12 +3123,12 @@ static Shader LoadStandardShader(void) 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 + // 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, DEFAULT_ATTRIB_POSITION_NAME); @@ -3131,10 +3142,18 @@ static void LoadDefaultShaderLocations(Shader *shader) shader->mvpLoc = glGetUniformLocation(shader->id, "mvpMatrix"); // Get handles to GLSL uniform locations (fragment shader) - shader->tintColorLoc = glGetUniformLocation(shader->id, "colDiffuse"); + shader->colDiffuseLoc = glGetUniformLocation(shader->id, "colDiffuse"); + shader->colAmbientLoc = glGetUniformLocation(shader->id, "colAmbient"); + shader->colSpecularLoc = glGetUniformLocation(shader->id, "colSpecular"); + shader->mapTexture0Loc = glGetUniformLocation(shader->id, "texture0"); shader->mapTexture1Loc = glGetUniformLocation(shader->id, "texture1"); shader->mapTexture2Loc = glGetUniformLocation(shader->id, "texture2"); + + // TODO: Try to find all expected/recognized shader locations (predefined names, must be documented) + + // Try to get lights location points (if available) + GetShaderLightsLocations(*shader); } // Unload default shader @@ -3425,7 +3444,7 @@ static void DrawDefaultBuffers(int eyesCount) Matrix matMVP = MatrixMultiply(modelview, projection); glUniformMatrix4fv(currentShader.mvpLoc, 1, false, MatrixToFloat(matMVP)); - glUniform4f(currentShader.tintColorLoc, 1.0f, 1.0f, 1.0f, 1.0f); + glUniform4f(currentShader.colDiffuseLoc, 1.0f, 1.0f, 1.0f, 1.0f); glUniform1i(currentShader.mapTexture0Loc, 0); // NOTE: Additional map textures not considered for default buffers drawing @@ -3620,82 +3639,100 @@ static void UnloadDefaultBuffers(void) free(quads.indices); } -// Setup shader uniform values for lights array -// NOTE: It would be far easier with shader UBOs but are not supported on OpenGL ES 2.0f -static void SetShaderLights(Shader shader) +// Get shader locations for lights (up to MAX_LIGHTS) +static void GetShaderLightsLocations(Shader shader) { - int locPoint = -1; - char locName[32] = "lights[x].position\0"; - + char locName[32] = "lights[x].\0"; + char locNameUpdated[64]; + for (int i = 0; i < MAX_LIGHTS; i++) { locName[7] = '0' + i; + + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "enabled\0"); + lightsLocs[i][0] = glGetUniformLocation(shader.id, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "type\0"); + lightsLocs[i][1] = glGetUniformLocation(shader.id, locNameUpdated); - if (lights[i] != NULL) // Only upload registered lights data + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "position\0"); + lightsLocs[i][2] = glGetUniformLocation(shader.id, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "direction\0"); + lightsLocs[i][3] = glGetUniformLocation(shader.id, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "radius\0"); + lightsLocs[i][4] = glGetUniformLocation(shader.id, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "diffuse\0"); + lightsLocs[i][5] = glGetUniformLocation(shader.id, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "intensity\0"); + lightsLocs[i][6] = glGetUniformLocation(shader.id, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "coneAngle\0"); + lightsLocs[i][7] = glGetUniformLocation(shader.id, locNameUpdated); + } +} + +// Set shader uniform values for lights +// NOTE: It would be far easier with shader UBOs but are not supported on OpenGL ES 2.0 +static void SetShaderLightsValues(Shader shader) +{ + for (int i = 0; i < MAX_LIGHTS; i++) + { + if (i < lightsCount) { - memcpy(&locName[10], "enabled\0", strlen("enabled\0") + 1); - locPoint = GetShaderLocation(shader, locName); - glUniform1i(locPoint, lights[i]->enabled); - - memcpy(&locName[10], "type\0", strlen("type\0") + 1); - locPoint = GetShaderLocation(shader, locName); - glUniform1i(locPoint, lights[i]->type); - - memcpy(&locName[10], "diffuse\0", strlen("diffuse\0") + 2); - locPoint = glGetUniformLocation(shader.id, locName); - glUniform4f(locPoint, (float)lights[i]->diffuse.r/255, (float)lights[i]->diffuse.g/255, (float)lights[i]->diffuse.b/255, (float)lights[i]->diffuse.a/255); - - memcpy(&locName[10], "intensity\0", strlen("intensity\0")); - locPoint = glGetUniformLocation(shader.id, locName); - glUniform1f(locPoint, lights[i]->intensity); + glUniform1i(lightsLocs[i][0], lights[i]->enabled); + + glUniform1i(lightsLocs[i][1], lights[i]->type); + glUniform4f(lightsLocs[i][5], (float)lights[i]->diffuse.r/255, (float)lights[i]->diffuse.g/255, (float)lights[i]->diffuse.b/255, (float)lights[i]->diffuse.a/255); + glUniform1f(lightsLocs[i][6], lights[i]->intensity); switch (lights[i]->type) { case LIGHT_POINT: { - memcpy(&locName[10], "position\0", strlen("position\0") + 1); - locPoint = GetShaderLocation(shader, locName); - glUniform3f(locPoint, lights[i]->position.x, lights[i]->position.y, lights[i]->position.z); - - memcpy(&locName[10], "radius\0", strlen("radius\0") + 2); - locPoint = GetShaderLocation(shader, locName); - glUniform1f(locPoint, lights[i]->radius); + glUniform3f(lightsLocs[i][2], lights[i]->position.x, lights[i]->position.y, lights[i]->position.z); + glUniform1f(lightsLocs[i][4], lights[i]->radius); } break; case LIGHT_DIRECTIONAL: { - memcpy(&locName[10], "direction\0", strlen("direction\0") + 2); - locPoint = GetShaderLocation(shader, locName); Vector3 direction = { lights[i]->target.x - lights[i]->position.x, lights[i]->target.y - lights[i]->position.y, lights[i]->target.z - lights[i]->position.z }; VectorNormalize(&direction); - glUniform3f(locPoint, direction.x, direction.y, direction.z); + glUniform3f(lightsLocs[i][3], direction.x, direction.y, direction.z); } break; case LIGHT_SPOT: { - memcpy(&locName[10], "position\0", strlen("position\0") + 1); - locPoint = GetShaderLocation(shader, locName); - glUniform3f(locPoint, lights[i]->position.x, lights[i]->position.y, lights[i]->position.z); - - memcpy(&locName[10], "direction\0", strlen("direction\0") + 2); - locPoint = GetShaderLocation(shader, locName); + glUniform3f(lightsLocs[i][2], lights[i]->position.x, lights[i]->position.y, lights[i]->position.z); Vector3 direction = { lights[i]->target.x - lights[i]->position.x, lights[i]->target.y - lights[i]->position.y, lights[i]->target.z - lights[i]->position.z }; VectorNormalize(&direction); - glUniform3f(locPoint, direction.x, direction.y, direction.z); + glUniform3f(lightsLocs[i][3], direction.x, direction.y, direction.z); - memcpy(&locName[10], "coneAngle\0", strlen("coneAngle\0")); - locPoint = GetShaderLocation(shader, locName); - glUniform1f(locPoint, lights[i]->coneAngle); + glUniform1f(lightsLocs[i][7], lights[i]->coneAngle); } break; default: break; } - - // TODO: Pass to the shader any other required data from LightData struct } - else // Not enabled lights + else { - memcpy(&locName[10], "enabled\0", strlen("enabled\0") + 1); - locPoint = GetShaderLocation(shader, locName); - glUniform1i(locPoint, 0); + glUniform1i(lightsLocs[i][0], 0); // Light disabled } } } diff --git a/src/rlgl.h b/src/rlgl.h index 3fc542196..5fc9f8b9a 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -168,7 +168,9 @@ typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; // Uniform locations int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) - int tintColorLoc; // Color uniform location point (fragment shader) + int colDiffuseLoc; // Color uniform location point (fragment shader) + int colAmbientLoc; // Ambient color uniform location point (fragment shader) + int colSpecularLoc; // Specular color uniform location point (fragment shader) // Texture map locations (generic for any kind of map) int mapTexture0Loc; // Map texture uniform location point (default-texture-unit = 0)