Browse Source

Add lighting system -IN PROGRESS-

Improved materials
raysan5 9 years ago
parent
commit
dcf5f45f68
4 changed files with 228 additions and 6 deletions
  1. 12 0
      src/models.c
  2. 29 1
      src/raylib.h
  3. 162 5
      src/rlgl.c
  4. 25 0
      src/rlgl.h

+ 12 - 0
src/models.c

@@ -732,6 +732,18 @@ Material LoadDefaultMaterial(void)
     return material;
 }
 
+// Load standard material (uses standard models shader)
+// NOTE: Standard shader supports multiple maps and lights
+Material LoadStandardMaterial(void)
+{
+    Material material = LoadDefaultMaterial();
+    
+    //material.shader = GetStandardShader();
+
+    return material;
+}
+
+// Unload material from memory
 void UnloadMaterial(Material material)
 {
     rlDeleteTextures(material.texDiffuse.id);

+ 29 - 1
src/raylib.h

@@ -422,13 +422,38 @@ typedef struct Material {
     float normalDepth;          // Normal map depth
 } Material;
 
-// 3d Model type
+// Model type
 typedef struct Model {
     Mesh mesh;                  // Vertex data buffers (RAM and VRAM)
     Matrix transform;           // Local transform matrix
     Material material;          // Shader and textures data
 } Model;
 
+// Light type
+// TODO: Review contained data to support different light types and features
+typedef struct LightData {
+    int id;
+    int type;           // LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT
+    bool enabled;
+    
+    Vector3 position;
+    Vector3 direction;  // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction)
+    float attenuation;  // Lost of light intensity with distance (use radius?)
+    
+    Color diffuse;      // Use Vector3 diffuse (including intensities)?
+    float intensity;
+    
+    Color specular;
+    //float specFactor;   // Specular intensity ?
+
+    //Color ambient;    // Required?
+    
+    float coneAngle;         // SpotLight
+} LightData, *Light;
+
+// Light types
+typedef enum { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT } LightType;
+
 // Ray type (useful for raycast)
 typedef struct Ray {
     Vector3 position;
@@ -849,6 +874,9 @@ void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat);       // S
 
 void SetBlendMode(int mode);                                        // Set blending mode (alpha, additive, multiplied)
 
+Light CreateLight(int type, Vector3 position, Color diffuse);       // Create a new light, initialize it and add to pool
+void DestroyLight(Light light);                                     // Destroy a light and take it out of the list
+
 //----------------------------------------------------------------------------------
 // Physics System Functions (Module: physac)
 //----------------------------------------------------------------------------------

+ 162 - 5
src/rlgl.c

@@ -71,6 +71,8 @@
 #define MAX_DRAWS_BY_TEXTURE      256   // Draws are organized by texture changes
 #define TEMP_VERTEX_BUFFER_SIZE  4096   // Temporal Vertex Buffer (required for vertex-transformations)
                                         // NOTE: Every vertex are 3 floats (12 bytes)
+                                        
+#define MAX_LIGHTS                  8   // Max lights supported by standard shader
 
 #ifndef GL_SHADING_LANGUAGE_VERSION
     #define GL_SHADING_LANGUAGE_VERSION         0x8B8C
@@ -199,6 +201,10 @@ static bool texCompETC1Supported = false;    // ETC1 texture compression support
 static bool texCompETC2Supported = false;    // ETC2/EAC texture compression support
 static bool texCompPVRTSupported = false;    // PVR texture compression support
 static bool texCompASTCSupported = false;    // ASTC texture compression support
+
+// Lighting data
+static Light lights[MAX_LIGHTS];              // Lights pool
+static int lightsCount;                       // Counts current enabled physic objects
 #endif
 
 // Compressed textures support flags
@@ -227,6 +233,7 @@ static void LoadCompressedTexture(unsigned char *data, int width, int height, in
 static unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr);  // Load custom shader strings and return program id
 
 static Shader LoadDefaultShader(void);      // Load default shader (just vertex positioning and texture coloring)
+static Shader LoadStandardShader(void);     // Load standard shader (support materials and lighting)
 static void LoadDefaultShaderLocations(Shader *shader); // Bind default shader locations (attributes and uniforms)
 static void UnloadDefaultShader(void);      // Unload default shader
 
@@ -235,6 +242,8 @@ static void UpdateDefaultBuffers(void);     // Update default internal buffers (
 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 void SetShaderLights(Shader shader); // Sets shader uniform values for lights array
+
 static char *ReadTextFile(const char *fileName);
 #endif
 
@@ -1749,11 +1758,19 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
     // Send combined model-view-projection matrix to shader
     glUniformMatrix4fv(material.shader.mvpLoc, 1, false, MatrixToFloat(matMVP));
 
-    // Apply color tinting (material.colDiffuse)
-    // NOTE: Just update one uniform on fragment shader
-    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);
-
+    // Setup shader uniforms for material related data
+    // TODO: Check if using standard shader to get location points
+    
+    // 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);
+    
+    // TODO: Upload to shader material.colAmbient
+    // glUniform4f(???, (float)material.colAmbient.r/255, (float)material.colAmbient.g/255, (float)material.colAmbient.b/255, (float)material.colAmbient.a/255);
+    
+    // TODO: Upload to shader material.colSpecular
+    // glUniform4f(???, (float)material.colSpecular.r/255, (float)material.colSpecular.g/255, (float)material.colSpecular.b/255, (float)material.colSpecular.a/255);
+    
     // Set shader textures (diffuse, normal, specular)
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, material.texDiffuse.id);
@@ -1764,6 +1781,9 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
         glActiveTexture(GL_TEXTURE1);
         glBindTexture(GL_TEXTURE_2D, material.texNormal.id);
         glUniform1i(material.shader.mapNormalLoc, 1);     // Texture fits in active texture unit 1
