Browse Source

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

victorfisac 9 years ago
parent
commit
8ae0da1fa1
16 changed files with 1669 additions and 1082 deletions
  1. 13 11
      examples/physics_basic_rigidbody.c
  2. 20 17
      examples/physics_rigidbody_force.c
  3. 44 1
      src/core.c
  4. 43 29
      src/easings.h
  5. 3 3
      src/models.c
  6. 18 14
      src/physac.c
  7. 4 3
      src/physac.h
  8. 6 6
      src/raylib.h
  9. 226 188
      src/raymath.h
  10. 2 0
      src/rlgl.c
  11. 5 4
      src/rlgl.h
  12. 349 213
      src/stb_image.h
  13. 446 132
      src/stb_image_write.h
  14. 35 21
      src/stb_truetype.h
  15. 418 412
      src/stb_vorbis.c
  16. 37 28
      src/stb_vorbis.h

+ 13 - 11
examples/physics_basic_rigidbody.c

@@ -32,28 +32,30 @@ int main()
     int screenHeight = 450;
     
     InitWindow(screenWidth, screenHeight, "raylib [physics] example - basic rigidbody");
-    SetTargetFPS(60);   // Enable v-sync
+
     InitPhysics();      // Initialize internal physics values   (max rigidbodies/colliders available: 1024)
     
     // Physics initialization
-    Physics worldPhysics = {true, false, (Vector2){0, -9.81f}};
+    Physics worldPhysics = { true, false, (Vector2){ 0, -9.81f } };
     
     // Set internal physics settings
     SetPhysics(worldPhysics);
     
     // Object initialization
     Transform player = (Transform){(Vector2){(screenWidth - OBJECT_SIZE) / 2, (screenHeight - OBJECT_SIZE) / 2}, 0.0f, (Vector2){OBJECT_SIZE, OBJECT_SIZE}};
-    AddCollider(PLAYER_INDEX, (Collider){true, RectangleCollider, (Rectangle){player.position.x, player.position.y, player.scale.x, player.scale.y}, 0});
+    AddCollider(PLAYER_INDEX, (Collider){true, COLLIDER_RECTANGLE, (Rectangle){player.position.x, player.position.y, player.scale.x, player.scale.y}, 0});
     AddRigidbody(PLAYER_INDEX, (Rigidbody){true, 1.0f, (Vector2){0, 0}, (Vector2){0, 0}, false, false, true, 0.5f, 1.0f});
     
     // Floor initialization 
     // NOTE: floor doesn't need a rigidbody because it's a static physic object, just a collider to collide with other dynamic colliders (with rigidbody)
     Transform floor = (Transform){(Vector2){0, screenHeight * 0.8f}, 0.0f, (Vector2){screenWidth, screenHeight * 0.2f}};
-    AddCollider(PLAYER_INDEX + 1, (Collider){true, RectangleCollider, (Rectangle){floor.position.x, floor.position.y, floor.scale.x, floor.scale.y}, 0});
+    AddCollider(PLAYER_INDEX + 1, (Collider){true, COLLIDER_RECTANGLE, (Rectangle){floor.position.x, floor.position.y, floor.scale.x, floor.scale.y}, 0});
     
     // Object properties initialization
     float moveSpeed = 6.0f;
-    float jumpForce = 4.5f;
+    float jumpForce = 5.0f;
+    
+    SetTargetFPS(60);
     //--------------------------------------------------------------------------------------
 
     // Main game loop
@@ -67,7 +69,7 @@ int main()
         ApplyPhysics(PLAYER_INDEX, &player.position);
         
         // Check jump button input
-        if(IsKeyDown(KEY_SPACE) && GetRigidbody(PLAYER_INDEX).isGrounded)
+        if (IsKeyDown(KEY_SPACE) && GetRigidbody(PLAYER_INDEX).isGrounded)
         {
             // Reset object Y velocity to avoid double jumping cases but keep the same X velocity that it already has
             SetRigidbodyVelocity(PLAYER_INDEX, (Vector2){GetRigidbody(PLAYER_INDEX).velocity.x, 0});
@@ -77,12 +79,12 @@ int main()
         }
         
         // Check movement buttons input
-        if(IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D))
+        if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D))
         {
             // Set rigidbody velocity in X based on moveSpeed value and apply the same Y velocity that it already has
             SetRigidbodyVelocity(PLAYER_INDEX, (Vector2){moveSpeed, GetRigidbody(PLAYER_INDEX).velocity.y});
         }
