Browse Source

Merge remote-tracking branch 'refs/remotes/raysan5/develop' into develop

Joshua Reisenauer 9 years ago
parent
commit
f232f34981
56 changed files with 1646 additions and 1161 deletions
  1. 1 0
      .gitignore
  2. 2 1
      examples/core_input_gamepad.c
  3. 9 8
      examples/physics_basic_rigidbody.c
  4. 7 7
      examples/physics_forces.c
  5. 1 1
      examples/resources/shaders/glsl100/bloom.fs
  6. 1 1
      examples/resources/shaders/glsl100/swirl.fs
  7. 1 1
      examples/resources/shaders/glsl330/bloom.fs
  8. 0 82
      examples/resources/shaders/glsl330/phong.fs
  9. 0 29
      examples/resources/shaders/glsl330/phong.vs
  10. 1 1
      examples/resources/shaders/glsl330/swirl.fs
  11. 136 0
      examples/resources/shaders/standard.fs
  12. 23 0
      examples/resources/shaders/standard.vs
  13. 0 171
      examples/shaders_basic_lighting.c
  14. 118 0
      examples/shaders_standard_lighting.c
  15. 10 4
      shaders/glsl100/base.vs
  16. 10 15
      shaders/glsl100/bloom.fs
  17. 5 0
      shaders/glsl100/blur.fs
  18. 4 1
      shaders/glsl100/cross_hatching.fs
  19. 4 1
      shaders/glsl100/cross_stitching.fs
  20. 3 0
      shaders/glsl100/dream_vision.fs
  21. 4 1
      shaders/glsl100/fisheye.fs
  22. 9 4
      shaders/glsl100/grayscale.fs
  23. 3 0
      shaders/glsl100/pixel.fs
  24. 3 0
      shaders/glsl100/posterization.fs
  25. 3 0
      shaders/glsl100/predator.fs
  26. 4 1
      shaders/glsl100/scanlines.fs
  27. 10 6
      shaders/glsl100/swirl.fs
  28. 4 0
      shaders/glsl100/template.fs
  29. 10 2
      shaders/glsl330/base.vs
  30. 15 19
      shaders/glsl330/bloom.fs
  31. 12 7
      shaders/glsl330/blur.fs
  32. 11 7
      shaders/glsl330/cross_hatching.fs
  33. 8 4
      shaders/glsl330/cross_stitching.fs
  34. 27 0
      shaders/glsl330/depth.fs
  35. 12 6
      shaders/glsl330/grayscale.fs
  36. 48 39
      shaders/glsl330/phong.fs
  37. 8 6
      shaders/glsl330/phong.vs
  38. 8 4
      shaders/glsl330/pixel.fs
  39. 14 9
      shaders/glsl330/posterization.fs
  40. 10 5
      shaders/glsl330/predator.fs
  41. 10 5
      shaders/glsl330/scanlines.fs
  42. 11 6
      shaders/glsl330/swirl.fs
  43. 8 3
      shaders/glsl330/template.fs
  44. 349 343
      src/audio.c
  45. 19 20
      src/audio.h
  46. 5 5
      src/easings.h
  47. 67 72
      src/models.c
  48. 6 6
      src/physac.c
  49. 6 6
      src/physac.h
  50. 55 31
      src/raylib.h
  51. 514 189
      src/rlgl.c
  52. 35 11
      src/rlgl.h
  53. 0 1
      src/shapes.c
  54. 2 0
      src/windows_compile.bat
  55. 0 10
      src_android/local.properties
  56. 0 10
      templates/android_project/local.properties

+ 1 - 0
.gitignore

@@ -6,6 +6,7 @@ src_android/obj/
 templates/android_project/bin/
 templates/android_project/bin/
 templates/android_project/obj/
 templates/android_project/obj/
 templates/android_project/libs/
 templates/android_project/libs/
+local.properties
 
 
 # Ignore thumbnails created by windows
 # Ignore thumbnails created by windows
 Thumbs.db
 Thumbs.db

+ 2 - 1
examples/core_input_gamepad.c

@@ -36,7 +36,8 @@ int main()
         //----------------------------------------------------------------------------------
         //----------------------------------------------------------------------------------
         if (IsGamepadAvailable(GAMEPAD_PLAYER1))
         if (IsGamepadAvailable(GAMEPAD_PLAYER1))
         {
         {
-            gamepadMovement = GetGamepadMovement(GAMEPAD_PLAYER1);
+            gamepadMovement.x = GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_XBOX_AXIS_LEFT_X);
+            gamepadMovement.y = GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_XBOX_AXIS_LEFT_Y);
 
 
             ballPosition.x += gamepadMovement.x;
             ballPosition.x += gamepadMovement.x;
             ballPosition.y -= gamepadMovement.y;
             ballPosition.y -= gamepadMovement.y;

+ 9 - 8
examples/physics_basic_rigidbody.c

@@ -30,26 +30,26 @@ int main()
     bool isDebug = false;
     bool isDebug = false;
     
     
     // Create rectangle physic object
     // Create rectangle physic object
-    PhysicObject *rectangle = CreatePhysicObject((Vector2){ screenWidth*0.25f, screenHeight/2 }, 0.0f, (Vector2){ 75, 50 });
+    PhysicObject rectangle = CreatePhysicObject((Vector2){ screenWidth*0.25f, screenHeight/2 }, 0.0f, (Vector2){ 75, 50 });
     rectangle->rigidbody.enabled = true;       // Enable physic object rigidbody behaviour
     rectangle->rigidbody.enabled = true;       // Enable physic object rigidbody behaviour
     rectangle->rigidbody.applyGravity = true;
     rectangle->rigidbody.applyGravity = true;
     rectangle->rigidbody.friction = 0.1f;
     rectangle->rigidbody.friction = 0.1f;
     rectangle->rigidbody.bounciness = 6.0f;
     rectangle->rigidbody.bounciness = 6.0f;
     
     
     // Create square physic object
     // Create square physic object
-    PhysicObject *square = CreatePhysicObject((Vector2){ screenWidth*0.75f, screenHeight/2 }, 0.0f, (Vector2){ 50, 50 });
+    PhysicObject square = CreatePhysicObject((Vector2){ screenWidth*0.75f, screenHeight/2 }, 0.0f, (Vector2){ 50, 50 });
     square->rigidbody.enabled = true;      // Enable physic object rigidbody behaviour
     square->rigidbody.enabled = true;      // Enable physic object rigidbody behaviour
     square->rigidbody.applyGravity = true;
     square->rigidbody.applyGravity = true;
     square->rigidbody.friction = 0.1f;
     square->rigidbody.friction = 0.1f;
     
     
     // Create walls physic objects
     // Create walls physic objects
-    PhysicObject *floor = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.95f }, 0.0f, (Vector2){ screenWidth*0.9f, 100 });
-    PhysicObject *leftWall = CreatePhysicObject((Vector2){ 0.0f, screenHeight/2 }, 0.0f, (Vector2){ screenWidth*0.1f, screenHeight });
-    PhysicObject *rightWall = CreatePhysicObject((Vector2){ screenWidth, screenHeight/2 }, 0.0f, (Vector2){ screenWidth*0.1f, screenHeight });
-    PhysicObject *roof = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.05f }, 0.0f, (Vector2){ screenWidth*0.9f, 100 });
+    PhysicObject floor = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.95f }, 0.0f, (Vector2){ screenWidth*0.9f, 100 });
+    PhysicObject leftWall = CreatePhysicObject((Vector2){ 0.0f, screenHeight/2 }, 0.0f, (Vector2){ screenWidth*0.1f, screenHeight });
+    PhysicObject rightWall = CreatePhysicObject((Vector2){ screenWidth, screenHeight/2 }, 0.0f, (Vector2){ screenWidth*0.1f, screenHeight });
+    PhysicObject roof = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.05f }, 0.0f, (Vector2){ screenWidth*0.9f, 100 });
     
     
     // Create pplatform physic object
     // Create pplatform physic object
-    PhysicObject *platform = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.7f }, 0.0f, (Vector2){ screenWidth*0.25f, 20 });
+    PhysicObject platform = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.7f }, 0.0f, (Vector2){ screenWidth*0.25f, 20 });
     
     
     //--------------------------------------------------------------------------------------
     //--------------------------------------------------------------------------------------
 
 
@@ -114,7 +114,8 @@ int main()
 
 
     // De-Initialization
     // De-Initialization
     //--------------------------------------------------------------------------------------
     //--------------------------------------------------------------------------------------
-    ClosePhysics();       // Unitialize physics module
+    ClosePhysics();       // Unitialize physics (including all loaded objects)
+    
     CloseWindow();        // Close window and OpenGL context
     CloseWindow();        // Close window and OpenGL context
     //--------------------------------------------------------------------------------------
     //--------------------------------------------------------------------------------------
 
 

+ 7 - 7
examples/physics_forces.c

@@ -17,7 +17,7 @@
 #define LINE_LENGTH         75
 #define LINE_LENGTH         75
 #define TRIANGLE_LENGTH     12
 #define TRIANGLE_LENGTH     12
 
 
-void DrawRigidbodyCircle(PhysicObject *obj, Color color);
+void DrawRigidbodyCircle(PhysicObject obj, Color color);
 
 
 int main()
 int main()
 {
 {
@@ -36,7 +36,7 @@ int main()
     bool isDebug = false;
     bool isDebug = false;
     
     
     // Create rectangle physic objects
     // Create rectangle physic objects
-    PhysicObject *rectangles[3];
+    PhysicObject rectangles[3];
     for (int i = 0; i < 3; i++)
     for (int i = 0; i < 3; i++)
     {
     {
         rectangles[i] = CreatePhysicObject((Vector2){ screenWidth/4*(i+1), (((i % 2) == 0) ? (screenHeight/3) : (screenHeight/1.5f)) }, 0.0f, (Vector2){ 50, 50 });
         rectangles[i] = CreatePhysicObject((Vector2){ screenWidth/4*(i+1), (((i % 2) == 0) ? (screenHeight/3) : (screenHeight/1.5f)) }, 0.0f, (Vector2){ 50, 50 });
@@ -46,7 +46,7 @@ int main()
     
     
     // Create circles physic objects
     // Create circles physic objects
     // NOTE: when creating circle physic objects, transform.scale must be { 0, 0 } and object radius must be defined in collider.radius and use this value to draw the circle.
     // NOTE: when creating circle physic objects, transform.scale must be { 0, 0 } and object radius must be defined in collider.radius and use this value to draw the circle.
-    PhysicObject *circles[3];
+    PhysicObject circles[3];
     for (int i = 0; i < 3; i++)
     for (int i = 0; i < 3; i++)
     {
     {
         circles[i] = CreatePhysicObject((Vector2){ screenWidth/4*(i+1), (((i % 2) == 0) ? (screenHeight/1.5f) : (screenHeight/4)) }, 0.0f, (Vector2){ 0, 0 });
         circles[i] = CreatePhysicObject((Vector2){ screenWidth/4*(i+1), (((i % 2) == 0) ? (screenHeight/1.5f) : (screenHeight/4)) }, 0.0f, (Vector2){ 0, 0 });
@@ -57,10 +57,10 @@ int main()
     }
     }
     
     
     // Create walls physic objects
     // Create walls physic objects
-    PhysicObject *leftWall = CreatePhysicObject((Vector2){ -25, screenHeight/2 }, 0.0f, (Vector2){ 50, screenHeight });
-    PhysicObject *rightWall = CreatePhysicObject((Vector2){ screenWidth + 25, screenHeight/2 }, 0.0f, (Vector2){ 50, screenHeight });
-    PhysicObject *topWall = CreatePhysicObject((Vector2){ screenWidth/2, -25 }, 0.0f, (Vector2){ screenWidth, 50 });
-    PhysicObject *bottomWall = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight + 25 }, 0.0f, (Vector2){ screenWidth, 50 });
+    PhysicObject leftWall = CreatePhysicObject((Vector2){ -25, screenHeight/2 }, 0.0f, (Vector2){ 50, screenHeight });
+    PhysicObject rightWall = CreatePhysicObject((Vector2){ screenWidth + 25, screenHeight/2 }, 0.0f, (Vector2){ 50, screenHeight });
+    PhysicObject topWall = CreatePhysicObject((Vector2){ screenWidth/2, -25 }, 0.0f, (Vector2){ screenWidth, 50 });
+    PhysicObject bottomWall = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight + 25 }, 0.0f, (Vector2){ screenWidth, 50 });
     
     
     //--------------------------------------------------------------------------------------
     //--------------------------------------------------------------------------------------
 
 

+ 1 - 1
examples/resources/shaders/glsl100/bloom.fs

@@ -33,5 +33,5 @@ void main()
     else if (texelColor.r < 0.5) tc = sum*sum*0.009 + texelColor;
     else if (texelColor.r < 0.5) tc = sum*sum*0.009 + texelColor;
     else tc = sum*sum*0.0075 + texelColor;
     else tc = sum*sum*0.0075 + texelColor;
     
     
-    finalColor = tc;
+    gl_FragColor = tc;
 }
 }

+ 1 - 1
examples/resources/shaders/glsl100/swirl.fs

@@ -20,7 +20,7 @@ float angle = 0.8;
 
 
 uniform vec2 center = vec2(200.0, 200.0);
 uniform vec2 center = vec2(200.0, 200.0);
 
 
