Browse Source

Update to version 1.0.5

Check CHANGELOG for changes
raysan5 11 năm trước cách đây
mục cha
commit
43b13d623b
10 tập tin đã thay đổi với 668 bổ sung122 xóa
  1. 8 0
      CHANGELOG
  2. 0 6
      examples/ex06b_logo_anim.c
  3. 2 0
      src/audio.c
  4. 23 2
      src/core.c
  5. 114 107
      src/models.c
  6. 4 4
      src/raylib.h
  7. 514 0
      src/stb_image_write.h
  8. 1 1
      src/text.c
  9. 2 2
      src/textures.c
  10. BIN
      tools/rrem.exe

+ 8 - 0
CHANGELOG

@@ -6,6 +6,14 @@ Current Release:    raylib 1.0.4 (January 2014)
 NOTE: Only versions marked as 'Release' are available on release folder, updates are only available as source.
 NOTE: Current Release includes all previous updates.
 
+-----------------------------------------------
+Update:     raylib 1.0.5 (28 January 2014)
+-----------------------------------------------
+[audio] LoadSound() - Corrected a bug, WAV file was not closed!
+[core] GetMouseWheelMove() - Added, check mouse wheel Y movement
+[models] LoadHeightmap() - Added, Heightmap can be loaded as a Model
+[tool] rREM updated, now supports (partially) drag and drop of files 
+
 -----------------------------------------------
 Release:     raylib 1.0.4 (23 January 2014)
 -----------------------------------------------

+ 0 - 6
examples/ex06b_logo_anim.c

@@ -11,12 +11,6 @@
 
 #include "raylib.h"
 
-// Useful function for fade-ins and fade-outs
-Color Fade(Color col, float alpha)
-{
-    return (Color){col.r, col.g, col.b, col.a*alpha};
-}
-
 int main()
 {
     // Initialization

+ 2 - 0
src/audio.c

@@ -504,6 +504,8 @@ static Wave LoadWAV(char *fileName)
     wave.channels = waveFormat.numChannels;
     wave.bitsPerSample = waveFormat.bitsPerSample;  
 
+    fclose(wavFile);
+    
     return wave;
 }
 

+ 23 - 2
src/core.c

@@ -77,6 +77,9 @@ static char currentMouseState[3] = { 0 };   // Required to check if mouse btn pr
 static char previousGamepadState[32] = {0}; // Required to check if gamepad btn pressed/released once
 static char currentGamepadState[32] = {0};  // Required to check if gamepad btn pressed/released once
 
+static int previousMouseWheelY = 0;
+static int currentMouseWheelY = 0;
+
 //----------------------------------------------------------------------------------
 // Other Modules Functions Declaration (required by core)
 //----------------------------------------------------------------------------------
@@ -89,6 +92,7 @@ extern void UnloadDefaultFont();             // [Module: text] Unloads default f
 static void InitGraphicsDevice();                                                          // Initialize Graphics Device (OpenGL stuff)
 static void ErrorCallback(int error, const char *description);                             // GLFW3 Error Callback, runs on GLFW3 error
 static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);  // GLFW3 Keyboard Callback, runs on key pressed
+static void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);            // GLFW3 Srolling Callback, runs on mouse wheel
 static void CursorEnterCallback(GLFWwindow* window, int enter);                            // GLFW3 Cursor Enter Callback, cursor enters client area
 static void WindowSizeCallback(GLFWwindow* window, int width, int height);                 // GLFW3 WindowSize Callback, runs when window is resized
 static void CameraLookAt(Vector3 position, Vector3 target, Vector3 up);                    // Setup camera view (updates MODELVIEW matrix)
@@ -133,6 +137,7 @@ void InitWindowEx(int width, int height, const char* title, bool resizable, cons
     
     glfwMakeContextCurrent(window);
     glfwSetKeyCallback(window, KeyCallback);
+    glfwSetScrollCallback(window, ScrollCallback);
     glfwSwapInterval(0);            // Disables GPU v-sync (if set), so frames are not limited to screen refresh rate (60Hz -> 60 FPS)
                                     // If not set, swap interval uses GPU v-sync configuration
                                     // Framerate can be setup using SetTargetFPS()
@@ -195,6 +200,8 @@ void ToggleFullscreen()
         fullscreen = !fullscreen;          // Toggle fullscreen flag
 
         glfwDestroyWindow(window);         // Destroy the current window (we will recreate it!)
+        
+        // TODO: WARNING! All loaded resources are lost, we loose Context!
 
         // NOTE: Window aspect ratio is always windowWidth / windowHeight
         if (fullscreen) window = glfwCreateWindow(windowWidth, windowHeight, windowTitle, glfwGetPrimaryMonitor(), NULL);    // Fullscreen mode
@@ -498,6 +505,16 @@ Vector2 GetMousePosition()
     return position;
 }
 
+// Returns mouse wheel movement Y
+int GetMouseWheelMove()
+{
+    previousMouseWheelY = currentMouseWheelY;
+
+    currentMouseWheelY = 0;
+    
+    return previousMouseWheelY;
+}
+
 // Detect if a gamepad is available
 bool IsGamepadAvailable(int gamepad)
 {
@@ -602,6 +619,12 @@ static void ErrorCallback(int error, const char *description)
     //fprintf(stderr, description);
 }
 