-        else if(IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A))
+        else if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A))
         {
             // Set rigidbody velocity in X based on moveSpeed negative value and apply the same Y velocity that it already has
             SetRigidbodyVelocity(PLAYER_INDEX, (Vector2){-moveSpeed, GetRigidbody(PLAYER_INDEX).velocity.y});
@@ -110,12 +112,12 @@ int main()
             DrawText("Use P to switch DEBUG MODE", (screenWidth - MeasureText("Use P to switch DEBUG MODE", 20)) / 2, screenHeight * 0.3f, 20, LIGHTGRAY);
             
             // Check if debug mode is enabled
-            if(worldPhysics.debug)
+            if (worldPhysics.debug)
             {
                 // Draw every internal physics stored collider if it is active
-                for(int i = 0; i < 2; i++)
+                for (int i = 0; i < 2; i++)
                 {
-                    if(GetCollider(i).enabled)
+                    if (GetCollider(i).enabled)
                     {
                         DrawRectangleLines(GetCollider(i).bounds.x, GetCollider(i).bounds.y, GetCollider(i).bounds.width, GetCollider(i).bounds.height, GREEN);
                     }

+ 20 - 17
examples/physics_rigidbody_force.c

@@ -11,11 +11,11 @@
 
 #include "raylib.h"
 
-#define MAX_OBJECTS 5
-#define OBJECTS_OFFSET 150
+#define MAX_OBJECTS           5
+#define OBJECTS_OFFSET      150
 
-#define FORCE_INTENSITY 250.0f  // Customize by user
-#define FORCE_RADIUS 100        // Customize by user    
+#define FORCE_INTENSITY  250.0f     // Customize by user
+#define FORCE_RADIUS        100     // Customize by user    
 
 int main()
 {
@@ -25,7 +25,7 @@ int main()
     int screenHeight = 450;
     
     InitWindow(screenWidth, screenHeight, "raylib [physics] example - rigidbodies forces");
-    SetTargetFPS(60);   // Enable v-sync
+
     InitPhysics();      // Initialize internal physics values   (max rigidbodies/colliders available: 1024)
     
     // Physics initialization
@@ -36,17 +36,20 @@ int main()
     
     // Objects initialization
     Transform objects[MAX_OBJECTS];
-    for(int i = 0; i < MAX_OBJECTS; i++)
+    
+    for (int i = 0; i < MAX_OBJECTS; i++)
     {
         objects[i] = (Transform){(Vector2){75 + OBJECTS_OFFSET * i, (screenHeight - 50) / 2}, 0.0f, (Vector2){50, 50}};
-        AddCollider(i, (Collider){true, RectangleCollider, (Rectangle){objects[i].position.x, objects[i].position.y, objects[i].scale.x, objects[i].scale.y}, 0});
+        AddCollider(i, (Collider){true, COLLIDER_RECTANGLE, (Rectangle){objects[i].position.x, objects[i].position.y, objects[i].scale.x, objects[i].scale.y}, 0});
         AddRigidbody(i, (Rigidbody){true, 1.0f, (Vector2){0, 0}, (Vector2){0, 0}, false, false, true, 0.5f, 0.5f});
     }
     
     // Floor initialization 
     // NOTE: floor doesn't need a rigidbody because it's a static physic object, just a collider to collide with other dynamic colliders (with rigidbody)
     Transform floor = (Transform){(Vector2){0, screenHeight * 0.8f}, 0.0f, (Vector2){screenWidth, screenHeight * 0.2f}};
-    AddCollider(MAX_OBJECTS, (Collider){true, RectangleCollider, (Rectangle){floor.position.x, floor.position.y, floor.scale.x, floor.scale.y}, 0});
+    AddCollider(MAX_OBJECTS, (Collider){true, COLLIDER_RECTANGLE, (Rectangle){floor.position.x, floor.position.y, floor.scale.x, floor.scale.y}, 0});
+
+    SetTargetFPS(60);
     //--------------------------------------------------------------------------------------
 
     // Main game loop
@@ -57,19 +60,19 @@ int main()
         
         // Update object physics 
         // NOTE: all physics detections and reactions are calculated in ApplyPhysics() function (You will live happier :D)
-        for(int i = 0; i < MAX_OBJECTS; i++)
+        for (int i = 0; i < MAX_OBJECTS; i++)
         {
             ApplyPhysics(i, &objects[i].position);
         }
         
         // Check foce button input
-        if(IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+        if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
         {
             AddForceAtPosition(GetMousePosition(), FORCE_INTENSITY, FORCE_RADIUS);
         }
         
         // Check debug mode toggle button input
-        if(IsKeyPressed(KEY_P))
+        if (IsKeyPressed(KEY_P))
         {
             // Update program physics value
             worldPhysics.debug = !worldPhysics.debug;
@@ -86,21 +89,21 @@ int main()
             ClearBackground(RAYWHITE);
             
             // Check if debug mode is enabled
-            if(worldPhysics.debug)
+            if (worldPhysics.debug)
             {
                 // Draw every internal physics stored collider if it is active (floor included)
-                for(int i = 0; i < MAX_OBJECTS + 1; i++)
+                for (int i = 0; i < MAX_OBJECTS + 1; i++)
                 {
-                    if(GetCollider(i).enabled)
+                    if (GetCollider(i).enabled)
                     {
                         // Draw collider bounds
                         DrawRectangleLines(GetCollider(i).bounds.x, GetCollider(i).bounds.y, GetCollider(i).bounds.width, GetCollider(i).bounds.height, GREEN);
                         
                         // Check if current collider is not floor
-                        if(i < MAX_OBJECTS)
+                        if (i < MAX_OBJECTS)
                         {
                             // Draw lines between mouse position and objects if they are in force range
-                            if(CheckCollisionPointCircle(GetMousePosition(), (Vector2){GetCollider(i).bounds.x + GetCollider(i).bounds.width / 2, GetCollider(i).bounds.y + GetCollider(i).bounds.height / 2}, FORCE_RADIUS))
+                            if (CheckCollisionPointCircle(GetMousePosition(), (Vector2){GetCollider(i).bounds.x + GetCollider(i).bounds.width / 2, GetCollider(i).bounds.y + GetCollider(i).bounds.height / 2}, FORCE_RADIUS))
                             {
                                 DrawLineV(GetMousePosition(), (Vector2){GetCollider(i).bounds.x + GetCollider(i).bounds.width / 2, GetCollider(i).bounds.y + GetCollider(i).bounds.height / 2}, RED);
                             }
@@ -114,7 +117,7 @@ int main()
             else
             {
                 // Draw objects
-                for(int i = 0; i < MAX_OBJECTS; i++)
+                for (int i = 0; i < MAX_OBJECTS; i++)
                 {
                     DrawRectangleRec((Rectangle){objects[i].position.x, objects[i].position.y, objects[i].scale.x, objects[i].scale.y}, GRAY);
                 }

+ 44 - 1
src/core.c

@@ -38,9 +38,12 @@
 
 #include "raylib.h"         // raylib main header
 #include "rlgl.h"           // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
-#include "raymath.h"        // Required for data type Matrix and Matrix functions
 #include "utils.h"          // TraceLog() function
                             // NOTE: Includes Android fopen map, InitAssetManager()
+                            
+#define RAYMATH_IMPLEMENTATION  // Use raymath as a header-only library (includes implementation)
+#define RAYMATH_EXTERN_INLINE   // Compile raymath functions as static inline (remember, it's a compiler hint)
+#include "raymath.h"            // Required for Vector3 and Matrix functions
 
 #include <stdio.h>          // Standard input / output lib
 #include <stdlib.h>         // Declares malloc() and free() for memory management, rand(), atexit()
@@ -643,6 +646,46 @@ float *ColorToFloat(Color color)
     return buffer;
 }
 
+// Converts Vector3 to float array
+float *VectorToFloat(Vector3 vec)
+{
+    static float buffer[3];
+
+    buffer[0] = vec.x;
+    buffer[1] = vec.y;
+    buffer[2] = vec.z;
+
+    return buffer;
+}
+
+// Converts Matrix to float array
+// NOTE: Returned vector is a transposed version of the Matrix struct, 
+// it should be this way because, despite raymath use OpenGL column-major convention,
+// Matrix struct memory alignment and variables naming are not coherent
+float *MatrixToFloat(Matrix mat)
+{
+    static float buffer[16];
+
+    buffer[0] = mat.m0;
+    buffer[1] = mat.m4;
+    buffer[2] = mat.m8;
+    buffer[3] = mat.m12;
+    buffer[4] = mat.m1;
+    buffer[5] = mat.m5;
+    buffer[6] = mat.m9;
+    buffer[7] = mat.m13;
+    buffer[8] = mat.m2;
+    buffer[9] = mat.m6;
+    buffer[10] = mat.m10;
+    buffer[11] = mat.m14;
+    buffer[12] = mat.m3;
+    buffer[13] = mat.m7;
+    buffer[14] = mat.m11;
+    buffer[15] = mat.m15;
+
+    return buffer;
+}
+
 // Returns a Color struct from hexadecimal value
 Color GetColor(int hexValue)
 {

+ 43 - 29
src/easings.h

@@ -1,6 +1,12 @@
 /*******************************************************************************************
 *
-*   raylib Easings - Useful easing functions for values animation
+*   raylib easings (header only file)
+*   
+*   Useful easing functions for values animation
+*
+*   This header uses:
+*       #define EASINGS_STATIC_INLINE       // Inlines all functions code, so it runs faster.
+*                                           // This requires lots of memory on system.
 *
 *   A port of Robert Penner's easing equations to C (http://robertpenner.com/easing/)
 *
@@ -56,6 +62,14 @@
 #ifndef EASINGS_H
 #define EASINGS_H
 
+#define EASINGS_STATIC_INLINE     // NOTE: By default, compile functions as static inline
+
+#if defined(EASINGS_STATIC_INLINE)
+    #define EASEDEF static inline
+#else
+    #define EASEDEF extern
+#endif
+
 #include <math.h>
 
 #ifdef __cplusplus
@@ -63,47 +77,47 @@ extern "C" {            // Prevents name mangling of functions
 #endif
 
 // Linear Easing functions
-float EaseLinearNone(float t, float b, float c, float d) { return (c*t/d + b); }
-float EaseLinearIn(float t, float b, float c, float d) { return (c*t/d + b); }
-float EaseLinearOut(float t, float b, float c, float d) { return (c*t/d + b); }
-float EaseLinearInOut(float t,float b, float c, float d) { return (c*t/d + b); }
+EASEDEF float EaseLinearNone(float t, float b, float c, float d) { return (c*t/d + b); }
+EASEDEF float EaseLinearIn(float t, float b, float c, float d) { return (c*t/d + b); }
+EASEDEF float EaseLinearOut(float t, float b, float c, float d) { return (c*t/d + b); }
+EASEDEF float EaseLinearInOut(float t,float b, float c, float d) { return (c*t/d + b); }
 
 // Sine Easing functions
-float EaseSineIn(float t, float b, float c, float d) { return (-c*cos(t/d*(PI/2)) + c + b); }
-float EaseSineOut(float t, float b, float c, float d) { return (c*sin(t/d*(PI/2)) + b); }
-float EaseSineInOut(float t, float b, float c, float d) { return (-c/2*(cos(PI*t/d) - 1) + b); }
+EASEDEF float EaseSineIn(float t, float b, float c, float d) { return (-c*cos(t/d*(PI/2)) + c + b); }
+EASEDEF float EaseSineOut(float t, float b, float c, float d) { return (c*sin(t/d*(PI/2)) + b); }
+EASEDEF float EaseSineInOut(float t, float b, float c, float d) { return (-c/2*(cos(PI*t/d) - 1) + b); }
 
 // Circular Easing functions
-float EaseCircIn(float t, float b, float c, float d) { return (-c*(sqrt(1 - (t/=d)*t) - 1) + b); }
-float EaseCircOut(float t, float b, float c, float d) { return (c*sqrt(1 - (t=t/d-1)*t) + b); }
-float EaseCircInOut(float t, float b, float c, float d) 
+EASEDEF float EaseCircIn(float t, float b, float c, float d) { return (-c*(sqrt(1 - (t/=d)*t) - 1) + b); }
+EASEDEF float EaseCircOut(float t, float b, float c, float d) { return (c*sqrt(1 - (t=t/d-1)*t) + b); }
+EASEDEF float EaseCircInOut(float t, float b, float c, float d) 
 {
     if ((t/=d/2) < 1) return (-c/2*(sqrt(1 - t*t) - 1) + b);
     return (c/2*(sqrt(1 - t*(t-=2)) + 1) + b);
 }
 
 // Cubic Easing functions
-float EaseCubicIn(float t, float b, float c, float d) { return (c*(t/=d)*t*t + b); }
-float EaseCubicOut(float t, float b, float c, float d) { return (c*((t=t/d-1)*t*t + 1) + b); }
-float EaseCubicInOut(float t, float b, float c, float d) 
+EASEDEF float EaseCubicIn(float t, float b, float c, float d) { return (c*(t/=d)*t*t + b); }
+EASEDEF float EaseCubicOut(float t, float b, float c, float d) { return (c*((t=t/d-1)*t*t + 1) + b); }
+EASEDEF float EaseCubicInOut(float t, float b, float c, float d) 
 { 
     if ((t/=d/2) < 1) return (c/2*t*t*t + b);
     return (c/2*((t-=2)*t*t + 2) + b);    
 }
 
 // Quadratic Easing functions
-float EaseQuadIn(float t, float b, float c, float d) { return (c*(t/=d)*t + b); }
-float EaseQuadOut(float t, float b, float c, float d) { return (-c*(t/=d)*(t-2) + b); }
-float EaseQuadInOut(float t, float b, float c, float d) 
+EASEDEF float EaseQuadIn(float t, float b, float c, float d) { return (c*(t/=d)*t + b); }
+EASEDEF float EaseQuadOut(float t, float b, float c, float d) { return (-c*(t/=d)*(t-2) + b); }
+EASEDEF float EaseQuadInOut(float t, float b, float c, float d) 
 {
     if ((t/=d/2) < 1) return (((c/2)*(t*t)) + b);
     return (-c/2*(((t-2)*(--t)) - 1) + b);
 }
 
 // Exponential Easing functions
-float EaseExpoIn(float t, float b, float c, float d) { return (t == 0) ? b : (c*pow(2, 10*(t/d - 1)) + b); }
-float EaseExpoOut(float t, float b, float c, float d) { return (t == d) ? (b + c) : (c*(-pow(2, -10*t/d) + 1) + b);    }
-float EaseExpoInOut(float t, float b, float c, float d) 
+EASEDEF float EaseExpoIn(float t, float b, float c, float d) { return (t == 0) ? b : (c*pow(2, 10*(t/d - 1)) + b); }
+EASEDEF float EaseExpoOut(float t, float b, float c, float d) { return (t == d) ? (b + c) : (c*(-pow(2, -10*t/d) + 1) + b);    }
+EASEDEF float EaseExpoInOut(float t, float b, float c, float d) 
 {
     if (t == 0) return b;
     if (t == d) return (b + c);
@@ -113,20 +127,20 @@ float EaseExpoInOut(float t, float b, float c, float d)
 }
 
 // Back Easing functions
-float EaseBackIn(float t, float b, float c, float d) 
+EASEDEF float EaseBackIn(float t, float b, float c, float d) 
 {
     float s = 1.70158f;
     float postFix = t/=d;
     return (c*(postFix)*t*((s + 1)*t - s) + b);
 }
 
-float EaseBackOut(float t, float b, float c, float d)
+EASEDEF float EaseBackOut(float t, float b, float c, float d)
 {    
     float s = 1.70158f;
     return (c*((t=t/d-1)*t*((s + 1)*t + s) + 1) + b);
 }
 
-float EaseBackInOut(float t, float b, float c, float d)
+EASEDEF float EaseBackInOut(float t, float b, float c, float d)
 {
     float s = 1.70158f;
     if ((t/=d/2) < 1) return (c/2*(t*t*(((s*=(1.525f)) + 1)*t - s)) + b);
@@ -136,8 +150,7 @@ float EaseBackInOut(float t, float b, float c, float d)
 }
 
 // Bounce Easing functions
-float EaseBounceIn(float t, float b, float c, float d) { return (c - EaseBounceOut(d-t, 0, c, d) + b); }
-float EaseBounceOut(float t, float b, float c, float d) 
+EASEDEF float EaseBounceOut(float t, float b, float c, float d) 
 {
     if ((t/=d) < (1/2.75f)) 
     {
@@ -160,14 +173,15 @@ float EaseBounceOut(float t, float b, float c, float d)
     }
 }
 
-float EaseBounceInOut(float t, float b, float c, float d) 
+EASEDEF float EaseBounceIn(float t, float b, float c, float d) { return (c - EaseBounceOut(d-t, 0, c, d) + b); }
+EASEDEF float EaseBounceInOut(float t, float b, float c, float d) 
 {
     if (t < d/2) return (EaseBounceIn(t*2, 0, c, d)*0.5f + b);
     else return (EaseBounceOut(t*2-d, 0, c, d)*0.5f + c*0.5f + b);
 }
 
 // Elastic Easing functions
-float EaseElasticIn(float t, float b, float c, float d) 
+EASEDEF float EaseElasticIn(float t, float b, float c, float d) 
 {
     if (t == 0) return b;
     if ((t/=d) == 1) return (b + c);
@@ -180,7 +194,7 @@ float EaseElasticIn(float t, float b, float c, float d)
     return (-(postFix*sin((t*d-s)*(2*PI)/p )) + b);
 }
 
-float EaseElasticOut(float t, float b, float c, float d)
+EASEDEF float EaseElasticOut(float t, float b, float c, float d)
 {
     if (t == 0) return b;
     if ((t/=d) == 1) return (b + c);
@@ -192,7 +206,7 @@ float EaseElasticOut(float t, float b, float c, float d)
     return (a*pow(2,-10*t)*sin((t*d-s)*(2*PI)/p) + c + b);    
 }
 
-float EaseElasticInOut(float t, float b, float c, float d)
+EASEDEF float EaseElasticInOut(float t, float b, float c, float d)
 {
     if (t == 0) return b;
     if ((t/=d/2) == 2) return (b + c);

+ 3 - 3
src/models.c

@@ -34,8 +34,8 @@
 #include <string.h>     // Required for strcmp()
 #include <math.h>       // Used for sin, cos, tan
 
-#include "raymath.h"    // Required for data type Matrix and Matrix functions
 #include "rlgl.h"       // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
+#include "raymath.h"    // Required for data type Matrix and Matrix functions
 
 //----------------------------------------------------------------------------------
 // Defines and Macros
@@ -1373,8 +1373,8 @@ bool CheckCollisionRayBox(Ray ray, Vector3 minBBox, Vector3 maxBBox)
 BoundingBox CalculateBoundingBox(Mesh mesh)
 {
     // Get min and max vertex to construct bounds (AABB)
-    Vector3 minVertex = mesh.vertices[0]; 
-    Vector3 maxVertex = mesh.vertices[0];
+    Vector3 minVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] };
+    Vector3 maxVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] };
 
     for (int i = 1; i < mesh.vertexCount; i++)
     {

+ 18 - 14
src/physac.c

@@ -55,8 +55,8 @@ static bool collisionChecker = false;
 // Module specific Functions Declarations
 //----------------------------------------------------------------------------------
 static float Vector2Length(Vector2 vector);
-static float Vector2LengthPoints(Vector2 a, Vector2 b);
-static Vector2 Vector2Normalize(Vector2 vector);
+static float Vector2Distance(Vector2 a, Vector2 b);
+static void Vector2Normalize(Vector2 *vector);
 
 //----------------------------------------------------------------------------------
 // Module Functions Definitions
@@ -183,9 +183,9 @@ void ApplyPhysics(int index, Vector2 *position)
             {
                 if (colliders[index].enabled && colliders[j].enabled)
                 {
-                    if (colliders[index].type == RectangleCollider)
+                    if (colliders[index].type == COLLIDER_RECTANGLE)
                     {
-                        if (colliders[j].type == RectangleCollider)
+                        if (colliders[j].type == COLLIDER_RECTANGLE)
                         {
                             if (CheckCollisionRecs(colliders[index].bounds, colliders[j].bounds))
                             {
@@ -207,7 +207,7 @@ void ApplyPhysics(int index, Vector2 *position)
                     }
                     else
                     {
-                        if (colliders[j].type == RectangleCollider)
+                        if (colliders[j].type == COLLIDER_RECTANGLE)
                         {
                             if (CheckCollisionCircleRec((Vector2){colliders[index].bounds.x, colliders[index].bounds.y}, colliders[index].radius, colliders[j].bounds))
                             {
@@ -277,7 +277,7 @@ void AddForceAtPosition(Vector2 position, float intensity, float radius)
             Vector2 pos = {colliders[i].bounds.x, colliders[i].bounds.y};
             
             // Get distance between rigidbody position and target position
-            float distance = Vector2LengthPoints(position, pos);
+            float distance = Vector2Distance(position, pos);
             
             if(distance <= radius)
             {
@@ -285,7 +285,7 @@ void AddForceAtPosition(Vector2 position, float intensity, float radius)
                 Vector2 force = {colliders[i].bounds.x - position.x, colliders[i].bounds.y - position.y};
                 
                 // Normalize the direction vector
-                force = Vector2Normalize(force);
+                Vector2Normalize(&force);
                 
                 // Invert y value
                 force.y *= -1;
@@ -323,20 +323,24 @@ static float Vector2Length(Vector2 vector)
     return sqrt((vector.x * vector.x) + (vector.y * vector.y));
 }
 
-static float Vector2LengthPoints(Vector2 a, Vector2 b)
+static float Vector2Distance(Vector2 a, Vector2 b)
 {
     Vector2 vector = {b.x - a.x, b.y - a.y};
     return sqrt((vector.x * vector.x) + (vector.y * vector.y));
 }
 
-static Vector2 Vector2Normalize(Vector2 vector)
+static void Vector2Normalize(Vector2 *vector)
 {
-    float length = Vector2Length(vector);
+    float length = Vector2Length(*vector);
     
-    if(length != 0)
+    if (length != 0.0f)
     {
-        return (Vector2){vector.x / length, vector.y / length};
+        vector->x /= length;
+        vector->y /= length;
+    }
+    else 
+    {
+        vector->x = 0.0f;
+        vector->y = 0.0f;
     }
-    
-    return (Vector2){0, 0};
 }

+ 4 - 3
src/physac.h

@@ -32,7 +32,8 @@
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
-typedef enum { RectangleCollider, CircleCollider } ColliderType;
+// Collider types
+typedef enum { COLLIDER_CIRCLE, COLLIDER_RECTANGLE, COLLIDER_CAPSULE } ColliderType;
 
 // Physics struct
 typedef struct Physics {
@@ -65,8 +66,8 @@ typedef struct Rigidbody {
 typedef struct Collider {
     bool enabled;
     ColliderType type;
-    Rectangle bounds;   // Just used for RectangleCollider type
-    int radius;     // Just used for CircleCollider type
+    Rectangle bounds;   // Used for COLLIDER_RECTANGLE and COLLIDER_CAPSULE
+    int radius;         // Used for COLLIDER_CIRCLE and COLLIDER_CAPSULE
 } Collider;
 
 #ifdef __cplusplus

+ 6 - 6
src/raylib.h

@@ -463,12 +463,12 @@ typedef struct {
 typedef enum { CAMERA_CUSTOM = 0, CAMERA_FREE, CAMERA_ORBITAL, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON } CameraMode;
 
 // Collider types
-typedef enum { RectangleCollider, CircleCollider } ColliderType;
+typedef enum { COLLIDER_CIRCLE, COLLIDER_RECTANGLE, COLLIDER_CAPSULE } ColliderType;
 
 // Physics struct
 typedef struct Physics {
     bool enabled;
-    bool debug;     // Should be used by programmer for testing purposes
+    bool debug;             // Should be used by programmer for testing purposes
     Vector2 gravity;
 } Physics;
 
@@ -496,8 +496,8 @@ typedef struct Rigidbody {
 typedef struct Collider {
     bool enabled;
     ColliderType type;
-    Rectangle bounds;   // Just used for RectangleCollider type
-    int radius;         // Just used for CircleCollider type
+    Rectangle bounds;   // Used for COLLIDER_RECTANGLE and COLLIDER_CAPSULE
+    int radius;         // Used for COLLIDER_CIRCLE and COLLIDER_CAPSULE
 } Collider;
 
 #ifdef __cplusplus
@@ -547,8 +547,8 @@ float GetFrameTime(void);                                   // Returns time in s
 Color GetColor(int hexValue);                               // Returns a Color struct from hexadecimal value
 int GetHexValue(Color color);                               // Returns hexadecimal value for a Color
 float *ColorToFloat(Color color);                           // Converts Color to float array and normalizes
-float *VectorToFloat(Vector3 vec);                          // Converts Vector3 to float array (defined in raymath module)
-float *MatrixToVector(Matrix mat);                          // Converts Matrix to float array (defined in raymath module)
+float *VectorToFloat(Vector3 vec);                          // Converts Vector3 to float array
+float *MatrixToFloat(Matrix mat);                           // Converts Matrix to float array
 
 int GetRandomValue(int min, int max);                       // Returns a random value between min and max (both included)
 Color Fade(Color color, float alpha);                       // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f

+ 226 - 188
src/raymath.h

@@ -1,9 +1,23 @@
 /**********************************************************************************************
 *
-*   raymath
+*   raymath (header only file)
 *
 *   Some useful functions to work with Vector3, Matrix and Quaternions
 *
+*   You must:
+*       #define RAYMATH_IMPLEMENTATION
+*   before you include this file in *only one* C or C++ file to create the implementation.
+*
+*   Example:
+*       #define RAYMATH_IMPLEMENTATION
+*       #include "raymath.h"
+*
+*   You can also use:
+*       #define RAYMATH_EXTERN_INLINE       // Inlines all functions code, so it runs faster.
+*                                           // This requires lots of memory on system.
+*       #define RAYMATH_STANDALONE          // Not dependent on raylib.h structs: Vector3, Matrix.
+*
+*
 *   Copyright (c) 2015 Ramon Santamaria (@raysan5)
 *
 *   This software is provided "as-is", without any express or implied warranty. In no event
@@ -22,37 +36,21 @@
 *     3. This notice may not be removed or altered from any source distribution.
 *
 **********************************************************************************************/
-//============================================================================
-//   YOU MUST                                                                  
-//                                                                             
-//      #define RAYMATH_DEFINE                                                     
-//                                                                             
-//   Like:                                                               
-//                                                                             
-//      #define RAYMATH_DEFINE                                                     
-//      #include "raymath.h"
-//
-//   YOU CAN:
-//      #define RAYMATH_INLINE //inlines all code, so it runs faster. This requires lots of memory on system.
-//   AND
-//      #define RAYMATH_STANDALONE //not dependent on outside libs
-//      
-//   This needs to be done for every library/source file.
-//============================================================================
-
-#ifdef RAYMATH_INLINE
-    #define RMDEF static inline
-#else
-    #define RMDEF static
-#endif
 
 #ifndef RAYMATH_H
 #define RAYMATH_H
 
-//#define RAYMATH_STANDALONE    // NOTE: To use raymath as standalone lib, just uncomment this line
+//#define RAYMATH_STANDALONE        // NOTE: To use raymath as standalone lib, just uncomment this line
+//#define RAYMATH_EXTERN_INLINE     // NOTE: To compile functions as static inline, uncomment this line
 
 #ifndef RAYMATH_STANDALONE
-    #include "raylib.h"         // Required for typedef: Vector3
+    #include "raylib.h"             // Required for structs: Vector3, Matrix
+#endif
+
+#if defined(RAYMATH_EXTERN_INLINE)
+    #define RMDEF extern inline
+#else
+    #define RMDEF extern
 #endif
 
 //----------------------------------------------------------------------------------
@@ -63,18 +61,18 @@
 #endif
 
 #ifndef DEG2RAD
-    #define DEG2RAD (PI / 180.0f)
+    #define DEG2RAD (PI/180.0f)
 #endif
 
 #ifndef RAD2DEG
-    #define RAD2DEG (180.0f / PI)
+    #define RAD2DEG (180.0f/PI)
 #endif
 
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
 
-#ifdef RAYMATH_STANDALONE
+#if defined(RAYMATH_STANDALONE)
 	// Vector2 type
     typedef struct Vector2 {
         float x;
@@ -105,7 +103,77 @@ typedef struct Quaternion {
     float w;
 } Quaternion;
 
-#ifdef RAYMATH_DEFINE
+#ifndef RAYMATH_EXTERN_INLINE
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------------
+// Functions Declaration to work with Vector3
+//------------------------------------------------------------------------------------
+RMDEF Vector3 VectorAdd(Vector3 v1, Vector3 v2);              // Add two vectors
+RMDEF Vector3 VectorSubtract(Vector3 v1, Vector3 v2);         // Substract two vectors
+RMDEF Vector3 VectorCrossProduct(Vector3 v1, Vector3 v2);     // Calculate two vectors cross product
+RMDEF Vector3 VectorPerpendicular(Vector3 v);                 // Calculate one vector perpendicular vector
+RMDEF float VectorDotProduct(Vector3 v1, Vector3 v2);         // Calculate two vectors dot product
+RMDEF float VectorLength(const Vector3 v);                    // Calculate vector lenght
+RMDEF void VectorScale(Vector3 *v, float scale);              // Scale provided vector
+RMDEF void VectorNegate(Vector3 *v);                          // Negate provided vector (invert direction)
+RMDEF void VectorNormalize(Vector3 *v);                       // Normalize provided vector
+RMDEF float VectorDistance(Vector3 v1, Vector3 v2);           // Calculate distance between two points
+RMDEF Vector3 VectorLerp(Vector3 v1, Vector3 v2, float amount); // Calculate linear interpolation between two vectors
+RMDEF Vector3 VectorReflect(Vector3 vector, Vector3 normal);  // Calculate reflected vector to normal
+RMDEF void VectorTransform(Vector3 *v, Matrix mat);           // Transforms a Vector3 by a given Matrix
+RMDEF Vector3 VectorZero(void);                               // Return a Vector3 init to zero
+
+//------------------------------------------------------------------------------------
+// Functions Declaration to work with Matrix
+//------------------------------------------------------------------------------------
+RMDEF float MatrixDeterminant(Matrix mat);                    // Compute matrix determinant
+RMDEF float MatrixTrace(Matrix mat);                          // Returns the trace of the matrix (sum of the values along the diagonal)
+RMDEF void MatrixTranspose(Matrix *mat);                      // Transposes provided matrix
+RMDEF void MatrixInvert(Matrix *mat);                         // Invert provided matrix
+RMDEF void MatrixNormalize(Matrix *mat);                      // Normalize provided matrix
+RMDEF Matrix MatrixIdentity(void);                            // Returns identity matrix
+RMDEF Matrix MatrixAdd(Matrix left, Matrix right);            // Add two matrices
+RMDEF Matrix MatrixSubstract(Matrix left, Matrix right);      // Substract two matrices (left - right)
+RMDEF Matrix MatrixTranslate(float x, float y, float z);      // Returns translation matrix
+RMDEF Matrix MatrixRotate(float angle, Vector3 axis);         // Returns rotation matrix for an angle around an specified axis (angle in radians)
+RMDEF Matrix MatrixRotateX(float angle);                      // Returns x-rotation matrix (angle in radians)
+RMDEF Matrix MatrixRotateY(float angle);                      // Returns y-rotation matrix (angle in radians)
+RMDEF Matrix MatrixRotateZ(float angle);                      // Returns z-rotation matrix (angle in radians)
+RMDEF Matrix MatrixScale(float x, float y, float z);          // Returns scaling matrix
+RMDEF Matrix MatrixMultiply(Matrix left, Matrix right);       // Returns two matrix multiplication
+RMDEF Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far);  // Returns perspective projection matrix
+RMDEF Matrix MatrixPerspective(double fovy, double aspect, double near, double far);                        // Returns perspective projection matrix
+RMDEF Matrix MatrixOrtho(double left, double right, double bottom, double top, double near, double far);    // Returns orthographic projection matrix
+RMDEF Matrix MatrixLookAt(Vector3 position, Vector3 target, Vector3 up);  // Returns camera look-at matrix (view matrix)
+RMDEF void PrintMatrix(Matrix m);                             // Print matrix utility
+
+//------------------------------------------------------------------------------------
+// Functions Declaration to work with Quaternions
+//------------------------------------------------------------------------------------
+RMDEF float QuaternionLength(Quaternion quat);                // Compute the length of a quaternion
+RMDEF void QuaternionNormalize(Quaternion *q);                // Normalize provided quaternion
+RMDEF Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2);    // Calculate two quaternion multiplication
+RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float slerp); // Calculates spherical linear interpolation between two quaternions
+RMDEF Quaternion QuaternionFromMatrix(Matrix matrix);                 // Returns a quaternion for a given rotation matrix
+RMDEF Matrix QuaternionToMatrix(Quaternion q);                        // Returns a matrix for a given quaternion
+RMDEF Quaternion QuaternionFromAxisAngle(float angle, Vector3 axis);  // Returns rotation quaternion for an angle and axis
+RMDEF void QuaternionToAxisAngle(Quaternion q, float *outAngle, Vector3 *outAxis); // Returns the rotation angle and axis for a given quaternion
+RMDEF void QuaternionTransform(Quaternion *q, Matrix mat);            // Transform a quaternion given a transformation matrix
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // notdef RAYMATH_EXTERN_INLINE
+
+//////////////////////////////////////////////////////////////////// end of header file
+
+#if defined(RAYMATH_IMPLEMENTATION) || defined(RAYMATH_EXTERN_INLINE)
+
 #include <stdio.h>      // Used only on PrintMatrix()
 #include <math.h>       // Standard math libary: sin(), cos(), tan()...
 #include <stdlib.h>     // Used for abs()
@@ -114,18 +182,6 @@ typedef struct Quaternion {
 // Module Functions Definition - Vector3 math
 //----------------------------------------------------------------------------------
 
-// Converts Vector3 to float array
-RMDEF float *VectorToFloat(Vector3 vec)
-{
-    static float buffer[3];
-
-    buffer[0] = vec.x;
-    buffer[1] = vec.y;
-    buffer[2] = vec.z;
-
-    return buffer;
-}
-
 // Add two vectors
 RMDEF Vector3 VectorAdd(Vector3 v1, Vector3 v2)
 {
@@ -229,9 +285,9 @@ RMDEF void VectorNormalize(Vector3 *v)
 
     length = VectorLength(*v);
 
-    if (length == 0) length = 1;
+    if (length == 0) length = 1.0f;
 
-    ilength = 1.0/length;
+    ilength = 1.0f/length;
 
     v->x *= ilength;
     v->y *= ilength;
@@ -257,9 +313,9 @@ RMDEF Vector3 VectorLerp(Vector3 v1, Vector3 v2, float amount)
 {
     Vector3 result;
 
-    result.x = v1.x + amount * (v2.x - v1.x);
-    result.y = v1.y + amount * (v2.y - v1.y);
-    result.z = v1.z + amount * (v2.z - v1.z);
+    result.x = v1.x + amount*(v2.x - v1.x);
+    result.y = v1.y + amount*(v2.y - v1.y);
+    result.z = v1.z + amount*(v2.z - v1.z);
 
     return result;
 }
@@ -269,15 +325,15 @@ RMDEF Vector3 VectorReflect(Vector3 vector, Vector3 normal)
 {
     // I is the original vector
     // N is the normal of the incident plane
-    // R = I - (2 * N * ( DotProduct[ I,N] ))
+    // R = I - (2*N*( DotProduct[ I,N] ))
 
     Vector3 result;
 
     float dotProduct = VectorDotProduct(vector, normal);
 
-    result.x = vector.x - (2.0 * normal.x) * dotProduct;
-    result.y = vector.y - (2.0 * normal.y) * dotProduct;
-    result.z = vector.z - (2.0 * normal.z) * dotProduct;
+    result.x = vector.x - (2.0f*normal.x)*dotProduct;
+    result.y = vector.y - (2.0f*normal.y)*dotProduct;
+    result.z = vector.z - (2.0f*normal.z)*dotProduct;
 
     return result;
 }
@@ -308,34 +364,6 @@ RMDEF Vector3 VectorZero(void)
 // Module Functions Definition - Matrix math
 //----------------------------------------------------------------------------------
 
-// Converts Matrix to float array
-// NOTE: Returned vector is a transposed version of the Matrix struct, 
-// it should be this way because, despite raymath use OpenGL column-major convention,
-// Matrix struct memory alignment and variables naming are not coherent
-RMDEF float *MatrixToFloat(Matrix mat)
-{
-    static float buffer[16];
-
-    buffer[0] = mat.m0;
-    buffer[1] = mat.m4;
-    buffer[2] = mat.m8;
-    buffer[3] = mat.m12;
-    buffer[4] = mat.m1;
-    buffer[5] = mat.m5;
-    buffer[6] = mat.m9;
-    buffer[7] = mat.m13;
-    buffer[8] = mat.m2;
-    buffer[9] = mat.m6;
-    buffer[10] = mat.m10;
-    buffer[11] = mat.m14;
-    buffer[12] = mat.m3;
-    buffer[13] = mat.m7;
-    buffer[14] = mat.m11;
-    buffer[15] = mat.m15;
-
-    return buffer;
-}
-
 // Compute matrix determinant
 RMDEF float MatrixDeterminant(Matrix mat)
 {
@@ -413,7 +441,7 @@ RMDEF void MatrixInvert(Matrix *mat)
     float b11 = a22*a33 - a23*a32;
 
     // Calculate the invert determinant (inlined to avoid double-caching)
-    float invDet = 1/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06);
+    float invDet = 1.0f/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06);
 
     temp.m0 = (a11*b11 - a12*b10 + a13*b09)*invDet;
     temp.m1 = (-a01*b11 + a02*b10 - a03*b09)*invDet;
@@ -461,7 +489,10 @@ RMDEF void MatrixNormalize(Matrix *mat)
 // Returns identity matrix
 RMDEF Matrix MatrixIdentity(void)
 {
-    Matrix result = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
+    Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 
+                      0.0f, 1.0f, 0.0f, 0.0f, 
+                      0.0f, 0.0f, 1.0f, 0.0f,
+                      0.0f, 0.0f, 0.0f, 1.0f };
 
     return result;
 }
@@ -519,7 +550,10 @@ RMDEF Matrix MatrixSubstract(Matrix left, Matrix right)
 // Returns translation matrix
 RMDEF Matrix MatrixTranslate(float x, float y, float z)
 {
-    Matrix result = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1 };
+    Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 
+                      0.0f, 1.0f, 0.0f, 0.0f, 
+                      0.0f, 0.0f, 1.0f, 0.0f, 
+                      x, y, z, 1.0f };
 
     return result;
 }
@@ -536,9 +570,9 @@ RMDEF Matrix MatrixRotate(float angle, Vector3 axis)
 
     float length = sqrt(x*x + y*y + z*z);
 
-    if ((length != 1) && (length != 0))
+    if ((length != 1.0f) && (length != 0.0f))
     {
-        length = 1/length;
+        length = 1.0f/length;
         x *= length;
         y *= length;
         z *= length;
@@ -594,15 +628,15 @@ RMDEF Matrix MatrixRotate(float angle, float x, float y, float z)
           m2 = result.m2, m6 = result.m6, m10 = result.m10, m14 = result.m14;
 
     // build rotation matrix
-    float r0 = x * x * c1 + c;
-    float r1 = x * y * c1 + z * s;
-    float r2 = x * z * c1 - y * s;
-    float r4 = x * y * c1 - z * s;
-    float r5 = y * y * c1 + c;
-    float r6 = y * z * c1 + x * s;
-    float r8 = x * z * c1 + y * s;
-    float r9 = y * z * c1 - x * s;
-    float r10= z * z * c1 + c;
+    float r0 = x*x*c1 + c;
+    float r1 = x*y*c1 + z*s;
+    float r2 = x*z*c1 - y*s;
+    float r4 = x*y*c1 - z*s;
+    float r5 = y*y*c1 + c;
+    float r6 = y*z*c1 + x*s;
+    float r8 = x*z*c1 + y*s;
+    float r9 = y*z*c1 - x*s;
+    float r10= z*z*c1 + c;
 
     // multiply rotation matrix
     result.m0 = r0*m0 + r4*m1 + r8*m2;
@@ -673,7 +707,10 @@ RMDEF Matrix MatrixRotateZ(float angle)
 // Returns scaling matrix
 RMDEF Matrix MatrixScale(float x, float y, float z)
 {
-    Matrix result = { x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1 };
+    Matrix result = { x, 0.0f, 0.0f, 0.0f, 
+                      0.0f, y, 0.0f, 0.0f, 
+                      0.0f, 0.0f, z, 0.0f, 
+                      0.0f, 0.0f, 0.0f, 1.0f };
 
     return result;
 }
@@ -713,25 +750,25 @@ RMDEF Matrix MatrixFrustum(double left, double right, double bottom, double top,
     float tb = (top - bottom);
     float fn = (far - near);
 
-    result.m0 = (near*2.0f) / rl;
-    result.m1 = 0;
-    result.m2 = 0;
-    result.m3 = 0;
+    result.m0 = (near*2.0f)/rl;
+    result.m1 = 0.0f;
+    result.m2 = 0.0f;
+    result.m3 = 0.0f;
 
-    result.m4 = 0;
-    result.m5 = (near*2.0f) / tb;
-    result.m6 = 0;
-    result.m7 = 0;
+    result.m4 = 0.0f;
+    result.m5 = (near*2.0f)/tb;
+    result.m6 = 0.0f;
+    result.m7 = 0.0f;
 
-    result.m8 = (right + left) / rl;
-    result.m9 = (top + bottom) / tb;
-    result.m10 = -(far + near) / fn;
+    result.m8 = (right + left)/rl;
+    result.m9 = (top + bottom)/tb;
+    result.m10 = -(far + near)/fn;
     result.m11 = -1.0f;
 
-    result.m12 = 0;
-    result.m13 = 0;
-    result.m14 = -(far*near*2.0f) / fn;
-    result.m15 = 0;
+    result.m12 = 0.0f;
+    result.m13 = 0.0f;
+    result.m14 = -(far*near*2.0f)/fn;
+    result.m15 = 0.0f;
 
     return result;
 }
@@ -739,7 +776,7 @@ RMDEF Matrix MatrixFrustum(double left, double right, double bottom, double top,
 // Returns perspective projection matrix
 RMDEF Matrix MatrixPerspective(double fovy, double aspect, double near, double far)
 {
-    double top = near*tanf(fovy*PI / 360.0f);
+    double top = near*tanf(fovy*PI/360.0f);
     double right = top*aspect;
 
     return MatrixFrustum(-right, right, -top, top, near, far);
@@ -754,22 +791,22 @@ RMDEF Matrix MatrixOrtho(double left, double right, double bottom, double top, d
     float tb = (top - bottom);
     float fn = (far - near);
 
-    result.m0 = 2 / rl;
-    result.m1 = 0;
-    result.m2 = 0;
-    result.m3 = 0;
-    result.m4 = 0;
-    result.m5 = 2 / tb;
-    result.m6 = 0;
-    result.m7 = 0;
-    result.m8 = 0;
-    result.m9 = 0;
-    result.m10 = -2 / fn;
-    result.m11 = 0;
-    result.m12 = -(left + right) / rl;
-    result.m13 = -(top + bottom) / tb;
-    result.m14 = -(far + near) / fn;
-    result.m15 = 1;
+    result.m0 = 2.0f/rl;
+    result.m1 = 0.0f;
+    result.m2 = 0.0f;
+    result.m3 = 0.0f;
+    result.m4 = 0.0f;
+    result.m5 = 2.0f/tb;
+    result.m6 = 0.0f;
+    result.m7 = 0.0f;
+    result.m8 = 0.0f;
+    result.m9 = 0.0f;
+    result.m10 = -2.0f/fn;
+    result.m11 = 0.0f;
+    result.m12 = -(left + right)/rl;
+    result.m13 = -(top + bottom)/tb;
+    result.m14 = -(far + near)/fn;
+    result.m15 = 1.0f;
 
     return result;
 }
@@ -789,19 +826,19 @@ RMDEF Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up)
     result.m0 = x.x;
     result.m1 = x.y;
     result.m2 = x.z;
-    result.m3 = -((x.x * eye.x) + (x.y * eye.y) + (x.z * eye.z));
+    result.m3 = -((x.x*eye.x) + (x.y*eye.y) + (x.z*eye.z));
     result.m4 = y.x;
     result.m5 = y.y;
     result.m6 = y.z;
-    result.m7 = -((y.x * eye.x) + (y.y * eye.y) + (y.z * eye.z));
+    result.m7 = -((y.x*eye.x) + (y.y*eye.y) + (y.z*eye.z));
     result.m8 = z.x;
     result.m9 = z.y;
     result.m10 = z.z;
-    result.m11 = -((z.x * eye.x) + (z.y * eye.y) + (z.z * eye.z));
-    result.m12 = 0;
-    result.m13 = 0;
-    result.m14 = 0;
-    result.m15 = 1;
+    result.m11 = -((z.x*eye.x) + (z.y*eye.y) + (z.z*eye.z));
+    result.m12 = 0.0f;
+    result.m13 = 0.0f;
+    result.m14 = 0.0f;
+    result.m15 = 1.0f;
 
     return result;
 }
@@ -834,9 +871,9 @@ RMDEF void QuaternionNormalize(Quaternion *q)
 
     length = QuaternionLength(*q);
 
-    if (length == 0) length = 1;
+    if (length == 0.0f) length = 1.0f;
 
-    ilength = 1.0/length;
+    ilength = 1.0f/length;
 
     q->x *= ilength;
     q->y *= ilength;
@@ -882,8 +919,8 @@ RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
         }
         else
         {
-            float ratioA = sin((1 - amount)*halfTheta) / sinHalfTheta;
-            float ratioB = sin(amount*halfTheta) / sinHalfTheta;
+            float ratioA = sin((1 - amount)*halfTheta)/sinHalfTheta;
+            float ratioB = sin(amount*halfTheta)/sinHalfTheta;
 
             result.x = (q1.x*ratioA + q2.x*ratioB);
             result.y = (q1.y*ratioA + q2.y*ratioB);
@@ -902,15 +939,15 @@ RMDEF Quaternion QuaternionFromMatrix(Matrix matrix)
 
     float trace = MatrixTrace(matrix);
 
-    if (trace > 0)
+    if (trace > 0.0f)
     {
-        float s = (float)sqrt(trace + 1) * 2;
-        float invS = 1 / s;
+        float s = (float)sqrt(trace + 1)*2.0f;
+        float invS = 1.0f/s;
 
-        result.w = s * 0.25;
-        result.x = (matrix.m6 - matrix.m9) * invS;
-        result.y = (matrix.m8 - matrix.m2) * invS;
-        result.z = (matrix.m1 - matrix.m4) * invS;
+        result.w = s*0.25f;
+        result.x = (matrix.m6 - matrix.m9)*invS;
+        result.y = (matrix.m8 - matrix.m2)*invS;
+        result.z = (matrix.m1 - matrix.m4)*invS;
     }
     else
     {
@@ -918,33 +955,33 @@ RMDEF Quaternion QuaternionFromMatrix(Matrix matrix)
 
         if (m00 > m11 && m00 > m22)
         {
-            float s = (float)sqrt(1 + m00 - m11 - m22) * 2;
-            float invS = 1 / s;
+            float s = (float)sqrt(1.0f + m00 - m11 - m22)*2.0f;
+            float invS = 1.0f/s;
 
-            result.w = (matrix.m6 - matrix.m9) * invS;
-            result.x = s * 0.25;
-            result.y = (matrix.m4 + matrix.m1) * invS;
-            result.z = (matrix.m8 + matrix.m2) * invS;
+            result.w = (matrix.m6 - matrix.m9)*invS;
+            result.x = s*0.25f;
+            result.y = (matrix.m4 + matrix.m1)*invS;
+            result.z = (matrix.m8 + matrix.m2)*invS;
         }
         else if (m11 > m22)
         {
-            float s = (float)sqrt(1 + m11 - m00 - m22) * 2;
-            float invS = 1 / s;
+            float s = (float)sqrt(1.0f + m11 - m00 - m22)*2.0f;
+            float invS = 1.0f/s;
 
-            result.w = (matrix.m8 - matrix.m2) * invS;
-            result.x = (matrix.m4 + matrix.m1) * invS;
-            result.y = s * 0.25;
-            result.z = (matrix.m9 + matrix.m6) * invS;
+            result.w = (matrix.m8 - matrix.m2)*invS;
+            result.x = (matrix.m4 + matrix.m1)*invS;
+            result.y = s*0.25f;
+            result.z = (matrix.m9 + matrix.m6)*invS;
         }
         else
         {
-            float s = (float)sqrt(1 + m22 - m00 - m11) * 2;
-            float invS = 1 / s;
+            float s = (float)sqrt(1.0f + m22 - m00 - m11)*2.0f;
+            float invS = 1.0f/s;
 
-            result.w = (matrix.m1 - matrix.m4) * invS;
-            result.x = (matrix.m8 + matrix.m2) * invS;
-            result.y = (matrix.m9 + matrix.m6) * invS;
-            result.z = s * 0.25;
+            result.w = (matrix.m1 - matrix.m4)*invS;
+            result.x = (matrix.m8 + matrix.m2)*invS;
+            result.y = (matrix.m9 + matrix.m6)*invS;
+            result.z = s*0.25f;
         }
     }
 
@@ -974,22 +1011,22 @@ RMDEF Matrix QuaternionToMatrix(Quaternion q)
     float wy = w*y2;
     float wz = w*z2;
 
-    result.m0 = 1 - (yy + zz);
+    result.m0 = 1.0f - (yy + zz);
     result.m1 = xy - wz;
     result.m2 = xz + wy;
-    result.m3 = 0;
+    result.m3 = 0.0f;
     result.m4 = xy + wz;
-    result.m5 = 1 - (xx + zz);
+    result.m5 = 1.0f - (xx + zz);
     result.m6 = yz - wx;
-    result.m7 = 0;
+    result.m7 = 0.0f;
     result.m8 = xz - wy;
     result.m9 = yz + wx;
-    result.m10 = 1 - (xx + yy);
-    result.m11 = 0;
-    result.m12 = 0;
-    result.m13 = 0;
-    result.m14 = 0;
-    result.m15 = 1;
+    result.m10 = 1.0f - (xx + yy);
+    result.m11 = 0.0f;
+    result.m12 = 0.0f;
+    result.m13 = 0.0f;
+    result.m14 = 0.0f;
+    result.m15 = 1.0f;
     
     return result;
 }
@@ -998,17 +1035,17 @@ RMDEF Matrix QuaternionToMatrix(Quaternion q)
 // NOTE: angle must be provided in radians
 RMDEF Quaternion QuaternionFromAxisAngle(float angle, Vector3 axis)
 {
-    Quaternion result = { 0, 0, 0, 1 };
+    Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f };
 
-    if (VectorLength(axis) != 0.0)
+    if (VectorLength(axis) != 0.0f)
 
-    angle *= 0.5;
+    angle *= 0.5f;
 
     VectorNormalize(&axis);
 
-    result.x = axis.x * (float)sin(angle);
-    result.y = axis.y * (float)sin(angle);
-    result.z = axis.z * (float)sin(angle);
+    result.x = axis.x*(float)sin(angle);
+    result.y = axis.y*(float)sin(angle);
+    result.z = axis.z*(float)sin(angle);
     result.w = (float)cos(angle);
 
     QuaternionNormalize(&result);
@@ -1021,23 +1058,23 @@ RMDEF void QuaternionToAxisAngle(Quaternion q, float *outAngle, Vector3 *outAxis
 {
     if (fabs(q.w) > 1.0f) QuaternionNormalize(&q);
 
-    Vector3 resAxis = { 0, 0, 0 };
-    float resAngle = 0;
+    Vector3 resAxis = { 0.0f, 0.0f, 0.0f };
+    float resAngle = 0.0f;
 
-    resAngle = 2.0f * (float)acos(q.w);
-    float den = (float)sqrt(1.0 - q.w * q.w);
+    resAngle = 2.0f*(float)acos(q.w);
+    float den = (float)sqrt(1.0f - q.w*q.w);
 
     if (den > 0.0001f)
     {
-        resAxis.x = q.x / den;
-        resAxis.y = q.y / den;
-        resAxis.z = q.z / den;
+        resAxis.x = q.x/den;
+        resAxis.y = q.y/den;
+        resAxis.z = q.z/den;
     }
     else
     {
         // This occurs when the angle is zero.
         // Not a problem: just set an arbitrary normalized axis.
-        resAxis.x = 1.0;
+        resAxis.x = 1.0f;
     }
 
     *outAxis = resAxis;
@@ -1058,5 +1095,6 @@ RMDEF void QuaternionTransform(Quaternion *q, Matrix mat)
     q->w = mat.m3*x + mat.m7*y + mat.m11*z + mat.m15*w;
 }
 
-#endif // RAYMATH_DEFINE
-#endif // RAYMATH_H
+#endif  // RAYMATH_IMPLEMENTATION
+
+#endif  // RAYMATH_H

+ 2 - 0
src/rlgl.c

@@ -32,6 +32,8 @@
 #include <stdlib.h>         // Declares malloc() and free() for memory management, rand()
 #include <string.h>         // Declares strcmp(), strlen(), strtok()
 
+#include "raymath.h"        // Required for Vector3 and Matrix functions
+
 #if defined(GRAPHICS_API_OPENGL_11)
     #ifdef __APPLE__                // OpenGL include for OSX
         #include <OpenGL/gl.h>

+ 5 - 4
src/rlgl.h

@@ -37,11 +37,12 @@
 #endif
 
 #if defined(RLGL_STANDALONE)
-    #define RAYMATH_STANDALONE
+    #define RAYMATH_IMPLEMENTATION  // Use raymath as a header-only library (includes implementation)
+    #define RAYMATH_EXTERN_INLINE   // Compile raymath functions as static inline (remember, it's a compiler hint)
+    #define RAYMATH_STANDALONE      // Not dependent on raylib.h structs: Vector3, Matrix
+    #include "raymath.h"            // Required for Vector3 and Matrix functions
 #endif
 
-#include "raymath.h"            // Required for data type Matrix and Matrix functions
-
 // Select desired OpenGL version
 // NOTE: Those preprocessor defines are only used on rlgl module,
 // if OpenGL version is required by any other module, it uses rlGetVersion()
@@ -92,7 +93,7 @@ typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode;
 
 typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion;
 
-#ifdef RLGL_STANDALONE
+#if defined(RLGL_STANDALONE)
     #ifndef __cplusplus
     // Boolean type
     typedef enum { false, true } bool;

File diff suppressed because it is too large
+ 349 - 213
src/stb_image.h


+ 446 - 132
src/stb_image_write.h

@@ -1,7 +1,6 @@
-/* stb_image_write - v0.98 - public domain - http://nothings.org/stb/stb_image_write.h
-   writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
-                            no warranty implied; use at your own risk
-
+/* stb_image_write - v1.01 - public domain - http://nothings.org/stb/stb_image_write.h
+   writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015
+                                     no warranty implied; use at your own risk
 
    Before #including,
 
@@ -18,7 +17,7 @@ ABOUT:
 
    The PNG output is not optimal; it is 20-50% larger than the file
    written by a decent optimizing implementation. This library is designed
-   for source code compactness and simplicitly, not optimal image file size
+   for source code compactness and simplicity, not optimal image file size
    or run-time performance.
 
 BUILDING:
@@ -35,7 +34,22 @@ USAGE:
      int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
      int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
      int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
-     int stbi_write_hdr(char const *filename, int w, int h, int comp, const void *data);
+     int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
+
+   There are also four equivalent functions that use an arbitrary write function. You are
+   expected to open/close your file-equivalent before and after calling these:
+
+     int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data, int stride_in_bytes);
+     int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);
+     int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);
+     int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
+
+   where the callback is:
+      void stbi_write_func(void *context, void *data, int size);
+
+   You can define STBI_WRITE_NO_STDIO to disable the file variant of these
+   functions, so the library will not use stdio.h at all. However, this will
+   also disable HDR writing, because it requires stdio for formatted output.
 
    Each function returns 0 on failure and non-0 on success.
 
@@ -63,6 +77,9 @@ USAGE:
    data, alpha (if provided) is discarded, and for monochrome data it is
    replicated across all three channels.
 
+   TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
+   data, set the global variable 'stbi_write_tga_with_rle' to 0.
+
 CREDITS:
 
    PNG/BMP/TGA
@@ -73,8 +90,25 @@ CREDITS:
       Jean-Sebastien Guay
    misc enhancements:
       Tim Kelsey
+   TGA RLE
+      Alan Hickman
+   initial file IO callback implementation
+      Emmanuel Julien
    bugfixes:
       github:Chribba
+      Guillaume Chereau
+      github:jry2
+      github:romigrou
+      Sergio Gonzalez
+      Jonas Karlsson
+      Filip Wasil
+      
+LICENSE
+
+This software is in the public domain. Where that dedication is not
+recognized, you are granted a perpetual, irrevocable license to copy,
+distribute, and modify this file as you see fit.
+
 */
 
 #ifndef INCLUDE_STB_IMAGE_WRITE_H
@@ -84,10 +118,26 @@ CREDITS:
 extern "C" {
 #endif
 
-extern int stbi_write_png(char const *filename, int w, int h, int comp, const void  *data, int stride_in_bytes);
-extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void  *data);
-extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void  *data);
-extern int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
+#ifdef STB_IMAGE_WRITE_STATIC
+#define STBIWDEF static
+#else
+#define STBIWDEF extern
+extern int stbi_write_tga_with_rle;
+#endif
+
+#ifndef STBI_WRITE_NO_STDIO
+STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void  *data, int stride_in_bytes);
+STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void  *data);
+STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void  *data);
+STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
+#endif
+
+typedef void stbi_write_func(void *context, void *data, int size);
+
+STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data, int stride_in_bytes);
+STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);
+STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);
+STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
 
 #ifdef __cplusplus
 }