-void main (void)
+void main()
 {
 {
     vec2 texSize = vec2(renderWidth, renderHeight);
     vec2 texSize = vec2(renderWidth, renderHeight);
     vec2 tc = fragTexCoord*texSize;
     vec2 tc = fragTexCoord*texSize;

+ 1 - 1
examples/resources/shaders/glsl330/bloom.fs

@@ -17,7 +17,7 @@ void main()
 {
 {
     vec4 sum = vec4(0);
     vec4 sum = vec4(0);
     vec4 tc = vec4(0);
     vec4 tc = vec4(0);
-    
+
     for (int i = -4; i < 4; i++)
     for (int i = -4; i < 4; i++)
     {
     {
         for (int j = -3; j < 3; j++)
         for (int j = -3; j < 3; j++)

+ 0 - 82
examples/resources/shaders/glsl330/phong.fs

@@ -1,82 +0,0 @@
-#version 330
-
-// Input vertex attributes (from vertex shader)
-in vec2 fragTexCoord;
-in vec3 fragNormal;
-
-// Input uniform values
-uniform sampler2D texture0;
-uniform vec4 fragTintColor;
-
-// Output fragment color
-out vec4 finalColor;
-
-// NOTE: Add here your custom variables
-
-// Light uniform values
-uniform vec3 lightAmbientColor = vec3(0.6, 0.3, 0.0);
-uniform vec3 lightDiffuseColor = vec3(1.0, 0.5, 0.0);
-uniform vec3 lightSpecularColor = vec3(0.0, 1.0, 0.0);
-uniform float lightIntensity = 1.0;
-uniform float lightSpecIntensity = 1.0;
-
-// Material uniform values
-uniform vec3 matAmbientColor = vec3(1.0, 1.0, 1.0);
-uniform vec3 matSpecularColor = vec3(1.0, 1.0, 1.0);
-uniform float matGlossiness = 50.0;
-
-// World uniform values
-uniform vec3 lightPosition;
-uniform vec3 cameraPosition;
-
-// Calculate ambient lighting component
-vec3 AmbientLighting()
-{
-    return (matAmbientColor*lightAmbientColor);
-}
-
-// Calculate diffuse lighting component
-vec3 DiffuseLighting(in vec3 N, in vec3 L)
-{
-    // Lambertian reflection calculation
-    float diffuse = clamp(dot(N, L), 0, 1);
-
-    return (fragTintColor.xyz*lightDiffuseColor*lightIntensity*diffuse);
-}
-
-// Calculate specular lighting component
-vec3 SpecularLighting(in vec3 N, in vec3 L, in vec3 V)
-{
-    float specular = 0.0;
-
-    // Calculate specular reflection only if the surface is oriented to the light source
-    if (dot(N, L) > 0)
-    {
-        // Calculate half vector
-        vec3 H = normalize(L + V);
-
-        // Calculate specular intensity
-        specular = pow(dot(N, H), 3 + matGlossiness);
-    }
-   
-    return (matSpecularColor*lightSpecularColor*lightSpecIntensity*specular);
-}
-
-void main()
-{
-    // Normalize input vectors
-    vec3 L = normalize(lightPosition);
-    vec3 V = normalize(cameraPosition);
-    vec3 N = normalize(fragNormal);
-    
-    // Calculate lighting components 
-    vec3 ambient = AmbientLighting();
-    vec3 diffuse = DiffuseLighting(N, L);
-    vec3 specular = SpecularLighting(N, L, V);
-    
-    // Texel color fetching from texture sampler
-    vec4 texelColor = texture(texture0, fragTexCoord);
-
-    // Calculate final fragment color
-    finalColor = vec4(texelColor.rgb*(ambient + diffuse + specular), texelColor.a);
-}

+ 0 - 29
examples/resources/shaders/glsl330/phong.vs

@@ -1,29 +0,0 @@
-#version 330
-
-// Input vertex attributes
-in vec3 vertexPosition;
-in vec2 vertexTexCoord;
-in vec3 vertexNormal;
-
-// Input uniform values
-uniform mat4 mvpMatrix;
-
-// Output vertex attributes (to fragment shader)
-out vec2 fragTexCoord;
-out vec3 fragNormal;
-
-// NOTE: Add here your custom variables
-uniform mat4 modelMatrix;
-
-void main()
-{
-    // Send vertex attributes to fragment shader
-    fragTexCoord = vertexTexCoord;
-
-    // Calculate view vector normal from model
-    mat3 normalMatrix = transpose(inverse(mat3(modelMatrix)));
-    fragNormal = normalize(normalMatrix*vertexNormal);
-    
-    // Calculate final vertex position
-    gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);
-}

+ 1 - 1
examples/resources/shaders/glsl330/swirl.fs

@@ -21,7 +21,7 @@ float angle = 0.8;
 
 
 uniform vec2 center = vec2(200.0, 200.0);
 uniform vec2 center = vec2(200.0, 200.0);
 
 
-void main (void)
+void main()
 {
 {
     vec2 texSize = vec2(renderWidth, renderHeight);
     vec2 texSize = vec2(renderWidth, renderHeight);
     vec2 tc = fragTexCoord*texSize;
     vec2 tc = fragTexCoord*texSize;

+ 136 - 0
examples/resources/shaders/standard.fs

@@ -0,0 +1,136 @@
+#version 330
+
+in vec3 fragPosition;
+in vec2 fragTexCoord;
+in vec4 fragColor;
+in vec3 fragNormal;
+
+out vec4 finalColor;
+
+uniform sampler2D texture0;
+
+uniform vec4 colAmbient;
+uniform vec4 colDiffuse;
+uniform vec4 colSpecular;
+uniform float glossiness;
+
+uniform mat4 modelMatrix;
+uniform vec3 viewDir;
+
+struct Light {
+    int enabled;
+    int type;
+    vec3 position;
+    vec3 direction;
+    vec4 diffuse;
+    float intensity;
+    float attenuation;
+    float coneAngle;
+};
+
+const int maxLights = 8;
+uniform int lightsCount;
+uniform Light lights[maxLights];
+
+vec3 CalcPointLight(Light l, vec3 n, vec3 v)
+{
+    vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1));
+    vec3 surfaceToLight = l.position - surfacePos;
+    
+    // Diffuse shading
+    float brightness = clamp(dot(n, surfaceToLight)/(length(surfaceToLight)*length(n)), 0, 1);
+    float diff = 1.0/dot(surfaceToLight/l.attenuation, surfaceToLight/l.attenuation)*brightness*l.intensity;
+    
+    // Specular shading
+    float spec = 0.0;
+    if (diff > 0.0)
+    {
+        vec3 h = normalize(-l.direction + v);
+        spec = pow(dot(n, h), 3 + glossiness);
+    }
+    
+    return (diff*l.diffuse.rgb*colDiffuse.rgb + spec*colSpecular.rgb);
+}
+
+vec3 CalcDirectionalLight(Light l, vec3 n, vec3 v)
+{
+    vec3 lightDir = normalize(-l.direction);
+    
+    // Diffuse shading
+    float diff = clamp(dot(n, lightDir), 0.0, 1.0)*l.intensity;
+    
+    // Specular shading
+    float spec = 0.0;
+    if (diff > 0.0)
+    {
+        vec3 h = normalize(lightDir + v);
+        spec = pow(dot(n, h), 3 + glossiness);
+    }
+    
+    // Combine results
+    return (diff*l.intensity*l.diffuse.rgb*colDiffuse.rgb + spec*colSpecular.rgb);
+}
+
+vec3 CalcSpotLight(Light l, vec3 n, vec3 v)
+{
+    vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1));
+    vec3 lightToSurface = normalize(surfacePos - l.position);
+    vec3 lightDir = normalize(-l.direction);
+    
+    // Diffuse shading
+    float diff = clamp(dot(n, lightDir), 0.0, 1.0)*l.intensity;
+    
+    // Spot attenuation
+    float attenuation = clamp(dot(n, lightToSurface), 0.0, 1.0);
+    attenuation = dot(lightToSurface, -lightDir);
+    float lightToSurfaceAngle = degrees(acos(attenuation));
+    if (lightToSurfaceAngle > l.coneAngle) attenuation = 0.0;
+    float falloff = (l.coneAngle - lightToSurfaceAngle)/l.coneAngle;
+    
+    // Combine diffuse and attenuation
+    float diffAttenuation = diff*attenuation;
+    
+    // Specular shading
+    float spec = 0.0;
+    if (diffAttenuation > 0.0)
+    {
+        vec3 h = normalize(lightDir + v);
+        spec = pow(dot(n, h), 3 + glossiness);
+    }
+    
+    return falloff*(diffAttenuation*l.diffuse.rgb + spec*colSpecular.rgb);
+}
+
+void main()
+{
+    // Calculate fragment normal in screen space
+    mat3 normalMatrix = transpose(inverse(mat3(modelMatrix)));
+    vec3 normal = normalize(normalMatrix*fragNormal);
+   
+    // Normalize normal and view direction vectors
+    vec3 n = normalize(normal);
+    vec3 v = normalize(viewDir);
+
+    // Calculate diffuse texture color fetching
+    vec4 texelColor = texture(texture0, fragTexCoord);
+    vec3 lighting = colAmbient.rgb;
+    
+    for (int i = 0; i < lightsCount; i++)
+    {
+        // Check if light is enabled
+        if (lights[i].enabled == 1)
+        {
+            // Calculate lighting based on light type
+            switch (lights[i].type)
+            {
+                case 0: lighting += CalcPointLight(lights[i], n, v); break;
+                case 1: lighting += CalcDirectionalLight(lights[i], n, v); break;
+                case 2: lighting += CalcSpotLight(lights[i], n, v); break;
+                default: break;
+            }
+        }
+    }
+    
+    // Calculate final fragment color
+    finalColor = vec4(texelColor.rgb*lighting, texelColor.a);
+}

+ 23 - 0
examples/resources/shaders/standard.vs

@@ -0,0 +1,23 @@
+#version 330 
+
+in vec3 vertexPosition;
+in vec3 vertexNormal;
+in vec2 vertexTexCoord;
+in vec4 vertexColor;
+
+out vec3 fragPosition;
+out vec2 fragTexCoord;
+out vec4 fragColor;
+out vec3 fragNormal;
+
+uniform mat4 mvpMatrix;
+
+void main()
+{
+    fragPosition = vertexPosition;
+    fragTexCoord = vertexTexCoord;
+    fragColor = vertexColor;
+    fragNormal = vertexNormal;
+
+    gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);
+}

+ 0 - 171
examples/shaders_basic_lighting.c

@@ -1,171 +0,0 @@
-/*******************************************************************************************
-*
-*   raylib [shaders] example - Basic lighting: Blinn-Phong
-*
-*   This example has been created using raylib 1.3 (www.raylib.com)
-*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
-*
-*   Copyright (c) 2014 Ramon Santamaria (@raysan5)
-*
-********************************************************************************************/
-
-#include "raylib.h"
-
-#define SHININESS_SPEED 1.0f
-#define LIGHT_SPEED 0.25f
-
-// Light type
-typedef struct Light {
-    Vector3 position;
-    Vector3 direction;
-    float intensity;
-    float specIntensity;
-    Color diffuse;
-    Color ambient;
-    Color specular;
-} Light;
-
-int main()
-{
-    // Initialization
-    //--------------------------------------------------------------------------------------
-    const int screenWidth = 800;
-    const int screenHeight = 450;
-    
-    SetConfigFlags(FLAG_MSAA_4X_HINT);
-    InitWindow(screenWidth, screenHeight, "raylib [shaders] example - basic lighting");
-    
-    // Camera initialization
-    Camera camera = {{ 8.0f, 8.0f, 8.0f }, { 0.0f, 3.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f };
-    
-    // Model initialization
-    Vector3 position = { 0.0f, 0.0f, 0.0f };
-    Model model = LoadModel("resources/model/dwarf.obj");
-    Shader shader = LoadShader("resources/shaders/glsl330/phong.vs", "resources/shaders/glsl330/phong.fs");
-    SetModelShader(&model, shader);
-    
-    // Shader locations initialization
-    int lIntensityLoc = GetShaderLocation(shader, "lightIntensity");
-    int lAmbientLoc = GetShaderLocation(shader, "lightAmbientColor");
-    int lDiffuseLoc = GetShaderLocation(shader, "lightDiffuseColor");
-    int lSpecularLoc = GetShaderLocation(shader, "lightSpecularColor");
-    int lSpecIntensityLoc = GetShaderLocation(shader, "lightSpecIntensity");
-    
-    int mAmbientLoc = GetShaderLocation(shader, "matAmbientColor");
-    int mSpecularLoc = GetShaderLocation(shader, "matSpecularColor");
-    int mGlossLoc = GetShaderLocation(shader, "matGlossiness");
-    
-    // Camera and light vectors shader locations
-    int cameraLoc = GetShaderLocation(shader, "cameraPosition");
-    int lightLoc = GetShaderLocation(shader, "lightPosition");
-    
-    // Model and View matrix locations (required for lighting)
-    int modelLoc = GetShaderLocation(shader, "modelMatrix");
-    //int viewLoc = GetShaderLocation(shader, "viewMatrix");        // Not used
-    
-    // Light and material definitions
-    Light light;
-    Material matBlinn;
-    
-    // Light initialization
-    light.position = (Vector3){ 4.0f, 2.0f, 0.0f };
-    light.direction = (Vector3){ 5.0f, 1.0f, 1.0f };
-    light.intensity = 1.0f;
-    light.diffuse = WHITE;
-    light.ambient = (Color){ 150, 75, 0, 255 };
-    light.specular = WHITE;
-    light.specIntensity = 1.0f;
-    
-    // Material initialization
-    matBlinn.colDiffuse = WHITE;
-    matBlinn.colAmbient = (Color){ 50, 50, 50, 255 };
-    matBlinn.colSpecular = WHITE;
-    matBlinn.glossiness = 50.0f;
-    
-    // Setup camera
-    SetCameraMode(CAMERA_FREE);             // Set camera mode
-    SetCameraPosition(camera.position);     // Set internal camera position to match our camera position
-    SetCameraTarget(camera.target);         // Set internal camera target to match our camera target
-    
-    SetTargetFPS(60);
-    //--------------------------------------------------------------------------------------
-    
-    // Main game loop
-    while (!WindowShouldClose())    // Detect window close button or ESC key
-    {
-        // Update
-        //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);      // Update camera position
-        
-        // NOTE: Model transform can be set in model.transform or directly with params at draw... WATCH OUT!
-        SetShaderValueMatrix(shader, modelLoc, model.transform);            // Send model matrix to shader
-        //SetShaderValueMatrix(shader, viewLoc, GetCameraMatrix(camera));   // Not used
-        
-        // Glossiness input control
-        if(IsKeyDown(KEY_UP)) matBlinn.glossiness += SHININESS_SPEED;
-        else if(IsKeyDown(KEY_DOWN))
-        {
-            matBlinn.glossiness -= SHININESS_SPEED;
-            if( matBlinn.glossiness < 0) matBlinn.glossiness = 0.0f;
-        }
-        
-        // Light X movement
-        if (IsKeyDown(KEY_D)) light.position.x += LIGHT_SPEED;
-        else if(IsKeyDown(KEY_A)) light.position.x -= LIGHT_SPEED;
-        
-        // Light Y movement
-        if (IsKeyDown(KEY_LEFT_SHIFT)) light.position.y += LIGHT_SPEED;
-        else if (IsKeyDown(KEY_LEFT_CONTROL)) light.position.y -= LIGHT_SPEED;
-
-        // Light Z movement
-        if (IsKeyDown(KEY_S)) light.position.z += LIGHT_SPEED;
-        else if (IsKeyDown(KEY_W)) light.position.z -= LIGHT_SPEED;
-        
-        // Send light values to shader
-        SetShaderValue(shader, lIntensityLoc, &light.intensity, 1);
-        SetShaderValue(shader, lAmbientLoc, ColorToFloat(light.ambient), 3);
-        SetShaderValue(shader, lDiffuseLoc, ColorToFloat(light.diffuse), 3);
-        SetShaderValue(shader, lSpecularLoc, ColorToFloat(light.specular), 3);
-        SetShaderValue(shader, lSpecIntensityLoc, &light.specIntensity, 1);
-        
-        // Send material values to shader
-        SetShaderValue(shader, mAmbientLoc, ColorToFloat(matBlinn.colAmbient), 3);
-        SetShaderValue(shader, mSpecularLoc, ColorToFloat(matBlinn.colSpecular), 3);
-        SetShaderValue(shader, mGlossLoc, &matBlinn.glossiness, 1);
-        
-        // Send camera and light transform values to shader
-        SetShaderValue(shader, cameraLoc, VectorToFloat(camera.position), 3);
-        SetShaderValue(shader, lightLoc, VectorToFloat(light.position), 3);
-        //----------------------------------------------------------------------------------
-        
-        // Draw
-        //----------------------------------------------------------------------------------
-        BeginDrawing();
-        
-            ClearBackground(RAYWHITE);
-            
-            Begin3dMode(camera);
-                
-                DrawModel(model, position, 4.0f, matBlinn.colDiffuse);
-                DrawSphere(light.position, 0.5f, GOLD);
-                
-                DrawGrid(20, 1.0f);
-                
-            End3dMode();
-            
-            DrawFPS(10, 10);                // Draw FPS
-            
-        EndDrawing();
-        //----------------------------------------------------------------------------------
-    }
-
-    // De-Initialization
-    //--------------------------------------------------------------------------------------
-    UnloadShader(shader);
-    UnloadModel(model);
-
-    CloseWindow();        // Close window and OpenGL context
-    //--------------------------------------------------------------------------------------
-    
-    return 0;
-}

+ 118 - 0
examples/shaders_standard_lighting.c

@@ -0,0 +1,118 @@
+/*******************************************************************************************
+*
+*   raylib [shaders] example - Standard lighting (materials and lights)
+*
+*   NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
+*         OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version.
+*
+*   NOTE: Shaders used in this example are #version 330 (OpenGL 3.3), to test this example
+*         on OpenGL ES 2.0 platforms (Android, Raspberry Pi, HTML5), use #version 100 shaders
+*         raylib comes with shaders ready for both versions, check raylib/shaders install folder
+*
+*   This example has been created using raylib 1.3 (www.raylib.com)
+*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
+*
+*   Copyright (c) 2016 Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include "raymath.h"
+
+int main()
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    int screenWidth = 800;
+    int screenHeight = 450;
+    
+    SetConfigFlags(FLAG_MSAA_4X_HINT);      // Enable Multi Sampling Anti Aliasing 4x (if available)
+
+    InitWindow(screenWidth, screenHeight, "raylib [shaders] example - model shader");
+
+    // Define the camera to look into our 3d world
+    Camera camera = {{ 4.0f, 4.0f, 4.0f }, { 0.0f, 1.5f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f };
+    Vector3 position = { 0.0f, 0.0f, 0.0f };   // Set model position
+    
+    Model dwarf = LoadModel("resources/model/dwarf.obj");                   // Load OBJ model
+    Texture2D texDiffuse = LoadTexture("resources/model/dwarf_diffuse.png");   // Load model diffuse texture
+
+    Material material = LoadStandardMaterial();
+    material.texDiffuse = texDiffuse;
+    material.colDiffuse = (Color){255, 255, 255, 255};
+    material.colAmbient = (Color){0, 0, 10, 255};
+    material.colSpecular = (Color){255, 255, 255, 255};
+    material.glossiness = 50.0f;
+    dwarf.material = material;      // Apply material to model
+    
+    Light spotLight = CreateLight(LIGHT_SPOT, (Vector3){3.0f, 5.0f, 2.0f}, (Color){255, 255, 255, 255});
+    spotLight->target = (Vector3){0.0f, 0.0f, 0.0f};
+    spotLight->intensity = 2.0f;
+    spotLight->diffuse = (Color){255, 100, 100, 255};
+    spotLight->coneAngle = 60.0f;
+    
+    Light dirLight = CreateLight(LIGHT_DIRECTIONAL, (Vector3){0.0f, -3.0f, -3.0f}, (Color){255, 255, 255, 255});
+    dirLight->target = (Vector3){1.0f, -2.0f, -2.0f};
+    dirLight->intensity = 2.0f;
+    dirLight->diffuse = (Color){100, 255, 100, 255};
+    
+    Light pointLight = CreateLight(LIGHT_POINT, (Vector3){0.0f, 4.0f, 5.0f}, (Color){255, 255, 255, 255});
+    pointLight->intensity = 2.0f;
+    pointLight->diffuse = (Color){100, 100, 255, 255};
+    pointLight->attenuation = 3.0f;
+
+    // Setup orbital camera
+    SetCameraMode(CAMERA_ORBITAL);          // Set a orbital camera mode
+    SetCameraPosition(camera.position);     // Set internal camera position to match our camera position
+    SetCameraTarget(camera.target);         // Set internal camera target to match our camera target
+
+    SetTargetFPS(60);                       // Set our game to run at 60 frames-per-second
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())            // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        UpdateCamera(&camera);              // Update internal camera and our camera
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+
+            Begin3dMode(camera);
+
+                DrawModel(dwarf, position, 2.0f, WHITE);   // Draw 3d model with texture
+                
+                DrawLights();   // Draw all created lights in 3D world
+
+                DrawGrid(10, 1.0f);     // Draw a grid
+
+            End3dMode();
+            
+            DrawText("(c) Dwarf 3D model by David Moreno", screenWidth - 200, screenHeight - 20, 10, GRAY);
+
+            DrawFPS(10, 10);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    UnloadMaterial(material);   // Unload material and assigned textures
+    UnloadModel(dwarf);         // Unload model
+    
+    // Destroy all created lights
+    DestroyLight(pointLight);
+    DestroyLight(dirLight);
+    DestroyLight(spotLight);
+
+    CloseWindow();              // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}

+ 10 - 4
shaders/glsl100/base.vs

@@ -1,20 +1,26 @@
 #version 100
 #version 100
 
 
+// Input vertex attributes
 attribute vec3 vertexPosition;
 attribute vec3 vertexPosition;
 attribute vec2 vertexTexCoord;
 attribute vec2 vertexTexCoord;
 attribute vec3 vertexNormal;
 attribute vec3 vertexNormal;
+attribute vec4 vertexColor;
 
 
-varying vec2 fragTexCoord;
-
+// Input uniform values
 uniform mat4 mvpMatrix;
 uniform mat4 mvpMatrix;
 
 
+// Output vertex attributes (to fragment shader)
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
 // NOTE: Add here your custom variables 
 // NOTE: Add here your custom variables 
 
 
 void main()
 void main()
 {
 {
-    vec3 normal = vertexNormal;
-    
+    // Send vertex attributes to fragment shader
     fragTexCoord = vertexTexCoord;
     fragTexCoord = vertexTexCoord;
+    fragColor = vertexColor;
     
     
+    // Calculate final vertex position
     gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);
     gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);
 }
 }

+ 10 - 15
shaders/glsl100/bloom.fs

@@ -2,8 +2,11 @@
 
 
 precision mediump float;
 precision mediump float;
 
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
@@ -22,21 +25,13 @@ void main()
         }
         }
     }
     }
     
     
-    if (texture2D(texture0, fragTexCoord).r < 0.3)
-    {
-        tc = sum*sum*0.012 + texture2D(texture0, fragTexCoord);
-    }
-    else
-    {
-        if (texture2D(texture0, fragTexCoord).r < 0.5)
-        {
-            tc = sum*sum*0.009 + texture2D(texture0, fragTexCoord);
-        }
-        else
-        {
-            tc = sum*sum*0.0075 + texture2D(texture0, fragTexCoord);
-        }
-    }
+    // Texel color fetching from texture sampler
+    vec4 texelColor = texture(texture0, fragTexCoord);
+    
+    // Calculate final fragment color
+    if (texelColor.r < 0.3) tc = sum*sum*0.012 + texelColor;
+    else if (texelColor.r < 0.5) tc = sum*sum*0.009 + texelColor;
+    else tc = sum*sum*0.0075 + texelColor;
     
     
     gl_FragColor = tc;
     gl_FragColor = tc;
 }
 }

+ 5 - 0
shaders/glsl100/blur.fs

@@ -2,7 +2,11 @@
 
 
 precision mediump float;
 precision mediump float;
 
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
@@ -16,6 +20,7 @@ float weight[3] = float[]( 0.2270270270, 0.3162162162, 0.0702702703 );
 
 
 void main() 
 void main() 
 { 
 { 
+    // Texel color fetching from texture sampler
     vec3 tc = texture2D(texture0, fragTexCoord).rgb*weight[0];
     vec3 tc = texture2D(texture0, fragTexCoord).rgb*weight[0];
 
 
     for (int i = 1; i < 3; i++) 
     for (int i = 1; i < 3; i++) 

+ 4 - 1
shaders/glsl100/cross_hatching.fs

@@ -2,12 +2,15 @@
 
 
 precision mediump float;
 precision mediump float;
 
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
-// NOTE: Add here your custom variables 
+// NOTE: Add here your custom variables
 
 
 float hatchOffsetY = 5.0f;
 float hatchOffsetY = 5.0f;
 float lumThreshold01 = 0.9f;
 float lumThreshold01 = 0.9f;

+ 4 - 1
shaders/glsl100/cross_stitching.fs

@@ -2,8 +2,11 @@
 
 
 precision mediump float;
 precision mediump float;
 
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
@@ -46,7 +49,7 @@ vec4 PostFX(sampler2D tex, vec2 uv)
     return c;
     return c;
 }
 }
 
 
-void main(void)
+void main()
 {
 {
     vec3 tc = PostFX(texture0, fragTexCoord).rgb;
     vec3 tc = PostFX(texture0, fragTexCoord).rgb;
 
 

+ 3 - 0
shaders/glsl100/dream_vision.fs

@@ -2,8 +2,11 @@
 
 
 precision mediump float;
 precision mediump float;
 
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 

+ 4 - 1
shaders/glsl100/fisheye.fs

@@ -2,12 +2,15 @@
 
 
 precision mediump float;
 precision mediump float;
 
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
-// NOTE: Add here your custom variables 
+// NOTE: Add here your custom variables
 
 
 const float PI = 3.1415926535;
 const float PI = 3.1415926535;
 
 

+ 9 - 4
shaders/glsl100/grayscale.fs

@@ -2,8 +2,11 @@
 
 
 precision mediump float;
 precision mediump float;
 
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
@@ -11,10 +14,12 @@ uniform vec4 fragTintColor;
 
 
 void main()
 void main()
 {
 {
-    vec4 base = texture2D(texture0, fragTexCoord)*fragTintColor;
+    // Texel color fetching from texture sampler
+    vec4 texelColor = texture(texture0, fragTexCoord)*fragTintColor*fragColor;
     
     
-    // Convert to grayscale using NTSC conversion weights
-    float gray = dot(base.rgb, vec3(0.299, 0.587, 0.114));
+    // Convert texel color to grayscale using NTSC conversion weights
+    float gray = dot(texelColor.rgb, vec3(0.299, 0.587, 0.114));
     
     
-    gl_FragColor = vec4(gray, gray, gray, fragTintColor.a);
+    // Calculate final fragment color
+    gl_FragColor = vec4(gray, gray, gray, texelColor.a);
 }
 }

+ 3 - 0
shaders/glsl100/pixel.fs

@@ -2,8 +2,11 @@
 
 
 precision mediump float;
 precision mediump float;
 
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 

+ 3 - 0
shaders/glsl100/posterization.fs

@@ -2,8 +2,11 @@
 
 
 precision mediump float;
 precision mediump float;
 
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 

+ 3 - 0
shaders/glsl100/predator.fs

@@ -2,8 +2,11 @@
 
 
 precision mediump float;
 precision mediump float;
 
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 

+ 4 - 1
shaders/glsl100/scanlines.fs

@@ -2,8 +2,11 @@
 
 
 precision mediump float;
 precision mediump float;
 
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
@@ -14,7 +17,7 @@ float frequency = 720/3.0;
 
 
 uniform float time;
 uniform float time;
 
 
-void main (void)
+void main()
 {
 {
 /*
 /*
     // Scanlines method 1
     // Scanlines method 1

+ 10 - 6
shaders/glsl100/swirl.fs

@@ -2,28 +2,32 @@
 
 
 precision mediump float;
 precision mediump float;
 
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
 // NOTE: Add here your custom variables
 // NOTE: Add here your custom variables
 
 
-const float renderWidth = 1280; 
-const float renderHeight = 720; 
+const float renderWidth = 800.0;      // HARDCODED for example!
+const float renderHeight = 480.0;     // Use uniforms instead...
 
 
 float radius = 250.0;
 float radius = 250.0;
 float angle = 0.8;
 float angle = 0.8;
 
 
-uniform vec2 center = vec2(200, 200);
+uniform vec2 center = vec2(200.0, 200.0);
 
 
-void main (void)
+void main()
 {
 {
     vec2 texSize = vec2(renderWidth, renderHeight);
     vec2 texSize = vec2(renderWidth, renderHeight);
     vec2 tc = fragTexCoord*texSize;
     vec2 tc = fragTexCoord*texSize;
     tc -= center;
     tc -= center;
-    float dist = length(tc);
     
     
+    float dist = length(tc);
+
     if (dist < radius) 
     if (dist < radius) 
     {
     {
         float percent = (radius - dist)/radius;
         float percent = (radius - dist)/radius;
@@ -33,7 +37,7 @@ void main (void)
         
         
         tc = vec2(dot(tc, vec2(c, -s)), dot(tc, vec2(s, c)));
         tc = vec2(dot(tc, vec2(c, -s)), dot(tc, vec2(s, c)));
     }
     }
-    
+
     tc += center;
     tc += center;
     vec3 color = texture2D(texture0, tc/texSize).rgb;
     vec3 color = texture2D(texture0, tc/texSize).rgb;
 
 

+ 4 - 0
shaders/glsl100/template.fs

@@ -2,8 +2,11 @@
 
 
 precision mediump float;
 precision mediump float;
 
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
@@ -11,6 +14,7 @@ uniform vec4 fragTintColor;
 
 
 void main()
 void main()
 {
 {
+    // Texel color fetching from texture sampler
     vec4 texelColor = texture2D(texture0, fragTexCoord);
     vec4 texelColor = texture2D(texture0, fragTexCoord);
     
     
     // NOTE: Implement here your fragment shader code
     // NOTE: Implement here your fragment shader code

+ 10 - 2
shaders/glsl330/base.vs

@@ -1,18 +1,26 @@
 #version 330
 #version 330
 
 
+// Input vertex attributes
 in vec3 vertexPosition;
 in vec3 vertexPosition;
 in vec2 vertexTexCoord;
 in vec2 vertexTexCoord;
 in vec3 vertexNormal;
 in vec3 vertexNormal;
+in vec4 vertexColor;
 
 
-out vec2 fragTexCoord;
-
+// Input uniform values
 uniform mat4 mvpMatrix;
 uniform mat4 mvpMatrix;
 
 
+// Output vertex attributes (to fragment shader)
+out vec2 fragTexCoord;
+out vec4 fragColor;
+
 // NOTE: Add here your custom variables 
 // NOTE: Add here your custom variables 
 
 
 void main()
 void main()
 {
 {
+    // Send vertex attributes to fragment shader
     fragTexCoord = vertexTexCoord;
     fragTexCoord = vertexTexCoord;
+    fragColor = vertexColor;
     
     
+    // Calculate final vertex position
     gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);
     gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);
 }
 }

+ 15 - 19
shaders/glsl330/bloom.fs

@@ -1,12 +1,16 @@
 #version 330
 #version 330
 
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
+// Output fragment color
+out vec4 finalColor;
+
 // NOTE: Add here your custom variables
 // NOTE: Add here your custom variables
 
 
 void main()
 void main()
@@ -18,25 +22,17 @@ void main()
     {
     {
         for (int j = -3; j < 3; j++)
         for (int j = -3; j < 3; j++)
         {
         {
-            sum += texture(texture0, fragTexCoord + vec2(j, i)*0.004) * 0.25;
+            sum += texture(texture0, fragTexCoord + vec2(j, i)*0.004)*0.25;
         }
         }
     }
     }
     
     
-    if (texture(texture0, fragTexCoord).r < 0.3)
-    {
-        tc = sum*sum*0.012 + texture(texture0, fragTexCoord);
-    }
-    else
-    {
-        if (texture(texture0, fragTexCoord).r < 0.5)
-        {
-            tc = sum*sum*0.009 + texture(texture0, fragTexCoord);
-        }
-        else
-        {
-            tc = sum*sum*0.0075 + texture(texture0, fragTexCoord);
-        }
-    }
+    // Texel color fetching from texture sampler
+    vec4 texelColor = texture(texture0, fragTexCoord);
     
     
-    fragColor = tc;
+    // Calculate final fragment color
+    if (texelColor.r < 0.3) tc = sum*sum*0.012 + texelColor;
+    else if (texelColor.r < 0.5) tc = sum*sum*0.009 + texelColor;
+    else tc = sum*sum*0.0075 + texelColor;
+
+    finalColor = tc;
 }
 }

+ 12 - 7
shaders/glsl330/blur.fs

@@ -1,12 +1,16 @@
 #version 330
 #version 330
 
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
+// Output fragment color
+out vec4 finalColor;
+
 // NOTE: Add here your custom variables
 // NOTE: Add here your custom variables
 
 
 const float renderWidth = 1280.0;
 const float renderWidth = 1280.0;
@@ -17,13 +21,14 @@ float weight[3] = float[](0.2270270270, 0.3162162162, 0.0702702703);
 
 
 void main()
 void main()
 {
 {
-    vec3 tc = texture(texture0, fragTexCoord).rgb*weight[0];
-
+    // Texel color fetching from texture sampler
+    vec3 texelColor = texture(texture0, fragTexCoord).rgb*weight[0];
+    
     for (int i = 1; i < 3; i++) 
     for (int i = 1; i < 3; i++) 
     {
     {
-        tc += texture(texture0, fragTexCoord + vec2(offset[i])/renderWidth, 0.0).rgb*weight[i];
-        tc += texture(texture0, fragTexCoord - vec2(offset[i])/renderWidth, 0.0).rgb*weight[i];
+        texelColor += texture(texture0, fragTexCoord + vec2(offset[i])/renderWidth, 0.0).rgb*weight[i];
+        texelColor += texture(texture0, fragTexCoord - vec2(offset[i])/renderWidth, 0.0).rgb*weight[i];
     }
     }
 
 
-    fragColor = vec4(tc, 1.0);
+    finalColor = vec4(texelColor, 1.0);
 }
 }

+ 11 - 7
shaders/glsl330/cross_hatching.fs

@@ -1,13 +1,17 @@
 #version 330
 #version 330
 
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
-// NOTE: Add here your custom variables 
+// Output fragment color
+out vec4 finalColor;
+
+// NOTE: Add here your custom variables
 
 
 float hatchOffsetY = 5.0;
 float hatchOffsetY = 5.0;
 float lumThreshold01 = 0.9;
 float lumThreshold01 = 0.9;
@@ -27,18 +31,18 @@ void main()
 
 
     if (lum < lumThreshold02) 
     if (lum < lumThreshold02) 
     {
     {
-        if (mod(gl_FragCoord .x - gl_FragCoord .y, 10.0) == 0.0) tc = vec3(0.0, 0.0, 0.0);
+        if (mod(gl_FragCoord.x - gl_FragCoord.y, 10.0) == 0.0) tc = vec3(0.0, 0.0, 0.0);
     }
     }
 
 
     if (lum < lumThreshold03) 
     if (lum < lumThreshold03) 
     {
     {
-        if (mod(gl_FragCoord .x + gl_FragCoord .y - hatchOffsetY, 10.0) == 0.0) tc = vec3(0.0, 0.0, 0.0);
+        if (mod(gl_FragCoord.x + gl_FragCoord.y - hatchOffsetY, 10.0) == 0.0) tc = vec3(0.0, 0.0, 0.0);
     }
     }
 
 
     if (lum < lumThreshold04) 
     if (lum < lumThreshold04) 
     {
     {
-        if (mod(gl_FragCoord .x - gl_FragCoord .y - hatchOffsetY, 10.0) == 0.0) tc = vec3(0.0, 0.0, 0.0);
+        if (mod(gl_FragCoord.x - gl_FragCoord.y - hatchOffsetY, 10.0) == 0.0) tc = vec3(0.0, 0.0, 0.0);
     }
     }
 
 
-    fragColor = vec4(tc, 1.0);
+    finalColor = vec4(tc, 1.0);
 }
 }

+ 8 - 4
shaders/glsl330/cross_stitching.fs

@@ -1,12 +1,16 @@
 #version 330
 #version 330
 
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
+// Output fragment color
+out vec4 finalColor;
+
 // NOTE: Add here your custom variables
 // NOTE: Add here your custom variables
 
 
 const float renderWidth = 1280.0;
 const float renderWidth = 1280.0;
@@ -46,9 +50,9 @@ vec4 PostFX(sampler2D tex, vec2 uv)
     return c;
     return c;
 }
 }
 
 
-void main(void)
+void main()
 {
 {
     vec3 tc = PostFX(texture0, fragTexCoord).rgb;
     vec3 tc = PostFX(texture0, fragTexCoord).rgb;
 
 
-    fragColor = vec4(tc, 1.0);
+    finalColor = vec4(tc, 1.0);
 }
 }

+ 27 - 0
shaders/glsl330/depth.fs

@@ -0,0 +1,27 @@
+#version 330
+
+// Input vertex attributes (from vertex shader)
+in vec2 fragTexCoord;
+in vec4 fragColor;
+
+// Input uniform values
+uniform sampler2D texture0;     // Depth texture
+uniform vec4 fragTintColor;
+
+// Output fragment color
+out vec4 finalColor;
+
+// NOTE: Add here your custom variables
+
+void main()
+{
+    float zNear = 0.01; // camera z near
+    float zFar = 10.0;  // camera z far
+    float z = texture(texture0, fragTexCoord).x;
+
+    // Linearize depth value
+    float depth = (2.0*zNear)/(zFar + zNear - z*(zFar - zNear));
+    
+    // Calculate final fragment color
+    finalColor = vec4(depth, depth, depth, 1.0f);
+}

+ 12 - 6
shaders/glsl330/grayscale.fs

@@ -1,20 +1,26 @@
 #version 330
 #version 330
 
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
+// Output fragment color
+out vec4 finalColor;
+
 // NOTE: Add here your custom variables
 // NOTE: Add here your custom variables
 
 
 void main()
 void main()
 {
 {
-    vec4 base = texture(texture0, fragTexCoord)*fragTintColor;
+    // Texel color fetching from texture sampler
+    vec4 texelColor = texture(texture0, fragTexCoord)*fragTintColor*fragColor;
     
     
-    // Convert to grayscale using NTSC conversion weights
-    float gray = dot(base.rgb, vec3(0.299, 0.587, 0.114));
+    // Convert texel color to grayscale using NTSC conversion weights
+    float gray = dot(texelColor.rgb, vec3(0.299, 0.587, 0.114));
     
     
-    fragColor = vec4(gray, gray, gray, fragTintColor.a);
+    // Calculate final fragment color
+    finalColor = vec4(gray, gray, gray, texelColor.a);
 }
 }

+ 48 - 39
shaders/glsl330/phong.fs

@@ -1,76 +1,85 @@
 #version 330
 #version 330
 
 
-// Vertex shader input data
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
 in vec2 fragTexCoord;
 in vec3 fragNormal;
 in vec3 fragNormal;
 
 
-// Diffuse data
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
-// Light attributes
-uniform vec3 light_ambientColor = vec3(0.6, 0.3, 0);
-uniform vec3 light_diffuseColor = vec3(1, 0.5, 0);
-uniform vec3 light_specularColor = vec3(0, 1, 0);
-uniform float light_intensity = 1;
-uniform float light_specIntensity = 1;
+// Output fragment color
+out vec4 finalColor;
 
 
-// Material attributes
-uniform vec3 mat_ambientColor = vec3(1, 1, 1);
-uniform vec3 mat_specularColor = vec3(1, 1, 1);
-uniform float mat_glossiness = 50;
+// NOTE: Add here your custom variables
 
 
-// World attributes
-uniform vec3 lightPos;
-uniform vec3 cameraPos;
+// Light uniform values
+uniform vec3 lightAmbientColor = vec3(0.6, 0.3, 0.0);
+uniform vec3 lightDiffuseColor = vec3(1.0, 0.5, 0.0);
+uniform vec3 lightSpecularColor = vec3(0.0, 1.0, 0.0);
+uniform float lightIntensity = 1.0;
+uniform float lightSpecIntensity = 1.0;
+
+// Material uniform values
+uniform vec3 matAmbientColor = vec3(1.0, 1.0, 1.0);
+uniform vec3 matSpecularColor = vec3(1.0, 1.0, 1.0);
+uniform float matGlossiness = 50.0;
+
+// World uniform values
+uniform vec3 lightPosition;
+uniform vec3 cameraPosition;
 
 
 // Fragment shader output data
 // Fragment shader output data
 out vec4 fragColor;
 out vec4 fragColor;
 
 
+// Calculate ambient lighting component
 vec3 AmbientLighting()
 vec3 AmbientLighting()
 {
 {
-   return mat_ambientColor * light_ambientColor;
+    return (matAmbientColor*lightAmbientColor);
 }
 }
 
 
+// Calculate diffuse lighting component
 vec3 DiffuseLighting(in vec3 N, in vec3 L)
 vec3 DiffuseLighting(in vec3 N, in vec3 L)
 {
 {
-   // Lambertian reflection calculation
-   float diffuse = clamp(dot(N, L), 0, 1);
-   
-   return tintColor.xyz * light_diffuseColor * light_intensity * diffuse;
+    // Lambertian reflection calculation
+    float diffuse = clamp(dot(N, L), 0, 1);
+
+    return (fragTintColor.xyz*lightDiffuseColor*lightIntensity*diffuse);
 }
 }
 
 
+// Calculate specular lighting component
 vec3 SpecularLighting(in vec3 N, in vec3 L, in vec3 V)
 vec3 SpecularLighting(in vec3 N, in vec3 L, in vec3 V)
 {
 {
-   float specular = 0;
-
-   // Calculate specular reflection only if the surface is oriented to the light source
-   if(dot(N, L) > 0)
-   {
-      // Calculate half vector
-      vec3 H = normalize(L + V);
-      
-      // Calculate specular intensity
-      specular = pow(dot(N, H), 3 + mat_glossiness);
-   }
+    float specular = 0.0;
+
+    // Calculate specular reflection only if the surface is oriented to the light source
+    if (dot(N, L) > 0)
+    {
+        // Calculate half vector
+        vec3 H = normalize(L + V);
+
+        // Calculate specular intensity
+        specular = pow(dot(N, H), 3 + matGlossiness);
+    }
    
    
-   return mat_specularColor * light_specularColor * light_specIntensity * specular;
+    return (matSpecularColor*lightSpecularColor*lightSpecIntensity*specular);
 }
 }
 
 
 void main()
 void main()
 {
 {
     // Normalize input vectors
     // Normalize input vectors
-    vec3 L = normalize(lightPos);
-    vec3 V = normalize(cameraPos);
+    vec3 L = normalize(lightPosition);
+    vec3 V = normalize(cameraPosition);
     vec3 N = normalize(fragNormal);
     vec3 N = normalize(fragNormal);
     
     
+    // Calculate lighting components 
     vec3 ambient = AmbientLighting();
     vec3 ambient = AmbientLighting();
     vec3 diffuse = DiffuseLighting(N, L);
     vec3 diffuse = DiffuseLighting(N, L);
     vec3 specular = SpecularLighting(N, L, V);
     vec3 specular = SpecularLighting(N, L, V);
     
     
-    // Get base color from texture
-    vec4 textureColor = texture(texture0, fragTexCoord);
-    vec3 finalColor = textureColor.rgb;
-    
-    fragColor = vec4(finalColor * (ambient + diffuse + specular), textureColor.a);
+    // Texel color fetching from texture sampler
+    vec4 texelColor = texture(texture0, fragTexCoord);
+
+    // Calculate final fragment color
+    finalColor = vec4(texelColor.rgb*(ambient + diffuse + specular), texelColor.a);
 }
 }

+ 8 - 6
shaders/glsl330/phong.vs

@@ -1,23 +1,25 @@
 #version 330
 #version 330
 
 
-// Vertex input data
+// Input vertex attributes
 in vec3 vertexPosition;
 in vec3 vertexPosition;
 in vec2 vertexTexCoord;
 in vec2 vertexTexCoord;
 in vec3 vertexNormal;
 in vec3 vertexNormal;
 
 
-// Projection and model data
+// Input uniform values
 uniform mat4 mvpMatrix;
 uniform mat4 mvpMatrix;
-uniform mat4 modelMatrix;
 
 
-// Attributes to fragment shader
+// Output vertex attributes (to fragment shader)
 out vec2 fragTexCoord;
 out vec2 fragTexCoord;
 out vec3 fragNormal;
 out vec3 fragNormal;
 
 
+// NOTE: Add here your custom variables
+uniform mat4 modelMatrix;
+
 void main()
 void main()
 {
 {
-    // Send texture coord to fragment shader
+    // Send vertex attributes to fragment shader
     fragTexCoord = vertexTexCoord;
     fragTexCoord = vertexTexCoord;
-    
+
     // Calculate view vector normal from model
     // Calculate view vector normal from model
     mat3 normalMatrix = transpose(inverse(mat3(modelMatrix)));
     mat3 normalMatrix = transpose(inverse(mat3(modelMatrix)));
     fragNormal = normalize(normalMatrix*vertexNormal);
     fragNormal = normalize(normalMatrix*vertexNormal);

+ 8 - 4
shaders/glsl330/pixel.fs

@@ -1,13 +1,17 @@
 #version 330
 #version 330
 
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
-// NOTE: Add here your custom variables 
+// Output fragment color
+out vec4 finalColor;
+
+// NOTE: Add here your custom variables
 
 
 const float renderWidth = 1280.0;
 const float renderWidth = 1280.0;
 const float renderHeight = 720.0;
 const float renderHeight = 720.0;
@@ -24,5 +28,5 @@ void main()
 
 
     vec3 tc = texture(texture0, coord).rgb;
     vec3 tc = texture(texture0, coord).rgb;
 
 
-    fragColor = vec4(tc, 1.0);
+    finalColor = vec4(tc, 1.0);
 }
 }

+ 14 - 9
shaders/glsl330/posterization.fs

@@ -1,12 +1,16 @@
 #version 330
 #version 330
 
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
+// Output fragment color
+out vec4 finalColor;
+
 // NOTE: Add here your custom variables
 // NOTE: Add here your custom variables
 
 
 float gamma = 0.6;
 float gamma = 0.6;
@@ -14,13 +18,14 @@ float numColors = 8.0;
 
 
 void main()
 void main()
 {
 {
-    vec3 color = texture(texture0, fragTexCoord.xy).rgb;
+    // Texel color fetching from texture sampler
+    vec3 texelColor = texture(texture0, fragTexCoord.xy).rgb;
     
     
-    color = pow(color, vec3(gamma, gamma, gamma));
-    color = color*numColors;
-    color = floor(color);
-    color = color/numColors;
-    color = pow(color, vec3(1.0/gamma));
+    texelColor = pow(texelColor, vec3(gamma, gamma, gamma));
+    texelColor = texelColor*numColors;
+    texelColor = floor(texelColor);
+    texelColor = texelColor/numColors;
+    texelColor = pow(texelColor, vec3(1.0/gamma));
     
     
-    fragColor = vec4(color, 1.0);
+    finalColor = vec4(texelColor, 1.0);
 }
 }

+ 10 - 5
shaders/glsl330/predator.fs

@@ -1,27 +1,32 @@
 #version 330
 #version 330
 
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
+// Output fragment color
+out vec4 finalColor;
+
 // NOTE: Add here your custom variables
 // NOTE: Add here your custom variables
 
 
 void main()
 void main()
 {
 {
-    vec3 color = texture(texture0, fragTexCoord).rgb;
+    // Texel color fetching from texture sampler
+    vec3 texelColor = texture(texture0, fragTexCoord).rgb;
     vec3 colors[3];
     vec3 colors[3];
     colors[0] = vec3(0.0, 0.0, 1.0);
     colors[0] = vec3(0.0, 0.0, 1.0);
     colors[1] = vec3(1.0, 1.0, 0.0);
     colors[1] = vec3(1.0, 1.0, 0.0);
     colors[2] = vec3(1.0, 0.0, 0.0);
     colors[2] = vec3(1.0, 0.0, 0.0);
     
     
-    float lum = (color.r + color.g + color.b)/3.0;
+    float lum = (texelColor.r + texelColor.g + texelColor.b)/3.0;
     
     
     int ix = (lum < 0.5)? 0:1;
     int ix = (lum < 0.5)? 0:1;
     
     
     vec3 tc = mix(colors[ix], colors[ix + 1], (lum - float(ix)*0.5)/0.5);
     vec3 tc = mix(colors[ix], colors[ix + 1], (lum - float(ix)*0.5)/0.5);
     
     
-    fragColor = vec4(tc, 1.0);
+    finalColor = vec4(tc, 1.0);
 }
 }

+ 10 - 5
shaders/glsl330/scanlines.fs

@@ -1,12 +1,16 @@
 #version 330
 #version 330
 
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
+// Output fragment color
+out vec4 finalColor;
+
 // NOTE: Add here your custom variables
 // NOTE: Add here your custom variables
 
 
 float offset = 0.0;
 float offset = 0.0;
@@ -14,7 +18,7 @@ float frequency = 720.0/3.0;
 
 
 uniform float time;
 uniform float time;
 
 
-void main (void)
+void main()
 {
 {
 /*
 /*
     // Scanlines method 1
     // Scanlines method 1
@@ -35,7 +39,8 @@ void main (void)
     float globalPos = (fragTexCoord.y + offset) * frequency;
     float globalPos = (fragTexCoord.y + offset) * frequency;
     float wavePos = cos((fract(globalPos) - 0.5)*3.14);
     float wavePos = cos((fract(globalPos) - 0.5)*3.14);
     
     
-    vec4 color = texture(texture0, fragTexCoord);
+    // Texel color fetching from texture sampler
+    vec4 texelColor = texture(texture0, fragTexCoord);
 
 
-    fragColor = mix(vec4(0.0, 0.3, 0.0, 0.0), color, wavePos);
+    finalColor = mix(vec4(0.0, 0.3, 0.0, 0.0), texelColor, wavePos);
 }
 }

+ 11 - 6
shaders/glsl330/swirl.fs

@@ -1,27 +1,32 @@
 #version 330
 #version 330
 
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
+// Output fragment color
+out vec4 finalColor;
+
 // NOTE: Add here your custom variables
 // NOTE: Add here your custom variables
 
 
-const float renderWidth = 1280.0; 
-const float renderHeight = 720.0; 
+const float renderWidth = 800.0;      // HARDCODED for example!
+const float renderHeight = 480.0;     // Use uniforms instead...
 
 
 float radius = 250.0;
 float radius = 250.0;
 float angle = 0.8;
 float angle = 0.8;
 
 
 uniform vec2 center = vec2(200.0, 200.0);
 uniform vec2 center = vec2(200.0, 200.0);
 
 
-void main (void)
+void main()
 {
 {
     vec2 texSize = vec2(renderWidth, renderHeight);
     vec2 texSize = vec2(renderWidth, renderHeight);
     vec2 tc = fragTexCoord*texSize;
     vec2 tc = fragTexCoord*texSize;
     tc -= center;
     tc -= center;
+    
     float dist = length(tc);
     float dist = length(tc);
 
 
     if (dist < radius) 
     if (dist < radius) 
@@ -37,5 +42,5 @@ void main (void)
     tc += center;
     tc += center;
     vec3 color = texture(texture0, tc/texSize).rgb;
     vec3 color = texture(texture0, tc/texSize).rgb;
 
 
-    fragColor = vec4(color, 1.0);;
+    finalColor = vec4(color, 1.0);;
 }
 }

+ 8 - 3
shaders/glsl330/template.fs

@@ -1,19 +1,24 @@
 #version 330
 #version 330
 
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 uniform vec4 fragTintColor;
 
 
+// Output fragment color
+out vec4 finalColor;
+
 // NOTE: Add here your custom variables
 // NOTE: Add here your custom variables
 
 
 void main()
 void main()
 {
 {
+    // Texel color fetching from texture sampler
     vec4 texelColor = texture(texture0, fragTexCoord);
     vec4 texelColor = texture(texture0, fragTexCoord);
     
     
     // NOTE: Implement here your fragment shader code
     // NOTE: Implement here your fragment shader code
     
     
-    fragColor = texelColor*fragTintColor;
+    finalColor = texelColor*fragTintColor;
 }
 }

+ 349 - 343
src/audio.c

@@ -59,8 +59,9 @@
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Defines and Macros
 // Defines and Macros
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
-#define MAX_STREAM_BUFFERS          2
-#define MAX_AUDIO_CONTEXTS          4             // Number of open AL sources
+#define MAX_STREAM_BUFFERS          2             // Number of buffers for each alSource
+#define MAX_MIX_CHANNELS            4             // Number of open AL sources
+#define MAX_MUSIC_STREAMS           2             // Number of simultanious music sources
 
 
 #if defined(PLATFORM_RPI) || defined(PLATFORM_ANDROID)
 #if defined(PLATFORM_RPI) || defined(PLATFORM_ANDROID)
     // NOTE: On RPI and Android should be lower to avoid frame-stalls
     // NOTE: On RPI and Android should be lower to avoid frame-stalls
@@ -76,37 +77,32 @@
 // Types and Structures Definition
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 
 
-// Music type (file streaming from memory)
-// NOTE: Anything longer than ~10 seconds should be streamed...
-typedef struct Music {
-    stb_vorbis *stream;
-    jar_xm_context_t *chipctx; // Stores jar_xm context
-
-    ALuint buffers[MAX_STREAM_BUFFERS];
-    ALuint source;
-    ALenum format;
-
-    int channels;
-    int sampleRate;
-    int totalSamplesLeft;
-    float totalLengthSeconds;
-    bool loop;
-    bool chipTune; // True if chiptune is loaded
-} Music;
-
-// Audio Context, used to create custom audio streams that are not bound to a sound file. There can be
-// no more than 4 concurrent audio contexts in use. This is due to each active context being tied to
-// a dedicated mix channel. All audio is 32bit floating point in stereo.
-typedef struct AudioContext_t {
+// Used to create custom audio streams that are not bound to a specific file. There can be
+// no more than 4 concurrent mixchannels in use. This is due to each active mixc being tied to
+// a dedicated mix channel.
+typedef struct MixChannel_t {
     unsigned short sampleRate;           // default is 48000
     unsigned short sampleRate;           // default is 48000
     unsigned char channels;              // 1=mono,2=stereo
     unsigned char channels;              // 1=mono,2=stereo
     unsigned char mixChannel;            // 0-3 or mixA-mixD, each mix channel can receive up to one dedicated audio stream
     unsigned char mixChannel;            // 0-3 or mixA-mixD, each mix channel can receive up to one dedicated audio stream
     bool floatingPoint;                  // if false then the short datatype is used instead
     bool floatingPoint;                  // if false then the short datatype is used instead
-    bool playing;
+    bool playing;                        // false if paused
     ALenum alFormat;                     // openAL format specifier
     ALenum alFormat;                     // openAL format specifier
     ALuint alSource;                     // openAL source
     ALuint alSource;                     // openAL source
     ALuint alBuffer[MAX_STREAM_BUFFERS]; // openAL sample buffer
     ALuint alBuffer[MAX_STREAM_BUFFERS]; // openAL sample buffer
-} AudioContext_t;
+} MixChannel_t;
+
+// Music type (file streaming from memory)
+// NOTE: Anything longer than ~10 seconds should be streamed into a mix channel...
+typedef struct Music {
+    stb_vorbis *stream;
+    jar_xm_context_t *chipctx; // Stores jar_xm mixc
+    MixChannel_t *mixc;        // mix channel
+    
+    int totalSamplesLeft;
+    float totalLengthSeconds;
+    bool loop;
+    bool chipTune;             // True if chiptune is loaded
+} Music;
 
 
 #if defined(AUDIO_STANDALONE)
 #if defined(AUDIO_STANDALONE)
 typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
 typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
@@ -115,23 +111,28 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Global Variables Definition
 // Global Variables Definition
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
-static AudioContext_t* mixChannelsActive_g[MAX_AUDIO_CONTEXTS];      // What mix channels are currently active
-static bool musicEnabled = false;
-static Music currentMusic;          // Current music loaded
-                                    // NOTE: Only one music file playing at a time
+static MixChannel_t* mixChannelsActive_g[MAX_MIX_CHANNELS];        // What mix channels are currently active
+static bool musicEnabled_g = false;
+static Music currentMusic[MAX_MUSIC_STREAMS];                      // Current music loaded, up to two can play at the same time
+
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
 // Module specific Functions Declaration
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
-static Wave LoadWAV(const char *fileName);          // Load WAV file
-static Wave LoadOGG(char *fileName);                // Load OGG file
-static void UnloadWave(Wave wave);                  // Unload wave data
+static Wave LoadWAV(const char *fileName);         // Load WAV file
+static Wave LoadOGG(char *fileName);               // Load OGG file
+static void UnloadWave(Wave wave);                 // Unload wave data
 
 
-static bool BufferMusicStream(ALuint buffer);       // Fill music buffers with data
-static void EmptyMusicStream(void);                 // Empty music buffers
+static bool BufferMusicStream(int index, int numBuffers); // Fill music buffers with data
+static void EmptyMusicStream(int index);                  // Empty music buffers
 
 
-static unsigned short FillAlBufferWithSilence(AudioContext_t *context, ALuint buffer);// fill buffer with zeros, returns number processed
-static void ResampleShortToFloat(short *shorts, float *floats, unsigned short len); // pass two arrays of the same legnth in
-static void ResampleByteToFloat(char *chars, float *floats, unsigned short len); // pass two arrays of same length in
+
+static MixChannel_t* InitMixChannel(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint); // For streaming into mix channels.
+static void CloseMixChannel(MixChannel_t* mixc); // Frees mix channel
+static int BufferMixChannel(MixChannel_t* mixc, void *data, int numberElements); // Pushes more audio data into mixc mix channel, if NULL is passed it pauses
+static int FillAlBufferWithSilence(MixChannel_t *mixc, ALuint buffer); // Fill buffer with zeros, returns number processed
+static void ResampleShortToFloat(short *shorts, float *floats, unsigned short len); // Pass two arrays of the same legnth in
+static void ResampleByteToFloat(char *chars, float *floats, unsigned short len); // Pass two arrays of same length in
+static int IsMusicStreamReadyForBuffering(int index); // Checks if music buffer is ready to be refilled
 
 
 #if defined(AUDIO_STANDALONE)
 #if defined(AUDIO_STANDALONE)
 const char *GetExtension(const char *fileName);     // Get the extension for a filename
 const char *GetExtension(const char *fileName);     // Get the extension for a filename
@@ -142,7 +143,7 @@ void TraceLog(int msgType, const char *text, ...);  // Outputs a trace log messa
 // Module Functions Definition - Audio Device initialization and Closing
 // Module Functions Definition - Audio Device initialization and Closing
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 
 
-// Initialize audio device and context
+// Initialize audio device and mixc
 void InitAudioDevice(void)
 void InitAudioDevice(void)
 {
 {
     // Open and initialize a device with default settings
     // Open and initialize a device with default settings
@@ -158,7 +159,7 @@ void InitAudioDevice(void)
 
 
         alcCloseDevice(device);
         alcCloseDevice(device);
 
 
-        TraceLog(ERROR, "Could not setup audio context");
+        TraceLog(ERROR, "Could not setup mix channel");
     }
     }
 
 
     TraceLog(INFO, "Audio device and context initialized successfully: %s", alcGetString(device, ALC_DEVICE_SPECIFIER));
     TraceLog(INFO, "Audio device and context initialized successfully: %s", alcGetString(device, ALC_DEVICE_SPECIFIER));
@@ -169,15 +170,19 @@ void InitAudioDevice(void)
     alListener3f(AL_ORIENTATION, 0, 0, -1);
     alListener3f(AL_ORIENTATION, 0, 0, -1);
 }
 }
 
 
-// Close the audio device for the current context, and destroys the context
+// Close the audio device for all contexts
 void CloseAudioDevice(void)
 void CloseAudioDevice(void)
 {
 {
-    StopMusicStream();      // Stop music streaming and close current stream
+    for(int index=0; index<MAX_MUSIC_STREAMS; index++)
+    {
+        if(currentMusic[index].mixc) StopMusicStream(index);      // Stop music streaming and close current stream
+    }
+    
 
 
     ALCdevice *device;
     ALCdevice *device;
     ALCcontext *context = alcGetCurrentContext();
     ALCcontext *context = alcGetCurrentContext();
 
 
-    if (context == NULL) TraceLog(WARNING, "Could not get current audio context for closing");
+    if (context == NULL) TraceLog(WARNING, "Could not get current mix channel for closing");
 
 
     device = alcGetContextsDevice(context);
     device = alcGetContextsDevice(context);
 
 
@@ -202,187 +207,141 @@ bool IsAudioDeviceReady(void)
 // Module Functions Definition - Custom audio output
 // Module Functions Definition - Custom audio output
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 
 
-// Audio contexts are for outputing custom audio waveforms, This will shut down any other sound sources currently playing
-// The mixChannel is what mix channel you want to operate on, 0-3 are the ones available. Each mix channel can only be used one at a time.
-// exmple usage is InitAudioContext(48000, 0, 2, true); // mixchannel 1, 48khz, stereo, floating point
-AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint)
+// For streaming into mix channels.
+// The mixChannel is what audio muxing channel you want to operate on, 0-3 are the ones available. Each mix channel can only be used one at a time.
+// exmple usage is InitMixChannel(48000, 0, 2, true); // mixchannel 1, 48khz, stereo, floating point
+static MixChannel_t* InitMixChannel(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint)
 {
 {
-    if(mixChannel >= MAX_AUDIO_CONTEXTS) return NULL;
+    if(mixChannel >= MAX_MIX_CHANNELS) return NULL;
     if(!IsAudioDeviceReady()) InitAudioDevice();
     if(!IsAudioDeviceReady()) InitAudioDevice();
-    else StopMusicStream();
     
     
     if(!mixChannelsActive_g[mixChannel]){
     if(!mixChannelsActive_g[mixChannel]){
-        AudioContext_t *ac = (AudioContext_t*)malloc(sizeof(AudioContext_t));
-        ac->sampleRate = sampleRate;
-        ac->channels = channels;
-        ac->mixChannel = mixChannel;
-        ac->floatingPoint = floatingPoint;
-        mixChannelsActive_g[mixChannel] = ac;
+        MixChannel_t *mixc = (MixChannel_t*)malloc(sizeof(MixChannel_t));
+        mixc->sampleRate = sampleRate;
+        mixc->channels = channels;
+        mixc->mixChannel = mixChannel;
+        mixc->floatingPoint = floatingPoint;
+        mixChannelsActive_g[mixChannel] = mixc;
         
         
         // setup openAL format
         // setup openAL format
         if(channels == 1)
         if(channels == 1)
         {
         {
             if(floatingPoint)
             if(floatingPoint)
-                ac->alFormat = AL_FORMAT_MONO_FLOAT32;
+                mixc->alFormat = AL_FORMAT_MONO_FLOAT32;
             else
             else
-                ac->alFormat = AL_FORMAT_MONO16;
+                mixc->alFormat = AL_FORMAT_MONO16;
         }
         }
         else if(channels == 2)
         else if(channels == 2)
         {
         {
             if(floatingPoint)
             if(floatingPoint)
-                ac->alFormat = AL_FORMAT_STEREO_FLOAT32;
+                mixc->alFormat = AL_FORMAT_STEREO_FLOAT32;
             else
             else
-                ac->alFormat = AL_FORMAT_STEREO16;
+                mixc->alFormat = AL_FORMAT_STEREO16;
         }
         }
         
         
         // Create an audio source
         // Create an audio source
-        alGenSources(1, &ac->alSource);
-        alSourcef(ac->alSource, AL_PITCH, 1);
-        alSourcef(ac->alSource, AL_GAIN, 1);
-        alSource3f(ac->alSource, AL_POSITION, 0, 0, 0);
-        alSource3f(ac->alSource, AL_VELOCITY, 0, 0, 0);
+        alGenSources(1, &mixc->alSource);
+        alSourcef(mixc->alSource, AL_PITCH, 1);
+        alSourcef(mixc->alSource, AL_GAIN, 1);
+        alSource3f(mixc->alSource, AL_POSITION, 0, 0, 0);
+        alSource3f(mixc->alSource, AL_VELOCITY, 0, 0, 0);
         
         
         // Create Buffer
         // Create Buffer
-        alGenBuffers(MAX_STREAM_BUFFERS, ac->alBuffer);
+        alGenBuffers(MAX_STREAM_BUFFERS, mixc->alBuffer);
         
         
         //fill buffers
         //fill buffers
         int x;
         int x;
         for(x=0;x<MAX_STREAM_BUFFERS;x++)
         for(x=0;x<MAX_STREAM_BUFFERS;x++)
-            FillAlBufferWithSilence(ac, ac->alBuffer[x]);
+            FillAlBufferWithSilence(mixc, mixc->alBuffer[x]);
         
         
-        alSourceQueueBuffers(ac->alSource, MAX_STREAM_BUFFERS, ac->alBuffer);
-        alSourcePlay(ac->alSource);
-        ac->playing = true;
+        alSourceQueueBuffers(mixc->alSource, MAX_STREAM_BUFFERS, mixc->alBuffer);
+        mixc->playing = true;
+        alSourcePlay(mixc->alSource);
         
         
-        return ac;
+        return mixc;
     }
     }
     return NULL;
     return NULL;
 }
 }
 
 
-// Frees buffer in audio context
-void CloseAudioContext(AudioContext ctx)
+// Frees buffer in mix channel
+static void CloseMixChannel(MixChannel_t* mixc)
 {
 {
-    AudioContext_t *context = (AudioContext_t*)ctx;
-    if(context){
-        alSourceStop(context->alSource);
-        context->playing = false;
+    if(mixc){
+        alSourceStop(mixc->alSource);
+        mixc->playing = false;
         
         
         //flush out all queued buffers
         //flush out all queued buffers
         ALuint buffer = 0;
         ALuint buffer = 0;
         int queued = 0;
         int queued = 0;
-        alGetSourcei(context->alSource, AL_BUFFERS_QUEUED, &queued);
+        alGetSourcei(mixc->alSource, AL_BUFFERS_QUEUED, &queued);
         while (queued > 0)
         while (queued > 0)
         {
         {
-            alSourceUnqueueBuffers(context->alSource, 1, &buffer);
+            alSourceUnqueueBuffers(mixc->alSource, 1, &buffer);
             queued--;
             queued--;
         }
         }
         
         
         //delete source and buffers
         //delete source and buffers
-        alDeleteSources(1, &context->alSource);
-        alDeleteBuffers(MAX_STREAM_BUFFERS, context->alBuffer);
-        mixChannelsActive_g[context->mixChannel] = NULL;
-        free(context);
-        ctx = NULL;
+        alDeleteSources(1, &mixc->alSource);
+        alDeleteBuffers(MAX_STREAM_BUFFERS, mixc->alBuffer);
+        mixChannelsActive_g[mixc->mixChannel] = NULL;
+        free(mixc);
+        mixc = NULL;
     }
     }
 }
 }
 
 
-// Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in.
-// Call "UpdateAudioContext(ctx, NULL, 0)" if you want to pause the audio.
+// Pushes more audio data into mixc mix channel, only one buffer per call
+// Call "BufferMixChannel(mixc, NULL, 0)" if you want to pause the audio.
 // @Returns number of samples that where processed.
 // @Returns number of samples that where processed.
-unsigned short UpdateAudioContext(AudioContext ctx, void *data, unsigned short numberElements)
+static int BufferMixChannel(MixChannel_t* mixc, void *data, int numberElements)
 {
 {
-    AudioContext_t *context = (AudioContext_t*)ctx;
-    
-    if(!context || (context->channels == 2 && numberElements % 2 != 0)) return 0; // when there is two channels there must be an even number of samples
+    if(!mixc || mixChannelsActive_g[mixc->mixChannel] != mixc) return 0; // when there is two channels there must be an even number of samples
     
     
     if (!data || !numberElements)
     if (!data || !numberElements)
     { // pauses audio until data is given
     { // pauses audio until data is given
-        alSourcePause(context->alSource);
-        context->playing = false;
+        if(mixc->playing){
+            alSourcePause(mixc->alSource);
+            mixc->playing = false;
+        }
         return 0;
         return 0;
     }
     }
-    else
+    else if(!mixc->playing)
     { // restart audio otherwise
     { // restart audio otherwise
-        ALint state;
-        alGetSourcei(context->alSource, AL_SOURCE_STATE, &state);
-        if (state != AL_PLAYING){
-            alSourcePlay(context->alSource);
-            context->playing = true;
-        }
+        alSourcePlay(mixc->alSource);
+        mixc->playing = true;
     }
     }
     
     
-    if (context && context->playing && mixChannelsActive_g[context->mixChannel] == context)
+   
+    ALuint buffer = 0;
+    
+    alSourceUnqueueBuffers(mixc->alSource, 1, &buffer);
+    if(!buffer) return 0;
+    if(mixc->floatingPoint) // process float buffers
     {
     {
-        ALint processed = 0;
-        ALuint buffer = 0;
-        unsigned short numberProcessed = 0;
-        unsigned short numberRemaining = numberElements;
-        
-        
-        alGetSourcei(context->alSource, AL_BUFFERS_PROCESSED, &processed); // Get the number of already processed buffers (if any)
-        if(!processed) return 0; // nothing to process, queue is still full
-        
-        
-        while (processed > 0)
-        {
-            if(context->floatingPoint) // process float buffers
-            {
-                float *ptr = (float*)data;
-                alSourceUnqueueBuffers(context->alSource, 1, &buffer);
-                if(numberRemaining >= MUSIC_BUFFER_SIZE_FLOAT)
-                {
-                    alBufferData(buffer, context->alFormat, &ptr[numberProcessed], MUSIC_BUFFER_SIZE_FLOAT*sizeof(float), context->sampleRate);
-                    numberProcessed+=MUSIC_BUFFER_SIZE_FLOAT;
-                    numberRemaining-=MUSIC_BUFFER_SIZE_FLOAT;
-                }
-                else
-                {
-                    alBufferData(buffer, context->alFormat, &ptr[numberProcessed], numberRemaining*sizeof(float), context->sampleRate);
-                    numberProcessed+=numberRemaining;
-                    numberRemaining=0;
-                }
-                alSourceQueueBuffers(context->alSource, 1, &buffer);
-                processed--;
-            }
-            else if(!context->floatingPoint) // process short buffers
-            {
-                short *ptr = (short*)data;
-                alSourceUnqueueBuffers(context->alSource, 1, &buffer);
-                if(numberRemaining >= MUSIC_BUFFER_SIZE_SHORT)
-                {
-                    alBufferData(buffer, context->alFormat, &ptr[numberProcessed], MUSIC_BUFFER_SIZE_FLOAT*sizeof(short), context->sampleRate);
-                    numberProcessed+=MUSIC_BUFFER_SIZE_SHORT;
-                    numberRemaining-=MUSIC_BUFFER_SIZE_SHORT;
-                }
-                else
-                {
-                    alBufferData(buffer, context->alFormat, &ptr[numberProcessed], numberRemaining*sizeof(short), context->sampleRate);
-                    numberProcessed+=numberRemaining;
-                    numberRemaining=0;
-                }
-                alSourceQueueBuffers(context->alSource, 1, &buffer);
-                processed--;
-            }
-            else
-                break;
-        }
-        return numberProcessed;
+        float *ptr = (float*)data;
+        alBufferData(buffer, mixc->alFormat, ptr, numberElements*sizeof(float), mixc->sampleRate);
+    }
+    else // process short buffers
+    {
+        short *ptr = (short*)data;
+        alBufferData(buffer, mixc->alFormat, ptr, numberElements*sizeof(short), mixc->sampleRate);
     }
     }
-    return 0;
+    alSourceQueueBuffers(mixc->alSource, 1, &buffer);
+    
+    return numberElements;
 }
 }
 
 
 // fill buffer with zeros, returns number processed
 // fill buffer with zeros, returns number processed
-static unsigned short FillAlBufferWithSilence(AudioContext_t *context, ALuint buffer)
+static int FillAlBufferWithSilence(MixChannel_t *mixc, ALuint buffer)
 {
 {
-    if(context->floatingPoint){
+    if(mixc->floatingPoint){
         float pcm[MUSIC_BUFFER_SIZE_FLOAT] = {0.f};
         float pcm[MUSIC_BUFFER_SIZE_FLOAT] = {0.f};
-        alBufferData(buffer, context->alFormat, pcm, MUSIC_BUFFER_SIZE_FLOAT*sizeof(float), context->sampleRate);
+        alBufferData(buffer, mixc->alFormat, pcm, MUSIC_BUFFER_SIZE_FLOAT*sizeof(float), mixc->sampleRate);
         return MUSIC_BUFFER_SIZE_FLOAT;
         return MUSIC_BUFFER_SIZE_FLOAT;
     }
     }
     else
     else
     {
     {
         short pcm[MUSIC_BUFFER_SIZE_SHORT] = {0};
         short pcm[MUSIC_BUFFER_SIZE_SHORT] = {0};
-        alBufferData(buffer, context->alFormat, pcm, MUSIC_BUFFER_SIZE_SHORT*sizeof(short), context->sampleRate);
+        alBufferData(buffer, mixc->alFormat, pcm, MUSIC_BUFFER_SIZE_SHORT*sizeof(short), mixc->sampleRate);
         return MUSIC_BUFFER_SIZE_SHORT;
         return MUSIC_BUFFER_SIZE_SHORT;
     }
     }
 }
 }
@@ -417,6 +376,42 @@ static void ResampleByteToFloat(char *chars, float *floats, unsigned short len)
     }
     }
 }
 }
 
 
+// used to output raw audio streams, returns negative numbers on error
+// if floating point is false the data size is 16bit short, otherwise it is float 32bit
+RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint)
+{
+    int mixIndex;
+    for(mixIndex = 0; mixIndex < MAX_MIX_CHANNELS; mixIndex++) // find empty mix channel slot
+    {
+        if(mixChannelsActive_g[mixIndex] == NULL) break;
+        else if(mixIndex == MAX_MIX_CHANNELS - 1) return -1; // error
+    }
+    
+    if(InitMixChannel(sampleRate, mixIndex, channels, floatingPoint))
+        return mixIndex;
+    else
+        return -2; // error
+}
+
+void CloseRawAudioContext(RawAudioContext ctx)
+{
+    if(mixChannelsActive_g[ctx])
+        CloseMixChannel(mixChannelsActive_g[ctx]);
+}
+
+int BufferRawAudioContext(RawAudioContext ctx, void *data, int numberElements)
+{
+    int numBuffered = 0;
+    if(ctx >= 0)
+    {
+        MixChannel_t* mixc = mixChannelsActive_g[ctx];
+        numBuffered = BufferMixChannel(mixc, data, numberElements);
+    }
+    return numBuffered;
+}
+
+
+
 
 
 
 
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
@@ -767,207 +762,216 @@ void SetSoundPitch(Sound sound, float pitch)
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 
 
 // Start music playing (open stream)
 // Start music playing (open stream)
-void PlayMusicStream(char *fileName)
+// returns 0 on success
+int PlayMusicStream(int musicIndex, char *fileName)
 {
 {
+    int mixIndex;
+    
+    if(currentMusic[musicIndex].stream || currentMusic[musicIndex].chipctx) return 1; // error
+    
+    for(mixIndex = 0; mixIndex < MAX_MIX_CHANNELS; mixIndex++) // find empty mix channel slot
+    {
+        if(mixChannelsActive_g[mixIndex] == NULL) break;
+        else if(mixIndex == MAX_MIX_CHANNELS - 1) return 2; // error
+    }
+    
     if (strcmp(GetExtension(fileName),"ogg") == 0)
     if (strcmp(GetExtension(fileName),"ogg") == 0)
     {
     {
-        // Stop current music, clean buffers, unload current stream
-        StopMusicStream();
-
         // Open audio stream
         // Open audio stream
-        currentMusic.stream = stb_vorbis_open_filename(fileName, NULL, NULL);
+        currentMusic[musicIndex].stream = stb_vorbis_open_filename(fileName, NULL, NULL);
 
 
-        if (currentMusic.stream == NULL)
+        if (currentMusic[musicIndex].stream == NULL)
         {
         {
             TraceLog(WARNING, "[%s] OGG audio file could not be opened", fileName);
             TraceLog(WARNING, "[%s] OGG audio file could not be opened", fileName);
+            return 3; // error
         }
         }
         else
         else
         {
         {
             // Get file info
             // Get file info
-            stb_vorbis_info info = stb_vorbis_get_info(currentMusic.stream);
-
-            currentMusic.channels = info.channels;
-            currentMusic.sampleRate = info.sample_rate;
+            stb_vorbis_info info = stb_vorbis_get_info(currentMusic[musicIndex].stream);
 
 
             TraceLog(INFO, "[%s] Ogg sample rate: %i", fileName, info.sample_rate);
             TraceLog(INFO, "[%s] Ogg sample rate: %i", fileName, info.sample_rate);
             TraceLog(INFO, "[%s] Ogg channels: %i", fileName, info.channels);
             TraceLog(INFO, "[%s] Ogg channels: %i", fileName, info.channels);
             TraceLog(DEBUG, "[%s] Temp memory required: %i", fileName, info.temp_memory_required);
             TraceLog(DEBUG, "[%s] Temp memory required: %i", fileName, info.temp_memory_required);
 
 
-            if (info.channels == 2) currentMusic.format = AL_FORMAT_STEREO16;
-            else currentMusic.format = AL_FORMAT_MONO16;
-
-            currentMusic.loop = true;                  // We loop by default
-            musicEnabled = true;
-
-            // Create an audio source
-            alGenSources(1, &currentMusic.source);     // Generate pointer to audio source
-
-            alSourcef(currentMusic.source, AL_PITCH, 1);
-            alSourcef(currentMusic.source, AL_GAIN, 1);
-            alSource3f(currentMusic.source, AL_POSITION, 0, 0, 0);
-            alSource3f(currentMusic.source, AL_VELOCITY, 0, 0, 0);
-            //alSourcei(currentMusic.source, AL_LOOPING, AL_TRUE);     // ERROR: Buffers do not queue!
-
-            // Generate two OpenAL buffers
-            alGenBuffers(2, currentMusic.buffers);
-
-            // Fill buffers with music...
-            BufferMusicStream(currentMusic.buffers[0]);
-            BufferMusicStream(currentMusic.buffers[1]);
-
-            // Queue buffers and start playing
-            alSourceQueueBuffers(currentMusic.source, 2, currentMusic.buffers);
-            alSourcePlay(currentMusic.source);
-
-            // NOTE: Regularly, we must check if a buffer has been processed and refill it: UpdateMusicStream()
+            currentMusic[musicIndex].loop = true;                  // We loop by default
+            musicEnabled_g = true;
+            
 
 
-            currentMusic.totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels;
-            currentMusic.totalLengthSeconds = stb_vorbis_stream_length_in_seconds(currentMusic.stream);
+            currentMusic[musicIndex].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[musicIndex].stream) * info.channels;
+            currentMusic[musicIndex].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(currentMusic[musicIndex].stream);
+            
+            if (info.channels == 2){
+                currentMusic[musicIndex].mixc = InitMixChannel(info.sample_rate, mixIndex, 2, false);
+                currentMusic[musicIndex].mixc->playing = true;
+            }
+            else{
+                currentMusic[musicIndex].mixc = InitMixChannel(info.sample_rate, mixIndex, 1, false);
+                currentMusic[musicIndex].mixc->playing = true;
+            }
+            if(!currentMusic[musicIndex].mixc) return 4; // error
         }
         }
     }
     }
     else if (strcmp(GetExtension(fileName),"xm") == 0)
     else if (strcmp(GetExtension(fileName),"xm") == 0)
     {
     {
-        // Stop current music, clean buffers, unload current stream
-        StopMusicStream();
-        
-        // new song settings for xm chiptune
-        currentMusic.chipTune = true;
-        currentMusic.channels = 2;
-        currentMusic.sampleRate = 48000;
-        currentMusic.loop = true;
-        
         // only stereo is supported for xm
         // only stereo is supported for xm
-        if(!jar_xm_create_context_from_file(&currentMusic.chipctx, currentMusic.sampleRate, fileName))
+        if(!jar_xm_create_context_from_file(&currentMusic[musicIndex].chipctx, 48000, fileName))
         {
         {
-            currentMusic.format = AL_FORMAT_STEREO16;
-            jar_xm_set_max_loop_count(currentMusic.chipctx, 0); // infinite number of loops
-            currentMusic.totalSamplesLeft =  jar_xm_get_remaining_samples(currentMusic.chipctx);
-            currentMusic.totalLengthSeconds = ((float)currentMusic.totalSamplesLeft) / ((float)currentMusic.sampleRate);
-            musicEnabled = true;
+            currentMusic[musicIndex].chipTune = true;
+            currentMusic[musicIndex].loop = true;
+            jar_xm_set_max_loop_count(currentMusic[musicIndex].chipctx, 0); // infinite number of loops
+            currentMusic[musicIndex].totalSamplesLeft =  jar_xm_get_remaining_samples(currentMusic[musicIndex].chipctx);
+            currentMusic[musicIndex].totalLengthSeconds = ((float)currentMusic[musicIndex].totalSamplesLeft) / 48000.f;
+            musicEnabled_g = true;
             
             
-            TraceLog(INFO, "[%s] XM number of samples: %i", fileName, currentMusic.totalSamplesLeft);
-            TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, currentMusic.totalLengthSeconds);
+            TraceLog(INFO, "[%s] XM number of samples: %i", fileName, currentMusic[musicIndex].totalSamplesLeft);
+            TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, currentMusic[musicIndex].totalLengthSeconds);
             
             
-            // Set up OpenAL
-            alGenSources(1, &currentMusic.source);
-            alSourcef(currentMusic.source, AL_PITCH, 1);
-            alSourcef(currentMusic.source, AL_GAIN, 1);
-            alSource3f(currentMusic.source, AL_POSITION, 0, 0, 0);
-            alSource3f(currentMusic.source, AL_VELOCITY, 0, 0, 0);
-            alGenBuffers(2, currentMusic.buffers);
-            BufferMusicStream(currentMusic.buffers[0]);
-            BufferMusicStream(currentMusic.buffers[1]);
-            alSourceQueueBuffers(currentMusic.source, 2, currentMusic.buffers);
-            alSourcePlay(currentMusic.source);
-            
-            // NOTE: Regularly, we must check if a buffer has been processed and refill it: UpdateMusicStream()
+            currentMusic[musicIndex].mixc = InitMixChannel(48000, mixIndex, 2, false);
+            if(!currentMusic[musicIndex].mixc) return 5; // error
+            currentMusic[musicIndex].mixc->playing = true;
         }
         }
-        else TraceLog(WARNING, "[%s] XM file could not be opened", fileName);
+        else
+        {
+            TraceLog(WARNING, "[%s] XM file could not be opened", fileName);
+            return 6; // error
+        }
+    }
+    else
+    {
+        TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", fileName);
+        return 7; // error
     }
     }
-    else TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", fileName);
+    return 0; // normal return
 }
 }
 
 
-// Stop music playing (close stream)
-void StopMusicStream(void)
+// Stop music playing for individual music index of currentMusic array (close stream)
+void StopMusicStream(int index)
 {
 {
-    if (musicEnabled)
+    if (index < MAX_MUSIC_STREAMS && currentMusic[index].mixc)
     {
     {
-        alSourceStop(currentMusic.source);
-        EmptyMusicStream(); // Empty music buffers
-        alDeleteSources(1, &currentMusic.source);
-        alDeleteBuffers(2, currentMusic.buffers);
+        CloseMixChannel(currentMusic[index].mixc);
         
         
-        if (currentMusic.chipTune)
+        if (currentMusic[index].chipTune)
         {
         {
-            jar_xm_free_context(currentMusic.chipctx);
+            jar_xm_free_context(currentMusic[index].chipctx);
         }
         }
         else
         else
         {
         {
-            stb_vorbis_close(currentMusic.stream);
+            stb_vorbis_close(currentMusic[index].stream);
+        }
+        
+        if(!getMusicStreamCount()) musicEnabled_g = false;
+        if(currentMusic[index].stream || currentMusic[index].chipctx)
+        {
+            currentMusic[index].stream = NULL;
+            currentMusic[index].chipctx = NULL;
         }
         }
     }
     }
+}
 
 
-    musicEnabled = false;
+//get number of music channels active at this time, this does not mean they are playing
+int getMusicStreamCount(void)
+{
+    int musicCount = 0;
+    for(int musicIndex = 0; musicIndex < MAX_MUSIC_STREAMS; musicIndex++) // find empty music slot
+        if(currentMusic[musicIndex].stream != NULL || currentMusic[musicIndex].chipTune) musicCount++;
+    
+    return musicCount;
 }
 }
 
 
 // Pause music playing
 // Pause music playing
-void PauseMusicStream(void)
+void PauseMusicStream(int index)
 {
 {
     // Pause music stream if music available!
     // Pause music stream if music available!
-    if (musicEnabled)
+    if (index < MAX_MUSIC_STREAMS && currentMusic[index].mixc && musicEnabled_g)
     {
     {
         TraceLog(INFO, "Pausing music stream");
         TraceLog(INFO, "Pausing music stream");
-        alSourcePause(currentMusic.source);
-        musicEnabled = false;
+        alSourcePause(currentMusic[index].mixc->alSource);
+        currentMusic[index].mixc->playing = false;
     }
     }
 }
 }
 
 
 // Resume music playing
 // Resume music playing
-void ResumeMusicStream(void)
+void ResumeMusicStream(int index)
 {
 {
     // Resume music playing... if music available!
     // Resume music playing... if music available!
     ALenum state;
     ALenum state;
-    alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state);
-
-    if (state == AL_PAUSED)
-    {
-        TraceLog(INFO, "Resuming music stream");
-        alSourcePlay(currentMusic.source);
-        musicEnabled = true;
+    if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc){
+        alGetSourcei(currentMusic[index].mixc->alSource, AL_SOURCE_STATE, &state);
+        if (state == AL_PAUSED)
+        {
+            TraceLog(INFO, "Resuming music stream");
+            alSourcePlay(currentMusic[index].mixc->alSource);
+            currentMusic[index].mixc->playing = true;
+        }
     }
     }
 }
 }
 
 
-// Check if music is playing
-bool IsMusicPlaying(void)
+// Check if any music is playing
+bool IsMusicPlaying(int index)
 {
 {
     bool playing = false;
     bool playing = false;
     ALint state;
     ALint state;
-
-    alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state);
-    if (state == AL_PLAYING) playing = true;
+    
+    if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc){
+        alGetSourcei(currentMusic[index].mixc->alSource, AL_SOURCE_STATE, &state);
+        if (state == AL_PLAYING) playing = true;
+    }
 
 
     return playing;
     return playing;
 }
 }
 
 
 // Set volume for music
 // Set volume for music
-void SetMusicVolume(float volume)
+void SetMusicVolume(int index, float volume)
 {
 {
-    alSourcef(currentMusic.source, AL_GAIN, volume);
+    if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc){
+        alSourcef(currentMusic[index].mixc->alSource, AL_GAIN, volume);
+    }
+}
+
+void SetMusicPitch(int index, float pitch)
+{
+    if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc){
+        alSourcef(currentMusic[index].mixc->alSource, AL_PITCH, pitch);
+    }
 }
 }
 
 
 // Get current music time length (in seconds)
 // Get current music time length (in seconds)
-float GetMusicTimeLength(void)
+float GetMusicTimeLength(int index)
 {
 {
     float totalSeconds;
     float totalSeconds;
-    if (currentMusic.chipTune)
+    if (currentMusic[index].chipTune)
     {
     {
-        totalSeconds = currentMusic.totalLengthSeconds;
+        totalSeconds = currentMusic[index].totalLengthSeconds;
     }
     }
     else
     else
     {
     {
-        totalSeconds = stb_vorbis_stream_length_in_seconds(currentMusic.stream);
+        totalSeconds = stb_vorbis_stream_length_in_seconds(currentMusic[index].stream);
     }
     }
 
 
     return totalSeconds;
     return totalSeconds;
 }
 }
 
 
 // Get current music time played (in seconds)
 // Get current music time played (in seconds)
-float GetMusicTimePlayed(void)
+float GetMusicTimePlayed(int index)
 {
 {
-    float secondsPlayed;
-    if (currentMusic.chipTune)
-    {
-        uint64_t samples;
-        jar_xm_get_position(currentMusic.chipctx, NULL, NULL, NULL, &samples);
-        secondsPlayed = (float)samples / (currentMusic.sampleRate * currentMusic.channels); // Not sure if this is the correct value
-    }
-    else
+    float secondsPlayed = 0.0f;
+    if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc)
     {
     {
-        int totalSamples = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels;
-        int samplesPlayed = totalSamples - currentMusic.totalSamplesLeft;
-        secondsPlayed = (float)samplesPlayed / (currentMusic.sampleRate * currentMusic.channels);
+        if (currentMusic[index].chipTune)
+        {
+            uint64_t samples;
+            jar_xm_get_position(currentMusic[index].chipctx, NULL, NULL, NULL, &samples);
+            secondsPlayed = (float)samples / (48000 * currentMusic[index].mixc->channels); // Not sure if this is the correct value
+        }
+        else
+        {
+            int totalSamples = stb_vorbis_stream_length_in_samples(currentMusic[index].stream) * currentMusic[index].mixc->channels;
+            int samplesPlayed = totalSamples - currentMusic[index].totalSamplesLeft;
+            secondsPlayed = (float)samplesPlayed / (currentMusic[index].mixc->sampleRate * currentMusic[index].mixc->channels);
+        }
     }
     }
-    
 
 
     return secondsPlayed;
     return secondsPlayed;
 }
 }
@@ -977,116 +981,118 @@ float GetMusicTimePlayed(void)
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 
 
 // Fill music buffers with new data from music stream
 // Fill music buffers with new data from music stream
-static bool BufferMusicStream(ALuint buffer)
+static bool BufferMusicStream(int index, int numBuffers)
 {
 {
     short pcm[MUSIC_BUFFER_SIZE_SHORT];
     short pcm[MUSIC_BUFFER_SIZE_SHORT];
+    float pcmf[MUSIC_BUFFER_SIZE_FLOAT];
     
     
-    int  size = 0;              // Total size of data steamed (in bytes)
-    int  streamedBytes = 0;     // samples of data obtained, channels are not included in calculation
+    int  size = 0;              // Total size of data steamed in L+R samples for xm floats, individual L or R for ogg shorts
     bool active = true;         // We can get more data from stream (not finished)
     bool active = true;         // We can get more data from stream (not finished)
-
-    if (musicEnabled)
+    
+    if (currentMusic[index].chipTune) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes.
     {
     {
-        if (currentMusic.chipTune) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes.
-        {
-            int readlen = MUSIC_BUFFER_SIZE_SHORT / 2;
-            jar_xm_generate_samples_16bit(currentMusic.chipctx, pcm, readlen); // reads 2*readlen shorts and moves them to buffer+size memory location
-            size += readlen * currentMusic.channels; // Not sure if this is what it needs
-        }
+        if(currentMusic[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT)
+            size = MUSIC_BUFFER_SIZE_SHORT / 2;
         else
         else
+            size = currentMusic[index].totalSamplesLeft / 2;
+        
+        for(int x=0; x<numBuffers; x++)
         {
         {
-            while (size < MUSIC_BUFFER_SIZE_SHORT)
+            jar_xm_generate_samples_16bit(currentMusic[index].chipctx, pcm, size); // reads 2*readlen shorts and moves them to buffer+size memory location
+            BufferMixChannel(currentMusic[index].mixc, pcm, size * 2);
+            currentMusic[index].totalSamplesLeft -= size * 2;
+            if(currentMusic[index].totalSamplesLeft <= 0)
             {
             {
-                streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic.stream, currentMusic.channels, pcm + size, MUSIC_BUFFER_SIZE_SHORT - size);
-                if (streamedBytes > 0) size += (streamedBytes*currentMusic.channels);
-                else break;
+                active = false;
+                break;
             }
             }
         }
         }
-        TraceLog(DEBUG, "Streaming music data to buffer. Bytes streamed: %i", size);
-    }
-
-    if (size > 0)
-    {
-        alBufferData(buffer, currentMusic.format, pcm, size*sizeof(short), currentMusic.sampleRate);
-        currentMusic.totalSamplesLeft -= size;
-        
-        if(currentMusic.totalSamplesLeft <= 0) active = false; // end if no more samples left
     }
     }
     else
     else
     {
     {
-        active = false;
-        TraceLog(WARNING, "No more data obtained from stream");
+        if(currentMusic[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT)
+            size = MUSIC_BUFFER_SIZE_SHORT;
+        else
+            size = currentMusic[index].totalSamplesLeft;
+        
+        for(int x=0; x<numBuffers; x++)
+        {
+            int streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic[index].stream, currentMusic[index].mixc->channels, pcm, size);
+            BufferMixChannel(currentMusic[index].mixc, pcm, streamedBytes * currentMusic[index].mixc->channels);
+            currentMusic[index].totalSamplesLeft -= streamedBytes * currentMusic[index].mixc->channels;
+            if(currentMusic[index].totalSamplesLeft <= 0)
+            {
+                active = false;
+                break;
+            }
+        }
     }
     }
 
 
     return active;
     return active;
 }
 }
 
 
 // Empty music buffers
 // Empty music buffers
-static void EmptyMusicStream(void)
+static void EmptyMusicStream(int index)
 {
 {
     ALuint buffer = 0;
     ALuint buffer = 0;
     int queued = 0;
     int queued = 0;
 
 
-    alGetSourcei(currentMusic.source, AL_BUFFERS_QUEUED, &queued);
+    alGetSourcei(currentMusic[index].mixc->alSource, AL_BUFFERS_QUEUED, &queued);
 
 
     while (queued > 0)
     while (queued > 0)
     {
     {
-        alSourceUnqueueBuffers(currentMusic.source, 1, &buffer);
+        alSourceUnqueueBuffers(currentMusic[index].mixc->alSource, 1, &buffer);
 
 
         queued--;
         queued--;
     }
     }
 }
 }
 
 
-// Update (re-fill) music buffers if data already processed
-void UpdateMusicStream(void)
+//determine if a music stream is ready to be written to
+static int IsMusicStreamReadyForBuffering(int index)
 {
 {
-    ALuint buffer = 0;
     ALint processed = 0;
     ALint processed = 0;
-    bool active = true;
+    alGetSourcei(currentMusic[index].mixc->alSource, AL_BUFFERS_PROCESSED, &processed);
+    return processed;
+}
 
 
-    if (musicEnabled)
+// Update (re-fill) music buffers if data already processed
+void UpdateMusicStream(int index)
+{
+    ALenum state;
+    bool active = true;
+    int numBuffers = IsMusicStreamReadyForBuffering(index);
+    
+    if (currentMusic[index].mixc->playing && index < MAX_MUSIC_STREAMS && musicEnabled_g && currentMusic[index].mixc && numBuffers)
     {
     {
-        // Get the number of already processed buffers (if any)
-        alGetSourcei(currentMusic.source, AL_BUFFERS_PROCESSED, &processed);
-
-        while (processed > 0)
+        active = BufferMusicStream(index, numBuffers);
+        
+        if (!active && currentMusic[index].loop)
         {
         {
-            // Recover processed buffer for refill
-            alSourceUnqueueBuffers(currentMusic.source, 1, &buffer);
-
-            // Refill buffer
-            active = BufferMusicStream(buffer);
-
-            // If no more data to stream, restart music (if loop)
-            if ((!active) && (currentMusic.loop))
+            if (currentMusic[index].chipTune)
             {
             {
-                if(currentMusic.chipTune)
-                {
-                    currentMusic.totalSamplesLeft = currentMusic.totalLengthSeconds * currentMusic.sampleRate;
-                }
-                else
-                {
-                    stb_vorbis_seek_start(currentMusic.stream);
-                    currentMusic.totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic.stream)*currentMusic.channels;
-                }
-                active = BufferMusicStream(buffer);
+                currentMusic[index].totalSamplesLeft = currentMusic[index].totalLengthSeconds * 48000;
             }
             }
-
-            // Add refilled buffer to queue again... don't let the music stop!
-            alSourceQueueBuffers(currentMusic.source, 1, &buffer);
-
-            if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data...");
-
-            processed--;
+            else
+            {
+                stb_vorbis_seek_start(currentMusic[index].stream);
+                currentMusic[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[index].stream) * currentMusic[index].mixc->channels;
+            }
+            active = true;
         }
         }
+        
 
 
-        ALenum state;
-        alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state);
+        if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data...");
+        
+        alGetSourcei(currentMusic[index].mixc->alSource, AL_SOURCE_STATE, &state);
 
 
-        if ((state != AL_PLAYING) && active) alSourcePlay(currentMusic.source);
+        if (state != AL_PLAYING && active) alSourcePlay(currentMusic[index].mixc->alSource);
 
 
-        if (!active) StopMusicStream();
+        if (!active) StopMusicStream(index);
+        
     }
     }
+    else
+        return;
+
 }
 }
 
 
 // Load WAV file into Wave structure
 // Load WAV file into Wave structure

+ 19 - 20
src/audio.h

@@ -61,10 +61,7 @@ typedef struct Wave {
     short channels;
     short channels;
 } Wave;
 } Wave;
 
 
-// Audio Context, used to create custom audio streams that are not bound to a sound file. There can be
-// no more than 4 concurrent audio contexts in use. This is due to each active context being tied to
-// a dedicated mix channel.
-typedef void* AudioContext;
+typedef int RawAudioContext;
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {            // Prevents name mangling of functions
 extern "C" {            // Prevents name mangling of functions
@@ -82,13 +79,6 @@ void InitAudioDevice(void);                                     // Initialize au
 void CloseAudioDevice(void);                                    // Close the audio device and context (and music stream)
 void CloseAudioDevice(void);                                    // Close the audio device and context (and music stream)
 bool IsAudioDeviceReady(void);                                  // True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet
 bool IsAudioDeviceReady(void);                                  // True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet
 
 
-// Audio contexts are for outputing custom audio waveforms, This will shut down any other sound sources currently playing
-// The mixChannel is what mix channel you want to operate on, 0-3 are the ones available. Each mix channel can only be used one at a time.
-// exmple usage is InitAudioContext(48000, 0, 2, true); // mixchannel 1, 48khz, stereo, floating point
-AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint);
-void CloseAudioContext(AudioContext ctx);                       // Frees audio context
-unsigned short UpdateAudioContext(AudioContext ctx, void *data, unsigned short numberElements); // Pushes more audio data into context mix channel, if NULL is passed to data then zeros are played
-
 Sound LoadSound(char *fileName);                                // Load sound to memory
 Sound LoadSound(char *fileName);                                // Load sound to memory
 Sound LoadSoundFromWave(Wave wave);                             // Load sound to memory from wave data
 Sound LoadSoundFromWave(Wave wave);                             // Load sound to memory from wave data
 Sound LoadSoundFromRES(const char *rresName, int resId);        // Load sound to memory from rRES file (raylib Resource)
 Sound LoadSoundFromRES(const char *rresName, int resId);        // Load sound to memory from rRES file (raylib Resource)
@@ -100,15 +90,24 @@ bool IsSoundPlaying(Sound sound);                               // Check if a so
 void SetSoundVolume(Sound sound, float volume);                 // Set volume for a sound (1.0 is max level)
 void SetSoundVolume(Sound sound, float volume);                 // Set volume for a sound (1.0 is max level)
 void SetSoundPitch(Sound sound, float pitch);                   // Set pitch for a sound (1.0 is base level)
 void SetSoundPitch(Sound sound, float pitch);                   // Set pitch for a sound (1.0 is base level)
 
 
-void PlayMusicStream(char *fileName);                           // Start music playing (open stream)
-void UpdateMusicStream(void);                                   // Updates buffers for music streaming
-void StopMusicStream(void);                                     // Stop music playing (close stream)
-void PauseMusicStream(void);                                    // Pause music playing
-void ResumeMusicStream(void);                                   // Resume playing paused music
-bool IsMusicPlaying(void);                                      // Check if music is playing
-void SetMusicVolume(float volume);                              // Set volume for music (1.0 is max level)
-float GetMusicTimeLength(void);                                 // Get music time length (in seconds)
-float GetMusicTimePlayed(void);                                 // Get current music time played (in seconds)
+int PlayMusicStream(int musicIndex, char *fileName);            // Start music playing (open stream)
+void UpdateMusicStream(int index);                              // Updates buffers for music streaming
+void StopMusicStream(int index);                                // Stop music playing (close stream)
+void PauseMusicStream(int index);                               // Pause music playing
+void ResumeMusicStream(int index);                              // Resume playing paused music
+bool IsMusicPlaying(int index);                                 // Check if music is playing
+void SetMusicVolume(int index, float volume);                   // Set volume for music (1.0 is max level)
+float GetMusicTimeLength(int index);                            // Get music time length (in seconds)
+float GetMusicTimePlayed(int index);                            // Get current music time played (in seconds)
+int getMusicStreamCount(void);
+void SetMusicPitch(int index, float pitch);
+
+// used to output raw audio streams, returns negative numbers on error
+// if floating point is false the data size is 16bit short, otherwise it is float 32bit
+RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint);
+
+void CloseRawAudioContext(RawAudioContext ctx);
+int BufferRawAudioContext(RawAudioContext ctx, void *data, int numberElements); // returns number of elements buffered
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 5 - 5
src/easings.h

@@ -18,11 +18,11 @@
 *   float speed = 1.f;
 *   float speed = 1.f;
 *   float currentTime = 0.f;
 *   float currentTime = 0.f;
 *   float currentPos[2] = {0,0};
 *   float currentPos[2] = {0,0};
-*   float newPos[2] = {1,1};
-*   float tempPosition[2] = currentPos;//x,y positions
-*   while(currentPos[0] < newPos[0])
-*       currentPos[0] = EaseSineIn(currentTime, tempPosition[0], tempPosition[0]-newPos[0], speed);
-*       currentPos[1] = EaseSineIn(currentTime, tempPosition[1], tempPosition[1]-newPos[0], speed);
+*   float finalPos[2] = {1,1};
+*   float startPosition[2] = currentPos;//x,y positions
+*   while(currentPos[0] < finalPos[0])
+*       currentPos[0] = EaseSineIn(currentTime, startPosition[0], startPosition[0]-finalPos[0], speed);
+*       currentPos[1] = EaseSineIn(currentTime, startPosition[1], startPosition[1]-finalPos[0], speed);
 *       currentTime += diffTime();
 *       currentTime += diffTime();
 *
 *
 *   A port of Robert Penner's easing equations to C (http://robertpenner.com/easing/)
 *   A port of Robert Penner's easing equations to C (http://robertpenner.com/easing/)

+ 67 - 72
src/models.c

@@ -65,6 +65,16 @@ static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize);
 // Module Functions Definition
 // Module Functions Definition
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 
 
+// Draw a line in 3D world space
+void Draw3DLine(Vector3 startPos, Vector3 endPos, Color color)
+{
+    rlBegin(RL_LINES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+        rlVertex3f(startPos.x, startPos.y, startPos.z);
+        rlVertex3f(endPos.x, endPos.y, endPos.z);
+    rlEnd();
+}
+
 // Draw cube
 // Draw cube
 // NOTE: Cube position is the center position
 // NOTE: Cube position is the center position
 void DrawCube(Vector3 position, float width, float height, float length, Color color)
 void DrawCube(Vector3 position, float width, float height, float length, Color color)
@@ -292,9 +302,9 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color
         rlBegin(RL_TRIANGLES);
         rlBegin(RL_TRIANGLES);
             rlColor4ub(color.r, color.g, color.b, color.a);
             rlColor4ub(color.r, color.g, color.b, color.a);
 
 
-            for(int i = 0; i < (rings + 2); i++)
+            for (int i = 0; i < (rings + 2); i++)
             {
             {
-                for(int j = 0; j < slices; j++)
+                for (int j = 0; j < slices; j++)
                 {
                 {
                     rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i)) * sin(DEG2RAD*(j*360/slices)),
                     rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i)) * sin(DEG2RAD*(j*360/slices)),
                                sin(DEG2RAD*(270+(180/(rings + 1))*i)),
                                sin(DEG2RAD*(270+(180/(rings + 1))*i)),
@@ -331,9 +341,9 @@ void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Col
         rlBegin(RL_LINES);
         rlBegin(RL_LINES);
             rlColor4ub(color.r, color.g, color.b, color.a);
             rlColor4ub(color.r, color.g, color.b, color.a);
 
 
-            for(int i = 0; i < (rings + 2); i++)
+            for (int i = 0; i < (rings + 2); i++)
             {
             {
-                for(int j = 0; j < slices; j++)
+                for (int j = 0; j < slices; j++)
                 {
                 {
                     rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i)) * sin(DEG2RAD*(j*360/slices)),
                     rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i)) * sin(DEG2RAD*(j*360/slices)),
                                sin(DEG2RAD*(270+(180/(rings + 1))*i)),
                                sin(DEG2RAD*(270+(180/(rings + 1))*i)),
@@ -376,7 +386,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h
             if (radiusTop > 0)
             if (radiusTop > 0)
             {
             {
                 // Draw Body -------------------------------------------------------------------------------------
                 // Draw Body -------------------------------------------------------------------------------------
-                for(int i = 0; i < 360; i += 360/sides)
+                for (int i = 0; i < 360; i += 360/sides)
                 {
                 {
                     rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom); //Bottom Left
                     rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom); //Bottom Left
                     rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom); //Bottom Right
                     rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom); //Bottom Right
@@ -388,7 +398,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h
                 }
                 }
 
 
                 // Draw Cap --------------------------------------------------------------------------------------
                 // Draw Cap --------------------------------------------------------------------------------------
-                for(int i = 0; i < 360; i += 360/sides)
+                for (int i = 0; i < 360; i += 360/sides)
                 {
                 {
                     rlVertex3f(0, height, 0);
                     rlVertex3f(0, height, 0);
                     rlVertex3f(sin(DEG2RAD*i) * radiusTop, height, cos(DEG2RAD*i) * radiusTop);
                     rlVertex3f(sin(DEG2RAD*i) * radiusTop, height, cos(DEG2RAD*i) * radiusTop);
@@ -398,7 +408,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h
             else
             else
             {
             {
                 // Draw Cone -------------------------------------------------------------------------------------
                 // Draw Cone -------------------------------------------------------------------------------------
-                for(int i = 0; i < 360; i += 360/sides)
+                for (int i = 0; i < 360; i += 360/sides)
                 {
                 {
                     rlVertex3f(0, height, 0);
                     rlVertex3f(0, height, 0);
                     rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom);
                     rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom);
@@ -407,7 +417,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h
             }
             }
 
 
             // Draw Base -----------------------------------------------------------------------------------------
             // Draw Base -----------------------------------------------------------------------------------------
-            for(int i = 0; i < 360; i += 360/sides)
+            for (int i = 0; i < 360; i += 360/sides)
             {
             {
                 rlVertex3f(0, 0, 0);
                 rlVertex3f(0, 0, 0);
                 rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom);
                 rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom);
@@ -421,7 +431,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h
 // NOTE: It could be also used for pyramid and cone
 // NOTE: It could be also used for pyramid and cone
 void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color)
 void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color)
 {
 {
-    if(sides < 3) sides = 3;
+    if (sides < 3) sides = 3;
 
 
     rlPushMatrix();
     rlPushMatrix();
         rlTranslatef(position.x, position.y, position.z);
         rlTranslatef(position.x, position.y, position.z);
@@ -429,7 +439,7 @@ void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, fl
         rlBegin(RL_LINES);
         rlBegin(RL_LINES);
             rlColor4ub(color.r, color.g, color.b, color.a);
             rlColor4ub(color.r, color.g, color.b, color.a);
 
 
-            for(int i = 0; i < 360; i += 360/sides)
+            for (int i = 0; i < 360; i += 360/sides)
             {
             {
                 rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom);
                 rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom);
                 rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom);
                 rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom);
@@ -490,7 +500,7 @@ void DrawGrid(int slices, float spacing)
     int halfSlices = slices / 2;
     int halfSlices = slices / 2;
 
 
     rlBegin(RL_LINES);
     rlBegin(RL_LINES);
-        for(int i = -halfSlices; i <= halfSlices; i++)
+        for (int i = -halfSlices; i <= halfSlices; i++)
         {
         {
             if (i == 0)
             if (i == 0)
             {
             {
@@ -553,7 +563,7 @@ Model LoadModel(const char *fileName)
     if (model.mesh.vertexCount == 0) TraceLog(WARNING, "Model could not be loaded");
     if (model.mesh.vertexCount == 0) TraceLog(WARNING, "Model could not be loaded");
     else
     else
     {
     {
-        rlglLoadMesh(&model.mesh);  // Upload vertex data to GPU
+        rlglLoadMesh(&model.mesh, false);  // Upload vertex data to GPU (static model)
         
         
         model.transform = MatrixIdentity();
         model.transform = MatrixIdentity();
         model.material = LoadDefaultMaterial();
         model.material = LoadDefaultMaterial();
@@ -563,13 +573,13 @@ Model LoadModel(const char *fileName)
 }
 }
 
 
 // Load a 3d model (from vertex data)
 // Load a 3d model (from vertex data)
-Model LoadModelEx(Mesh data)
+Model LoadModelEx(Mesh data, bool dynamic)
 {
 {
     Model model = { 0 };
     Model model = { 0 };
 
 
     model.mesh = data;
     model.mesh = data;
     
     
-    rlglLoadMesh(&model.mesh);      // Upload vertex data to GPU
+    rlglLoadMesh(&model.mesh, dynamic);  // Upload vertex data to GPU
     
     
     model.transform = MatrixIdentity();
     model.transform = MatrixIdentity();
     model.material = LoadDefaultMaterial();
     model.material = LoadDefaultMaterial();
@@ -668,7 +678,7 @@ Model LoadHeightmap(Image heightmap, Vector3 size)
     
     
     model.mesh = GenMeshHeightmap(heightmap, size);
     model.mesh = GenMeshHeightmap(heightmap, size);
     
     
-    rlglLoadMesh(&model.mesh);
+    rlglLoadMesh(&model.mesh, false);  // Upload vertex data to GPU (static model)
     
     
     model.transform = MatrixIdentity();
     model.transform = MatrixIdentity();
     model.material = LoadDefaultMaterial();
     model.material = LoadDefaultMaterial();
@@ -683,7 +693,7 @@ Model LoadCubicmap(Image cubicmap)
     
     
     model.mesh = GenMeshCubicmap(cubicmap, (Vector3){ 1.0, 1.0, 1.5f });
     model.mesh = GenMeshCubicmap(cubicmap, (Vector3){ 1.0, 1.0, 1.5f });
     
     
-    rlglLoadMesh(&model.mesh);
+    rlglLoadMesh(&model.mesh, false);  // Upload vertex data to GPU (static model)
     
     
     model.transform = MatrixIdentity();
     model.transform = MatrixIdentity();
     model.material = LoadDefaultMaterial();
     model.material = LoadDefaultMaterial();
@@ -691,31 +701,14 @@ Model LoadCubicmap(Image cubicmap)
     return model;
     return model;
 }
 }
 
 
-// Unload 3d model from memory
+// Unload 3d model from memory (mesh and material)
 void UnloadModel(Model model)
 void UnloadModel(Model model)
 {
 {
-    // Unload mesh data
-    if (model.mesh.vertices != NULL) free(model.mesh.vertices);
-    if (model.mesh.texcoords != NULL) free(model.mesh.texcoords);
-    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);
-    if (model.mesh.indices != NULL) free(model.mesh.indices);
-    
-    TraceLog(INFO, "Unloaded model data from RAM (CPU)");
-    
-    rlDeleteBuffers(model.mesh.vboId[0]);   // vertex
-    rlDeleteBuffers(model.mesh.vboId[1]);   // texcoords
-    rlDeleteBuffers(model.mesh.vboId[2]);   // normals
-    rlDeleteBuffers(model.mesh.vboId[3]);   // colors
-    rlDeleteBuffers(model.mesh.vboId[4]);   // tangents
-    rlDeleteBuffers(model.mesh.vboId[5]);   // texcoords2
-    rlDeleteBuffers(model.mesh.vboId[6]);   // indices
-
-    rlDeleteVertexArrays(model.mesh.vaoId);
-    
+    rlglUnloadMesh(&model.mesh);
+
     UnloadMaterial(model.material);
     UnloadMaterial(model.material);
+    
+    TraceLog(INFO, "Unloaded model data from RAM and VRAM");
 }
 }
 
 
 // Load material data (from file)
 // Load material data (from file)
@@ -749,6 +742,18 @@ Material LoadDefaultMaterial(void)
     return material;
     return material;
 }
 }
 
 
+// Load standard material (uses material attributes and lighting 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)
 void UnloadMaterial(Material material)
 {
 {
     rlDeleteTextures(material.texDiffuse.id);
     rlDeleteTextures(material.texDiffuse.id);
@@ -793,9 +798,9 @@ static Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
 
 
     Vector3 scaleFactor = { size.x/mapX, size.y/255.0f, size.z/mapZ };
     Vector3 scaleFactor = { size.x/mapX, size.y/255.0f, size.z/mapZ };
 
 
-    for(int z = 0; z < mapZ-1; z++)
+    for (int z = 0; z < mapZ-1; z++)
     {
     {
-        for(int x = 0; x < mapX-1; x++)
+        for (int x = 0; x < mapX-1; x++)
         {
         {
             // Fill vertices array with data
             // Fill vertices array with data
             //----------------------------------------------------------
             //----------------------------------------------------------
@@ -1245,42 +1250,29 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota
     //Matrix matModel = MatrixMultiply(model.transform, matTransform);    // Transform to world-space coordinates
     //Matrix matModel = MatrixMultiply(model.transform, matTransform);    // Transform to world-space coordinates
     
     
     model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
     model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
-    model.material.colDiffuse = tint;
+    // model.material.colDiffuse = tint;
     
     
-    rlglDrawEx(model.mesh, model.material, model.transform, false);
+    rlglDrawMesh(model.mesh, model.material, model.transform);
 }
 }
 
 
 // Draw a model wires (with texture if set)
 // Draw a model wires (with texture if set)
 void DrawModelWires(Model model, Vector3 position, float scale, Color tint)
 void DrawModelWires(Model model, Vector3 position, float scale, Color tint)
 {
 {
-    Vector3 vScale = { scale, scale, scale };
-    Vector3 rotationAxis = { 0.0f, 0.0f, 0.0f };
-
-    // 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);
+    rlEnableWireMode();
     
     
-    model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
-    model.material.colDiffuse = tint;
+    DrawModel(model, position, scale, tint);
     
     
-    rlglDrawEx(model.mesh, model.material, model.transform, true);
+    rlDisableWireMode();
 }
 }
 
 
 // Draw a model wires (with texture if set) with extended parameters
 // 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)
 void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
 {
 {
-    // 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);
+    rlEnableWireMode();
     
     
-    model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
-    model.material.colDiffuse = tint;
+    DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint);
     
     
-    rlglDrawEx(model.mesh, model.material, model.transform, true);
+    rlDisableWireMode();
 }
 }
 
 
 // Draw a billboard
 // Draw a billboard
@@ -1425,7 +1417,7 @@ bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius
     float vector = VectorDotProduct(raySpherePos, ray.direction);
     float vector = VectorDotProduct(raySpherePos, ray.direction);
     float d = sphereRadius*sphereRadius - (distance*distance - vector*vector);
     float d = sphereRadius*sphereRadius - (distance*distance - vector*vector);
     
     
-    if(d >= 0.0f) collision = true;
+    if (d >= 0.0f) collision = true;
     
     
     return collision;
     return collision;
 }
 }
@@ -1440,14 +1432,14 @@ bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadi
     float vector = VectorDotProduct(raySpherePos, ray.direction);
     float vector = VectorDotProduct(raySpherePos, ray.direction);
     float d = sphereRadius*sphereRadius - (distance*distance - vector*vector);
     float d = sphereRadius*sphereRadius - (distance*distance - vector*vector);
     
     
-    if(d >= 0.0f) collision = true;
+    if (d >= 0.0f) collision = true;
     
     
     // Calculate collision point
     // Calculate collision point
     Vector3 offset = ray.direction;
     Vector3 offset = ray.direction;
     float collisionDistance = 0;
     float collisionDistance = 0;
     
     
     // Check if ray origin is inside the sphere to calculate the correct collision point
     // Check if ray origin is inside the sphere to calculate the correct collision point
-    if(distance < sphereRadius) collisionDistance = vector + sqrt(d);
+    if (distance < sphereRadius) collisionDistance = vector + sqrt(d);
     else collisionDistance = vector - sqrt(d);
     else collisionDistance = vector - sqrt(d);
     
     
     VectorScale(&offset, collisionDistance);
     VectorScale(&offset, collisionDistance);
@@ -1785,11 +1777,11 @@ static Mesh LoadOBJ(const char *fileName)
     // First reading pass: Get numVertex, numNormals, numTexCoords, numTriangles
     // First reading pass: Get numVertex, numNormals, numTexCoords, numTriangles
     // NOTE: vertex, texcoords and normals could be optimized (to be used indexed on faces definition)
     // NOTE: vertex, texcoords and normals could be optimized (to be used indexed on faces definition)
     // NOTE: faces MUST be defined as TRIANGLES (3 vertex per face)
     // NOTE: faces MUST be defined as TRIANGLES (3 vertex per face)
-    while(!feof(objFile))
+    while (!feof(objFile))
     {
     {
         fscanf(objFile, "%c", &dataType);
         fscanf(objFile, "%c", &dataType);
 
 
-        switch(dataType)
+        switch (dataType)
         {
         {
             case '#':   // Comments
             case '#':   // Comments
             case 'o':   // Object name (One OBJ file can contain multible named meshes)
             case 'o':   // Object name (One OBJ file can contain multible named meshes)
@@ -1850,11 +1842,11 @@ static Mesh LoadOBJ(const char *fileName)
     // Second reading pass: Get vertex data to fill intermediate arrays
     // Second reading pass: Get vertex data to fill intermediate arrays
     // NOTE: This second pass is required in case of multiple meshes defined in same OBJ
     // NOTE: This second pass is required in case of multiple meshes defined in same OBJ
     // TODO: Consider that different meshes can have different vertex data available (position, texcoords, normals)
     // TODO: Consider that different meshes can have different vertex data available (position, texcoords, normals)
-    while(!feof(objFile))
+    while (!feof(objFile))
     {
     {
         fscanf(objFile, "%c", &dataType);
         fscanf(objFile, "%c", &dataType);
 
 
-        switch(dataType)
+        switch (dataType)
         {
         {
             case '#': case 'o': case 'g': case 's': case 'm': case 'u': case 'f': fgets(comments, 200, objFile); break;
             case '#': case 'o': case 'g': case 's': case 'm': case 'u': case 'f': fgets(comments, 200, objFile); break;
             case 'v':
             case 'v':
@@ -1911,11 +1903,11 @@ static Mesh LoadOBJ(const char *fileName)
     if (numNormals == 0) TraceLog(INFO, "[%s] No normals data on OBJ, normals will be generated from faces data", fileName);
     if (numNormals == 0) TraceLog(INFO, "[%s] No normals data on OBJ, normals will be generated from faces data", fileName);
 
 
     // Third reading pass: Get faces (triangles) data and fill VertexArray
     // Third reading pass: Get faces (triangles) data and fill VertexArray
-    while(!feof(objFile))
+    while (!feof(objFile))
     {
     {
         fscanf(objFile, "%c", &dataType);
         fscanf(objFile, "%c", &dataType);
 
 
-        switch(dataType)
+        switch (dataType)
         {
         {
             case '#': case 'o': case 'g': case 's': case 'm': case 'u': case 'v': fgets(comments, 200, objFile); break;
             case '#': case 'o': case 'g': case 's': case 'm': case 'u': case 'v': fgets(comments, 200, objFile); break;
             case 'f':
             case 'f':
@@ -2031,7 +2023,7 @@ static Material LoadMTL(const char *fileName)
         return material;
         return material;
     }
     }
 
 
-    while(!feof(mtlFile))
+    while (!feof(mtlFile))
     {
     {
         fgets(buffer, MAX_BUFFER_SIZE, mtlFile);
         fgets(buffer, MAX_BUFFER_SIZE, mtlFile);
         
         
@@ -2086,7 +2078,10 @@ static Material LoadMTL(const char *fileName)
             {
             {
                 if (buffer[1] == 's')       // Ns int   Shininess (specular exponent). Ranges from 0 to 1000.
                 if (buffer[1] == 's')       // Ns int   Shininess (specular exponent). Ranges from 0 to 1000.
                 {
                 {
-                    sscanf(buffer, "Ns %i", &material.glossiness);
+                    int shininess = 0;
+                    sscanf(buffer, "Ns %i", &shininess);
+                    
+                    material.glossiness = (float)shininess;
                 }
                 }
                 else if (buffer[1] == 'i')  // Ni int   Refraction index.
                 else if (buffer[1] == 'i')  // Ni int   Refraction index.
                 {
                 {

+ 6 - 6
src/physac.c

@@ -49,7 +49,7 @@
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Global Variables Definition
 // Global Variables Definition
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
-static PhysicObject *physicObjects[MAX_PHYSIC_OBJECTS];             // Physic objects pool
+static PhysicObject physicObjects[MAX_PHYSIC_OBJECTS];              // Physic objects pool
 static int physicObjectsCount;                                      // Counts current enabled physic objects
 static int physicObjectsCount;                                      // Counts current enabled physic objects
 static Vector2 gravityForce;                                        // Gravity force
 static Vector2 gravityForce;                                        // Gravity force
 
 
@@ -463,10 +463,10 @@ void ClosePhysics()
 }
 }
 
 
 // Create a new physic object dinamically, initialize it and add to pool
 // Create a new physic object dinamically, initialize it and add to pool
-PhysicObject *CreatePhysicObject(Vector2 position, float rotation, Vector2 scale)
+PhysicObject CreatePhysicObject(Vector2 position, float rotation, Vector2 scale)
 {
 {
     // Allocate dynamic memory
     // Allocate dynamic memory
-    PhysicObject *obj = (PhysicObject *)malloc(sizeof(PhysicObject));
+    PhysicObject obj = (PhysicObject)malloc(sizeof(PhysicObjectData));
     
     
     // Initialize physic object values with generic values
     // Initialize physic object values with generic values
     obj->id = physicObjectsCount;
     obj->id = physicObjectsCount;
@@ -498,7 +498,7 @@ PhysicObject *CreatePhysicObject(Vector2 position, float rotation, Vector2 scale
 }
 }
 
 
 // Destroy a specific physic object and take it out of the list
 // Destroy a specific physic object and take it out of the list
-void DestroyPhysicObject(PhysicObject *pObj)
+void DestroyPhysicObject(PhysicObject pObj)
 {
 {
     // Free dynamic memory allocation
     // Free dynamic memory allocation
     free(physicObjects[pObj->id]);
     free(physicObjects[pObj->id]);
@@ -520,7 +520,7 @@ void DestroyPhysicObject(PhysicObject *pObj)
 }
 }
 
 
 // Apply directional force to a physic object
 // Apply directional force to a physic object
-void ApplyForce(PhysicObject *pObj, Vector2 force)
+void ApplyForce(PhysicObject pObj, Vector2 force)
 {
 {
     if (pObj->rigidbody.enabled)
     if (pObj->rigidbody.enabled)
     {
     {
@@ -571,7 +571,7 @@ Rectangle TransformToRectangle(Transform transform)
 }
 }
 
 
 // Draw physic object information at screen position
 // Draw physic object information at screen position
-void DrawPhysicObjectInfo(PhysicObject *pObj, Vector2 position, int fontSize)
+void DrawPhysicObjectInfo(PhysicObject pObj, Vector2 position, int fontSize)
 {
 {
     // Draw physic object ID
     // Draw physic object ID
     DrawText(FormatText("PhysicObject ID: %i - Enabled: %i", pObj->id, pObj->enabled), position.x, position.y, fontSize, BLACK);
     DrawText(FormatText("PhysicObject ID: %i - Enabled: %i", pObj->id, pObj->enabled), position.x, position.y, fontSize, BLACK);

+ 6 - 6
src/physac.h

@@ -66,13 +66,13 @@ typedef struct Collider {
     int radius;             // Used for COLLIDER_CIRCLE
     int radius;             // Used for COLLIDER_CIRCLE
 } Collider;
 } Collider;
 
 
-typedef struct PhysicObject {
+typedef struct PhysicObjectData {
     unsigned int id;
     unsigned int id;
     Transform transform;
     Transform transform;
     Rigidbody rigidbody;
     Rigidbody rigidbody;
     Collider collider;
     Collider collider;
     bool enabled;
     bool enabled;
-} PhysicObject;
+} PhysicObjectData, *PhysicObject;
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {            // Prevents name mangling of functions
 extern "C" {            // Prevents name mangling of functions
@@ -85,14 +85,14 @@ void InitPhysics(Vector2 gravity);
 void UpdatePhysics();                                                                   // Update physic objects, calculating physic behaviours and collisions detection
 void UpdatePhysics();                                                                   // Update physic objects, calculating physic behaviours and collisions detection
 void ClosePhysics();                                                                    // Unitialize all physic objects and empty the objects pool
 void ClosePhysics();                                                                    // Unitialize all physic objects and empty the objects pool
 
 
-PhysicObject *CreatePhysicObject(Vector2 position, float rotation, Vector2 scale);      // Create a new physic object dinamically, initialize it and add to pool
-void DestroyPhysicObject(PhysicObject *pObj);                                           // Destroy a specific physic object and take it out of the list
+PhysicObject CreatePhysicObject(Vector2 position, float rotation, Vector2 scale);       // Create a new physic object dinamically, initialize it and add to pool
+void DestroyPhysicObject(PhysicObject pObj);                                            // Destroy a specific physic object and take it out of the list
 
 
-void ApplyForce(PhysicObject *pObj, Vector2 force);                                     // Apply directional force to a physic object
+void ApplyForce(PhysicObject pObj, Vector2 force);                                      // Apply directional force to a physic object
 void ApplyForceAtPosition(Vector2 position, float force, float radius);                 // Apply radial force to all physic objects in range
 void ApplyForceAtPosition(Vector2 position, float force, float radius);                 // Apply radial force to all physic objects in range
 
 
 Rectangle TransformToRectangle(Transform transform);                                    // Convert Transform data type to Rectangle (position and scale)
 Rectangle TransformToRectangle(Transform transform);                                    // Convert Transform data type to Rectangle (position and scale)
-void DrawPhysicObjectInfo(PhysicObject *pObj, Vector2 position, int fontSize);          // Draw physic object information at screen position
+void DrawPhysicObjectInfo(PhysicObject pObj, Vector2 position, int fontSize);           // Draw physic object information at screen position
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 55 - 31
src/raylib.h

@@ -398,7 +398,7 @@ typedef struct Shader {
 
 
     // Uniform locations
     // Uniform locations
     int mvpLoc;           // ModelView-Projection matrix uniform location point (vertex shader)
     int mvpLoc;           // ModelView-Projection matrix uniform location point (vertex shader)
-    int tintColorLoc;     // Color uniform location point (fragment shader)
+    int tintColorLoc;     // Diffuse color uniform location point (fragment shader)
     
     
     // Texture map locations
     // Texture map locations
     int mapDiffuseLoc;    // Diffuse map texture uniform location point (fragment shader)
     int mapDiffuseLoc;    // Diffuse map texture uniform location point (fragment shader)
@@ -418,18 +418,36 @@ typedef struct Material {
     Color colAmbient;           // Ambient color
     Color colAmbient;           // Ambient color
     Color colSpecular;          // Specular color
     Color colSpecular;          // Specular color
     
     
-    float glossiness;           // Glossiness level
+    float glossiness;           // Glossiness level (Ranges from 0 to 1000)
     float normalDepth;          // Normal map depth
     float normalDepth;          // Normal map depth
 } Material;
 } Material;
 
 
-// 3d Model type
-// TODO: Replace shader/testure by material
+// Model type
 typedef struct Model {
 typedef struct Model {
     Mesh mesh;                  // Vertex data buffers (RAM and VRAM)
     Mesh mesh;                  // Vertex data buffers (RAM and VRAM)
     Matrix transform;           // Local transform matrix
     Matrix transform;           // Local transform matrix
     Material material;          // Shader and textures data
     Material material;          // Shader and textures data
 } Model;
 } Model;
 
 
+// Light type
+typedef struct LightData {
+    int id;
+    int type;           // LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT
+    bool enabled;
+    
+    Vector3 position;
+    Vector3 target;     // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target)
+    float attenuation;  // Lost of light intensity with distance (world distance)
+    
+    Color diffuse;      // Use Vector3 diffuse
+    float intensity;
+    
+    float coneAngle;    // Spot light max angle
+} LightData, *Light;
+
+// Light types
+typedef enum { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT } LightType;
+
 // Ray type (useful for raycast)
 // Ray type (useful for raycast)
 typedef struct Ray {
 typedef struct Ray {
     Vector3 position;
     Vector3 position;
@@ -451,10 +469,7 @@ typedef struct Wave {
     short channels;
     short channels;
 } Wave;
 } Wave;
 
 
-// Audio Context, used to create custom audio streams that are not bound to a sound file. There can be
-// no more than 4 concurrent audio contexts in use. This is due to each active context being tied to
-// a dedicated mix channel.
-typedef void* AudioContext;
+typedef int RawAudioContext;
 
 
 // Texture formats
 // Texture formats
 // NOTE: Support depends on OpenGL version and platform
 // NOTE: Support depends on OpenGL version and platform
@@ -539,13 +554,13 @@ typedef struct Collider {
     int radius;             // Used for COLLIDER_CIRCLE
     int radius;             // Used for COLLIDER_CIRCLE
 } Collider;
 } Collider;
 
 
-typedef struct PhysicObject {
+typedef struct PhysicObjectData {
     unsigned int id;
     unsigned int id;
     Transform transform;
     Transform transform;
     Rigidbody rigidbody;
     Rigidbody rigidbody;
     Collider collider;
     Collider collider;
     bool enabled;
     bool enabled;
-} PhysicObject;
+} PhysicObjectData, *PhysicObject;
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {            // Prevents name mangling of functions
 extern "C" {            // Prevents name mangling of functions
@@ -787,6 +802,7 @@ const char *SubText(const char *text, int position, int length);
 //------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------
 // Basic 3d Shapes Drawing Functions (Module: models)
 // Basic 3d Shapes Drawing Functions (Module: models)
 //------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------
+void Draw3DLine(Vector3 startPos, Vector3 endPos, Color color);                                    // Draw a line in 3D world space
 void DrawCube(Vector3 position, float width, float height, float lenght, Color color);             // Draw cube
 void DrawCube(Vector3 position, float width, float height, float lenght, Color color);             // Draw cube
 void DrawCubeV(Vector3 position, Vector3 size, Color color);                                       // Draw cube (Vector version)
 void DrawCubeV(Vector3 position, Vector3 size, Color color);                                       // Draw cube (Vector version)
 void DrawCubeWires(Vector3 position, float width, float height, float lenght, Color color);        // Draw cube wires
 void DrawCubeWires(Vector3 position, float width, float height, float lenght, Color color);        // Draw cube wires
@@ -806,7 +822,7 @@ void DrawGizmo(Vector3 position);
 // Model 3d Loading and Drawing Functions (Module: models)
 // Model 3d Loading and Drawing Functions (Module: models)
 //------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------
 Model LoadModel(const char *fileName);                          // Load a 3d model (.OBJ)
 Model LoadModel(const char *fileName);                          // Load a 3d model (.OBJ)
-Model LoadModelEx(Mesh data);                                   // Load a 3d model (from mesh data)
+Model LoadModelEx(Mesh data, bool dynamic);                     // Load a 3d model (from mesh data)
 Model LoadModelFromRES(const char *rresName, int resId);        // Load a 3d model from rRES file (raylib Resource)
 Model LoadModelFromRES(const char *rresName, int resId);        // Load a 3d model from rRES file (raylib Resource)
 Model LoadHeightmap(Image heightmap, Vector3 size);             // Load a heightmap image as a 3d model
 Model 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)
 Model LoadCubicmap(Image cubicmap);                             // Load a map image as a 3d model (cubes based)
@@ -815,6 +831,7 @@ void SetModelTexture(Model *model, Texture2D texture);          // Link a textur
 
 
 Material LoadMaterial(const char *fileName);                    // Load material data (from file)
 Material LoadMaterial(const char *fileName);                    // Load material data (from file)
 Material LoadDefaultMaterial(void);                             // Load default material (uses default models shader)
 Material LoadDefaultMaterial(void);                             // Load default material (uses default models shader)
+Material LoadStandardMaterial(void);                            // Load standard material (uses material attributes and lighting shader)
 void UnloadMaterial(Material material);                         // Unload material textures from VRAM
 void UnloadMaterial(Material material);                         // Unload material textures from VRAM
 
 
 void DrawModel(Model model, Vector3 position, float scale, Color tint);                            // Draw a model (with texture if set)
 void DrawModel(Model model, Vector3 position, float scale, Color tint);                            // Draw a model (with texture if set)
@@ -844,6 +861,7 @@ void UnloadShader(Shader shader);                                   // Unload a
 void SetDefaultShader(void);                                        // Set default shader to be used in batch draw
 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 SetCustomShader(Shader shader);                                // Set custom shader to be used in batch draw
 Shader GetDefaultShader(void);                                      // Get default shader
 Shader GetDefaultShader(void);                                      // Get default shader
+Shader GetStandardShader(void);                                     // Get default shader
 Texture2D GetDefaultTexture(void);                                  // Get default texture
 Texture2D GetDefaultTexture(void);                                  // Get default texture
 
 
 int GetShaderLocation(Shader shader, const char *uniformName);              // Get shader uniform location
 int GetShaderLocation(Shader shader, const char *uniformName);              // Get shader uniform location
@@ -853,6 +871,10 @@ void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat);       // S
 
 
 void SetBlendMode(int mode);                                        // Set blending mode (alpha, additive, multiplied)
 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 DrawLights(void);                                              // Draw all created lights in 3D world
+void DestroyLight(Light light);                                     // Destroy a light and take it out of the list
+
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Physics System Functions (Module: physac)
 // Physics System Functions (Module: physac)
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
@@ -860,14 +882,14 @@ void InitPhysics(Vector2 gravity);
 void UpdatePhysics();                                                                   // Update physic objects, calculating physic behaviours and collisions detection
 void UpdatePhysics();                                                                   // Update physic objects, calculating physic behaviours and collisions detection
 void ClosePhysics();                                                                    // Unitialize all physic objects and empty the objects pool
 void ClosePhysics();                                                                    // Unitialize all physic objects and empty the objects pool
 
 
-PhysicObject *CreatePhysicObject(Vector2 position, float rotation, Vector2 scale);      // Create a new physic object dinamically, initialize it and add to pool
-void DestroyPhysicObject(PhysicObject *pObj);                                           // Destroy a specific physic object and take it out of the list
+PhysicObject CreatePhysicObject(Vector2 position, float rotation, Vector2 scale);       // Create a new physic object dinamically, initialize it and add to pool
+void DestroyPhysicObject(PhysicObject pObj);                                            // Destroy a specific physic object and take it out of the list
 
 
-void ApplyForce(PhysicObject *pObj, Vector2 force);                                     // Apply directional force to a physic object
+void ApplyForce(PhysicObject pObj, Vector2 force);                                      // Apply directional force to a physic object
 void ApplyForceAtPosition(Vector2 position, float force, float radius);                 // Apply radial force to all physic objects in range
 void ApplyForceAtPosition(Vector2 position, float force, float radius);                 // Apply radial force to all physic objects in range
 
 
 Rectangle TransformToRectangle(Transform transform);                                    // Convert Transform data type to Rectangle (position and scale)
 Rectangle TransformToRectangle(Transform transform);                                    // Convert Transform data type to Rectangle (position and scale)
-void DrawPhysicObjectInfo(PhysicObject *pObj, Vector2 position, int fontSize);          // Draw physic object information at screen position
+void DrawPhysicObjectInfo(PhysicObject pObj, Vector2 position, int fontSize);           // Draw physic object information at screen position
 
 
 //------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------
 // Audio Loading and Playing Functions (Module: audio)
 // Audio Loading and Playing Functions (Module: audio)
@@ -876,13 +898,6 @@ void InitAudioDevice(void);                                     // Initialize au
 void CloseAudioDevice(void);                                    // Close the audio device and context (and music stream)
 void CloseAudioDevice(void);                                    // Close the audio device and context (and music stream)
 bool IsAudioDeviceReady(void);                                  // True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet
 bool IsAudioDeviceReady(void);                                  // True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet
 
 
-// Audio contexts are for outputing custom audio waveforms, This will shut down any other sound sources currently playing
-// The mixChannel is what mix channel you want to operate on, 0-3 are the ones available. Each mix channel can only be used one at a time.
-// exmple usage is InitAudioContext(48000, 0, 2, true); // mixchannel 1, 48khz, stereo, floating point
-AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint);
-void CloseAudioContext(AudioContext ctx);                       // Frees audio context
-unsigned short UpdateAudioContext(AudioContext ctx, void *data, unsigned short numberElements); // Pushes more audio data into context mix channel, if NULL is passed to data then zeros are played
-
 Sound LoadSound(char *fileName);                                // Load sound to memory
 Sound LoadSound(char *fileName);                                // Load sound to memory
 Sound LoadSoundFromWave(Wave wave);                             // Load sound to memory from wave data
 Sound LoadSoundFromWave(Wave wave);                             // Load sound to memory from wave data
 Sound LoadSoundFromRES(const char *rresName, int resId);        // Load sound to memory from rRES file (raylib Resource)
 Sound LoadSoundFromRES(const char *rresName, int resId);        // Load sound to memory from rRES file (raylib Resource)
@@ -894,15 +909,24 @@ bool IsSoundPlaying(Sound sound);                               // Check if a so
 void SetSoundVolume(Sound sound, float volume);                 // Set volume for a sound (1.0 is max level)
 void SetSoundVolume(Sound sound, float volume);                 // Set volume for a sound (1.0 is max level)
 void SetSoundPitch(Sound sound, float pitch);                   // Set pitch for a sound (1.0 is base level)
 void SetSoundPitch(Sound sound, float pitch);                   // Set pitch for a sound (1.0 is base level)
 
 
-void PlayMusicStream(char *fileName);                           // Start music playing (open stream)
-void UpdateMusicStream(void);                                   // Updates buffers for music streaming
-void StopMusicStream(void);                                     // Stop music playing (close stream)
-void PauseMusicStream(void);                                    // Pause music playing
-void ResumeMusicStream(void);                                   // Resume playing paused music
-bool IsMusicPlaying(void);                                      // Check if music is playing
-void SetMusicVolume(float volume);                              // Set volume for music (1.0 is max level)
-float GetMusicTimeLength(void);                                 // Get current music time length (in seconds)
-float GetMusicTimePlayed(void);                                 // Get current music time played (in seconds)
+int PlayMusicStream(int musicIndex, char *fileName);            // Start music playing (open stream)
+void UpdateMusicStream(int index);                              // Updates buffers for music streaming
+void StopMusicStream(int index);                                // Stop music playing (close stream)
+void PauseMusicStream(int index);                               // Pause music playing
+void ResumeMusicStream(int index);                              // Resume playing paused music
+bool IsMusicPlaying(int index);                                 // Check if music is playing
+void SetMusicVolume(int index, float volume);                   // Set volume for music (1.0 is max level)
+float GetMusicTimeLength(int index);                            // Get current music time length (in seconds)
+float GetMusicTimePlayed(int index);                            // Get current music time played (in seconds)
+int getMusicStreamCount(void);
+void SetMusicPitch(int index, float pitch);
+
+// used to output raw audio streams, returns negative numbers on error
+// if floating point is false the data size is 16bit short, otherwise it is float 32bit
+RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint);
+
+void CloseRawAudioContext(RawAudioContext ctx);
+int BufferRawAudioContext(RawAudioContext ctx, void *data, int numberElements); // returns number of elements buffered
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 514 - 189
src/rlgl.c

@@ -71,6 +71,8 @@
 #define MAX_DRAWS_BY_TEXTURE      256   // Draws are organized by texture changes
 #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)
 #define TEMP_VERTEX_BUFFER_SIZE  4096   // Temporal Vertex Buffer (required for vertex-transformations)
                                         // NOTE: Every vertex are 3 floats (12 bytes)
                                         // NOTE: Every vertex are 3 floats (12 bytes)
+                                        
+#define MAX_LIGHTS                  8   // Max lights supported by standard shader
 
 
 #ifndef GL_SHADING_LANGUAGE_VERSION
 #ifndef GL_SHADING_LANGUAGE_VERSION
     #define GL_SHADING_LANGUAGE_VERSION         0x8B8C
     #define GL_SHADING_LANGUAGE_VERSION         0x8B8C
@@ -189,6 +191,7 @@ static bool useTempBuffer = false;
 
 
 // Shader Programs
 // Shader Programs
 static Shader defaultShader;
 static Shader defaultShader;
+static Shader standardShader;
 static Shader currentShader;            // By default, defaultShader
 static Shader currentShader;            // By default, defaultShader
 
 
 // Flags for supported extensions
 // Flags for supported extensions
@@ -199,6 +202,10 @@ static bool texCompETC1Supported = false;    // ETC1 texture compression support
 static bool texCompETC2Supported = false;    // ETC2/EAC texture compression support
 static bool texCompETC2Supported = false;    // ETC2/EAC texture compression support
 static bool texCompPVRTSupported = false;    // PVR texture compression support
 static bool texCompPVRTSupported = false;    // PVR texture compression support
 static bool texCompASTCSupported = false;    // ASTC 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
 #endif
 
 
 // Compressed textures support flags
 // Compressed textures support flags
@@ -227,14 +234,18 @@ 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 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 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 LoadDefaultShaderLocations(Shader *shader); // Bind default shader locations (attributes and uniforms)
 static void UnloadDefaultShader(void);      // Unload default shader
 static void UnloadDefaultShader(void);      // Unload default shader
+static void UnloadStandardShader(void);      // Unload standard shader
 
 
 static void LoadDefaultBuffers(void);       // Load default internal buffers (lines, triangles, quads)
 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 UpdateDefaultBuffers(void);     // Update default internal buffers (VAOs/VBOs) with vertex data
 static void DrawDefaultBuffers(void);       // Draw default internal buffers 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 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);
 static char *ReadTextFile(const char *fileName);
 #endif
 #endif
 
 
@@ -740,6 +751,24 @@ void rlDisableDepthTest(void)
     glDisable(GL_DEPTH_TEST);
     glDisable(GL_DEPTH_TEST);
 }
 }
 
 
+// Enable wire mode
+void rlEnableWireMode(void)
+{
+#if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
+    // NOTE: glPolygonMode() not available on OpenGL ES
+    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+#endif
+}
+
+// Disable wire mode
+void rlDisableWireMode(void)
+{
+#if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
+    // NOTE: glPolygonMode() not available on OpenGL ES
+    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+#endif
+}
+
 // Unload texture from GPU memory
 // Unload texture from GPU memory
 void rlDeleteTextures(unsigned int id)
 void rlDeleteTextures(unsigned int id)
 {
 {
@@ -991,6 +1020,7 @@ void rlglInit(void)
 
 
     // Init default Shader (customized for GL 3.3 and ES2)
     // Init default Shader (customized for GL 3.3 and ES2)
     defaultShader = LoadDefaultShader();
     defaultShader = LoadDefaultShader();
+    standardShader = LoadStandardShader();
     currentShader = defaultShader;
     currentShader = defaultShader;
 
 
     LoadDefaultBuffers();        // Initialize default vertex arrays buffers (lines, triangles, quads)
     LoadDefaultBuffers();        // Initialize default vertex arrays buffers (lines, triangles, quads)
@@ -1019,6 +1049,7 @@ void rlglClose(void)
 {
 {
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
     UnloadDefaultShader();
     UnloadDefaultShader();
+    UnloadStandardShader();
     UnloadDefaultBuffers();
     UnloadDefaultBuffers();
     
     
     // Delete default white texture
     // Delete default white texture
@@ -1033,175 +1064,15 @@ void rlglClose(void)
 void rlglDraw(void)
 void rlglDraw(void)
 {
 {
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-    UpdateDefaultBuffers();
-    DrawDefaultBuffers();
-#endif
-}
-
-// 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
-    if (wires) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-#endif
-
-#if defined(GRAPHICS_API_OPENGL_11)
-    glEnable(GL_TEXTURE_2D);
-    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
-    if (mesh.normals != NULL) glEnableClientState(GL_NORMAL_ARRAY);     // Enable normals array
-    if (mesh.colors != NULL) glEnableClientState(GL_COLOR_ARRAY);       // Enable colors array
-
-    glVertexPointer(3, GL_FLOAT, 0, mesh.vertices);         // Pointer to vertex coords array
-    glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords);      // Pointer to texture coords array
-    if (mesh.normals != NULL) glNormalPointer(GL_FLOAT, 0, mesh.normals);           // Pointer to normals array
-    if (mesh.colors != NULL) glColorPointer(4, GL_UNSIGNED_BYTE, 0, mesh.colors);   // Pointer to colors array
-
-    rlPushMatrix();
-        rlMultMatrixf(MatrixToFloat(transform));
-        rlColor4ub(material.colDiffuse.r, material.colDiffuse.g, material.colDiffuse.b, material.colDiffuse.a);
-        
-        if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, mesh.indices);
-        else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
-    rlPopMatrix();
-
-    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(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 model-view matrix combining matModel and matView
-    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(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);
-
-    // Set shader textures (diffuse, normal, specular)
-    glActiveTexture(GL_TEXTURE0);
-    glBindTexture(GL_TEXTURE_2D, material.texDiffuse.id);
-    glUniform1i(material.shader.mapDiffuseLoc, 0);        // Texture fits in active texture unit 0
-    
-    if ((material.texNormal.id != 0) && (material.shader.mapNormalLoc != -1))
-    {
-        glActiveTexture(GL_TEXTURE1);
-        glBindTexture(GL_TEXTURE_2D, material.texNormal.id);
-        glUniform1i(material.shader.mapNormalLoc, 1);     // Texture fits in active texture unit 1
-    }
-    
-    if ((material.texSpecular.id != 0) && (material.shader.mapSpecularLoc != -1))
-    {
-        glActiveTexture(GL_TEXTURE2);
-        glBindTexture(GL_TEXTURE_2D, material.texSpecular.id);
-        glUniform1i(material.shader.mapSpecularLoc, 2);   // Texture fits in active texture unit 2
-    }
-
-    if (vaoSupported)
-    {
-        glBindVertexArray(mesh.vaoId);
-    }
-    else
-    {
-        // 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 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 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, mesh.vboId[3]);
-            glVertexAttribPointer(material.shader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
-            glEnableVertexAttribArray(material.shader.colorLoc);
-        }
-        
-        // Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
-        if (material.shader.tangentLoc != -1)
-        {
-            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[4]);
-            glVertexAttribPointer(material.shader.tangentLoc, 3, GL_FLOAT, 0, 0, 0);
-            glEnableVertexAttribArray(material.shader.tangentLoc);
-        }
-        
-        // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
-        if (material.shader.texcoord2Loc != -1)
-        {
-            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[5]);
-            glVertexAttribPointer(material.shader.texcoord2Loc, 2, GL_FLOAT, 0, 0, 0);
-            glEnableVertexAttribArray(material.shader.texcoord2Loc);
-        }
-        
-        if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]);
-    }
-
-    // Draw call!
-    if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, 0); // Indexed vertices draw
-    else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
-    
-    if (material.texNormal.id != 0)
-    {
-        glActiveTexture(GL_TEXTURE1);
-        glBindTexture(GL_TEXTURE_2D, 0);
-    }
-    
-    if (material.texSpecular.id != 0)
+/*
+    for (int i = 0; i < modelsCount; i++)
     {
     {
-        glActiveTexture(GL_TEXTURE2);
-        glBindTexture(GL_TEXTURE_2D, 0);
+        rlglDrawMesh(models[i]->mesh, models[i]->material, models[i]->transform);
     }
     }
-
-    glActiveTexture(GL_TEXTURE0);               // Set shader active texture to default 0
-    glBindTexture(GL_TEXTURE_2D, 0);            // Unbind textures
-
-    if (vaoSupported) glBindVertexArray(0);     // Unbind VAO
-    else
-    {
-        glBindBuffer(GL_ARRAY_BUFFER, 0);      // Unbind VBOs
-        if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-    }
-
-    glUseProgram(0);        // Unbind shader program
-#endif
-
-#if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
-    // NOTE: glPolygonMode() not available on OpenGL ES
-    if (wires) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+*/
+    // NOTE: Default buffers always drawn at the end
+    UpdateDefaultBuffers();
+    DrawDefaultBuffers();
 #endif
 #endif
 }
 }
 
 
@@ -1526,7 +1397,7 @@ RenderTexture2D rlglLoadRenderTexture(int width, int height)
     {
     {
         TraceLog(WARNING, "Framebuffer object could not be created...");
         TraceLog(WARNING, "Framebuffer object could not be created...");
         
         
-        switch(status)
+        switch (status)
         {
         {
             case GL_FRAMEBUFFER_UNSUPPORTED: TraceLog(WARNING, "Framebuffer is unsupported"); break;
             case GL_FRAMEBUFFER_UNSUPPORTED: TraceLog(WARNING, "Framebuffer is unsupported"); break;
             case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: TraceLog(WARNING, "Framebuffer incomplete attachment"); break;
             case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: TraceLog(WARNING, "Framebuffer incomplete attachment"); break;
@@ -1642,7 +1513,7 @@ void rlglGenerateMipmaps(Texture2D texture)
 }
 }
 
 
 // Upload vertex data into a VAO (if supported) and VBO
 // Upload vertex data into a VAO (if supported) and VBO
-void rlglLoadMesh(Mesh *mesh)
+void rlglLoadMesh(Mesh *mesh, bool dynamic)
 {
 {
     mesh->vaoId = 0;        // Vertex Array Object
     mesh->vaoId = 0;        // Vertex Array Object
     mesh->vboId[0] = 0;     // Vertex positions VBO
     mesh->vboId[0] = 0;     // Vertex positions VBO
@@ -1652,6 +1523,9 @@ void rlglLoadMesh(Mesh *mesh)
     mesh->vboId[4] = 0;     // Vertex tangents VBO
     mesh->vboId[4] = 0;     // Vertex tangents VBO
     mesh->vboId[5] = 0;     // Vertex texcoords2 VBO
     mesh->vboId[5] = 0;     // Vertex texcoords2 VBO
     mesh->vboId[6] = 0;     // Vertex indices VBO
     mesh->vboId[6] = 0;     // Vertex indices VBO
+    
+    int drawHint = GL_STATIC_DRAW;
+    if (dynamic) drawHint = GL_DYNAMIC_DRAW;
 
 
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
     GLuint vaoId = 0;       // Vertex Array Objects (VAO)
     GLuint vaoId = 0;       // Vertex Array Objects (VAO)
@@ -1669,14 +1543,14 @@ void rlglLoadMesh(Mesh *mesh)
     // Enable vertex attributes: position (shader-location = 0)
     // Enable vertex attributes: position (shader-location = 0)
     glGenBuffers(1, &vboId[0]);
     glGenBuffers(1, &vboId[0]);
     glBindBuffer(GL_ARRAY_BUFFER, vboId[0]);
     glBindBuffer(GL_ARRAY_BUFFER, vboId[0]);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->vertices, GL_STATIC_DRAW);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->vertices, drawHint);
     glVertexAttribPointer(0, 3, GL_FLOAT, 0, 0, 0);
     glVertexAttribPointer(0, 3, GL_FLOAT, 0, 0, 0);
     glEnableVertexAttribArray(0);
     glEnableVertexAttribArray(0);
 
 
     // Enable vertex attributes: texcoords (shader-location = 1)
     // Enable vertex attributes: texcoords (shader-location = 1)
     glGenBuffers(1, &vboId[1]);
     glGenBuffers(1, &vboId[1]);
     glBindBuffer(GL_ARRAY_BUFFER, vboId[1]);
     glBindBuffer(GL_ARRAY_BUFFER, vboId[1]);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords, GL_STATIC_DRAW);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords, drawHint);
     glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, 0);
     glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, 0);
     glEnableVertexAttribArray(1);
     glEnableVertexAttribArray(1);
 
 
