2
0
Эх сурвалжийг харах

Added full support for HTML5 (emscripten)

Corrected some bugs on the way...
Automatically convert textures to POT on RPI and WEB
raysan5 10 жил өмнө
parent
commit
905b6ec53d
14 өөрчлөгдсөн 515 нэмэгдсэн , 222 устгасан
  1. 31 18
      src/audio.c
  2. 215 36
      src/core.c
  3. 8 6
      src/makefile
  4. 36 6
      src/models.c
  5. 7 5
      src/raylib.h
  6. 43 4
      src/raymath.c
  7. 2 2
      src/raymath.h
  8. 20 15
      src/rlgl.c
  9. 3 2
      src/rlgl.h
  10. 2 2
      src/shapes.c
  11. 65 109
      src/text.c
  12. 48 7
      src/textures.c
  13. 34 10
      src/utils.c
  14. 1 0
      src/utils.h

+ 31 - 18
src/audio.c

@@ -45,9 +45,14 @@
 // Defines and Macros
 //----------------------------------------------------------------------------------
 #define MUSIC_STREAM_BUFFERS        2
-#define MUSIC_BUFFER_SIZE      4096*2   // PCM data buffer (short) - 16Kb
-                                        // NOTE: Reduced to avoid frame-stalls on RPI
-//#define MUSIC_BUFFER_SIZE    4096*8   // PCM data buffer (short) - 64Kb
+
+#if defined(PLATFORM_RPI)
+    // NOTE: On RPI should be lower to avoid frame-stalls
+    #define MUSIC_BUFFER_SIZE      4096*2   // PCM data buffer (short) - 16Kb (RPI)
+#else                            
+    // NOTE: On HTML5 (emscripten) this is allocated on heap, by default it's only 16MB!...just take care...
+    #define MUSIC_BUFFER_SIZE      4096*8   // PCM data buffer (short) - 64Kb
+#endif
 
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
@@ -97,7 +102,7 @@ void InitAudioDevice(void)
     // Open and initialize a device with default settings
     ALCdevice *device = alcOpenDevice(NULL);
 
-    if(!device) TraceLog(ERROR, "Could not open audio device");
+    if(!device) TraceLog(ERROR, "Audio device could not be opened");
 
     ALCcontext *context = alcCreateContext(device, NULL);
 
@@ -196,13 +201,12 @@ Sound LoadSound(char *fileName)
 
         // Attach sound buffer to source
         alSourcei(source, AL_BUFFER, buffer);
+        
+        TraceLog(INFO, "[%s] Sound file loaded successfully (SampleRate: %i, BitRate: %i, Channels: %i)", fileName, wave.sampleRate, wave.bitsPerSample, wave.channels);
 
         // Unallocate WAV data
         UnloadWave(wave);
 
-        TraceLog(INFO, "[%s] Sound file loaded successfully", fileName);
-        TraceLog(INFO, "[%s] Sample rate: %i - Channels: %i", fileName, wave.sampleRate, wave.channels);
-
         sound.source = source;
         sound.buffer = buffer;
     }
@@ -254,8 +258,7 @@ Sound LoadSoundFromWave(Wave wave)
         // Unallocate WAV data
         UnloadWave(wave);
 
-        TraceLog(INFO, "[Wave] Sound file loaded successfully");
-        TraceLog(INFO, "[Wave] Sample rate: %i - Channels: %i", wave.sampleRate, wave.channels);
+        TraceLog(INFO, "[Wave] Sound file loaded successfully (SampleRate: %i, BitRate: %i, Channels: %i)", wave.sampleRate, wave.bitsPerSample, wave.channels);
 
         sound.source = source;
         sound.buffer = buffer;
@@ -280,7 +283,10 @@ Sound LoadSoundFromRES(const char *rresName, int resId)
 
     FILE *rresFile = fopen(rresName, "rb");
 
-    if (!rresFile) TraceLog(WARNING, "[%s] Could not open raylib resource file", rresName);
+    if (rresFile == NULL) 
+    {
+        TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", rresName);
+    }
     else
     {
         // Read rres file (basic file check - id)
@@ -372,12 +378,12 @@ Sound LoadSoundFromRES(const char *rresName, int resId)
 
                         // Attach sound buffer to source
                         alSourcei(source, AL_BUFFER, buffer);
+                        
+                        TraceLog(INFO, "[%s] Sound loaded successfully from resource (SampleRate: %i, BitRate: %i, Channels: %i)", rresName, wave.sampleRate, wave.bitsPerSample, wave.channels);
 
                         // Unallocate WAV data
                         UnloadWave(wave);
 
-                        TraceLog(INFO, "[%s] Sound loaded successfully from resource, sample rate: %i", rresName, (int)sampleRate);
-
                         sound.source = source;
                         sound.buffer = buffer;
                     }
@@ -492,7 +498,10 @@ void PlayMusicStream(char *fileName)
         // Open audio stream
         currentMusic.stream = stb_vorbis_open_filename(fileName, NULL, NULL);
 
-        if (currentMusic.stream == NULL) TraceLog(WARNING, "[%s] Could not open ogg audio file", fileName);
+        if (currentMusic.stream == NULL)
+        {
+            TraceLog(WARNING, "[%s] OGG audio file could not be opened", fileName);
+        }
         else
         {
             // Get file info
@@ -582,11 +591,13 @@ void ResumeMusicStream(void)
 // Check if music is playing
 bool MusicIsPlaying(void)
 {
-    ALenum state;
+    bool playing = false;
+    ALint state;
 
     alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state);
+    if (state == AL_PLAYING) playing = true;
 
-    return (state == AL_PLAYING);
+    return playing;
 }
 
 // Set volume for music
@@ -757,9 +768,9 @@ static Wave LoadWAV(const char *fileName)
 
     wavFile = fopen(fileName, "rb");
 
-    if (!wavFile)
+    if (wavFile == NULL)
     {
-        TraceLog(WARNING, "[%s] Could not open WAV file", fileName);
+        TraceLog(WARNING, "[%s] WAV file could not be opened", fileName);
     }
     else
     {
@@ -811,7 +822,7 @@ static Wave LoadWAV(const char *fileName)
                     wave.channels = waveFormat.numChannels;
                     wave.bitsPerSample = waveFormat.bitsPerSample;
 
-                    TraceLog(INFO, "[%s] Wave file loaded successfully", fileName);
+                    TraceLog(INFO, "[%s] WAV file loaded successfully (SampleRate: %i, BitRate: %i, Channels: %i)", fileName, wave.sampleRate, wave.bitsPerSample, wave.channels);
                 }
             }
         }
@@ -860,6 +871,8 @@ static Wave LoadOGG(char *fileName)
     int samplesObtained = stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, wave.data, totalSamplesLength);
 
     TraceLog(DEBUG, "[%s] Samples obtained: %i", fileName, samplesObtained);
+    
+    TraceLog(INFO, "[%s] OGG file loaded successfully (SampleRate: %i, BitRate: %i, Channels: %i)", fileName, wave.sampleRate, wave.bitsPerSample, wave.channels);
 
     stb_vorbis_close(oggFile);
 

+ 215 - 36
src/core.c

@@ -92,7 +92,7 @@
 //----------------------------------------------------------------------------------
 // Defines and Macros
 //----------------------------------------------------------------------------------
-// ...
+#define MAX_TOUCH_POINTS 256
 
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
@@ -112,7 +112,14 @@ static bool windowReady = false;                // Used to detect display initia
 
 // Gestures detection variables
 static float tapTouchX, tapTouchY;