@@ -97,25 +147,43 @@ extern int stbi_write_hdr(char const *filename, int w, int h, int comp, const fl
 
 #ifdef STB_IMAGE_WRITE_IMPLEMENTATION
 
+#ifdef _WIN32
+   #ifndef _CRT_SECURE_NO_WARNINGS
+   #define _CRT_SECURE_NO_WARNINGS
+   #endif
+   #ifndef _CRT_NONSTDC_NO_DEPRECATE
+   #define _CRT_NONSTDC_NO_DEPRECATE
+   #endif
+#endif
+
+#ifndef STBI_WRITE_NO_STDIO
+#include <stdio.h>
+#endif // STBI_WRITE_NO_STDIO
+
 #include <stdarg.h>
 #include <stdlib.h>
-#include <stdio.h>
 #include <string.h>
 #include <math.h>
 
-#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && defined(STBIW_REALLOC)
+#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))
 // ok
-#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC)
+#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)
 // ok
 #else
-#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC."
+#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)."
 #endif
 
 #ifndef STBIW_MALLOC
-#define STBIW_MALLOC(sz)    malloc(sz)
-#define STBIW_REALLOC(p,sz) realloc(p,sz)
-#define STBIW_FREE(p)       free(p)
+#define STBIW_MALLOC(sz)        malloc(sz)
+#define STBIW_REALLOC(p,newsz)  realloc(p,newsz)
+#define STBIW_FREE(p)           free(p)
 #endif
+
+#ifndef STBIW_REALLOC_SIZED
+#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)
+#endif
+
+
 #ifndef STBIW_MEMMOVE
 #define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
 #endif
@@ -126,22 +194,73 @@ extern int stbi_write_hdr(char const *filename, int w, int h, int comp, const fl
 #define STBIW_ASSERT(x) assert(x)
 #endif
 
+#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
+
+typedef struct
+{
+   stbi_write_func *func;
+   void *context;
+} stbi__write_context;
+
+// initialize a callback-based context
+static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context)
+{
+   s->func    = c;
+   s->context = context;
+}
+
+#ifndef STBI_WRITE_NO_STDIO
+
+static void stbi__stdio_write(void *context, void *data, int size)
+{
+   fwrite(data,1,size,(FILE*) context);
+}
+
+static int stbi__start_write_file(stbi__write_context *s, const char *filename)
+{
+   FILE *f = fopen(filename, "wb");
+   stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);
+   return f != NULL;
+}
+
+static void stbi__end_write_file(stbi__write_context *s)
+{
+   fclose((FILE *)s->context);
+}
+
+#endif // !STBI_WRITE_NO_STDIO
+
 typedef unsigned int stbiw_uint32;
 typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
 