@@ -1685,7 +1559,7 @@ void rlglLoadMesh(Mesh *mesh)
     {
     {
         glGenBuffers(1, &vboId[2]);
         glGenBuffers(1, &vboId[2]);
         glBindBuffer(GL_ARRAY_BUFFER, vboId[2]);
         glBindBuffer(GL_ARRAY_BUFFER, vboId[2]);
-        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->normals, GL_STATIC_DRAW);
+        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->normals, drawHint);
         glVertexAttribPointer(2, 3, GL_FLOAT, 0, 0, 0);
         glVertexAttribPointer(2, 3, GL_FLOAT, 0, 0, 0);
         glEnableVertexAttribArray(2);
         glEnableVertexAttribArray(2);
     }
     }
@@ -1701,7 +1575,7 @@ void rlglLoadMesh(Mesh *mesh)
     {
     {
         glGenBuffers(1, &vboId[3]);
         glGenBuffers(1, &vboId[3]);
         glBindBuffer(GL_ARRAY_BUFFER, vboId[3]);
         glBindBuffer(GL_ARRAY_BUFFER, vboId[3]);
-        glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*mesh->vertexCount, mesh->colors, GL_STATIC_DRAW);
+        glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*mesh->vertexCount, mesh->colors, drawHint);
         glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
         glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
         glEnableVertexAttribArray(3);
         glEnableVertexAttribArray(3);
     }
     }