+        
+        // TODO: Upload to shader normalDepth
+        //glUniform1f(???, material.normalDepth);
     }
     
     if ((material.texSpecular.id != 0) && (material.shader.mapSpecularLoc != -1))
@@ -1771,7 +1791,13 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
         glActiveTexture(GL_TEXTURE2);
         glBindTexture(GL_TEXTURE_2D, material.texSpecular.id);
         glUniform1i(material.shader.mapSpecularLoc, 2);   // Texture fits in active texture unit 2
+        
+        // TODO: Upload to shader glossiness
+        //glUniform1f(???, material.glossiness);
     }
+    
+    // Setup shader uniforms for lights
+    SetShaderLights(material.shader);
 
     if (vaoSupported)
     {
@@ -2198,6 +2224,55 @@ void SetBlendMode(int mode)
     }
 }
 
+// Create a new light, initialize it and add to pool
+// TODO: Review creation parameters (only generic ones)
+Light CreateLight(int type, Vector3 position, Color diffuse)
+{
+    // Allocate dynamic memory
+    Light light = (Light)malloc(sizeof(LightData));
+    
+    // Initialize light values with generic values
+    light->id = lightsCount;
+    light->type = type;
+    light->enabled = true;
+    
+    light->position = position;
+    light->direction = (Vector3){ 0.0f, 0.0f, 0.0f };
+    light->intensity = 1.0f;
+    light->diffuse = diffuse;
+    light->specular = WHITE;
+    
+    // Add new light to the array
+    lights[lightsCount] = light;
+    
+    // Increase enabled lights count
+    lightsCount++;
+    
+    return light;
+}
+
+// Destroy a light and take it out of the list
+void DestroyLight(Light light)
+{
+    // Free dynamic memory allocation
+    free(lights[light->id]);
+    
+    // Remove *obj from the pointers array
+    for (int i = light->id; i < lightsCount; i++)
+    {
+        // Resort all the following pointers of the array
+        if ((i + 1) < lightsCount)
+        {
+            lights[i] = lights[i + 1];
+            lights[i]->id = lights[i + 1]->id;
+        }
+        else free(lights[i]);
+    }
+    
+    // Decrease enabled physic objects count
+    lightsCount--;
+}
+
 //----------------------------------------------------------------------------------
 // Module specific Functions Definition
 //----------------------------------------------------------------------------------
@@ -2415,6 +2490,32 @@ static Shader LoadDefaultShader(void)
     return shader;
 }
 