+static int64_t lastTapTime = 0;
+static float lastTapX = 0, lastTapY = 0;
 static bool touchTap = false;
+static bool doubleTap = false;
+static bool drag = false;
+static int stdVector[MAX_TOUCH_POINTS];
+static int indexPosition = 0;
+const AInputEvent* eventDrag;
 static int32_t touchId;
 const int32_t DOUBLE_TAP_TIMEOUT = 300*1000000;
 const int32_t DOUBLE_TAP_SLOP = 100;
@@ -184,6 +191,7 @@ static int previousMouseWheelY = 0;         // Required to track mouse wheel var
 static int currentMouseWheelY = 0;          // Required to track mouse wheel variation
 
 static int exitKey = KEY_ESCAPE;            // Default exit key (ESC)
+static int lastKeyPressed = -1;
 #endif
 
 #if defined(PLATFORM_ANDROID)
@@ -230,6 +238,8 @@ static void InitGamepad(void);                          // Init raw gamepad inpu
 #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
 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 MouseButtonCallback(GLFWwindow *window, int button, int action, int mods);     // GLFW3 Mouse Button Callback, runs on mouse button pressed
+static void CharCallback(GLFWwindow *window, unsigned int key);                            // GLFW3 Char Key Callback, runs on key pressed (get char value)
 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
@@ -441,6 +451,12 @@ int GetScreenHeight(void)
     return screenHeight;
 }
 