@@ -1717,7 +1591,7 @@ void rlglLoadMesh(Mesh *mesh)
     {
     {
         glGenBuffers(1, &vboId[4]);
         glGenBuffers(1, &vboId[4]);
         glBindBuffer(GL_ARRAY_BUFFER, vboId[4]);
         glBindBuffer(GL_ARRAY_BUFFER, vboId[4]);
-        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->tangents, GL_STATIC_DRAW);
+        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->tangents, drawHint);
         glVertexAttribPointer(4, 3, GL_FLOAT, 0, 0, 0);
         glVertexAttribPointer(4, 3, GL_FLOAT, 0, 0, 0);
         glEnableVertexAttribArray(4);
         glEnableVertexAttribArray(4);
     }
     }
@@ -1733,7 +1607,7 @@ void rlglLoadMesh(Mesh *mesh)
     {
     {
         glGenBuffers(1, &vboId[5]);
         glGenBuffers(1, &vboId[5]);
         glBindBuffer(GL_ARRAY_BUFFER, vboId[5]);
         glBindBuffer(GL_ARRAY_BUFFER, vboId[5]);
-        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords2, GL_STATIC_DRAW);
+        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords2, drawHint);
         glVertexAttribPointer(5, 2, GL_FLOAT, 0, 0, 0);
         glVertexAttribPointer(5, 2, GL_FLOAT, 0, 0, 0);
         glEnableVertexAttribArray(5);
         glEnableVertexAttribArray(5);
     }
     }