-static void writefv(FILE *f, const char *fmt, va_list v)
+#ifdef STB_IMAGE_WRITE_STATIC
+static int stbi_write_tga_with_rle = 1;
+#else
+int stbi_write_tga_with_rle = 1;
+#endif
+
+static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
 {
    while (*fmt) {
       switch (*fmt++) {
          case ' ': break;
-         case '1': { unsigned char x = (unsigned char) va_arg(v, int); fputc(x,f); break; }
-         case '2': { int x = va_arg(v,int); unsigned char b[2];
-                     b[0] = (unsigned char) x; b[1] = (unsigned char) (x>>8);
-                     fwrite(b,2,1,f); break; }
-         case '4': { stbiw_uint32 x = va_arg(v,int); unsigned char b[4];
-                     b[0]=(unsigned char)x; b[1]=(unsigned char)(x>>8);
-                     b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24);
-                     fwrite(b,4,1,f); break; }
+         case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int));
+                     s->func(s->context,&x,1);
+                     break; }
+         case '2': { int x = va_arg(v,int);
+                     unsigned char b[2];
+                     b[0] = STBIW_UCHAR(x);
+                     b[1] = STBIW_UCHAR(x>>8);
+                     s->func(s->context,b,2);
+                     break; }
+         case '4': { stbiw_uint32 x = va_arg(v,int);
+                     unsigned char b[4];
+                     b[0]=STBIW_UCHAR(x);
+                     b[1]=STBIW_UCHAR(x>>8);
+                     b[2]=STBIW_UCHAR(x>>16);
+                     b[3]=STBIW_UCHAR(x>>24);
+                     s->func(s->context,b,4);
+                     break; }
          default:
             STBIW_ASSERT(0);
             return;