+// Get the last key pressed
+int GetKeyPressed(void)
+{
+    return lastKeyPressed;
+}
+
 // Sets Background Color
 void ClearBackground(Color color)
 {
@@ -623,13 +639,7 @@ bool IsKeyPressed(int key)
 {
     bool pressed = false;
 
-    currentKeyState[key] = IsKeyDown(key);
-
-    if (currentKeyState[key] != previousKeyState[key])
-    {
-        if (currentKeyState[key]) pressed = true;
-        previousKeyState[key] = currentKeyState[key];
-    }
+    if ((currentKeyState[key] != previousKeyState[key]) && (currentKeyState[key] == 1)) pressed = true;
     else pressed = false;
 
     return pressed;
@@ -647,13 +657,7 @@ bool IsKeyReleased(int key)
 {
     bool released = false;
 
-    currentKeyState[key] = IsKeyUp(key);
-
-    if (currentKeyState[key] != previousKeyState[key])
-    {
-        if (currentKeyState[key]) released = true;
-        previousKeyState[key] = currentKeyState[key];
-    }
+    if ((currentKeyState[key] != previousKeyState[key]) && (currentKeyState[key] == 0)) released = true;
     else released = false;
 
     return released;
@@ -671,13 +675,7 @@ bool IsMouseButtonPressed(int button)
 {
     bool pressed = false;
 
-    currentMouseState[button] = IsMouseButtonDown(button);
-
-    if (currentMouseState[button] != previousMouseState[button])
-    {
-        if (currentMouseState[button]) pressed = true;
-        previousMouseState[button] = currentMouseState[button];
-    }
+    if ((currentMouseState[button] != previousMouseState[button]) && (currentMouseState[button] == 1)) pressed = true;
     else pressed = false;
 
     return pressed;
@@ -695,13 +693,7 @@ bool IsMouseButtonReleased(int button)
 {
     bool released = false;
 
-    currentMouseState[button] = IsMouseButtonUp(button);
-
-    if (currentMouseState[button] != previousMouseState[button])
-    {
-        if (currentMouseState[button]) released = true;
-        previousMouseState[button] = currentMouseState[button];
-    }
+    if ((currentMouseState[button] != previousMouseState[button]) && (currentMouseState[button] == 0)) released = true;
     else released = false;
 
     return released;
@@ -858,6 +850,18 @@ bool IsScreenTouched(void)
     return touchTap;
 }
 
+bool IsDoubleTap(void)
+{
+    if (doubleTap) TraceLog(INFO, "DOUBLE TAP gesture detected");
+
+    return doubleTap;
+}
+
+bool IsDragGesture(void)
+{
+    return drag;
+}
+
 // Returns touch position X
 int GetTouchX(void)
 {
@@ -877,6 +881,27 @@ Vector2 GetTouchPosition(void)
 
     return position;
 }
+
+/*bool GetPointer(Vector2 *dragPositions)
+{
+    //static int stdVector[MAX_TOUCH_POINTS];
+    //static int indexPosition = 0;
+    //if (indexPosition == 0) return false;
+    Vector2 vec_pointers_[];
+
+    //eventDrag
+    int32_t iIndex = FindIndex( eventDrag, vec_pointers_[0] );
+    
+    if (iIndex == -1) return false;
+
+    float x = AMotionEvent_getX(eventDrag, iIndex);
+    float y = AMotionEvent_getY(eventDrag, iIndex);
+
+    *dragPositions = Vector2( x, y );
+
+
+    return true;
+}*/
 #endif
 
 //----------------------------------------------------------------------------------
@@ -977,6 +1002,8 @@ static void InitDisplay(int width, int height)
     glfwSetWindowSizeCallback(window, WindowSizeCallback);
     glfwSetCursorEnterCallback(window, CursorEnterCallback);
     glfwSetKeyCallback(window, KeyCallback);
+    glfwSetMouseButtonCallback(window, MouseButtonCallback);
+    glfwSetCharCallback(window, CharCallback);
     glfwSetScrollCallback(window, ScrollCallback);
 
     glfwMakeContextCurrent(window);
@@ -1168,6 +1195,25 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
         TakeScreenshot();
     }
 #endif
+    else currentKeyState[key] = action;
+
+    // HACK for GuiTextBox, to deteck back key
+    // TODO: Review...
+    if ((key == 259) && (action == GLFW_PRESS)) lastKeyPressed = 3;
+}
+
+// GLFW3 Mouse Button Callback, runs on mouse button pressed
+static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods)
+{
+    currentMouseState[button] = action;
+}
+
+// GLFW3 Char Key Callback, runs on key pressed (get char value)
+static void CharCallback(GLFWwindow *window, unsigned int key)
+{
+    lastKeyPressed = key;
+    
+    //TraceLog(INFO, "Char Callback Key pressed: %i\n", key);
 }
 
 // GLFW3 CursorEnter Callback, when cursor enters the window
@@ -1203,6 +1249,7 @@ static int32_t InputCallback(struct android_app *app, AInputEvent *event)
 
     if (type == AINPUT_EVENT_TYPE_MOTION)
     {
+        // Detect TOUCH position
         if ((screenWidth > displayWidth) || (screenHeight > displayHeight))
         {
             // TODO: Seems to work ok but... review!
@@ -1266,7 +1313,124 @@ static int32_t InputCallback(struct android_app *app, AInputEvent *event)
         //size_t pointerCount =  AMotionEvent_getPointerCount(event);
         //float AMotionEvent_getPressure(const AInputEvent *motion_event, size_t pointer_index); // 0 to 1
         //float AMotionEvent_getSize(const AInputEvent *motion_event, size_t pointer_index); // Pressed area
+        
+        // Detect DOUBLE TAP event
+        bool tapDetected = touchTap;
 
+        switch (flags)
+        {
+            case AMOTION_EVENT_ACTION_DOWN:
+            {
+                int64_t eventTime = AMotionEvent_getEventTime(event);
+                
+                if (eventTime - lastTapTime <= DOUBLE_TAP_TIMEOUT)
+                {
+                    float x = AMotionEvent_getX(event, 0) - lastTapX;
+                    float y = AMotionEvent_getY(event, 0) - lastTapY;
+                    
+                    float densityFactor = 1.0f;
+                    
+                    if ((x*x + y*y) < (DOUBLE_TAP_SLOP*DOUBLE_TAP_SLOP*densityFactor))
+                    {
+                        // Doubletap detected
+                        doubleTap = true;
+                        
+                    }
+                }
+            } break;
+            case AMOTION_EVENT_ACTION_UP:
+            {
+                if (tapDetected)
+                {
+                    lastTapTime = AMotionEvent_getEventTime(event);
+                    lastTapX = AMotionEvent_getX(event, 0);
+                    lastTapY = AMotionEvent_getY(event, 0);
+                    
+                }
+            } break;
+        }
+        
+        
+        // Detect DRAG event
+        //int32_t action = AMotionEvent_getAction(event);
+
+        int32_t index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+        //uint32_t flags = action & AMOTION_EVENT_ACTION_MASK;
+        //event_ = event;
+
+        int32_t count = AMotionEvent_getPointerCount(event);
+
+        switch (flags)
+        {
+            case AMOTION_EVENT_ACTION_DOWN:
+            {
+                stdVector[indexPosition] = AMotionEvent_getPointerId(event, 0);
+                indexPosition++;
+                TraceLog(INFO, "ACTION_DOWN");
+                
+                //ret = GESTURE_STATE_START;
+            } break;
+            case AMOTION_EVENT_ACTION_POINTER_DOWN:
+            {
+                stdVector[indexPosition] = AMotionEvent_getPointerId(event, index);
+                indexPosition++;
+                TraceLog(INFO, "ACTION_POINTER_DOWN");
+                
+            } break;
+            case AMOTION_EVENT_ACTION_UP:
+            {
+                //int value = stdVector[indexPosition];
+                indexPosition--;
+                //ret = GESTURE_STATE_END;
+                TraceLog(INFO, "ACTION_UP");
+                
+            } break;
+            case AMOTION_EVENT_ACTION_POINTER_UP:
+            {
+                int32_t releasedPointerId = AMotionEvent_getPointerId(event, index);
+                
+                int i = 0;
+                for (i = 0; i < MAX_TOUCH_POINTS; i++)
+                {
+                    if (stdVector[i] == releasedPointerId)
+                    {
+                        for (int k = i; k < indexPosition - 1; k++)
+                        {
+                            stdVector[k] = stdVector[k + 1];
+                        }
+                        
+                        //indexPosition--;
+                        indexPosition = 0;
+                        break;
+                    }
+                }
+                
+                if (i <= 1)
+                {
+                    // Reset pinch or drag
+                    //if (count == 2) //ret = GESTURE_STATE_START;
+                }
+                TraceLog(INFO, "ACTION_POINTER_UP");
+                
+            } break;
+            case AMOTION_EVENT_ACTION_MOVE:
+            {
+                if (count == 1)
+                {
+                    //TraceLog(INFO, "DRAG gesture detected");
+                
+                    drag = true; //ret = GESTURE_STATE_MOVE;
+                }
+                else break;
+                TraceLog(INFO, "ACTION_MOVE");
+
+            } break;
+            case AMOTION_EVENT_ACTION_CANCEL: break;
+            default: break;
+        }
+
+        //--------------------------------------------------------------------
+        
         return 1;
     }
     else if (type == AINPUT_EVENT_TYPE_KEY)
@@ -1467,14 +1631,23 @@ static void PollInputEvents(void)
 
     // Keyboard polling
     // Automatically managed by GLFW3 through callback
-
+    lastKeyPressed = -1;
+    
+    // Register previous keys states
+    for (int i = 0; i < 512; i++) previousKeyState[i] = currentKeyState[i];
+    
+    // Register previous mouse states
+    for (int i = 0; i < 3; i++) previousMouseState[i] = currentMouseState[i];
+    
     glfwPollEvents();       // Register keyboard/mouse events
 #elif defined(PLATFORM_ANDROID)
 
     // TODO: Check virtual keyboard (?)
 
-    // Reset touchTap event
+    // Reset touch events
     touchTap = false;
+    doubleTap = false;
+    drag = false;
 
     // Poll Events (registered events)
     while ((ident = ALooper_pollAll(0, NULL, &events,(void**)&source)) >= 0)
@@ -1623,14 +1796,17 @@ static void PollInputEvents(void)
 static void InitMouse(void)
 {
     // NOTE: We can use /dev/input/mice to read from all available mice
-    if ((mouseStream = open(DEFAULT_MOUSE_DEV, O_RDONLY|O_NONBLOCK)) < 0) TraceLog(WARNING, "Could not open mouse device, no mouse available");
+    if ((mouseStream = open(DEFAULT_MOUSE_DEV, O_RDONLY|O_NONBLOCK)) < 0)
+    {
+        TraceLog(WARNING, "Mouse device could not be opened, no mouse available");
+    }
     else
     {
         mouseReady = true;
 
-        int err = pthread_create(&mouseThreadId, NULL, &MouseThread, NULL);
+        int error = pthread_create(&mouseThreadId, NULL, &MouseThread, NULL);
 
-        if (err != 0) TraceLog(WARNING, "Error creating mouse input event thread");
+        if (error != 0) TraceLog(WARNING, "Error creating mouse input event thread");
         else TraceLog(INFO, "Mouse device initialized successfully");
     }
 }
@@ -1741,7 +1917,7 @@ static void RestoreKeyboard(void)
 static void InitGamepad(void)
 {
     // TODO: Gamepad support
-    if ((gamepadStream = open(DEFAULT_GAMEPAD_DEV, O_RDONLY|O_NONBLOCK)) < 0) TraceLog(WARNING, "Could not open gamepad device, no gamepad available");
+    if ((gamepadStream = open(DEFAULT_GAMEPAD_DEV, O_RDONLY|O_NONBLOCK)) < 0) TraceLog(WARNING, "Gamepad device could not be opened, no gamepad available");
     else TraceLog(INFO, "Gamepad device initialized successfully");
 }
 #endif
@@ -1763,7 +1939,7 @@ static void SetupFramebufferSize(int displayWidth, int displayHeight)
     // Calculate renderWidth and renderHeight, we have the display size (input params) and the desired screen size (global var)
     if ((screenWidth > displayWidth) || (screenHeight > displayHeight))
     {
-        TraceLog(WARNING, "DOWNSCALING: Required screen size (%i x %i) is bigger than display size (%i x %i)", screenWidth, screenHeight, displayWidth, displayHeight);
+        TraceLog(WARNING, "DOWNSCALING: Required screen size (%ix%i) is bigger than display size (%ix%i)", screenWidth, screenHeight, displayWidth, displayHeight);
 
         // Downscaling to fit display with border-bars
         float widthRatio = (float)displayWidth/(float)screenWidth;
@@ -1832,6 +2008,7 @@ static void SetupFramebufferSize(int displayWidth, int displayHeight)
 // Plays raylib logo appearing animation
 static void LogoAnimation(void)
 {
+#ifndef PLATFORM_WEB
     int logoPositionX = screenWidth/2 - 128;
     int logoPositionY = screenHeight/2 - 128;
 
@@ -1949,6 +2126,8 @@ static void LogoAnimation(void)
         EndDrawing();
         //----------------------------------------------------------------------------------
     }
+#endif
 
     showLogo = false;  // Prevent for repeating when reloading window (Android)
 }
+

+ 8 - 6
src/makefile

@@ -1,8 +1,6 @@
 #**************************************************************************************************
 #
-#   raylib for Raspberry Pi and Windows desktop
-#
-#   makefile for library compilation (raylib.a)
+#   raylib makefile for desktop platforms, Raspberry Pi and HTML5 (emscripten)
 #
 #   Copyright (c) 2014 Ramon Santamaria (Ray San - [email protected])
 #    
@@ -23,8 +21,8 @@
 #
 #**************************************************************************************************
 
-# define raylib platform (by default, compile for RPI)
-# Other possible platforms: PLATFORM_DESKTOP_WIN PLATFORM_DESKTOP_LINUX PLATFORM_WEB
+# define raylib platform to compile for
+# possible platforms: PLATFORM_DESKTOP PLATFORM_RPI PLATFORM_WEB
 PLATFORM ?= PLATFORM_DESKTOP
 
 # define raylib graphics api depending on selected platform
@@ -81,7 +79,7 @@ default: raylib
 # compile raylib library
 raylib: $(OBJS)
 ifeq ($(PLATFORM),PLATFORM_WEB)
-	emcc -O1 $(OBJS) -o raylib.bc
+	emcc -O1 $(OBJS) -o libraylib.bc
 else
 	ar rcs libraylib.a $(OBJS)
 endif
@@ -135,9 +133,13 @@ else
 ifeq ($(PLATFORM),PLATFORM_DESKTOP_LINUX)
 	find . -type f -executable -delete
 	rm -f *.o libraylib.a
+else
+ifeq ($(PLATFORM),PLATFORM_WEB)
+	del *.o libraylib.bc
 else
 	del *.o libraylib.a
 endif
+endif
 endif
 	@echo Cleaning done
 

+ 36 - 6
src/models.c

@@ -50,7 +50,7 @@
 //----------------------------------------------------------------------------------
 // Global Variables Definition
 //----------------------------------------------------------------------------------
-// It's lonely here...
+extern unsigned int whiteTexture;
 
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
@@ -476,7 +476,7 @@ void DrawQuad(Vector3 vertices[4], Vector2 textcoords[4], Vector3 normals[4], Co
 void DrawPlane(Vector3 centerPos, Vector2 size, Vector3 rotation, Color color)
 {
     // NOTE: QUADS usage require defining a texture on OpenGL 3.3+
-    if (rlGetVersion() != OPENGL_11) rlEnableTexture(1);    // Default white texture
+    if (rlGetVersion() != OPENGL_11) rlEnableTexture(whiteTexture);    // Default white texture
 
     // NOTE: Plane is always created on XZ ground and then rotated
     rlPushMatrix();
@@ -812,7 +812,7 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
 }
 
 // Load a map image as a 3d model (cubes based)
-Model LoadCubesmap(Image cubesmap)
+Model LoadCubicmap(Image cubesmap)
 {
     VertexData vData;
 
@@ -1068,8 +1068,6 @@ Model LoadCubesmap(Image cubesmap)
     // Move data from mapVertices temp arays to vertices float array
     vData.vertexCount = vCounter;
 
-    //printf("Vertex count: %i\n", vCounter);
-
     vData.vertices = (float *)malloc(vData.vertexCount * 3 * sizeof(float));
     vData.normals = (float *)malloc(vData.vertexCount * 3 * sizeof(float));
     vData.texcoords = (float *)malloc(vData.vertexCount * 2 * sizeof(float));
@@ -1523,4 +1521,36 @@ static VertexData LoadOBJ(const char *fileName)
     TraceLog(INFO, "[%s] Model loaded successfully in RAM (CPU)", fileName);
 
     return vData;
-}
+}
+
+bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB)
+{
+
+    return false;
+}
+
+bool CheckCollisionBoxes(Vector3 minBBox1, Vector3 maxBBox1, Vector3 minBBox2, Vector3 maxBBox2)
+{
+    /*
+    // Get min and max vertex to construct bounds (AABB)
+    Vector3 minVertex = tempVertices[0]; 
+    Vector3 maxVertex = tempVertices[0];
+    
+    for (int i = 1; i < tempVertices.Count; i++)
+    {
+        minVertex = Vector3.Min(minVertex, tempVertices[i]);
+        maxVertex = Vector3.Max(maxVertex, tempVertices[i]);
+    }
+    
+    bounds = new BoundingBox(minVertex, maxVertex);
+    */
+    return false;
+}
+
+bool CheckCollisionBoxSphere(Vector3 minBBox, Vector3 maxBBox, Vector3 centerSphere, Vector3 radiusSphere)
+{
+
+    return false;
+}
+
+//BoundingBox GetCollisionArea(BoundingBox box1, BoundingBox box2)

+ 7 - 5
src/raylib.h

@@ -63,6 +63,7 @@
 //#define PLATFORM_DESKTOP      // Windows, Linux or OSX
 //#define PLATFORM_ANDROID      // Android device
 //#define PLATFORM_RPI          // Raspberry Pi
+//#define PLATFORM_WEB          // HTML5 (emscripten, asm.js)
 
 // Security check in case no PLATFORM_* defined
 #if !defined(PLATFORM_DESKTOP) && !defined(PLATFORM_ANDROID) && !defined(PLATFORM_RPI) && !defined(PLATFORM_WEB)
@@ -298,7 +299,7 @@ extern "C" {            // Prevents name mangling of functions
 //------------------------------------------------------------------------------------
 #if defined(PLATFORM_ANDROID)
 void InitWindow(int width, int height, struct android_app *state);  // Init Android activity
-#elif defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
+#elif defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB)
 void InitWindow(int width, int height, const char *title);  // Initialize Window and OpenGL Graphics
 #endif
 
@@ -311,6 +312,7 @@ void SetExitKey(int key);                                   // Set a custom key
 #endif
 int GetScreenWidth(void);                                   // Get current screen width
 int GetScreenHeight(void);                                  // Get current screen height
+int GetKeyPressed(void);                                    // Get latest key pressed
 
 void ClearBackground(Color color);                          // Sets Background Color
 void BeginDrawing(void);                                    // Setup drawing canvas to start drawing
@@ -330,8 +332,7 @@ int GetRandomValue(int min, int max);                       // Returns a random
 Color Fade(Color color, float alpha);                       // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
 
 void SetupFlags(char flags);                                // Enable some window configurations
-
-void ShowLogo(void);                                        // Activates raylib logo at startup
+void ShowLogo(void);                                        // Activates raylib logo at startup (can be done with flags)
 
 //------------------------------------------------------------------------------------
 // Input Handling Functions (Module: core)
@@ -410,6 +411,7 @@ Texture2D LoadTextureFromImage(Image image, bool genMipmaps);
 Texture2D CreateTexture(Image image, bool genMipmaps);                                             // [DEPRECATED] Same as LoadTextureFromImage()
 void UnloadImage(Image image);                                                                     // Unload image from CPU memory (RAM)
 void UnloadTexture(Texture2D texture);                                                             // Unload texture from GPU memory
+void ConvertToPOT(Image *image, Color fillColor);                                                  // Convert image to POT (power-of-two)
 
 void DrawTexture(Texture2D texture, int posX, int posY, Color tint);                               // Draw a Texture2D
 void DrawTextureV(Texture2D texture, Vector2 position, Color tint);                                // Draw a Texture2D with position defined as Vector2
@@ -460,7 +462,7 @@ void DrawGizmoEx(Vector3 position, Vector3 rotation, float scale);
 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
-Model LoadCubesmap(Image cubesmap);                                                                // Load a map image as a 3d model (cubes based)
+Model LoadCubicmap(Image cubicmap);                                                                // Load a map image as a 3d model (cubes based)
 void UnloadModel(Model model);                                                                     // Unload 3d model from memory
 void SetModelTexture(Model *model, Texture2D texture);                                             // Link a texture to a model
 
@@ -478,7 +480,7 @@ void InitAudioDevice(void);                                     // Initialize au
 void CloseAudioDevice(void);                                    // Close the audio device and context (and music stream)
 
 Sound LoadSound(char *fileName);                                // Load sound to memory
-Sound LoadSoundFromWave(Wave wave);                             // Load sound from wave data
+Sound LoadSoundFromWave(Wave wave);                             // Load sound to memory from wave data
 Sound LoadSoundFromRES(const char *rresName, int resId);        // Load sound to memory from rRES file (raylib Resource)
 void UnloadSound(Sound sound);                                  // Unload sound
 void PlaySound(Sound sound);                                    // Play a sound

+ 43 - 4
src/raymath.c

@@ -329,8 +329,6 @@ void MatrixInvert(Matrix *mat)
     // Calculate the invert determinant (inlined to avoid double-caching)
     float invDet = 1/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06);
 
-    printf("%f\n", invDet);
-
     temp.m0 = (a11*b11 - a12*b10 + a13*b09)*invDet;
     temp.m1 = (-a01*b11 + a02*b10 - a03*b09)*invDet;
     temp.m2 = (a31*b05 - a32*b04 + a33*b03)*invDet;
@@ -492,6 +490,48 @@ Matrix MatrixRotate(float angleX, float angleY, float angleZ)
     return result;
 }
 