@@ -1776,6 +1650,270 @@ void rlglLoadMesh(Mesh *mesh)
 #endif
 #endif
 }
 }
 
 
+// Update vertex data on GPU (upload new data to one buffer)
+void rlglUpdateMesh(Mesh mesh, int buffer, int numVertex)
+{
+    // Activate mesh VAO
+    if (vaoSupported) glBindVertexArray(mesh.vaoId);
+        
+    switch (buffer)
+    {
+        case 0:     // Update vertices (vertex position)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
+            if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*numVertex, mesh.vertices, GL_DYNAMIC_DRAW);
+            else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*numVertex, mesh.vertices);
+            
+        } break;
+        case 1:     // Update texcoords (vertex texture coordinates)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]);
+            if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*numVertex, mesh.texcoords, GL_DYNAMIC_DRAW);
+            else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*numVertex, mesh.texcoords);
+            
+        } break;
+        case 2:     // Update normals (vertex normals)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
+            if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*numVertex, mesh.normals, GL_DYNAMIC_DRAW);
+            else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*numVertex, mesh.normals);
+            
+        } break;
+        case 3:     // Update colors (vertex colors)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[2]);
+            if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*numVertex, mesh.colors, GL_DYNAMIC_DRAW);
+            else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*numVertex, mesh.colors);
+            
+        } break;
+        case 4:     // Update tangents (vertex tangents)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
+            if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*numVertex, mesh.tangents, GL_DYNAMIC_DRAW);
+            else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*numVertex, mesh.tangents);
+        } break;
+        case 5:     // Update texcoords2 (vertex second texture coordinates)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]);
+            if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*numVertex, mesh.texcoords2, GL_DYNAMIC_DRAW);
+            else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*numVertex, mesh.texcoords2);
+        } break;
+        default: break;
+    }
+    
+    // Unbind the current VAO
+    if (vaoSupported) glBindVertexArray(0);
+
+    // Another option would be using buffer mapping...
+    //mesh.vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
+    // Now we can modify vertices
+    //glUnmapBuffer(GL_ARRAY_BUFFER);
+}
+
+// Draw a 3d mesh with material and transform
+void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
+{
+#if defined(GRAPHICS_API_OPENGL_11)
+    glEnable(GL_TEXTURE_2D);
+    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
+    if (mesh.normals != NULL) glEnableClientState(GL_NORMAL_ARRAY);     // Enable normals array
+    if (mesh.colors != NULL) glEnableClientState(GL_COLOR_ARRAY);       // Enable colors array
+
+    glVertexPointer(3, GL_FLOAT, 0, mesh.vertices);         // Pointer to vertex coords array
+    glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords);      // Pointer to texture coords array
+    if (mesh.normals != NULL) glNormalPointer(GL_FLOAT, 0, mesh.normals);           // Pointer to normals array
+    if (mesh.colors != NULL) glColorPointer(4, GL_UNSIGNED_BYTE, 0, mesh.colors);   // Pointer to colors array
+
+    rlPushMatrix();
+        rlMultMatrixf(MatrixToFloat(transform));
+        rlColor4ub(material.colDiffuse.r, material.colDiffuse.g, material.colDiffuse.b, material.colDiffuse.a);
+        
+        if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, mesh.indices);
+        else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
+    rlPopMatrix();
+
+    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(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 model-view matrix combining matModel and matView
+    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(material.shader.mvpLoc, 1, false, MatrixToFloat(matMVP));
+    
+    // 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);
+
+    // 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)
+    {
+        // Send model transformations matrix to shader
+        glUniformMatrix4fv(glGetUniformLocation(material.shader.id, "modelMatrix"), 1, false, MatrixToFloat(transform));
+        
+        // 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);
+    }    
+    
+    // Set shader textures (diffuse, normal, specular)
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, material.texDiffuse.id);
+    glUniform1i(material.shader.mapDiffuseLoc, 0);        // Texture fits in active texture unit 0
+    
+    if ((material.texNormal.id != 0) && (material.shader.mapNormalLoc != -1))
+    {
+        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))
+    {
+        glActiveTexture(GL_TEXTURE2);
+        glBindTexture(GL_TEXTURE_2D, material.texSpecular.id);
+        glUniform1i(material.shader.mapSpecularLoc, 2);   // Texture fits in active texture unit 2
+    }
+
+    if (vaoSupported)
+    {
+        glBindVertexArray(mesh.vaoId);
+    }
+    else
+    {
+        // 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 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 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, mesh.vboId[3]);
+            glVertexAttribPointer(material.shader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
+            glEnableVertexAttribArray(material.shader.colorLoc);
+        }
+        
+        // Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
+        if (material.shader.tangentLoc != -1)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[4]);
+            glVertexAttribPointer(material.shader.tangentLoc, 3, GL_FLOAT, 0, 0, 0);
+            glEnableVertexAttribArray(material.shader.tangentLoc);
+        }
+        
+        // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
+        if (material.shader.texcoord2Loc != -1)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[5]);
+            glVertexAttribPointer(material.shader.texcoord2Loc, 2, GL_FLOAT, 0, 0, 0);
+            glEnableVertexAttribArray(material.shader.texcoord2Loc);
+        }
+        
+        if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]);
+    }
+
+    // Draw call!
+    if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, 0); // Indexed vertices draw
+    else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
+    
+    if (material.texNormal.id != 0)
+    {
+        glActiveTexture(GL_TEXTURE1);
+        glBindTexture(GL_TEXTURE_2D, 0);
+    }
+    
+    if (material.texSpecular.id != 0)
+    {
+        glActiveTexture(GL_TEXTURE2);
+        glBindTexture(GL_TEXTURE_2D, 0);
+    }
+
+    glActiveTexture(GL_TEXTURE0);               // Set shader active texture to default 0
+    glBindTexture(GL_TEXTURE_2D, 0);            // Unbind textures
+
+    if (vaoSupported) glBindVertexArray(0);     // Unbind VAO
+    else
+    {
+        glBindBuffer(GL_ARRAY_BUFFER, 0);      // Unbind VBOs
+        if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+    }
+
+    glUseProgram(0);        // Unbind shader program
+#endif
+}
+
+// Unload mesh data from CPU and GPU
+void rlglUnloadMesh(Mesh *mesh)
+{
+    if (mesh->vertices != NULL) free(mesh->vertices);
+    if (mesh->texcoords != NULL) free(mesh->texcoords);
+    if (mesh->normals != NULL) free(mesh->normals);
+    if (mesh->colors != NULL) free(mesh->colors);
+    if (mesh->tangents != NULL) free(mesh->tangents);
+    if (mesh->texcoords2 != NULL) free(mesh->texcoords2);
+    if (mesh->indices != NULL) free(mesh->indices);
+
+    rlDeleteBuffers(mesh->vboId[0]);   // vertex
+    rlDeleteBuffers(mesh->vboId[1]);   // texcoords
+    rlDeleteBuffers(mesh->vboId[2]);   // normals
+    rlDeleteBuffers(mesh->vboId[3]);   // colors
+    rlDeleteBuffers(mesh->vboId[4]);   // tangents
+    rlDeleteBuffers(mesh->vboId[5]);   // texcoords2
+    rlDeleteBuffers(mesh->vboId[6]);   // indices
+
+    rlDeleteVertexArrays(mesh->vaoId);
+}
+
 // Read screen pixel data (color buffer)
 // Read screen pixel data (color buffer)
 unsigned char *rlglReadScreenPixels(int width, int height)
 unsigned char *rlglReadScreenPixels(int width, int height)
 {
 {
@@ -2022,6 +2160,17 @@ Shader GetDefaultShader(void)
 #endif
 #endif
 }
 }
 
 