@@ -149,18 +268,60 @@ static void writefv(FILE *f, const char *fmt, va_list v)
    }
 }
 
-static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c)
+static void stbiw__writef(stbi__write_context *s, const char *fmt, ...)
+{
+   va_list v;
+   va_start(v, fmt);
+   stbiw__writefv(s, fmt, v);
+   va_end(v);
+}
+
+static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
 {
    unsigned char arr[3];
    arr[0] = a, arr[1] = b, arr[2] = c;
-   fwrite(arr, 3, 1, f);
+   s->func(s->context, arr, 3);
 }
 
-static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)
+static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d)
 {
    unsigned char bg[3] = { 255, 0, 255}, px[3];
+   int k;
+
+   if (write_alpha < 0)
+      s->func(s->context, &d[comp - 1], 1);
+
+   switch (comp) {
+      case 1:
+         s->func(s->context,d,1);
+         break;
+      case 2:
+         if (expand_mono)
+            stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp
+         else
+            s->func(s->context, d, 1);  // monochrome TGA
+         break;
+      case 4:
+         if (!write_alpha) {
+            // composite against pink background
+            for (k = 0; k < 3; ++k)
+               px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;
+            stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);
+            break;
+         }
+         /* FALLTHROUGH */
+      case 3:
+         stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);
+         break;
+   }
+   if (write_alpha > 0)
+      s->func(s->context, &d[comp - 1], 1);
+}
+
+static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)
+{
    stbiw_uint32 zero = 0;
-   int i,j,k, j_end;
+   int i,j, j_end;
 
    if (y <= 0)
       return;
@@ -173,73 +334,148 @@ static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp,
    for (; j != j_end; j += vdir) {
       for (i=0; i < x; ++i) {
          unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
-         if (write_alpha < 0)
-            fwrite(&d[comp-1], 1, 1, f);
-         switch (comp) {
-            case 1: fwrite(d, 1, 1, f);
-                    break;
-            case 2: if (expand_mono)
-                       write3(f, d[0],d[0],d[0]); // monochrome bmp
-                    else
-                       fwrite(d, 1, 1, f);  // monochrome TGA
-                    break;
-            case 4:
-               if (!write_alpha) {
-                  // composite against pink background
-                  for (k=0; k < 3; ++k)
-                     px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255;
-                  write3(f, px[1-rgb_dir],px[1],px[1+rgb_dir]);
-                  break;
-               }
-               /* FALLTHROUGH */
-            case 3:
-               write3(f, d[1-rgb_dir],d[1],d[1+rgb_dir]);
-               break;
-         }
-         if (write_alpha > 0)
-            fwrite(&d[comp-1], 1, 1, f);
+         stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);
       }
-      fwrite(&zero,scanline_pad,1,f);
+      s->func(s->context, &zero, scanline_pad);
    }
 }
 