+/*
+Matrix MatrixRotate(float angle, float x, float y, float z)
+{
+    Matrix result = MatrixIdentity();
+
+    float c = cosf(angle*DEG2RAD);    // cosine
+    float s = sinf(angle*DEG2RAD);    // sine
+    float c1 = 1.0f - c;              // 1 - c
+    
+    float m0 = result.m0, m4 = result.m4, m8 = result.m8, m12 = result.m12,
+          m1 = result.m1, m5 = result.m5, m9 = result.m9,  m13 = result.m13,
+          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;
+
+    // multiply rotation matrix
+    result.m0 = r0*m0 + r4*m1 + r8*m2;
+    result.m1 = r1*m0 + r5*m1 + r9*m2;
+    result.m2 = r2*m0 + r6*m1 + r10*m2;
+    result.m4 = r0*m4 + r4*m5 + r8*m6;
+    result.m5 = r1*m4 + r5*m5 + r9*m6;
+    result.m6 = r2*m4 + r6*m5 + r10*m6;
+    result.m8 = r0*m8 + r4*m9 + r8*m10;
+    result.m9 = r1*m8 + r5*m9 + r9*m10;
+    result.m10 = r2*m8 + r6*m9 + r10*m10;
+    result.m12 = r0*m12+ r4*m13 + r8*m14;
+    result.m13 = r1*m12+ r5*m13 + r9*m14;
+    result.m14 = r2*m12+ r6*m13 + r10*m14;
+
+    return result;
+}
+*/
+
 // Create rotation matrix from axis and angle
 // TODO: Test this function
 // NOTE: NO prototype defined!