+// Get default shader
+Shader GetStandardShader(void)
+{
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+    return standardShader;
+#else
+    Shader shader = { 0 };
+    return shader;
+#endif
+}
+
 // Get shader uniform location
 // Get shader uniform location
 int GetShaderLocation(Shader shader, const char *uniformName)
 int GetShaderLocation(Shader shader, const char *uniformName)
 {
 {
@@ -2098,6 +2247,78 @@ void SetBlendMode(int mode)
     }
     }
 }
 }
 
 
+// Create a new light, initialize it and add to pool
+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->target = (Vector3){ 0.0f, 0.0f, 0.0f };
+    light->intensity = 1.0f;
+    light->diffuse = diffuse;
+    
+    // Add new light to the array
+    lights[lightsCount] = light;
+    
+    // Increase enabled lights count
+    lightsCount++;
+    
+    return light;
+}
+
+// Draw all created lights in 3D world
+void DrawLights(void)
+{
+    for (int i = 0; i < lightsCount; i++)
+    {
+        switch (lights[i]->type)
+        {
+            case LIGHT_POINT: DrawSphereWires(lights[i]->position, 0.3f*lights[i]->intensity, 4, 8, (lights[i]->enabled ? lights[i]->diffuse : BLACK)); break;
+            case LIGHT_DIRECTIONAL:
+            {                
+                Draw3DLine(lights[i]->position, lights[i]->target, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
+                DrawSphereWires(lights[i]->position, 0.3f*lights[i]->intensity, 4, 8, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
+                DrawCubeWires(lights[i]->target, 0.3f, 0.3f, 0.3f, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
+            } break;
+            case LIGHT_SPOT:
+            {                
+                Draw3DLine(lights[i]->position, lights[i]->target, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
+                DrawCylinderWires(lights[i]->position, 0.0f, 0.3f*lights[i]->coneAngle/50, 0.6f, 5, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
+                DrawCubeWires(lights[i]->target, 0.3f, 0.3f, 0.3f, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
+            } break;
+            default: break;
+        }
+    }
+}
+
+// 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
 // Module specific Functions Definition
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
@@ -2293,15 +2514,15 @@ static Shader LoadDefaultShader(void)
         "varying vec4 fragColor;            \n"
         "varying vec4 fragColor;            \n"
 #endif
 #endif
         "uniform sampler2D texture0;        \n"
         "uniform sampler2D texture0;        \n"
-        "uniform vec4 fragTintColor;        \n"
+        "uniform vec4 colDiffuse;           \n"
         "void main()                        \n"
         "void main()                        \n"
         "{                                  \n"
         "{                                  \n"
 #if defined(GRAPHICS_API_OPENGL_33)
 #if defined(GRAPHICS_API_OPENGL_33)
         "    vec4 texelColor = texture(texture0, fragTexCoord);   \n"
         "    vec4 texelColor = texture(texture0, fragTexCoord);   \n"
-        "    finalColor = texelColor*fragTintColor*fragColor;     \n"
+        "    finalColor = texelColor*colDiffuse*fragColor;        \n"
 #elif defined(GRAPHICS_API_OPENGL_ES2)
 #elif defined(GRAPHICS_API_OPENGL_ES2)
         "    vec4 texelColor = texture2D(texture0, fragTexCoord); \n" // NOTE: texture2D() is deprecated on OpenGL 3.3 and ES 3.0
         "    vec4 texelColor = texture2D(texture0, fragTexCoord); \n" // NOTE: texture2D() is deprecated on OpenGL 3.3 and ES 3.0
-        "    gl_FragColor = texelColor*fragTintColor*fragColor;   \n"
+        "    gl_FragColor = texelColor*colDiffuse*fragColor;      \n"
 #endif
 #endif
         "}                                  \n";
         "}                                  \n";
 
 
@@ -2315,6 +2536,24 @@ static Shader LoadDefaultShader(void)
     return shader;
     return shader;
 }
 }
 
 
+// Load standard shader
+// NOTE: This shader supports: 
+//      - Up to 3 different maps: diffuse, normal, specular
+//      - Material properties: colAmbient, colDiffuse, colSpecular, glossiness, normalDepth
+//      - Up to 8 lights: Point, Directional or Spot
+static Shader LoadStandardShader(void)
+{
+    // Load standard shader (TODO: rewrite as char pointers)
+    Shader shader = LoadShader("resources/shaders/standard.vs", "resources/shaders/standard.fs");
+
+    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);
+
+    return shader;
+}
+
 // Get location handlers to for shader attributes and uniforms
 // Get location handlers to for shader attributes and uniforms
 // NOTE: If any location is not found, loc point becomes -1
 // NOTE: If any location is not found, loc point becomes -1
 static void LoadDefaultShaderLocations(Shader *shader)
 static void LoadDefaultShaderLocations(Shader *shader)
@@ -2328,18 +2567,18 @@ static void LoadDefaultShaderLocations(Shader *shader)
     //          vertex texcoord2 location = 5
     //          vertex texcoord2 location = 5
     
     
     // Get handles to GLSL input attibute locations
     // 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");
+    shader->vertexLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_POSITION_NAME);
+    shader->texcoordLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TEXCOORD_NAME);
+    shader->normalLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_NORMAL_NAME);
+    shader->colorLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_COLOR_NAME);
+    shader->tangentLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TANGENT_NAME);
+    shader->texcoord2Loc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TEXCOORD2_NAME);
 
 
     // Get handles to GLSL uniform locations (vertex shader)
     // Get handles to GLSL uniform locations (vertex shader)
     shader->mvpLoc  = glGetUniformLocation(shader->id, "mvpMatrix");
     shader->mvpLoc  = glGetUniformLocation(shader->id, "mvpMatrix");
 
 
     // Get handles to GLSL uniform locations (fragment shader)
     // Get handles to GLSL uniform locations (fragment shader)