+// Load standard shader
+// NOTE: This shader supports: 
+//      - Up to 3 different maps: diffuse, normal, specular
+//      - Material properties: colDiffuse, colAmbient, colSpecular, glossiness, normalDepth
+//      - Up to 8 lights: Point, Directional or Spot
+static Shader LoadStandardShader(void)
+{
+    Shader shader;
+    
+    char *vShaderStr;
+    char *fShaderStr;
+    
+    // TODO: Implement standard uber-shader, supporting all features (GLSL 100 / GLSL 330)
+    
+    // NOTE: Shader could be quite extensive so it could be implemented in external files (standard.vs/standard.fs)
+    
+    shader.id = LoadShaderProgram(vShaderStr, fShaderStr);
+
+    if (shader.id != 0) TraceLog(INFO, "[SHDR ID %i] Standard shader loaded successfully", shader.id);
+    else TraceLog(WARNING, "[SHDR ID %i] Standard shader could not be loaded", shader.id);
+
+    if (shader.id != 0) LoadDefaultShaderLocations(&shader);    // TODO: Review locations fetching
+
+    return shader;
+}
+
 // Get location handlers to for shader attributes and uniforms
 // NOTE: If any location is not found, loc point becomes -1
 static void LoadDefaultShaderLocations(Shader *shader)
@@ -2900,6 +3001,62 @@ static void UnloadDefaultBuffers(void)
     free(quads.indices);
 }
 
+// Sets shader uniform values for lights array
+// NOTE: It would be far easier with shader UBOs but are not supported on OpenGL ES 2.0f
+// TODO: Review memcpy() and parameters pass
+static void SetShaderLights(Shader shader)
+{
+    /*
+    // NOTE: Standard Shader must include the following data:
+        
+    // Shader Light struct
+    struct Light {
+        vec3 position;
+        vec3 direction;
+        
+        vec3 diffuse;
+        float intensity;
+    }
+
+    const int maxLights = 8;
+    uniform int lightsCount;            // Number of lights
+    uniform Light lights[maxLights];
+    */
+    
+    int locPoint;
+    char locName[32] = "lights[x].position\0";
+    
+    glUseProgram(shader.id);
+
+    locPoint = glGetUniformLocation(shader.id, "lightsCount");
+    glUniform1i(locPoint, lightsCount);
+
+    for (int i = 0; i < lightsCount; i++)
+    {
+        locName[7] = '0' + i;
+        
+        memcpy(&locName[10], "position\0", strlen("position\0"));
+        locPoint = glGetUniformLocation(shader.id, locName);
+        glUniform3f(locPoint, lights[i]->position.x, lights[i]->position.y, lights[i]->position.z);
+        
+        memcpy(&locName[10], "direction\0", strlen("direction\0"));
+        locPoint = glGetUniformLocation(shader.id, locName);       
+        glUniform3f(locPoint, lights[i]->direction.x, lights[i]->direction.y, lights[i]->direction.z);
+
+        memcpy(&locName[10], "diffuse\0", strlen("diffuse\0"));
+        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);
+        
+        // TODO: Pass to the shader any other required data from LightData struct
+    }
+    
+    glUseProgram(0);
+}
+
 // Read text data from file
 // NOTE: text chars array should be freed manually
 static char *ReadTextFile(const char *fileName)

+ 25 - 0
src/rlgl.h

@@ -209,6 +209,28 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion;
         float glossiness;
         float normalDepth;
     } Material;
+    
+    // Light type
+    // TODO: Review contained data to support different light types and features
+    typedef struct LightData {
+        int id;
+        int type;           // LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT
+        bool enabled;
+        
+        Vector3 position;
+        Vector3 direction;  // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction)
+        float attenuation;  // Lost of light intensity with distance (use radius?)
+        
+        Color diffuse;      // Use Vector3 diffuse (including intensities)?
+        float intensity;
+        
+        Color specular;
+        //float specFactor;   // Specular intensity ?
+
+        //Color ambient;    // Required?
+        
+        float coneAngle;         // SpotLight
+    } LightData, *Light;
 	
     // Color blending modes (pre-defined)
     typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode;
@@ -311,6 +333,9 @@ void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size);  // S
 void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat);       // Set shader uniform value (matrix 4x4)
 
 void SetBlendMode(int mode);                                        // Set blending mode (alpha, additive, multiplied)
+
+Light CreateLight(int type, Vector3 position, Color diffuse);       // Create a new light, initialize it and add to pool
+void DestroyLight(Light light);                                     // Destroy a light and take it out of the list
 #endif
 
 #ifdef __cplusplus