@@ -668,12 +708,11 @@ Matrix MatrixScale(float x, float y, float z)
 
 // Returns transformation matrix for a given translation, rotation and scale
 // NOTE: Transformation order is rotation -> scale -> translation
+// NOTE: Rotation angles should come in radians
 Matrix MatrixTransform(Vector3 translation, Vector3 rotation, Vector3 scale)
 {
     Matrix result = MatrixIdentity();
 
-	// TODO: Review, use DEG2RAD here?
-	//Matrix mRotation = MatrixRotate(rotation.x*DEG2RAD, rotation.y*DEG2RAD, rotation.z*DEG2RAD);
     Matrix mRotation = MatrixRotate(rotation.x, rotation.y, rotation.z);
     Matrix mScale = MatrixScale(scale.x, scale.y, scale.z);
     Matrix mTranslate = MatrixTranslate(translation.x, translation.y, translation.z);

+ 2 - 2
src/raymath.h

@@ -55,7 +55,7 @@
     } Vector3;
 #endif
 
-// Matrix type (OpenGL style 4x4 - right handed)
+// Matrix type (OpenGL style 4x4 - right handed, column major)
 typedef struct Matrix {
     float m0, m4, m8, m12;
     float m1, m5, m9, m13;
@@ -107,7 +107,7 @@ Matrix MatrixIdentity(void);                            // Returns identity matr
 Matrix MatrixAdd(Matrix left, Matrix right);            // Add two matrices
 Matrix MatrixSubstract(Matrix left, Matrix right);      // Substract two matrices (left - right)
 Matrix MatrixTranslate(float x, float y, float z);      // Returns translation matrix
-Matrix MatrixRotate(float angleX, float angleY, float angleZ); // Returns rotation matrix
+Matrix MatrixRotate(float axisX, float axisY, float axisZ); // Returns rotation matrix
 Matrix MatrixFromAxisAngle(Vector3 axis, float angle);      // Returns rotation matrix for an angle around an specified axis
 Matrix MatrixFromAxisAngle2(Vector3 axis, float angle);     // Returns rotation matrix for an angle around an specified axis (test another implemntation)
 Matrix MatrixFromQuaternion(Quaternion q);              // Returns rotation matrix for a given quaternion

+ 20 - 15
src/rlgl.c

@@ -169,7 +169,8 @@ static int tempBufferCount = 0;
 static bool useTempBuffer = false;
 
 // White texture useful for plain color polys (required by shader)
-static GLuint whiteTexture;
+// NOTE: It's required in shapes and models modules!
+extern unsigned int whiteTexture;
 
 // Support for VAOs (OpenGL ES2 could not support VAO extensions)
 static bool vaoSupported = false;
@@ -772,7 +773,7 @@ void rlglInit(void)
 #endif
 
 #if defined(GRAPHICS_API_OPENGL_ES2)
-	// NOTE: emscripten does not support VAOs
+	// NOTE: emscripten does not support VAOs natively, it uses emulation and it reduces overall performance...
 #if !defined(PLATFORM_WEB)
     glGenVertexArrays = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress("glGenVertexArraysOES");
     glBindVertexArray = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress("glBindVertexArrayOES");
@@ -1128,6 +1129,8 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotation, Vector3 scal
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
     glUseProgram(shaderProgram);        // Use our shader
 
+    VectorScale(&rotation, DEG2RAD);
+    
     // Get transform matrix (rotation -> scale -> translation)
     Matrix transform = MatrixTransform(position, rotation, scale);
     Matrix modelviewworld = MatrixMultiply(transform, modelview);
@@ -1340,7 +1343,7 @@ unsigned int rlglLoadTexture(unsigned char *data, int width, int height, bool ge
     // Unbind current texture
     glBindTexture(GL_TEXTURE_2D, 0);
 
-    TraceLog(INFO, "[TEX ID %i] Texture created successfully (%i x %i)", id, width, height);
+    TraceLog(INFO, "[TEX ID %i] Texture created successfully (%ix%i)", id, width, height);
 
     return id;
 }
@@ -1690,33 +1693,35 @@ static GLuint LoadShaders(char *vertexFileName, char *fragmentFileName)
 }
 
 // Read shader text file