-static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)
+static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)
 {
-   FILE *f;
-   if (y < 0 || x < 0) return 0;
-   f = fopen(filename, "wb");
-   if (f) {
+   if (y < 0 || x < 0) {
+      return 0;
+   } else {
       va_list v;
       va_start(v, fmt);
-      writefv(f, fmt, v);
+      stbiw__writefv(s, fmt, v);
       va_end(v);
-      write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad,expand_mono);
-      fclose(f);
+      stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono);
+      return 1;
    }
-   return f != NULL;
 }
 
-int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
+static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
 {
    int pad = (-x*3) & 3;
-   return outfile(filename,-1,-1,x,y,comp,1,(void *) data,0,pad,
+   return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
            "11 4 22 4" "4 44 22 444444",
            'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40,  // file header
             40, x,y, 1,24, 0,0,0,0,0,0);             // bitmap header
 }
 
-int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
+STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
+{
+   stbi__write_context s;
+   stbi__start_write_callbacks(&s, func, context);
+   return stbi_write_bmp_core(&s, x, y, comp, data);
+}
+
+#ifndef STBI_WRITE_NO_STDIO
+STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
+{
+   stbi__write_context s;
+   if (stbi__start_write_file(&s,filename)) {
+      int r = stbi_write_bmp_core(&s, x, y, comp, data);
+      stbi__end_write_file(&s);
+      return r;
+   } else
+      return 0;
+}
+#endif //!STBI_WRITE_NO_STDIO
+
+static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data)
 {
    int has_alpha = (comp == 2 || comp == 4);
    int colorbytes = has_alpha ? comp-1 : comp;
    int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
-   return outfile(filename, -1,-1, x, y, comp, 0, (void *) data, has_alpha, 0,
-                  "111 221 2222 11", 0,0,format, 0,0,0, 0,0,x,y, (colorbytes+has_alpha)*8, has_alpha*8);
+
+   if (y < 0 || x < 0)
+      return 0;
+
+   if (!stbi_write_tga_with_rle) {
+      return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0,
+         "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);
+   } else {
+      int i,j,k;
+
+      stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8);
+
+      for (j = y - 1; j >= 0; --j) {
+          unsigned char *row = (unsigned char *) data + j * x * comp;
+         int len;
+
+         for (i = 0; i < x; i += len) {
+            unsigned char *begin = row + i * comp;
+            int diff = 1;
+            len = 1;
+
+            if (i < x - 1) {
+               ++len;
+               diff = memcmp(begin, row + (i + 1) * comp, comp);
+               if (diff) {
+                  const unsigned char *prev = begin;
+                  for (k = i + 2; k < x && len < 128; ++k) {
+                     if (memcmp(prev, row + k * comp, comp)) {
+                        prev += comp;
+                        ++len;
+                     } else {
+                        --len;
+                        break;
+                     }
+                  }
+               } else {
+                  for (k = i + 2; k < x && len < 128; ++k) {
+                     if (!memcmp(begin, row + k * comp, comp)) {
+                        ++len;
+                     } else {
+                        break;
+                     }
+                  }
+               }
+            }
+
+            if (diff) {
+               unsigned char header = STBIW_UCHAR(len - 1);
+               s->func(s->context, &header, 1);
+               for (k = 0; k < len; ++k) {
+                  stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
+               }
+            } else {
+               unsigned char header = STBIW_UCHAR(len - 129);
+               s->func(s->context, &header, 1);
+               stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);
+            }
+         }
+      }
+   }
+   return 1;
+}
+
+int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
+{
+   stbi__write_context s;
+   stbi__start_write_callbacks(&s, func, context);
+   return stbi_write_tga_core(&s, x, y, comp, (void *) data);
 }
 