+// GLFW3 Srolling Callback, runs on mouse wheel
+static void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
+{
+    currentMouseWheelY = (int)yoffset;
+}
+
 // GLFW3 Keyboard Callback, runs on key pressed
 static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
 {
@@ -662,8 +685,6 @@ static void InitGraphicsDevice()
     glMatrixMode(GL_MODELVIEW);                 // Switch back to MODELVIEW matrix
     glLoadIdentity();                           // Reset current matrix (MODELVIEW)
     
-    glDisable(GL_LIGHTING);                     // Lighting Disabled...
-    
     // TODO: Create an efficient Lighting System with proper functions (raylib 1.x)
 /*    
     glEnable(GL_COLOR_MATERIAL);                        // Enable materials, causes some glMaterial atributes to track the current color (glColor)...

+ 114 - 107
src/models.c

@@ -49,7 +49,7 @@
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
 //----------------------------------------------------------------------------------
-// No private (static) functions in this module
+static float GetHeightValue(Color pixel);
 
 //----------------------------------------------------------------------------------
 // Module Functions Definition
@@ -465,100 +465,100 @@ Model LoadModel(const char *fileName)
     int numTexCoords = 0;
     int numTriangles = 0;
 
-    FILE* objfile;
+    FILE* objFile;
 
-    objfile = fopen(fileName, "rt");
+    objFile = fopen(fileName, "rt");
     
-    while(!feof(objfile))
+    while(!feof(objFile))
     {
-        fscanf(objfile, "%c", &dataType);
+        fscanf(objFile, "%c", &dataType);
         
         switch(dataType)
         {
             case '#':         // It's a comment
             {
-                fgets(comments, 200, objfile);                
+                fgets(comments, 200, objFile);                
             } break;
             case 'v': 
             {
-                fscanf(objfile, "%c", &dataType);
+                fscanf(objFile, "%c", &dataType);
                 
                 if (dataType == 't')    // Read texCoord
                 {
-                    fgets(comments, 200, objfile);
-                    fscanf(objfile, "%c", &dataType);
+                    fgets(comments, 200, objFile);
+                    fscanf(objFile, "%c", &dataType);
                 
                     while (dataType == 'v')
                     {
-                        fgets(comments, 200, objfile);
-                        fscanf(objfile, "%c", &dataType);
+                        fgets(comments, 200, objFile);
+                        fscanf(objFile, "%c", &dataType);
                     }
                     
                     if (dataType == '#')
                     {
-                        fscanf(objfile, "%i", &numTexCoords);
+                        fscanf(objFile, "%i", &numTexCoords);
                     }
                     else printf("Ouch! Something was wrong...");
                     
-                    fgets(comments, 200, objfile);
+                    fgets(comments, 200, objFile);
                 }
                 else if (dataType == 'n')    // Read normals
                 {
-                    fgets(comments, 200, objfile);
-                    fscanf(objfile, "%c", &dataType);
+                    fgets(comments, 200, objFile);
+                    fscanf(objFile, "%c", &dataType);
                 
                     while (dataType == 'v')
                     {
-                        fgets(comments, 200, objfile);
-                        fscanf(objfile, "%c", &dataType);
+                        fgets(comments, 200, objFile);
+                        fscanf(objFile, "%c", &dataType);
                     }
                     
                     if (dataType == '#')
                     {
-                        fscanf(objfile, "%i", &numNormals);
+                        fscanf(objFile, "%i", &numNormals);
                     }
                     else printf("Ouch! Something was wrong...");
                 
-                    fgets(comments, 200, objfile);
+                    fgets(comments, 200, objFile);
                 }
                 else    // Read vertex
                 {
-                    fgets(comments, 200, objfile);
-                    fscanf(objfile, "%c", &dataType);
+                    fgets(comments, 200, objFile);
+                    fscanf(objFile, "%c", &dataType);
                 
                     while (dataType == 'v')
                     {
-                        fgets(comments, 200, objfile);
-                        fscanf(objfile, "%c", &dataType);
+                        fgets(comments, 200, objFile);
+                        fscanf(objFile, "%c", &dataType);
                     }
                     
                     if (dataType == '#')
                     {
-                        fscanf(objfile, "%i", &numVertex);
+                        fscanf(objFile, "%i", &numVertex);
                     }
                     else printf("Ouch! Something was wrong...");
                     
-                    fgets(comments, 200, objfile);
+                    fgets(comments, 200, objFile);
                 }
             } break;
             case 'f':
             {
-                fgets(comments, 200, objfile);
-                fscanf(objfile, "%c", &dataType);
+                fgets(comments, 200, objFile);
+                fscanf(objFile, "%c", &dataType);
             
                 while (dataType == 'f')
                 {
-                    fgets(comments, 200, objfile);
-                    fscanf(objfile, "%c", &dataType);
+                    fgets(comments, 200, objFile);
+                    fscanf(objFile, "%c", &dataType);
                 }
                 
                 if (dataType == '#')
                 {
-                    fscanf(objfile, "%i", &numTriangles);
+                    fscanf(objFile, "%i", &numTriangles);
                 }
                 else printf("Ouch! Something was wrong...");
                 
-                fgets(comments, 200, objfile);
+                fgets(comments, 200, objFile);
             
             } break;
             default: break;
@@ -581,51 +581,51 @@ Model LoadModel(const char *fileName)
     
     int countMaxVertex = 0;
     
-    rewind(objfile);
+    rewind(objFile);
     
-    while(!feof(objfile))
+    while(!feof(objFile))
     {
-        fscanf(objfile, "%c", &dataType);
+        fscanf(objFile, "%c", &dataType);
         
         switch(dataType)
         {
             case '#': 
             {
-                fgets(comments, 200, objfile);                
+                fgets(comments, 200, objFile);                
             } break;
             case 'v': 
             {
-                fscanf(objfile, "%c", &dataType);
+                fscanf(objFile, "%c", &dataType);
                 
                 if (dataType == 't')    // Read texCoord
                 {
                     float useless = 0;
                 
-                    fscanf(objfile, "%f %f %f", &midTexCoords[countTexCoords].x, &midTexCoords[countTexCoords].y, &useless);
+                    fscanf(objFile, "%f %f %f", &midTexCoords[countTexCoords].x, &midTexCoords[countTexCoords].y, &useless);
                     countTexCoords++;
                     
-                    fscanf(objfile, "%c", &dataType);
+                    fscanf(objFile, "%c", &dataType);
                 }
                 else if (dataType == 'n')    // Read normals
                 {
-                    fscanf(objfile, "%f %f %f", &midNormals[countNormals].x, &midNormals[countNormals].y, &midNormals[countNormals].z );
+                    fscanf(objFile, "%f %f %f", &midNormals[countNormals].x, &midNormals[countNormals].y, &midNormals[countNormals].z );
                     countNormals++;
                     
-                    fscanf(objfile, "%c", &dataType);
+                    fscanf(objFile, "%c", &dataType);
                 }
                 else    // Read vertex
                 {
-                    fscanf(objfile, "%f %f %f", &midVertices[countVertex].x, &midVertices[countVertex].y, &midVertices[countVertex].z );
+                    fscanf(objFile, "%f %f %f", &midVertices[countVertex].x, &midVertices[countVertex].y, &midVertices[countVertex].z );
                     countVertex++;
                     
-                    fscanf(objfile, "%c", &dataType);
+                    fscanf(objFile, "%c", &dataType);
                 }
             } break;
             case 'f':
             {
                 int vNum, vtNum, vnNum;
-                fscanf(objfile, "%c", &dataType);
-                fscanf(objfile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
+                fscanf(objFile, "%c", &dataType);
+                fscanf(objFile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
                 
                 model.vertices[countMaxVertex] = midVertices[vNum-1];
                 model.normals[countMaxVertex] = midNormals[vnNum-1];
@@ -633,7 +633,7 @@ Model LoadModel(const char *fileName)
                 model.texcoords[countMaxVertex].y = -midTexCoords[vtNum-1].y;
                 countMaxVertex++;
                                 
-                fscanf(objfile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
+                fscanf(objFile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
                 
                 model.vertices[countMaxVertex] = midVertices[vNum-1];
                 model.normals[countMaxVertex] = midNormals[vnNum-1];
@@ -641,7 +641,7 @@ Model LoadModel(const char *fileName)
                 model.texcoords[countMaxVertex].y = -midTexCoords[vtNum-1].y;
                 countMaxVertex++;
                 
-                fscanf(objfile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
+                fscanf(objFile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
                 
                 model.vertices[countMaxVertex] = midVertices[vNum-1];
                 model.normals[countMaxVertex] = midNormals[vnNum-1];
@@ -653,14 +653,13 @@ Model LoadModel(const char *fileName)
         }
     }
     
-    fclose(objfile);
+    fclose(objFile);
     
     return model;
 }
 
 // Load a heightmap image as a 3d model
-// TODO: Just do it...
-Model LoadHeightmap(Image heightmap, Vector3 resolution)
+Model LoadHeightmap(Image heightmap, float maxHeight)
 {
     Model model;
     
@@ -676,17 +675,72 @@ Model LoadHeightmap(Image heightmap, Vector3 resolution)
     model.vertices = (Vector3 *)malloc(model.numVertices * sizeof(Vector3));
     model.normals = (Vector3 *)malloc(model.numVertices * sizeof(Vector3));
     model.texcoords = (Vector2 *)malloc(model.numVertices * sizeof(Vector2));
+    
+    int vCounter = 0;
+    int trisCounter = 0;
+    
+    float scaleFactor = maxHeight/255;    // TODO: Review scaleFactor calculation
 
-	for(int z = 0; z < mapZ; z++)
+	for(int z = 0; z < mapZ-1; z++)
 	{
-		for(int x = 0; x < mapX; x++)
+		for(int x = 0; x < mapX-1; x++)
 		{
-			// TODO: Fill vertices array with data
+			// Fill vertices array with data
+            //----------------------------------------------------------
+            
+            // one triangle - 3 vertex
+            model.vertices[vCounter].x = x;
+            model.vertices[vCounter].y = GetHeightValue(heightmap.pixels[x + z*mapX])*scaleFactor;
+            model.vertices[vCounter].z = z;
+            
+            model.vertices[vCounter+1].x = x;
+            model.vertices[vCounter+1].y = GetHeightValue(heightmap.pixels[x + (z+1)*mapX])*scaleFactor;
+            model.vertices[vCounter+1].z = z+1;
+            
+            model.vertices[vCounter+2].x = x+1;
+            model.vertices[vCounter+2].y = GetHeightValue(heightmap.pixels[(x+1) + z*mapX])*scaleFactor;
+            model.vertices[vCounter+2].z = z;
+            
+            // another triangle - 3 vertex
+            model.vertices[vCounter+3] = model.vertices[vCounter+2];
+            model.vertices[vCounter+4] = model.vertices[vCounter+1];
+            
+            model.vertices[vCounter+5].x = x+1;
+            model.vertices[vCounter+5].y = GetHeightValue(heightmap.pixels[(x+1) + (z+1)*mapX])*scaleFactor;
+            model.vertices[vCounter+5].z = z+1;
+            
+            // Fill texcoords array with data
+            //--------------------------------------------------------------
+            model.texcoords[vCounter].x = (float)x / (mapX-1);
+            model.texcoords[vCounter].y = (float)z / (mapZ-1);
+            
+            model.texcoords[vCounter+1].x = (float)x / (mapX-1);
+            model.texcoords[vCounter+1].y = (float)(z+1) / (mapZ-1);
+            
+            model.texcoords[vCounter+2].x = (float)(x+1) / (mapX-1);
+            model.texcoords[vCounter+2].y = (float)z / (mapZ-1);
+            
+            model.texcoords[vCounter+3] = model.texcoords[vCounter+2];
+            model.texcoords[vCounter+4] = model.texcoords[vCounter+1];
+            
+            model.texcoords[vCounter+5].x = (float)(x+1) / (mapX-1);
+            model.texcoords[vCounter+5].y = (float)(z+1) / (mapZ-1);
+            
+            // Fill normals array with data
+            //--------------------------------------------------------------
+            // TODO: Review normals calculation
+            model.normals[vCounter] = (Vector3){ 0.0f, 1.0f, 0.0f };
+            model.normals[vCounter+1] = (Vector3){ 0.0f, 1.0f, 0.0f };
+            model.normals[vCounter+2] = (Vector3){ 0.0f, 1.0f, 0.0f };
+            model.normals[vCounter+3] = (Vector3){ 0.0f, 1.0f, 0.0f };
+            model.normals[vCounter+4] = (Vector3){ 0.0f, 1.0f, 0.0f };
+            model.normals[vCounter+5] = (Vector3){ 0.0f, 1.0f, 0.0f };
+            
+            vCounter += 6;
+            trisCounter += 2;
 		}
 	}
 
-	//SmoothHeightmap(&model);    // TODO: Smooth vertex interpolation
-    
     return model;
 }
 
@@ -702,6 +756,7 @@ void UnloadModel(Model model)
 void DrawModel(Model model, Vector3 position, float scale, Color color)
 {
     // NOTE: For models we use Vertex Arrays (OpenGL 1.1)
+    //static int rotation = 0;
     
     glEnableClientState(GL_VERTEX_ARRAY);                     // Enable vertex array
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);              // Enable texture coords array
@@ -725,6 +780,8 @@ void DrawModel(Model model, Vector3 position, float scale, Color color)
     glDisableClientState(GL_VERTEX_ARRAY);                     // Disable vertex array
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);              // Disable texture coords array
     glDisableClientState(GL_NORMAL_ARRAY);                     // Disable normals array
+    
+    //rotation += 10;
 }
 
 // Draw a textured model
@@ -787,58 +844,8 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vec
     glDisable(GL_TEXTURE_2D);
 }
 
-// Draw a heightmap using a provided image data
-void DrawHeightmap(Image heightmap, Vector3 centerPos, Vector3 scale, Color color)
+// Get current vertex y altitude (proportional to pixel colors in grayscale)
+static float GetHeightValue(Color pixel)
 {
-    // NOTE: Pixel-data is interpreted as grey-scale (even being a color image)
-    // NOTE: Heightmap resolution will depend on image size (one quad per pixel)
-
-    // TODO: Review how this function works... probably we need:
-    // Model LoadHeightmap(Image heightmap, Vector3 resolution);
-    
-    // NOTE: We are allocating and de-allocating vertex data every frame! --> framerate drops 80%! CRAZY!
-    Vector3 *terrainVertex = (Vector3 *)malloc(heightmap.width * heightmap.height * sizeof(Vector3));
-
-    for (int z = 0; z < heightmap.height; z++)
-    {
-        for (int x = 0; x < heightmap.width; x++)
-        {
-            terrainVertex[z*heightmap.height + x].x = (float)(x*scale.x);
-            terrainVertex[z*heightmap.height + x].y = ((float)heightmap.pixels[z*heightmap.height + x].r +
-                                    (float)heightmap.pixels[z*heightmap.height + x].g +
-                                    (float)heightmap.pixels[z*heightmap.height + x].b) / 3 * scale.y;
-            terrainVertex[z*heightmap.height + x].z = (float)(-z*scale.z);
-        }
-    }
-    
-    // TODO: Texture coordinates and normals computing
-    
-    for (int z = 0; z < heightmap.height-1; z++)
-    {
-        glBegin(GL_TRIANGLE_STRIP);
-        for (int x = 0; x < heightmap.width; x++)
-        {
-            glColor3f((float)heightmap.pixels[z*heightmap.height + x].r / 255.0f,
-                      (float)heightmap.pixels[z*heightmap.height + x].g / 255.0f,
-                      (float)heightmap.pixels[z*heightmap.height + x].b / 255.0f);
-            
-            glVertex3f(terrainVertex[z*heightmap.height + x].x, terrainVertex[z*heightmap.height + x].y, terrainVertex[z*heightmap.height + x].z);
-            glVertex3f(terrainVertex[(z+1)*heightmap.height + x].x, terrainVertex[(z+1)*heightmap.height + x].y, terrainVertex[(z+1)*heightmap.height + x].z);
-        }
-        glEnd();
-    }
-    
-    free(terrainVertex);
-}
-
-void DrawHeightmapEx(Image heightmap, Texture2D texture, Vector3 centerPos, Vector3 scale, Color tint)
-{
-    glEnable(GL_TEXTURE_2D);
-    
-    glBindTexture(GL_TEXTURE_2D, texture.glId);
-    
-    // NOTE: No texture coordinates or normals defined at this moment...
-    DrawHeightmap(heightmap, centerPos, scale, tint);
-    
-    glDisable(GL_TEXTURE_2D);
+    return (((float)pixel.r + (float)pixel.g + (float)pixel.b)/3);
 }

+ 4 - 4
src/raylib.h

@@ -65,6 +65,7 @@
 #define KEY_SPACE            32
 #define KEY_ESCAPE          256
 #define KEY_ENTER           257
+#define KEY_BACKSPACE       259
 #define KEY_RIGHT           262
 #define KEY_LEFT            263
 #define KEY_DOWN            264
@@ -278,6 +279,7 @@ bool IsMouseButtonUp(int button);                       // Detect if a mouse but
 int GetMouseX();                                        // Returns mouse position X
 int GetMouseY();                                        // Returns mouse position Y
 Vector2 GetMousePosition();                             // Returns mouse position XY
+int GetMouseWheelMove();                                // Returns mouse wheel movement Y
 
 bool IsGamepadAvailable(int gamepad);                   // Detect if a gamepad is available
 Vector2 GetGamepadMovement(int gamepad);                // Return axis movement vector for a gamepad
@@ -323,7 +325,7 @@ Image LoadImage(const char *fileName);
 Image LoadImageFromRES(const char *rresName, int resId);                                           // Load an image from rRES file (raylib Resource)
 Texture2D LoadTexture(const char *fileName);                                                       // Load an image as texture into GPU memory
 Texture2D LoadTextureFromRES(const char *rresName, int resId);                                     // Load an image as texture from rRES file (raylib Resource)
-Texture2D CreateTexture2D(Image image);                                                            // Create a Texture2D from Image data
+Texture2D CreateTexture(Image image);                                                            // Create a Texture2D from Image data
 void UnloadImage(Image image);                                                                     // Unload image from CPU memory (RAM)
 void UnloadTexture(Texture2D texture);                                                             // Unload texture from GPU memory
 
@@ -370,17 +372,15 @@ void DrawGizmo(Vector3 position, bool orbits);
 //------------------------------------------------------------------------------------
 Model LoadModel(const char *fileName);                                                             // Load a 3d model (.OBJ)
 //Model LoadModelFromRES(const char *rresName, int resId);                                         // TODO: Load a 3d model from rRES file (raylib Resource)
+Model LoadHeightmap(Image heightmap, float maxHeight);                                             // Load a heightmap image as a 3d model
 void UnloadModel(Model model);                                                                     // Unload 3d model from memory
 void DrawModel(Model model, Vector3 position, float scale, Color color);                           // Draw a model
 void DrawModelEx(Model model, Texture2D texture, Vector3 position, float scale, Color tint);       // Draw a textured model
 void DrawModelWires(Model model, Vector3 position, float scale, Color color);                      // Draw a model wires
 
 // NOTE: The following functions work but are incomplete or require some revision
-// DrawHeightmap is extremely inefficient and can impact performance up to 60%
 void DrawBillboard(Camera camera, Texture2D texture, Vector3 basePos, float size, Color tint);                         // REVIEW: Draw a billboard (raylib 1.x)
 void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 basePos, float size, Color tint); // REVIEW: Draw a billboard (raylib 1.x)
-void DrawHeightmap(Image heightmap, Vector3 centerPos, Vector3 scale, Color color);                                    // REVIEW: Draw heightmap using image map (raylib 1.x)
-void DrawHeightmapEx(Image heightmap, Texture2D texture, Vector3 centerPos, Vector3 scale, Color tint);                // REVIEW: Draw textured heightmap (raylib 1.x)
 
 //------------------------------------------------------------------------------------
 // Audio Loading and Playing Functions (Module: audio)

+ 514 - 0
src/stb_image_write.h

@@ -0,0 +1,514 @@
+/* stbiw-0.92 - 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
+
+
+Before #including,
+
+    #define STB_IMAGE_WRITE_IMPLEMENTATION
+
+in the file that you want to have the implementation.
+
+
+ABOUT:
+
+   This header file is a library for writing images to C stdio. It could be
+   adapted to write to memory or a general streaming interface; let me know.
+
+   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
+   or run-time performance.
+
+USAGE:
+
+   There are three functions, one for each image file format:
+
+     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);
+
+   Each function returns 0 on failure and non-0 on success.
+   
+   The functions create an image file defined by the parameters. The image
+   is a rectangle of pixels stored from left-to-right, top-to-bottom.
+   Each pixel contains 'comp' channels of data stored interleaved with 8-bits
+   per channel, in the following order: 1=L, 2=LA, 3=RGB, 4=RGBA. (L is
+   luminance, i.e. monochrome "color", i.e. grey value.) The rectangle is
+   'w' pixels wide and 'h' pixels tall. The *data pointer points to the
+   first byte of the top-left-most pixel. For PNG, "stride_in_bytes" is
+   the distance in bytes from the first byte of a row of pixels to the
+   first byte of the next row of pixels. Other file formats assume the
+   first byte of the each row of pixels begins immediately after the last
+   byte of the previous row.
+
+   PNG creates output files with the same number of components as the input.
+   The BMP and TGA formats expand Y to RGB in the file format. BMP does not
+   output alpha.
+   
+   PNG supports writing rectangles of data even when the bytes storing rows of
+   data are not consecutive in memory (e.g. sub-rectangles of a larger image),
+   by supplying the stride between the beginning of adjacent rows. The other
+   formats do not. (Thus you cannot write an in-memory BMP through the BMP
+   writer, both because it is in BGR order and because it may have padding
+   at the end of the line.)
+*/
+
+#ifndef INCLUDE_STB_IMAGE_WRITE_H
+#define INCLUDE_STB_IMAGE_WRITE_H
+
+#ifdef __cplusplus
+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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif//INCLUDE_STB_IMAGE_WRITE_H
+
+#ifdef STB_IMAGE_WRITE_IMPLEMENTATION
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+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)
+{
+   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; }
+         default:
+            assert(0);
+            return;
+      }
+   }
+}
+
+static void write3(FILE *f, 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);
+}
+
+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)
+{
+   unsigned char bg[3] = { 255, 0, 255}, px[3];
+   stbiw_uint32 zero = 0;
+   int i,j,k, j_end;
+
+   if (y <= 0)
+      return;
+
+   if (vdir < 0) 
+      j_end = -1, j = y-1;
+   else
+      j_end =  y, j = 0;
+
+   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:
+            case 2: write3(f, d[0],d[0],d[0]);
+                    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);
+      }
+      fwrite(&zero,scanline_pad,1,f);
+   }
+}
+
+static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, void *data, int alpha, int pad, const char *fmt, ...)
+{
+   FILE *f;
+   if (y < 0 || x < 0) return 0;
+   f = fopen(filename, "wb");
+   if (f) {
+      va_list v;
+      va_start(v, fmt);
+      writefv(f, fmt, v);
+      va_end(v);
+      write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad);
+      fclose(f);
+   }
+   return f != NULL;
+}
+
+int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
+{
+   int pad = (-x*3) & 3;
+   return outfile(filename,-1,-1,x,y,comp,(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)
+{
+   int has_alpha = !(comp & 1);
+   return outfile(filename, -1,-1, x, y, comp, (void *) data, has_alpha, 0,
+                  "111 221 2222 11", 0,0,2, 0,0,0, 0,0,x,y, 24+8*has_alpha, 8*has_alpha);
+}
+
+// stretchy buffer; stbi__sbpush() == vector<>::push_back() -- stbi__sbcount() == vector<>::size()
+#define stbi__sbraw(a) ((int *) (a) - 2)
+#define stbi__sbm(a)   stbi__sbraw(a)[0]
+#define stbi__sbn(a)   stbi__sbraw(a)[1]
+
+#define stbi__sbneedgrow(a,n)  ((a)==0 || stbi__sbn(a)+n >= stbi__sbm(a))
+#define stbi__sbmaybegrow(a,n) (stbi__sbneedgrow(a,(n)) ? stbi__sbgrow(a,n) : 0)
+#define stbi__sbgrow(a,n)  stbi__sbgrowf((void **) &(a), (n), sizeof(*(a)))
+
+#define stbi__sbpush(a, v)      (stbi__sbmaybegrow(a,1), (a)[stbi__sbn(a)++] = (v))
+#define stbi__sbcount(a)        ((a) ? stbi__sbn(a) : 0)
+#define stbi__sbfree(a)         ((a) ? free(stbi__sbraw(a)),0 : 0)
+
+static void *stbi__sbgrowf(void **arr, int increment, int itemsize)
+{
+   int m = *arr ? 2*stbi__sbm(*arr)+increment : increment+1;
+   void *p = realloc(*arr ? stbi__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
+   assert(p);
+   if (p) {
+      if (!*arr) ((int *) p)[1] = 0;
+      *arr = (void *) ((int *) p + 2);
+      stbi__sbm(*arr) = m;
+   }
+   return *arr;
+}
+
+static unsigned char *stbi__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
+{
+   while (*bitcount >= 8) {
+      stbi__sbpush(data, (unsigned char) *bitbuffer);
+      *bitbuffer >>= 8;
+      *bitcount -= 8;
+   }
+   return data;
+}
+
+static int stbi__zlib_bitrev(int code, int codebits)
+{
+   int res=0;
+   while (codebits--) {
+      res = (res << 1) | (code & 1);
+      code >>= 1;
+   }
+   return res;
+}
+
+static unsigned int stbi__zlib_countm(unsigned char *a, unsigned char *b, int limit)
+{
+   int i;
+   for (i=0; i < limit && i < 258; ++i)
+      if (a[i] != b[i]) break;
+   return i;
+}
+
+static unsigned int stbi__zhash(unsigned char *data)
+{
+   stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
+   hash ^= hash << 3;
+   hash += hash >> 5;
+   hash ^= hash << 4;
+   hash += hash >> 17;
+   hash ^= hash << 25;
+   hash += hash >> 6;
+   return hash;
+}
+
+#define stbi__zlib_flush() (out = stbi__zlib_flushf(out, &bitbuf, &bitcount))
+#define stbi__zlib_add(code,codebits) \
+      (bitbuf |= (code) << bitcount, bitcount += (codebits), stbi__zlib_flush())
+#define stbi__zlib_huffa(b,c)  stbi__zlib_add(stbi__zlib_bitrev(b,c),c)
+// default huffman tables
+#define stbi__zlib_huff1(n)  stbi__zlib_huffa(0x30 + (n), 8)
+#define stbi__zlib_huff2(n)  stbi__zlib_huffa(0x190 + (n)-144, 9)
+#define stbi__zlib_huff3(n)  stbi__zlib_huffa(0 + (n)-256,7)
+#define stbi__zlib_huff4(n)  stbi__zlib_huffa(0xc0 + (n)-280,8)
+#define stbi__zlib_huff(n)  ((n) <= 143 ? stbi__zlib_huff1(n) : (n) <= 255 ? stbi__zlib_huff2(n) : (n) <= 279 ? stbi__zlib_huff3(n) : stbi__zlib_huff4(n))
+#define stbi__zlib_huffb(n) ((n) <= 143 ? stbi__zlib_huff1(n) : stbi__zlib_huff2(n))
+
+#define stbi__ZHASH   16384
+
+unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
+{
+   static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
+   static unsigned char  lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,  4,  5,  5,  5,  5,  0 };
+   static unsigned short distc[]   = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
+   static unsigned char  disteb[]  = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };
+   unsigned int bitbuf=0;
+   int i,j, bitcount=0;
+   unsigned char *out = NULL;
+   unsigned char **hash_table[stbi__ZHASH]; // 64KB on the stack!
+   if (quality < 5) quality = 5;
+
+   stbi__sbpush(out, 0x78);   // DEFLATE 32K window
+   stbi__sbpush(out, 0x5e);   // FLEVEL = 1
+   stbi__zlib_add(1,1);  // BFINAL = 1
+   stbi__zlib_add(1,2);  // BTYPE = 1 -- fixed huffman
+
+   for (i=0; i < stbi__ZHASH; ++i)
+      hash_table[i] = NULL;
+
+   i=0;
+   while (i < data_len-3) {
+      // hash next 3 bytes of data to be compressed 
+      int h = stbi__zhash(data+i)&(stbi__ZHASH-1), best=3;
+      unsigned char *bestloc = 0;
+      unsigned char **hlist = hash_table[h];
+      int n = stbi__sbcount(hlist);
+      for (j=0; j < n; ++j) {
+         if (hlist[j]-data > i-32768) { // if entry lies within window
+            int d = stbi__zlib_countm(hlist[j], data+i, data_len-i);
+            if (d >= best) best=d,bestloc=hlist[j];
+         }
+      }
+      // when hash table entry is too long, delete half the entries
+      if (hash_table[h] && stbi__sbn(hash_table[h]) == 2*quality) {
+         memcpy(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
+         stbi__sbn(hash_table[h]) = quality;
+      }
+      stbi__sbpush(hash_table[h],data+i);
+
+      if (bestloc) {
+         // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
+         h = stbi__zhash(data+i+1)&(stbi__ZHASH-1);
+         hlist = hash_table[h];
+         n = stbi__sbcount(hlist);
+         for (j=0; j < n; ++j) {
+            if (hlist[j]-data > i-32767) {
+               int e = stbi__zlib_countm(hlist[j], data+i+1, data_len-i-1);
+               if (e > best) { // if next match is better, bail on current match
+                  bestloc = NULL;
+                  break;
+               }
+            }
+         }
+      }
+
+      if (bestloc) {
+         int d = data+i - bestloc; // distance back
+         assert(d <= 32767 && best <= 258);
+         for (j=0; best > lengthc[j+1]-1; ++j);
+         stbi__zlib_huff(j+257);
+         if (lengtheb[j]) stbi__zlib_add(best - lengthc[j], lengtheb[j]);
+         for (j=0; d > distc[j+1]-1; ++j);
+         stbi__zlib_add(stbi__zlib_bitrev(j,5),5);
+         if (disteb[j]) stbi__zlib_add(d - distc[j], disteb[j]);
+         i += best;
+      } else {
+         stbi__zlib_huffb(data[i]);
+         ++i;
+      }
+   }
+   // write out final bytes
+   for (;i < data_len; ++i)
+      stbi__zlib_huffb(data[i]);
+   stbi__zlib_huff(256); // end of block
+   // pad with 0 bits to byte boundary
+   while (bitcount)
+      stbi__zlib_add(0,1);
+
+   for (i=0; i < stbi__ZHASH; ++i)
+      (void) stbi__sbfree(hash_table[i]);
+
+   {
+      // compute adler32 on input
+      unsigned int i=0, s1=1, s2=0, blocklen = data_len % 5552;
+      int 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;
+      }
+      stbi__sbpush(out, (unsigned char) (s2 >> 8));
+      stbi__sbpush(out, (unsigned char) s2);
+      stbi__sbpush(out, (unsigned char) (s1 >> 8));
+      stbi__sbpush(out, (unsigned char) s1);
+   }
+   *out_len = stbi__sbn(out);
+   // make returned pointer freeable
+   memmove(stbi__sbraw(out), out, *out_len);
+   return (unsigned char *) stbi__sbraw(out);
+}
+
+unsigned int stbi__crc32(unsigned char *buffer, int len)
+{
+   static unsigned int crc_table[256];
+   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);
+   for (i=0; i < len; ++i)
+      crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
+   return ~crc;
+}
+
+#define stbi__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 stbi__wp32(data,v) stbi__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
+#define stbi__wptag(data,s) stbi__wpng4(data, s[0],s[1],s[2],s[3])
+
+static void stbi__wpcrc(unsigned char **data, int len)
+{
+   unsigned int crc = stbi__crc32(*data - len - 4, len+4);
+   stbi__wp32(*data, crc);
+}
+
+static unsigned char stbi__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;
+}
+
+unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
+{
+   int ctype[5] = { -1, 0, 4, 2, 6 };
+   unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
+   unsigned char *out,*o, *filt, *zlib;
+   signed char *line_buffer;
+   int i,j,k,p,zlen;
+
+   if (stride_bytes == 0)
+      stride_bytes = x * n;
+
+   filt = (unsigned char *) malloc((x*n+1) * y); if (!filt) return 0;
+   line_buffer = (signed char *) malloc(x * n); if (!line_buffer) { free(filt); return 0; }
+   for (j=0; j < y; ++j) {
+      static int mapping[] = { 0,1,2,3,4 };
+      static int firstmap[] = { 0,1,0,5,6 };
+      int *mymap = j ? mapping : firstmap;
+      int best = 0, bestval = 0x7fffffff;
+      for (p=0; p < 2; ++p) {
+         for (k= p?best:0; k < 5; ++k) {
+            int type = mymap[k],est=0;
+            unsigned char *z = pixels + stride_bytes*j;
+            for (i=0; i < n; ++i)
+               switch (type) {
+                  case 0: line_buffer[i] = z[i]; break;
+                  case 1: line_buffer[i] = z[i]; break;
+                  case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
+                  case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
+                  case 4: line_buffer[i] = (signed char) (z[i] - stbi__paeth(0,z[i-stride_bytes],0)); break;
+                  case 5: line_buffer[i] = z[i]; break;
+                  case 6: line_buffer[i] = z[i]; break;
+               }
+            for (i=n; i < x*n; ++i) {
+               switch (type) {
+                  case 0: line_buffer[i] = z[i]; break;
+                  case 1: line_buffer[i] = z[i] - z[i-n]; break;
+                  case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
+                  case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
+                  case 4: line_buffer[i] = z[i] - stbi__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
+                  case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
+                  case 6: line_buffer[i] = z[i] - stbi__paeth(z[i-n], 0,0); break;
+               }
+            }
+            if (p) break;
+            for (i=0; i < x*n; ++i)
+               est += abs((signed char) line_buffer[i]);
+            if (est < bestval) { bestval = est; best = k; }
+         }
+      }
+      // when we get here, best contains the filter type, and line_buffer contains the data
+      filt[j*(x*n+1)] = (unsigned char) best;
+      memcpy(filt+j*(x*n+1)+1, line_buffer, x*n);
+   }
+   free(line_buffer);
+   zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
+   free(filt);
+   if (!zlib) return 0;
+
+   // each tag requires 12 bytes of overhead
+   out = (unsigned char *) malloc(8 + 12+13 + 12+zlen + 12); 
+   if (!out) return 0;
+   *out_len = 8 + 12+13 + 12+zlen + 12;
+
+   o=out;
+   memcpy(o,sig,8); o+= 8;
+   stbi__wp32(o, 13); // header length
+   stbi__wptag(o, "IHDR");
+   stbi__wp32(o, x);
+   stbi__wp32(o, y);
+   *o++ = 8;
+   *o++ = (unsigned char) ctype[n];
+   *o++ = 0;
+   *o++ = 0;
+   *o++ = 0;
+   stbi__wpcrc(&o,13);
+
+   stbi__wp32(o, zlen);
+   stbi__wptag(o, "IDAT");
+   memcpy(o, zlib, zlen); o += zlen; free(zlib);
+   stbi__wpcrc(&o, zlen);
+
+   stbi__wp32(o,0);
+   stbi__wptag(o, "IEND");
+   stbi__wpcrc(&o,0);
+
+   assert(o == out + *out_len);
+
+   return out;
+}
+
+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;
+   f = fopen(filename, "wb");
+   if (!f) { free(png); return 0; }
+   fwrite(png, 1, len, f);
+   fclose(f);
+   free(png);
+   return 1;
+}
+#endif // STB_IMAGE_WRITE_IMPLEMENTATION
+
+/* Revision history
+
+      0.92 (2010-08-01)
+             casts to unsigned char to fix warnings
+      0.91 (2010-07-17)
+             first public release
+      0.90   first internal release
+*/

+ 1 - 1
src/text.c

@@ -611,7 +611,7 @@ static SpriteFont LoadRBMF(const char *fileName)
     
     printf("Image reconstructed correctly... now converting it to texture...");
     
-    spriteFont.texture = CreateTexture2D(image);
+    spriteFont.texture = CreateTexture(image);
     
     UnloadImage(image);     // Unload image data
     

+ 2 - 2
src/textures.c

@@ -259,7 +259,7 @@ Texture2D LoadTextureFromRES(const char *rresName, int resId)
     Texture2D texture;
 
     Image image = LoadImageFromRES(rresName, resId);
-    texture = CreateTexture2D(image);
+    texture = CreateTexture(image);
     
     return texture;
 }
@@ -283,7 +283,7 @@ Texture2D LoadTextureEx(const char *fileName, bool createPOT, bool mipmaps)
 
 // Create a Texture2D from Image data
 // NOTE: Image is not unloaded, it should be done manually...
-Texture2D CreateTexture2D(Image image)
+Texture2D CreateTexture(Image image)
 {
     Texture2D texture;
     

BIN
tools/rrem.exe