-static char *TextFileRead(char *fn)
+static char *TextFileRead(char *fileName)
 {
-    FILE *fp;
+    FILE *textFile;
     char *text = NULL;
 
     int count=0;
 
-    if (fn != NULL)
+    if (fileName != NULL)
     {
-        fp = fopen(fn,"rt");
+        textFile = fopen(fileName,"rt");
 
-        if (fp != NULL)
+        if (textFile != NULL)
         {
-            fseek(fp, 0, SEEK_END);
-            count = ftell(fp);
-            rewind(fp);
+            fseek(textFile, 0, SEEK_END);
+            count = ftell(textFile);
+            rewind(textFile);
 
             if (count > 0)
             {
                 text = (char *)malloc(sizeof(char) * (count+1));
-                count = fread(text, sizeof(char), count, fp);
+                count = fread(text, sizeof(char), count, textFile);
                 text[count] = '\0';
             }
 
-            fclose(fp);
+            fclose(textFile);
         }
+        else TraceLog(WARNING, "[%s] Text file could not be opened", fileName);
     }
+    
     return text;
 }
 
@@ -1992,7 +1997,7 @@ static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight)
         j++;
     }
 
-    TraceLog(DEBUG, "Mipmap base (%i, %i)", width, height);
+    TraceLog(DEBUG, "Mipmap base (%ix%i)", width, height);
 
     for (int mip = 1; mip < mipmapCount; mip++)
     {
@@ -2063,7 +2068,7 @@ static pixel *GenNextMipmap(pixel *srcData, int srcWidth, int srcHeight)
         }
     }
 
-    TraceLog(DEBUG, "Mipmap generated successfully (%i, %i)", width, height);
+    TraceLog(DEBUG, "Mipmap generated successfully (%ix%i)", width, height);
 
     return mipmap;
 }

+ 3 - 2
src/rlgl.h

@@ -72,8 +72,9 @@
     #define MAX_TRIANGLES_BATCH     4096
     #define MAX_QUADS_BATCH         4096
 #elif defined(GRAPHICS_API_OPENGL_ES2)
-    // NOTE: Reduce memory sizes for embedded systems (RPI)
-    #define MAX_LINES_BATCH         2048    // Critical for wire shapes (sphere)
+    // NOTE: Reduce memory sizes for embedded systems (RPI and HTML5)
+    // NOTE: On HTML5 (emscripten) this is allocated on heap, by default it's only 16MB!...just take care...
+    #define MAX_LINES_BATCH         1024    // Critical for wire shapes (sphere)
     #define MAX_TRIANGLES_BATCH     2048    // Critical for some shapes (sphere)
     #define MAX_QUADS_BATCH         1024    // Be careful with text, every letter maps a quad
 #endif

+ 2 - 2
src/shapes.c

@@ -44,7 +44,7 @@
 //----------------------------------------------------------------------------------
 // Global Variables Definition
 //----------------------------------------------------------------------------------
-// It's lonely here...
+extern unsigned int whiteTexture;
 
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
@@ -197,7 +197,7 @@ void DrawRectangleV(Vector2 position, Vector2 size, Color color)
     else if ((rlGetVersion() == OPENGL_33) || (rlGetVersion() == OPENGL_ES_20))
     {
         // NOTE: This shape uses QUADS to avoid drawing order issues (view rlglDraw)
-        rlEnableTexture(1); // Default white texture
+        rlEnableTexture(whiteTexture); // Default white texture
 
         rlBegin(RL_QUADS);
             rlColor4ub(color.r, color.g, color.b, color.a);

+ 65 - 109
src/text.c

@@ -63,7 +63,6 @@ static SpriteFont defaultFont;        // Default font provided by raylib
 //----------------------------------------------------------------------------------
 static bool PixelIsMagenta(Color p);                // Check if a pixel is magenta
 static int ParseImageData(Color *imgDataPixel, int imgWidth, int imgHeight, Character **charSet);    // Parse image pixel data to obtain character set measures
-static int GetNextPOT(int num);                     // Calculate next power-of-two value for a given value
 static SpriteFont LoadRBMF(const char *fileName);   // Load a rBMF font file (raylib BitMap Font)
 
 extern void LoadDefaultFont(void);
@@ -195,9 +194,10 @@ SpriteFont LoadSpriteFont(const char *fileName)
         Image image = LoadImage(fileName);
 
         // At this point we have a pixel array with all the data...
-
-        TraceLog(INFO, "[%s] SpriteFont image loaded: %i x %i", fileName, image.width, image.height);
-
+        
+#if defined(PLATFORM_RPI) || defined(PLATFORM_WEB)
+        ConvertToPOT(&image, MAGENTA);
+#endif
         // Process bitmap Font pixel data to get measures (Character array)
         // spriteFont.charSet data is filled inside the function and memory is allocated!
         int numChars = ParseImageData(image.pixels, image.width, image.height, &spriteFont.charSet);
@@ -207,40 +207,8 @@ SpriteFont LoadSpriteFont(const char *fileName)
 
         spriteFont.numChars = numChars;
 
-        // Convert image font to POT image before conversion to texture
-        // NOTE: Not required, we skip this step
-/*
-        // Just add the required amount of pixels at the right and bottom sides of image...
-        int potWidth = GetNextPOT(image.width);
-        int potHeight = GetNextPOT(image.height);
-
-        // Check if POT texture generation is required (if texture is not already POT)
-        if ((potWidth != image.width) || (potHeight != image.height))
-        {
-            Color *imgDataPixelPOT = NULL;
-
-            // Generate POT array from NPOT data
-            imgDataPixelPOT = (Color *)malloc(potWidth * potHeight * sizeof(Color));
-
-            for (int j = 0; j < potHeight; j++)
-            {
-                for (int i = 0; i < potWidth; i++)
-                {
-                    if ((j < image.height) && (i < image.width)) imgDataPixelPOT[j*potWidth + i] = image.pixels[j*image.width + i];
-                    else imgDataPixelPOT[j*potWidth + i] = MAGENTA;
-                }
-            }
-
-            TraceLog(WARNING, "SpriteFont texture converted to POT: %ix%i", potWidth, potHeight);
-
-            free(image.pixels);
-
-            image.pixels = imgDataPixelPOT;
-            image.width = potWidth;
-            image.height = potHeight;
-        }
-*/
         spriteFont.texture = LoadTextureFromImage(image, false); // Convert loaded image to OpenGL texture
+        
         UnloadImage(image);
     }
 
@@ -475,23 +443,6 @@ static int ParseImageData(Color *imgDataPixel, int imgWidth, int imgHeight, Char
     return index;
 }
 