+#ifndef STBI_WRITE_NO_STDIO
+int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
+{
+   stbi__write_context s;
+   if (stbi__start_write_file(&s,filename)) {
+      int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);
+      stbi__end_write_file(&s);
+      return r;
+   } else
+      return 0;
+}
+#endif
+
 // *************************************************************************************************
 // Radiance RGBE HDR writer
 // by Baldur Karlsson
+#ifndef STBI_WRITE_NO_STDIO
+
 #define stbiw__max(a, b)  ((a) > (b) ? (a) : (b))
 
 void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
@@ -247,7 +483,7 @@ void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
    int exponent;
    float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
 
-   if (maxcomp < 1e-32) {
+   if (maxcomp < 1e-32f) {
       rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
    } else {
       float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;
@@ -259,23 +495,23 @@ void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
    }
 }
 
-void stbiw__write_run_data(FILE *f, int length, unsigned char databyte)
+void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)
 {
-   unsigned char lengthbyte = (unsigned char) (length+128);
+   unsigned char lengthbyte = STBIW_UCHAR(length+128);
    STBIW_ASSERT(length+128 <= 255);
-   fwrite(&lengthbyte, 1, 1, f);
-   fwrite(&databyte, 1, 1, f);
+   s->func(s->context, &lengthbyte, 1);
+   s->func(s->context, &databyte, 1);
 }
 
-void stbiw__write_dump_data(FILE *f, int length, unsigned char *data)
+void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)
 {
-   unsigned char lengthbyte = (unsigned char )(length & 0xff);
+   unsigned char lengthbyte = STBIW_UCHAR(length);
    STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
-   fwrite(&lengthbyte, 1, 1, f);
-   fwrite(data, length, 1, f);
+   s->func(s->context, &lengthbyte, 1);
+   s->func(s->context, data, length);
 }
 
-void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scratch, const float *scanline)
+void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline)
 {
    unsigned char scanlineheader[4] = { 2, 2, 0, 0 };
    unsigned char rgbe[4];
@@ -288,31 +524,31 @@ void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scra
    /* skip RLE for images too small or large */
    if (width < 8 || width >= 32768) {
       for (x=0; x < width; x++) {
-         switch (comp) {
+         switch (ncomp) {
             case 4: /* fallthrough */
-            case 3: linear[2] = scanline[x*comp + 2];
-                    linear[1] = scanline[x*comp + 1];
-                    linear[0] = scanline[x*comp + 0];
+            case 3: linear[2] = scanline[x*ncomp + 2];
+                    linear[1] = scanline[x*ncomp + 1];
+                    linear[0] = scanline[x*ncomp + 0];
                     break;
-            case 2: /* fallthrough */
-            case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0];
+            default:
+                    linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
                     break;
          }
          stbiw__linear_to_rgbe(rgbe, linear);
-         fwrite(rgbe, 4, 1, f);
+         s->func(s->context, rgbe, 4);
       }
    } else {
       int c,r;
       /* encode into scratch buffer */
       for (x=0; x < width; x++) {
-         switch(comp) {
+         switch(ncomp) {
             case 4: /* fallthrough */
-            case 3: linear[2] = scanline[x*comp + 2];
-                    linear[1] = scanline[x*comp + 1];
-                    linear[0] = scanline[x*comp + 0];
+            case 3: linear[2] = scanline[x*ncomp + 2];
+                    linear[1] = scanline[x*ncomp + 1];
+                    linear[0] = scanline[x*ncomp + 0];
                     break;
-            case 2: /* fallthrough */
-            case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0];
+            default:
+                    linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
                     break;
          }
          stbiw__linear_to_rgbe(rgbe, linear);
@@ -322,7 +558,7 @@ void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scra
          scratch[x + width*3] = rgbe[3];
       }
 
-      fwrite(scanlineheader, 4, 1, f);
+      s->func(s->context, scanlineheader, 4);
 
       /* RLE each component separately */
       for (c=0; c < 4; c++) {
@@ -343,7 +579,7 @@ void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scra
             while (x < r) {
                int len = r-x;
                if (len > 128) len = 128;
-               stbiw__write_dump_data(f, len, &comp[x]);
+               stbiw__write_dump_data(s, len, &comp[x]);
                x += len;
             }
             // if there's a run, output it
@@ -355,7 +591,7 @@ void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scra
                while (x < r) {
                   int len = r-x;
                   if (len > 127) len = 127;
-                  stbiw__write_run_data(f, len, comp[x]);
+                  stbiw__write_run_data(s, len, comp[x]);
                   x += len;
                }
             }
@@ -364,27 +600,52 @@ void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scra
    }
 }
 
-int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
+static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data)
 {
-   int i;
-   FILE *f;
-   if (y <= 0 || x <= 0 || data == NULL) return 0;
-   f = fopen(filename, "wb");
-   if (f) {
-      /* Each component is stored separately. Allocate scratch space for full output scanline. */
+   if (y <= 0 || x <= 0 || data == NULL)
+      return 0;
+   else {
+      // Each component is stored separately. Allocate scratch space for full output scanline.
       unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);
-      fprintf(f, "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"      );
-      fprintf(f, "EXPOSURE=          1.0000000000000\n\n-Y %d +X %d\n"                 , y, x);
+      int i, len;
+      char buffer[128];
+      char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
+      s->func(s->context, header, sizeof(header)-1);
+
+      len = sprintf(buffer, "EXPOSURE=          1.0000000000000\n\n-Y %d +X %d\n", y, x);
+      s->func(s->context, buffer, len);
+
       for(i=0; i < y; i++)
-         stbiw__write_hdr_scanline(f, x, comp, scratch, data + comp*i*x);
+         stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x);
       STBIW_FREE(scratch);
-      fclose(f);
+      return 1;
    }
-   return f != NULL;
 }
 
-/////////////////////////////////////////////////////////
-// PNG
+int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)
+{
+   stbi__write_context s;
+   stbi__start_write_callbacks(&s, func, context);
+   return stbi_write_hdr_core(&s, x, y, comp, (float *) data);
+}
+
+int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
+{
+   stbi__write_context s;
+   if (stbi__start_write_file(&s,filename)) {
+      int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);
+      stbi__end_write_file(&s);
+      return r;
+   } else
+      return 0;
+}
+#endif // STBI_WRITE_NO_STDIO
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// PNG writer
+//
 
 // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
 #define stbiw__sbraw(a) ((int *) (a) - 2)
@@ -402,7 +663,7 @@ int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *da
 static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
 {
    int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
-   void *p = STBIW_REALLOC(*arr ? stbiw__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
+   void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);
    STBIW_ASSERT(p);
    if (p) {
       if (!*arr) ((int *) p)[1] = 0;
@@ -415,7 +676,7 @@ static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
 static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
 {
    while (*bitcount >= 8) {
-      stbiw__sbpush(data, (unsigned char) *bitbuffer);
+      stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));
       *bitbuffer >>= 8;
       *bitcount -= 8;
    }
@@ -550,18 +811,19 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
 
    {
       // compute adler32 on input
-      unsigned int i=0, s1=1, s2=0, blocklen = data_len % 5552;
-      int j=0;
+      unsigned int s1=1, s2=0;
+      int blocklen = (int) (data_len % 5552);
+      j=0;
       while (j < data_len) {
          for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
          s1 %= 65521, s2 %= 65521;
          j += blocklen;
          blocklen = 5552;
       }
-      stbiw__sbpush(out, (unsigned char) (s2 >> 8));
-      stbiw__sbpush(out, (unsigned char) s2);
-      stbiw__sbpush(out, (unsigned char) (s1 >> 8));
-      stbiw__sbpush(out, (unsigned char) s1);
+      stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));
+      stbiw__sbpush(out, STBIW_UCHAR(s2));
+      stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));
+      stbiw__sbpush(out, STBIW_UCHAR(s1));
    }
    *out_len = stbiw__sbn(out);
    // make returned pointer freeable
@@ -569,21 +831,52 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
    return (unsigned char *) stbiw__sbraw(out);
 }
 
-unsigned int stbiw__crc32(unsigned char *buffer, int len)
+static unsigned int stbiw__crc32(unsigned char *buffer, int len)
 {
-   static unsigned int crc_table[256];
+   static unsigned int crc_table[256] =
+   {
+      0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+      0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+      0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+      0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+      0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+      0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+      0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+      0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+      0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+      0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+      0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+      0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+      0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+      0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+      0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+      0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+      0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+      0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+      0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+      0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+      0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+      0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+      0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+      0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+      0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+      0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+      0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+      0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+      0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+      0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+      0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+      0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+   };
+
    unsigned int crc = ~0u;
-   int i,j;
-   if (crc_table[1] == 0)
-      for(i=0; i < 256; i++)
-         for (crc_table[i]=i, j=0; j < 8; ++j)
-            crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0);
+   int i;
    for (i=0; i < len; ++i)
       crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
    return ~crc;
 }
 
-#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=(unsigned char)(a),(o)[1]=(unsigned char)(b),(o)[2]=(unsigned char)(c),(o)[3]=(unsigned char)(d),(o)+=4)
+#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4)
 #define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
 #define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
 
@@ -596,9 +889,9 @@ static void stbiw__wpcrc(unsigned char **data, int len)
 static unsigned char stbiw__paeth(int a, int b, int c)
 {
    int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
-   if (pa <= pb && pa <= pc) return (unsigned char) a;
-   if (pb <= pc) return (unsigned char) b;
-   return (unsigned char) c;
+   if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);
+   if (pb <= pc) return STBIW_UCHAR(b);
+   return STBIW_UCHAR(c);
 }
 
 unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
@@ -671,7 +964,7 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
    stbiw__wp32(o, x);
    stbiw__wp32(o, y);
    *o++ = 8;
-   *o++ = (unsigned char) ctype[n];
+   *o++ = STBIW_UCHAR(ctype[n]);
    *o++ = 0;
    *o++ = 0;
    *o++ = 0;
@@ -693,12 +986,13 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
    return out;
 }
 