-    shader->tintColorLoc = glGetUniformLocation(shader->id, "fragTintColor");
+    shader->tintColorLoc = glGetUniformLocation(shader->id, "colDiffuse");
     shader->mapDiffuseLoc = glGetUniformLocation(shader->id, "texture0");
     shader->mapDiffuseLoc = glGetUniformLocation(shader->id, "texture0");
     shader->mapNormalLoc = glGetUniformLocation(shader->id, "texture1");
     shader->mapNormalLoc = glGetUniformLocation(shader->id, "texture1");
     shader->mapSpecularLoc = glGetUniformLocation(shader->id, "texture2");
     shader->mapSpecularLoc = glGetUniformLocation(shader->id, "texture2");
@@ -2350,13 +2589,26 @@ static void UnloadDefaultShader(void)
 {
 {
     glUseProgram(0);
     glUseProgram(0);
 
 
-    //glDetachShader(defaultShaderProgram, vertexShader);
-    //glDetachShader(defaultShaderProgram, fragmentShader);
+    //glDetachShader(defaultShader, vertexShader);
+    //glDetachShader(defaultShader, fragmentShader);
     //glDeleteShader(vertexShader);     // Already deleted on shader compilation
     //glDeleteShader(vertexShader);     // Already deleted on shader compilation
-    //glDeleteShader(fragmentShader);   // Already deleted on sahder compilation
+    //glDeleteShader(fragmentShader);   // Already deleted on shader compilation
     glDeleteProgram(defaultShader.id);
     glDeleteProgram(defaultShader.id);
 }
 }
 
 