-// Calculate next power-of-two value for a given num
-static int GetNextPOT(int num)
-{
-    if (num != 0)
-    {
-        num--;
-        num |= (num >> 1);     // Or first 2 bits
-        num |= (num >> 2);     // Or next 2 bits
-        num |= (num >> 4);     // Or next 4 bits
-        num |= (num >> 8);     // Or next 8 bits
-        num |= (num >> 16);    // Or next 16 bits
-        num++;
-    }
-
-    return num;
-}
-
 // Load a rBMF font file (raylib BitMap Font)
 static SpriteFont LoadRBMF(const char *fileName)
 {
@@ -517,91 +468,96 @@ static SpriteFont LoadRBMF(const char *fileName)
     Image image;
 
     rbmfInfoHeader rbmfHeader;
-    unsigned int *rbmfFileData;
-    unsigned char *rbmfCharWidthData;
+    unsigned int *rbmfFileData = NULL;
+    unsigned char *rbmfCharWidthData = NULL;
 
     int charsDivisor = 1;    // Every char is separated from the consecutive by a 1 pixel divisor, horizontally and vertically
 
     FILE *rbmfFile = fopen(fileName, "rb");        // Define a pointer to bitmap file and open it in read-binary mode
 
-    // TODO: Check if file could be loaded! (rbmfFile == NULL)?
+    if (rbmfFile == NULL)
+    {
+        TraceLog(WARNING, "[%s] rBMF font file could not be opened", fileName);
+    }
+    else
+    {
+        fread(&rbmfHeader, sizeof(rbmfInfoHeader), 1, rbmfFile);
 
-    fread(&rbmfHeader, sizeof(rbmfInfoHeader), 1, rbmfFile);
+        TraceLog(INFO, "[%s] Loading rBMF file, size: %ix%i, numChars: %i, charHeight: %i", fileName, rbmfHeader.imgWidth, rbmfHeader.imgHeight, rbmfHeader.numChars, rbmfHeader.charHeight);
 
-    TraceLog(INFO, "[%s] Loading rBMF file, size: %ix%i, numChars: %i, charHeight: %i", fileName, rbmfHeader.imgWidth, rbmfHeader.imgHeight, rbmfHeader.numChars, rbmfHeader.charHeight);
+        spriteFont.numChars = (int)rbmfHeader.numChars;
 
-    spriteFont.numChars = (int)rbmfHeader.numChars;
+        image.width = (int)rbmfHeader.imgWidth;
+        image.height = (int)rbmfHeader.imgHeight;
 
-    image.width = (int)rbmfHeader.imgWidth;
-    image.height = (int)rbmfHeader.imgHeight;
+        int numPixelBits = rbmfHeader.imgWidth * rbmfHeader.imgHeight / 32;
 
-    int numPixelBits = rbmfHeader.imgWidth * rbmfHeader.imgHeight / 32;
+        rbmfFileData = (unsigned int *)malloc(numPixelBits * sizeof(unsigned int));
 
-    rbmfFileData = (unsigned int *)malloc(numPixelBits * sizeof(unsigned int));
+        for(int i = 0; i < numPixelBits; i++) fread(&rbmfFileData[i], sizeof(unsigned int), 1, rbmfFile);
 
-    for(int i = 0; i < numPixelBits; i++) fread(&rbmfFileData[i], sizeof(unsigned int), 1, rbmfFile);
+        rbmfCharWidthData = (unsigned char *)malloc(spriteFont.numChars * sizeof(unsigned char));
 
-    rbmfCharWidthData = (unsigned char *)malloc(spriteFont.numChars * sizeof(unsigned char));
+        for(int i = 0; i < spriteFont.numChars; i++) fread(&rbmfCharWidthData[i], sizeof(unsigned char), 1, rbmfFile);
 
-    for(int i = 0; i < spriteFont.numChars; i++) fread(&rbmfCharWidthData[i], sizeof(unsigned char), 1, rbmfFile);
+        // Re-construct image from rbmfFileData
+        //-----------------------------------------
+        image.pixels = (Color *)malloc(image.width * image.height * sizeof(Color));
 
-    // Re-construct image from rbmfFileData
-    //-----------------------------------------
-    image.pixels = (Color *)malloc(image.width * image.height * sizeof(Color));
+        for (int i = 0; i < image.width * image.height; i++) image.pixels[i] = BLANK;        // Initialize array
 
-    for (int i = 0; i < image.width * image.height; i++) image.pixels[i] = BLANK;        // Initialize array
+        int counter = 0;        // Font data elements counter
 
-    int counter = 0;        // Font data elements counter
-
-    // Fill image data (convert from bit to pixel!)
-    for (int i = 0; i < image.width * image.height; i += 32)
-    {
-        for (int j = 31; j >= 0; j--)
+        // Fill image data (convert from bit to pixel!)
+        for (int i = 0; i < image.width * image.height; i += 32)
         {
-            if (BIT_CHECK(rbmfFileData[counter], j)) image.pixels[i+j] = WHITE;
-        }
+            for (int j = 31; j >= 0; j--)
+            {
+                if (BIT_CHECK(rbmfFileData[counter], j)) image.pixels[i+j] = WHITE;
+            }
 
-        counter++;
-    }
+            counter++;
+        }
 
-    TraceLog(INFO, "[%s] Image reconstructed correctly, now converting it to texture", fileName);
+        TraceLog(INFO, "[%s] Image reconstructed correctly, now converting it to texture", fileName);
 
-    spriteFont.texture = LoadTextureFromImage(image, false);
-    UnloadImage(image);     // Unload image data
+        spriteFont.texture = LoadTextureFromImage(image, false);
+        UnloadImage(image);     // Unload image data
 
-    TraceLog(INFO, "[%s] Starting charSet reconstruction", fileName);
+        //TraceLog(INFO, "[%s] Starting charSet reconstruction", fileName);
 
-    // Reconstruct charSet using rbmfCharWidthData, rbmfHeader.charHeight, charsDivisor, rbmfHeader.numChars
-    spriteFont.charSet = (Character *)malloc(spriteFont.numChars * sizeof(Character));     // Allocate space for our character data
+        // Reconstruct charSet using rbmfCharWidthData, rbmfHeader.charHeight, charsDivisor, rbmfHeader.numChars
+        spriteFont.charSet = (Character *)malloc(spriteFont.numChars * sizeof(Character));     // Allocate space for our character data
 
-    int currentLine = 0;
-    int currentPosX = charsDivisor;
-    int testPosX = charsDivisor;
+        int currentLine = 0;
+        int currentPosX = charsDivisor;
+        int testPosX = charsDivisor;
 
-    for (int i = 0; i < spriteFont.numChars; i++)
-    {
-        spriteFont.charSet[i].value = (int)rbmfHeader.firstChar + i;
-        spriteFont.charSet[i].x = currentPosX;
-        spriteFont.charSet[i].y = charsDivisor + currentLine * ((int)rbmfHeader.charHeight + charsDivisor);
-        spriteFont.charSet[i].w = (int)rbmfCharWidthData[i];
-        spriteFont.charSet[i].h = (int)rbmfHeader.charHeight;
+        for (int i = 0; i < spriteFont.numChars; i++)
+        {
+            spriteFont.charSet[i].value = (int)rbmfHeader.firstChar + i;
+            spriteFont.charSet[i].x = currentPosX;
+            spriteFont.charSet[i].y = charsDivisor + currentLine * ((int)rbmfHeader.charHeight + charsDivisor);
+            spriteFont.charSet[i].w = (int)rbmfCharWidthData[i];
+            spriteFont.charSet[i].h = (int)rbmfHeader.charHeight;
 
-        testPosX += (spriteFont.charSet[i].w + charsDivisor);
+            testPosX += (spriteFont.charSet[i].w + charsDivisor);
 
-        if (testPosX > spriteFont.texture.width)
-        {
-            currentLine++;
-            currentPosX = 2 * charsDivisor + (int)rbmfCharWidthData[i];
-            testPosX = currentPosX;
+            if (testPosX > spriteFont.texture.width)
+            {
+                currentLine++;
+                currentPosX = 2 * charsDivisor + (int)rbmfCharWidthData[i];
+                testPosX = currentPosX;
 
-            spriteFont.charSet[i].x = charsDivisor;
-            spriteFont.charSet[i].y = charsDivisor + currentLine * (rbmfHeader.charHeight + charsDivisor);
+                spriteFont.charSet[i].x = charsDivisor;
+                spriteFont.charSet[i].y = charsDivisor + currentLine * (rbmfHeader.charHeight + charsDivisor);
+            }
+            else currentPosX = testPosX;
         }
-        else currentPosX = testPosX;
-    }
-
-    TraceLog(INFO, "[%s] rBMF file loaded correctly as SpriteFont", fileName);
 
+        TraceLog(INFO, "[%s] rBMF file loaded correctly as SpriteFont", fileName);
+    }
+    
     fclose(rbmfFile);
 
     free(rbmfFileData);                // Now we can free loaded data from RAM memory

+ 48 - 7
src/textures.c

@@ -126,7 +126,7 @@ Image LoadImage(const char *fileName)
             image.width = imgWidth;
             image.height = imgHeight;
 
-            TraceLog(INFO, "[%s] Image loaded successfully", fileName);
+            TraceLog(INFO, "[%s] Image loaded successfully (%ix%i)", fileName, image.width, image.height);
         }
         else TraceLog(WARNING, "[%s] Image could not be loaded, file not recognized", fileName);
     }