-int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
+#ifndef STBI_WRITE_NO_STDIO
+STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
 {
    FILE *f;
    int len;
    unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
-   if (!png) return 0;
+   if (png == NULL) return 0;
    f = fopen(filename, "wb");
    if (!f) { STBIW_FREE(png); return 0; }
    fwrite(png, 1, len, f);
@@ -706,9 +1000,29 @@ int stbi_write_png(char const *filename, int x, int y, int comp, const void *dat
    STBIW_FREE(png);
    return 1;
 }
+#endif
+
+STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes)
+{
+   int len;
+   unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
+   if (png == NULL) return 0;
+   func(context, png, len);
+   STBIW_FREE(png);
+   return 1;
+}
+
 #endif // STB_IMAGE_WRITE_IMPLEMENTATION
 
 /* Revision history
+      1.01 (2016-01-16)
+             STBIW_REALLOC_SIZED: support allocators with no realloc support
+             avoid race-condition in crc initialization
+             minor compile issues
+      1.00 (2015-09-14)
+             installable file IO function
+      0.99 (2015-09-13)
+             warning fixes; TGA rle support
       0.98 (2015-04-08)
              added STBIW_MALLOC, STBIW_ASSERT etc
       0.97 (2015-01-18)

+ 35 - 21
src/stb_truetype.h

@@ -1,4 +1,4 @@
-// stb_truetype.h - v1.08 - public domain
+// stb_truetype.h - v1.09 - public domain
 // authored from 2009-2015 by Sean Barrett / RAD Game Tools
 //
 //   This library processes TrueType files:
@@ -42,12 +42,15 @@
 //       Sergey Popov
 //       Giumo X. Clanjor
 //       Higor Euripedes
+//       Thomas Fields
+//       Derek Vinyard
 //
 //   Misc other:
 //       Ryan Gordon
 //
 // VERSION HISTORY
 //
+//   1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly
 //   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
 //   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
 //                     variant PackFontRanges to pack and render in separate phases;
@@ -1556,7 +1559,7 @@ STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)
 
 STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
 {
-   int x0,y0,x1,y1;
+   int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning
    if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {
       // e.g. space character
       if (ix0) *ix0 = 0;
@@ -1672,6 +1675,7 @@ static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, i
 {
    stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
    float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
+   STBTT_assert(z != NULL);
    if (!z) return z;
    
    // round dx down to avoid overshooting
@@ -1693,6 +1697,7 @@ static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, i
 {
    stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
    float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
+   STBTT_assert(z != NULL);
    //STBTT_assert(e->y0 <= start_point);
    if (!z) return z;
    z->fdx = dxdy;
@@ -1817,21 +1822,23 @@ static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e,
          while (e->y0 <= scan_y) {
             if (e->y1 > scan_y) {
                stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata);
-               // find insertion point
-               if (active == NULL)
-                  active = z;
-               else if (z->x < active->x) {
-                  // insert at front
-                  z->next = active;
-                  active = z;
-               } else {
-                  // find thing to insert AFTER
-                  stbtt__active_edge *p = active;
-                  while (p->next && p->next->x < z->x)
-                     p = p->next;
-                  // at this point, p->next->x is NOT < z->x
-                  z->next = p->next;
-                  p->next = z;
+               if (z != NULL) {
+                  // find insertion point
+                  if (active == NULL)
+                     active = z;
+                  else if (z->x < active->x) {
+                     // insert at front
+                     z->next = active;
+                     active = z;
+                  } else {
+                     // find thing to insert AFTER
+                     stbtt__active_edge *p = active;
+                     while (p->next && p->next->x < z->x)
+                        p = p->next;
+                     // at this point, p->next->x is NOT < z->x
+                     z->next = p->next;
+                     p->next = z;
+                  }
                }
             }
             ++e;
@@ -2101,10 +2108,12 @@ static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e,
       while (e->y0 <= scan_y_bottom) {
          if (e->y0 != e->y1) {
             stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);
-            STBTT_assert(z->ey >= scan_y_top);
-            // insert at front
-            z->next = active;
-            active = z;
+            if (z != NULL) {
+               STBTT_assert(z->ey >= scan_y_top);
+               // insert at front
+               z->next = active;
+               active = z;
+            }
          }
          ++e;
       }
@@ -2513,6 +2522,7 @@ STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,  // fo
    float scale;
    int x,y,bottom_y, i;
    stbtt_fontinfo f;
+   f.userdata = NULL;
    if (!stbtt_InitFont(&f, data, offset))
       return -1;
    STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels
@@ -2706,6 +2716,7 @@ static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_i
    unsigned char buffer[STBTT_MAX_OVERSAMPLE];
    int safe_w = w - kernel_width;
    int j;
+   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
    for (j=0; j < h; ++j) {
       int i;
       unsigned int total;
@@ -2767,6 +2778,7 @@ static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_i
    unsigned char buffer[STBTT_MAX_OVERSAMPLE];
    int safe_h = h - kernel_width;
    int j;
+   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
    for (j=0; j < w; ++j) {
       int i;
       unsigned int total;
@@ -2975,6 +2987,7 @@ STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontd
    if (rects == NULL)
       return 0;
 
+   info.userdata = spc->user_allocator_context;
    stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));
 
    n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);
@@ -3192,6 +3205,7 @@ STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *font_collection, const
 
 // FULL VERSION HISTORY
 //
+//   1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges
 //   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
 //   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
 //                     allow PackFontRanges to pack and render in separate phases;

File diff suppressed because it is too large
+ 418 - 412
src/stb_vorbis.c


+ 37 - 28
src/stb_vorbis.h

@@ -1,35 +1,45 @@
-// Ogg Vorbis audio decoder - v1.05 - public domain
+// Ogg Vorbis audio decoder - v1.07 - public domain
 // http://nothings.org/stb_vorbis/
 //
-// Written by Sean Barrett in 2007, last updated in 2014
-// Sponsored by RAD Game Tools.
+// Original version written by Sean Barrett in 2007.
 //
-// Placed in the public domain April 2007 by the author: no copyright
-// is claimed, and you may use it for any purpose you like.
+// Originally sponsored by RAD Game Tools. Seeking sponsored
+// by Phillip Bennefall, Marc Andersen, Aaron Baker, Elias Software,
+// Aras Pranckevicius, and Sean Barrett.
+//
+// LICENSE
+//
+//   This software is in the public domain. Where that dedication is not
+//   recognized, you are granted a perpetual, irrevocable license to copy,
+//   distribute, and modify this file as you see fit.
 //
 // No warranty for any purpose is expressed or implied by the author (nor
 // by RAD Game Tools). Report bugs and send enhancements to the author.
 //
 // Limitations:
 //
-//   - seeking not supported except manually via PUSHDATA api
 //   - floor 0 not supported (used in old ogg vorbis files pre-2004)
 //   - lossless sample-truncation at beginning ignored
 //   - cannot concatenate multiple vorbis streams
 //   - sample positions are 32-bit, limiting seekable 192Khz
 //       files to around 6 hours (Ogg supports 64-bit)
 //
+// Feature contributors:
+//    Dougall Johnson (sample-exact seeking)
+//
 // Bugfix/warning contributors:
 //    Terje Mathisen     Niklas Frykholm     Andy Hill
 //    Casey Muratori     John Bolton         Gargaj
 //    Laurent Gomila     Marc LeBlanc        Ronny Chevalier
-//    Bernhard Wodo      Evan Balster			"alxprd"@github
+//    Bernhard Wodo      Evan Balster        "alxprd"@github
 //    Tom Beaumont       Ingo Leitgeb        Nicolas Guillemot
-// (If you reported a bug but do not appear in this list, it is because
-// someone else reported the bug before you. There were too many of you to
-// list them all because I was lax about updating for a long time, sorry.)
+//    Phillip Bennefall  Rohit
 //
 // Partial history:
+//    1.07    - 2015/01/16 - fixes for crashes on invalid files; warning fixes; const
+//    1.06    - 2015/08/31 - full, correct support for seeking API (Dougall Johnson)
+//                           some crash fixes when out of memory or with corrupt files
+//                           fix some inappropriately signed shifts
 //    1.05    - 2015/04/19 - don't define __forceinline if it's redundant
 //    1.04    - 2014/08/27 - fix missing const-correct case in API
 //    1.03    - 2014/08/07 - warning fixes
@@ -37,8 +47,6 @@
 //    1.01    - 2014/06/18 - fix stb_vorbis_get_samples_float (interleaved was correct)
 //    1.0     - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in >2-channel;
 //                           (API change) report sample rate for decode-full-file funcs
-//    0.99996 -            - bracket #include <malloc.h> for macintosh compilation
-//    0.99995 -            - avoid alias-optimization issue in float-to-int conversion
 //
 // See end of file for full version history.
 
@@ -157,10 +165,10 @@ extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f);
 // specification does not bound the size of an individual frame.
 
 extern stb_vorbis *stb_vorbis_open_pushdata(
-         unsigned char *datablock, int datablock_length_in_bytes,
+         const unsigned char * datablock, int datablock_length_in_bytes,
          int *datablock_memory_consumed_in_bytes,
          int *error,
-         stb_vorbis_alloc *alloc_buffer);
+         const stb_vorbis_alloc *alloc_buffer);
 // create a vorbis decoder by passing in the initial data block containing
 //    the ogg&vorbis headers (you don't need to do parse them, just provide
 //    the first N bytes of the file--you're told if it's not enough, see below)
@@ -171,7 +179,8 @@ extern stb_vorbis *stb_vorbis_open_pushdata(
 //       incomplete and you need to pass in a larger block from the start of the file
 
 extern int stb_vorbis_decode_frame_pushdata(
-         stb_vorbis *f, unsigned char *datablock, int datablock_length_in_bytes,
+         stb_vorbis *f,
+         const unsigned char *datablock, int datablock_length_in_bytes,
          int *channels,             // place to write number of float * buffers
          float ***output,           // place to write float ** array of float * buffers
          int *samples               // place to write number of output samples
@@ -235,18 +244,18 @@ extern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *chan
 // When you're done with it, just free() the pointer returned in *output.
 
 extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len,
-                                  int *error, stb_vorbis_alloc *alloc_buffer);
+                                  int *error, const stb_vorbis_alloc *alloc_buffer);
 // create an ogg vorbis decoder from an ogg vorbis stream in memory (note
 // this must be the entire stream!). on failure, returns NULL and sets *error
 
 #ifndef STB_VORBIS_NO_STDIO
 extern stb_vorbis * stb_vorbis_open_filename(const char *filename,
-                                  int *error, stb_vorbis_alloc *alloc_buffer);
+                                  int *error, const stb_vorbis_alloc *alloc_buffer);
 // create an ogg vorbis decoder from a filename via fopen(). on failure,
 // returns NULL and sets *error (possibly to VORBIS_file_open_failure).
 
 extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
-                                  int *error, stb_vorbis_alloc *alloc_buffer);
+                                  int *error, const stb_vorbis_alloc *alloc_buffer);
 // create an ogg vorbis decoder from an open FILE *, looking for a stream at
 // the _current_ seek point (ftell). on failure, returns NULL and sets *error.
 // note that stb_vorbis must "own" this stream; if you seek it in between
@@ -256,7 +265,7 @@ extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
 // function, stb_vorbis_open_file_section(), to limit it.
 
 extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close,
-                int *error, stb_vorbis_alloc *alloc_buffer, unsigned int len);
+                int *error, const stb_vorbis_alloc *alloc_buffer, unsigned int len);
 // create an ogg vorbis decoder from an open FILE *, looking for a stream at
 // the _current_ seek point (ftell); the stream will be of length 'len' bytes.
 // on failure, returns NULL and sets *error. note that stb_vorbis must "own"
@@ -266,7 +275,6 @@ extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_cl
 
 extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number);
 extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number);
-// NOT WORKING YET
 // these functions seek in the Vorbis file to (approximately) 'sample_number'.
 // after calling seek_frame(), the next call to get_frame_*() will include
 // the specified sample. after calling stb_vorbis_seek(), the next call to
@@ -275,8 +283,7 @@ extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number);
 // you can also use seek_frame().
 
 extern void stb_vorbis_seek_start(stb_vorbis *f);
-// this function is equivalent to stb_vorbis_seek(f,0), but it
-// actually works
+// this function is equivalent to stb_vorbis_seek(f,0)
 
 extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f);
 extern float        stb_vorbis_stream_length_in_seconds(stb_vorbis *f);
@@ -296,15 +303,17 @@ extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***out
 extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts);
 extern int stb_vorbis_get_frame_short            (stb_vorbis *f, int num_c, short **buffer, int num_samples);
 #endif
-// decode the next frame and return the number of samples per channel. the
-// data is coerced to the number of channels you request according to the
+// decode the next frame and return the number of *samples* per channel.
+// Note that for interleaved data, you pass in the number of shorts (the
+// size of your array), but the return value is the number of samples per
+// channel, not the total number of samples.
+//
+// The data is coerced to the number of channels you request according to the
 // channel coercion rules (see below). You must pass in the size of your
 // buffer(s) so that stb_vorbis will not overwrite the end of the buffer.
 // The maximum buffer size needed can be gotten from get_info(); however,
 // the Vorbis I specification implies an absolute maximum of 4096 samples
-// per channel. Note that for interleaved data, you pass in the number of
-// shorts (the size of your array), but the return value is the number of
-// samples per channel, not the total number of samples.
+// per channel.
 
 // Channel coercion rules:
 //    Let M be the number of channels requested, and N the number of channels present,
@@ -371,7 +380,7 @@ enum STBVorbisError
    VORBIS_invalid_first_page,
    VORBIS_bad_packet_type,
    VORBIS_cant_find_last_page,
-   VORBIS_seek_failed,
+   VORBIS_seek_failed
 };
 
 

Some files were not shown because too many files changed in this diff