+// Unload standard shader 
+static void UnloadStandardShader(void)
+{
+    glUseProgram(0);
+
+    //glDetachShader(defaultShader, vertexShader);
+    //glDetachShader(defaultShader, fragmentShader);
+    //glDeleteShader(vertexShader);     // Already deleted on shader compilation
+    //glDeleteShader(fragmentShader);   // Already deleted on shader compilation
+    glDeleteProgram(standardShader.id);
+}
+
+
 // Load default internal buffers (lines, triangles, quads)
 // Load default internal buffers (lines, triangles, quads)
 static void LoadDefaultBuffers(void)
 static void LoadDefaultBuffers(void)
 {
 {
@@ -2800,6 +3052,79 @@ static void UnloadDefaultBuffers(void)
     free(quads.indices);
     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
+static void SetShaderLights(Shader shader)
+{
+    int locPoint = glGetUniformLocation(shader.id, "lightsCount");
+    glUniform1i(locPoint, lightsCount);
+    
+    char locName[32] = "lights[x].position\0";
+
+    for (int i = 0; i < lightsCount; i++)
+    {
+        locName[7] = '0' + i;
+        
+        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);
+        
+        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], "attenuation\0", strlen("attenuation\0"));
+                locPoint = GetShaderLocation(shader, locName);
+                glUniform1f(locPoint, lights[i]->attenuation);
+            } 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);
+            } 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);
+                
+                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);
+                
+                memcpy(&locName[10], "coneAngle\0", strlen("coneAngle\0"));
+                locPoint = GetShaderLocation(shader, locName);
+                glUniform1f(locPoint, lights[i]->coneAngle);
+            } break;
+            default: break;
+        }
+        
+        // TODO: Pass to the shader any other required data from LightData struct
+    }
+}
+
 // Read text data from file
 // Read text data from file
 // NOTE: text chars array should be freed manually
 // NOTE: text chars array should be freed manually
 static char *ReadTextFile(const char *fileName)
 static char *ReadTextFile(const char *fileName)
@@ -2970,7 +3295,7 @@ static void TraceLog(int msgType, const char *text, ...)
     va_list args;
     va_list args;
     va_start(args, text);
     va_start(args, text);
 
 
-    switch(msgType)
+    switch (msgType)
     {
     {
         case INFO: fprintf(stdout, "INFO: "); break;
         case INFO: fprintf(stdout, "INFO: "); break;
         case ERROR: fprintf(stdout, "ERROR: "); break;
         case ERROR: fprintf(stdout, "ERROR: "); break;

+ 35 - 11
src/rlgl.h

@@ -196,19 +196,35 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion;
     
     
     // Material type
     // Material type
     typedef struct Material {
     typedef struct Material {
-        Shader shader;
+        Shader shader;              // Standard shader (supports 3 map types: diffuse, normal, specular)
 
 
-        Texture2D texDiffuse;      // Diffuse texture
-        Texture2D texNormal;       // Normal texture
-        Texture2D texSpecular;     // Specular texture
+        Texture2D texDiffuse;       // Diffuse texture
+        Texture2D texNormal;        // Normal texture
+        Texture2D texSpecular;      // Specular texture
         
         
-        Color colDiffuse;
-        Color colAmbient;
-        Color colSpecular;
+        Color colDiffuse;           // Diffuse color
+        Color colAmbient;           // Ambient color
+        Color colSpecular;          // Specular color
         
         
-        float glossiness;
-        float normalDepth;
+        float glossiness;           // Glossiness level (Ranges from 0 to 1000)
+        float normalDepth;          // Normal map depth
     } Material;
     } Material;
+    
+    // Light type
+    typedef struct LightData {
+        int id;
+        int type;           // LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT
+        bool enabled;
+        
+        Vector3 position;
+        Vector3 target;     // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target)
+        float attenuation;  // Lost of light intensity with distance (world distance)
+        
+        Color diffuse;      // Use Vector3 diffuse
+        float intensity;
+        
+        float coneAngle;    // Spot light max angle
+    } LightData, *Light;
 	
 	
     // Color blending modes (pre-defined)
     // Color blending modes (pre-defined)
     typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode;
     typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode;
@@ -256,6 +272,8 @@ void rlEnableRenderTexture(unsigned int id);    // Enable render texture (fbo)
 void rlDisableRenderTexture(void);              // Disable render texture (fbo), return to default framebuffer
 void rlDisableRenderTexture(void);              // Disable render texture (fbo), return to default framebuffer
 void rlEnableDepthTest(void);                   // Enable depth test
 void rlEnableDepthTest(void);                   // Enable depth test
 void rlDisableDepthTest(void);                  // Disable depth test
 void rlDisableDepthTest(void);                  // Disable depth test
+void rlEnableWireMode(void);                    // Enable wire mode
+void rlDisableWireMode(void);                   // Disable wire mode
 void rlDeleteTextures(unsigned int id);         // Delete OpenGL texture from GPU
 void rlDeleteTextures(unsigned int id);         // Delete OpenGL texture from GPU
 void rlDeleteRenderTextures(RenderTexture2D target);    // Delete render textures (fbo) from GPU
 void rlDeleteRenderTextures(RenderTexture2D target);    // Delete render textures (fbo) from GPU
 void rlDeleteShader(unsigned int id);           // Delete OpenGL shader program from GPU
 void rlDeleteShader(unsigned int id);           // Delete OpenGL shader program from GPU
@@ -277,8 +295,11 @@ 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)
 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 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
 void rlglGenerateMipmaps(Texture2D texture);                             // Generate mipmap data for selected texture
-void rlglLoadMesh(Mesh *mesh);           // Upload vertex data into GPU and provided VAO/VBO ids
-void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires);
+
+void rlglLoadMesh(Mesh *mesh, bool dynamic);                        // Upload vertex data into GPU and provided VAO/VBO ids
+void rlglUpdateMesh(Mesh mesh, int buffer, int numVertex);          // Update vertex data on GPU (upload new data to one buffer)
+void rlglDrawMesh(Mesh mesh, Material material, Matrix transform);  // Draw a 3d mesh with material and transform
+void rlglUnloadMesh(Mesh *mesh);                                    // Unload mesh data from CPU and GPU
 
 
 Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view);    // Get world coordinates from screen coordinates
 Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view);    // Get world coordinates from screen coordinates
 
 
@@ -306,6 +327,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 SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat);       // Set shader uniform value (matrix 4x4)
 
 
 void SetBlendMode(int mode);                                        // Set blending mode (alpha, additive, multiplied)
 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
 #endif
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus

+ 0 - 1
src/shapes.c

@@ -446,7 +446,6 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
 }
 }
 
 
 // Get collision rectangle for two rectangles collision
 // Get collision rectangle for two rectangles collision
-// TODO: Depending on rec1 and rec2 order, it fails -> Review!
 Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
 Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
 {
 {
     Rectangle retRec = { 0, 0, 0, 0 };
     Rectangle retRec = { 0, 0, 0, 0 };

+ 2 - 0
src/windows_compile.bat

@@ -0,0 +1,2 @@
+set PATH=C:\raylib\MinGW\bin;%PATH%
+mingw32-make

+ 0 - 10
src_android/local.properties

@@ -1,10 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must *NOT* be checked into Version Control Systems,
-# as it contains information specific to your local configuration.
-
-# location of the SDK. This is only used by Ant
-# For customization when using a Version Control System, please read the
-# header note.
-sdk.dir=C:\\android-sdk

+ 0 - 10
templates/android_project/local.properties

@@ -1,10 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must *NOT* be checked into Version Control Systems,
-# as it contains information specific to your local configuration.
-
-# location of the SDK. This is only used by Ant
-# For customization when using a Version Control System, please read the
-# header note.
-sdk.dir=C:\\android-sdk