@@ -187,7 +187,10 @@ Image LoadImageFromRES(const char *rresName, int resId)
 
     FILE *rresFile = fopen(rresName, "rb");
 
-    if (!rresFile) TraceLog(WARNING, "[%s] Could not open raylib resource file", rresName);
+    if (rresFile == NULL) 
+    {
+        TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", rresName);
+    }
     else
     {
         // Read rres file (basic file check - id)
@@ -337,9 +340,12 @@ Texture2D LoadTexture(const char *fileName)
     else
     {
         Image image = LoadImage(fileName);
-
+        
         if (image.pixels != NULL)
         {
+#if defined(PLATFORM_RPI) || defined(PLATFORM_WEB)
+            ConvertToPOT(&image, BLANK);
+#endif
             texture = LoadTextureFromImage(image, false);
             UnloadImage(image);
         }
@@ -425,6 +431,41 @@ void UnloadTexture(Texture2D texture)
     rlDeleteTextures(texture.id);
 }
 
+// Convert image to POT (power-of-two)
+// NOTE: Requirement on OpenGL ES 2.0 (RPI, HTML5)
+void ConvertToPOT(Image *image, Color fillColor)
+{
+    // Just add the required amount of pixels at the right and bottom sides of image...
+    int potWidth = GetNextPOT(image->width);
+    int potHeight = GetNextPOT(image->height);
+
+    // Check if POT texture generation is required (if texture is not already POT)
+    if ((potWidth != image->width) || (potHeight != image->height))
+    {
+        Color *imgDataPixelPOT = NULL;
+
+        // Generate POT array from NPOT data
+        imgDataPixelPOT = (Color *)malloc(potWidth * potHeight * sizeof(Color));
+
+        for (int j = 0; j < potHeight; j++)
+        {
+            for (int i = 0; i < potWidth; i++)
+            {
+                if ((j < image->height) && (i < image->width)) imgDataPixelPOT[j*potWidth + i] = image->pixels[j*image->width + i];
+                else imgDataPixelPOT[j*potWidth + i] = fillColor;
+            }
+        }
+
+        TraceLog(WARNING, "Image converted to POT: (%ix%i) -> (%ix%i)", image->width, image->height, potWidth, potHeight);
+
+        free(image->pixels);
+
+        image->pixels = imgDataPixelPOT;
+        image->width = potWidth;
+        image->height = potHeight;
+    }
+}
+
 // Draw a Texture2D
 void DrawTexture(Texture2D texture, int posX, int posY, Color tint)
 {
@@ -559,7 +600,7 @@ static ImageEx LoadDDS(const char *fileName)
 
     if (ddsFile == NULL)
     {
-        TraceLog(WARNING, "DDS File could not be opened");
+        TraceLog(WARNING, "[%s] DDS image file could not be opened", fileName);
     }
     else
     {
@@ -570,7 +611,7 @@ static ImageEx LoadDDS(const char *fileName)
 
         if (strncmp(filecode, "DDS ", 4) != 0)
         {
-            TraceLog(WARNING, "DDS File does not seem to be valid");
+            TraceLog(WARNING, "[%s] DDS file does not seem to be a valid image", fileName);
             fclose(ddsFile);
         }
         else
@@ -705,7 +746,7 @@ static ImageEx LoadPKM(const char *fileName)
 
     if (pkmFile == NULL)
     {
-        TraceLog(WARNING, "[%s] PKM File could not be opened", fileName);
+        TraceLog(WARNING, "[%s] PKM image file could not be opened", fileName);
     }
     else
     {
@@ -716,7 +757,7 @@ static ImageEx LoadPKM(const char *fileName)
 
         if (strncmp(filecode, "PKM ", 4) != 0)
         {
-            TraceLog(WARNING, "[%s] PKM File does not seem to be valid", fileName);
+            TraceLog(WARNING, "[%s] PKM file does not seem to be a valid image", fileName);
             fclose(pkmFile);
         }
         else

+ 34 - 10
src/utils.c

@@ -133,18 +133,25 @@ void WriteBitmap(const char *fileName, unsigned char *imgData, int width, int he
 
     FILE *bmpFile = fopen(fileName, "wb");    // Define a pointer to bitmap file and open it in write-binary mode
 
-    // NOTE: fwrite parameters are: data pointer, size in bytes of each element to be written, number of elements, file-to-write pointer
-    fwrite(bmpFileHeader, sizeof(unsigned char), 14, bmpFile);    // Write BMP file header data
-    fwrite(bmpInfoHeader, sizeof(unsigned char), 40, bmpFile);    // Write BMP info header data
-
-    // Write pixel data to file
-    for (int y = 0; y < height ; y++)
+    if (bmpFile == NULL)
+    {
+        TraceLog(WARNING, "[%s] BMP file could not be created", fileName);
+    }
+    else
     {
-        for (int x = 0; x < width; x++)
+        // NOTE: fwrite parameters are: data pointer, size in bytes of each element to be written, number of elements, file-to-write pointer
+        fwrite(bmpFileHeader, sizeof(unsigned char), 14, bmpFile);    // Write BMP file header data
+        fwrite(bmpInfoHeader, sizeof(unsigned char), 40, bmpFile);    // Write BMP info header data
+
+        // Write pixel data to file
+        for (int y = 0; y < height ; y++)
         {
-            fputc(imgData[(x*4)+2 + (y*width*4)], bmpFile);
-            fputc(imgData[(x*4)+1 + (y*width*4)], bmpFile);
-            fputc(imgData[(x*4) + (y*width*4)], bmpFile);
+            for (int x = 0; x < width; x++)
+            {
+                fputc(imgData[(x*4)+2 + (y*width*4)], bmpFile);
+                fputc(imgData[(x*4)+1 + (y*width*4)], bmpFile);
+                fputc(imgData[(x*4) + (y*width*4)], bmpFile);
+            }
         }
     }
 
@@ -264,6 +271,23 @@ const char *GetExtension(const char *fileName)
     return (dot + 1);
 }
 
+// Calculate next power-of-two value for a given num
+int GetNextPOT(int num)
+{
+    if (num != 0)
+    {
+        num--;
+        num |= (num >> 1);     // Or first 2 bits
+        num |= (num >> 2);     // Or next 2 bits
+        num |= (num >> 4);     // Or next 4 bits
+        num |= (num >> 8);     // Or next 8 bits
+        num |= (num >> 16);    // Or next 16 bits
+        num++;
+    }
+
+    return num;
+}
+
 //----------------------------------------------------------------------------------
 // Module specific Functions Definition
 //----------------------------------------------------------------------------------

+ 1 - 0
src/utils.h

@@ -77,6 +77,7 @@ void WritePNG(const char *fileName, unsigned char *imgData, int width, int heigh
 
 void TraceLog(int msgType, const char *text, ...);  // Outputs a trace log message
 const char *GetExtension(const char *fileName);     // Returns extension of a filename
+int GetNextPOT(int num);                            // Calculate next power-of-two value for a given num
 
 #if defined(PLATFORM_ANDROID)
 void InitAssetManager(AAssetManager *manager);  // Initialize asset manager from android app