Sfoglia il codice sorgente

Updated to raylib 3.0.cb4c676.

Fixes #1.
Brucey 5 anni fa
parent
commit
129b5e4e70
57 ha cambiato i file con 4768 aggiunte e 3843 eliminazioni
  1. 7 0
      audio.mod/audio.bmx
  2. 1 0
      audio.mod/common.bmx
  3. 2 2
      examples/textures/textures_mouse_painting.bmx
  4. 12 0
      lib.mod/common.bmx
  5. 5 1
      lib.mod/lib.bmx
  6. 1 0
      lib.mod/raylib/BINDINGS.md
  7. 5 5
      lib.mod/raylib/examples/Makefile
  8. 8 5
      lib.mod/raylib/examples/core/core_storage_values.c
  9. 3 3
      lib.mod/raylib/examples/models/resources/shaders/glsl330/irradiance.fs
  10. 1 1
      lib.mod/raylib/examples/models/resources/shaders/glsl330/pbr.vs
  11. 4 4
      lib.mod/raylib/examples/models/resources/shaders/glsl330/prefilter.fs
  12. 154 167
      lib.mod/raylib/examples/network/network_ping_pong.c
  13. 55 57
      lib.mod/raylib/examples/network/network_resolve_host.c
  14. 120 129
      lib.mod/raylib/examples/network/network_tcp_client.c
  15. 138 141
      lib.mod/raylib/examples/network/network_tcp_server.c
  16. 64 48
      lib.mod/raylib/examples/network/network_test.c
  17. 104 108
      lib.mod/raylib/examples/network/network_udp_client.c
  18. 110 116
      lib.mod/raylib/examples/network/network_udp_server.c
  19. 10 8
      lib.mod/raylib/examples/others/rlgl_standalone.c
  20. 0 1
      lib.mod/raylib/examples/shaders/resources/shaders/glsl100/base.fs
  21. 59 0
      lib.mod/raylib/examples/shaders/resources/shaders/glsl100/base_lighting.vs
  22. 94 0
      lib.mod/raylib/examples/shaders/resources/shaders/glsl100/fog.fs
  23. 81 0
      lib.mod/raylib/examples/shaders/resources/shaders/glsl100/lighting.fs
  24. 24 0
      lib.mod/raylib/examples/shaders/resources/shaders/glsl100/mask.fs
  25. 1 1
      lib.mod/raylib/examples/shaders/resources/shaders/glsl330/base_lighting.vs
  26. 8 12
      lib.mod/raylib/examples/shaders/resources/shaders/glsl330/fog.fs
  27. 0 32
      lib.mod/raylib/examples/shaders/resources/shaders/glsl330/fog.vs
  28. 1 1
      lib.mod/raylib/examples/shaders/resources/shaders/glsl330/lighting.fs
  29. 4 3
      lib.mod/raylib/examples/shaders/resources/shaders/glsl330/mask.fs
  30. 0 21
      lib.mod/raylib/examples/shaders/resources/shaders/glsl330/mask.vs
  31. 3 7
      lib.mod/raylib/examples/shaders/rlights.h
  32. 6 6
      lib.mod/raylib/examples/shaders/shaders_basic_lighting.c
  33. 8 1
      lib.mod/raylib/examples/shaders/shaders_fog.c
  34. 9 3
      lib.mod/raylib/examples/shaders/shaders_simple_mask.c
  35. 3 3
      lib.mod/raylib/examples/textures/textures_mouse_painting.c
  36. 227 74
      lib.mod/raylib/projects/Notepad++/raylib_npp_parser/raylib_npp.xml
  37. 62 34
      lib.mod/raylib/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h
  38. 18 16
      lib.mod/raylib/src/Makefile
  39. 9 6
      lib.mod/raylib/src/config.h
  40. 291 201
      lib.mod/raylib/src/core.c
  41. 655 75
      lib.mod/raylib/src/external/miniaudio.h
  42. 2 2
      lib.mod/raylib/src/external/tinyobj_loader_c.h
  43. 54 45
      lib.mod/raylib/src/models.c
  44. 99 138
      lib.mod/raylib/src/raudio.c
  45. 1 0
      lib.mod/raylib/src/raudio.h
  46. 11 6
      lib.mod/raylib/src/raylib.h
  47. 15 7
      lib.mod/raylib/src/raymath.h
  48. 48 74
      lib.mod/raylib/src/rlgl.h
  49. 0 2024
      lib.mod/raylib/src/rnet.c.review
  50. 1948 112
      lib.mod/raylib/src/rnet.h
  51. 5 6
      lib.mod/raylib/src/shapes.c
  52. 7 7
      lib.mod/raylib/src/shell.html
  53. 15 41
      lib.mod/raylib/src/text.c
  54. 61 88
      lib.mod/raylib/src/textures.c
  55. 128 1
      lib.mod/raylib/src/utils.c
  56. 1 0
      math.mod/common.bmx
  57. 6 0
      math.mod/math.bmx

+ 7 - 0
audio.mod/audio.bmx

@@ -426,3 +426,10 @@ End Rem
 Function SetAudioStreamPitch(stream:RAudioStream, pitch:Float)
 	bmx_raylib_SetAudioStreamPitch(stream, pitch)
 End Function
+
+Rem
+bbdoc: Sets the default buffer size for new audio streams.
+End Rem
+Function SetAudioStreamBufferSizeDefault(size:Int)
+	bmx_raylib_SetAudioStreamBufferSizeDefault(size)
+End Function

+ 1 - 0
audio.mod/common.bmx

@@ -80,6 +80,7 @@ Extern
 	Function bmx_raylib_StopAudioStream(stream:RAudioStream)="StopAudioStream"
 	Function bmx_raylib_SetAudioStreamVolume(stream:RAudioStream, volume:Float)="SetAudioStreamVolume"
 	Function bmx_raylib_SetAudioStreamPitch(stream:RAudioStream, pitch:Float)="SetAudioStreamPitch"
+	Function bmx_raylib_SetAudioStreamBufferSizeDefault(size:Int)="SetAudioStreamBufferSizeDefault"
 
 End Extern
 

+ 2 - 2
examples/textures/textures_mouse_painting.bmx

@@ -99,7 +99,7 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 		EndTextureMode()
 	End If
 
-	If IsMouseButtonDown(MOUSE_LEFT_BUTTON) Then
+	If IsMouseButtonDown(MOUSE_LEFT_BUTTON) Or (GetGestureDetected() = GESTURE_DRAG) Then
 		' Paint circle into render texture
 		' NOTE: To avoid discontinuous circles, we could store
 		' previous-next mouse points and just draw a line using brush size
@@ -162,7 +162,7 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 		' Draw drawing circle for reference
 		If mousePos.y > 50 Then
 			If IsMouseButtonDown(MOUSE_RIGHT_BUTTON) Then
-				DrawCircleLines(mousePos.x, mousePos.y, brushSize, colors[colorSelected])
+				DrawCircleLines(mousePos.x, mousePos.y, brushSize, GRAY)
 			Else
 				DrawCircle(GetMouseX(), GetMouseY(), brushSize, colors[colorSelected])
 			End If

+ 12 - 0
lib.mod/common.bmx

@@ -972,3 +972,15 @@ Const COMPRESSED_PVRT_RGB:Int = 18
 Const COMPRESSED_PVRT_RGBA:Int = 19
 Const COMPRESSED_ASTC_4x4_RGBA:Int = 20
 Const COMPRESSED_ASTC_8x8_RGBA:Int = 21
+
+Const GESTURE_NONE:Int = 0
+Const GESTURE_TAP:Int = 1
+Const GESTURE_DOUBLETAP:Int = 2
+Const GESTURE_HOLD:Int = 4
+Const GESTURE_DRAG:Int = 8
+Const GESTURE_SWIPE_RIGHT:Int = 16
+Const GESTURE_SWIPE_LEFT:Int = 32
+Const GESTURE_SWIPE_UP:Int = 64
+Const GESTURE_SWIPE_DOWN:Int = 128
+Const GESTURE_PINCH_IN:Int = 256
+Const GESTURE_PINCH_OUT:Int = 512

+ 5 - 1
lib.mod/lib.bmx

@@ -26,11 +26,13 @@ bbdoc: Raylib - Simple Games Programming
 End Rem
 Module Ray.Lib
 
-ModuleInfo "Version: 1.00"
+ModuleInfo "Version: 1.01"
 ModuleInfo "License: zlib"
 ModuleInfo "Copyright: Wrapper - 2020 Bruce A Henderson"
 ModuleInfo "Copyright: raylib - 2013-2020 Ramon Santamaria"
 
+ModuleInfo "History: 1.01"
+ModuleInfo "History: Updated to raylib 3.0.cb4c676."
 ModuleInfo "History: 1.00"
 ModuleInfo "History: Initial Release."
 
@@ -63,6 +65,8 @@ Import "common.bmx"
 '
 ' Changed easings.h to not use static inline.
 '
+' Changed config.h to include more image/audio formats.
+'
 
 Rem
 bbdoc: Initializes window and OpenGL context.

+ 1 - 0
lib.mod/raylib/BINDINGS.md

@@ -55,6 +55,7 @@ Some people ported raylib to other languages in form of bindings or wrappers to
 | jaylib             | Janet          | https://github.com/janet-lang/jaylib                                 |
 | raykit             | Kit            | https://github.com/Gamerfiend/raykit                                 |
 | vraylib            | V              | https://github.com/MajorHard/vraylib                                 |
+| ray.mod            | BlitzMax       | https://github.com/bmx-ng/ray.mod  |
 | raylib.cbl         | COBOL          | *[code examples](https://github.com/Martinfx/Cobol/tree/master/OpenCobol/Games/raylib)* |
  
 Missing some language? Check the [bindings not yet in this list](https://gist.github.com/raysan5/5764cc5b885183f523fce47f098f3d9b#bindings-not-yet-in-the-official-list) or create a new binding! :)

+ 5 - 5
lib.mod/raylib/examples/Makefile

@@ -116,9 +116,9 @@ endif
 ifeq ($(PLATFORM),PLATFORM_WEB)
     # Emscripten required variables
     EMSDK_PATH         ?= C:/emsdk
-    EMSCRIPTEN_PATH    ?= $(EMSDK_PATH)/fastcomp/emscripten
-    CLANG_PATH          = $(EMSDK_PATH)/fastcomp/bin
-    PYTHON_PATH         = $(EMSDK_PATH)/python/2.7.13.1_64bit/python-2.7.13.amd64
+    EMSCRIPTEN_PATH    ?= $(EMSDK_PATH)/upstream/emscripten
+    CLANG_PATH          = $(EMSDK_PATH)/upstream/bin
+    PYTHON_PATH         = $(EMSDK_PATH)/python/3.7.4_64bit
     NODE_PATH           = $(EMSDK_PATH)/node/12.9.1_64bit/bin
     export PATH         = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH);C:\raylib\MinGW\bin:$$(PATH)
 endif
@@ -196,7 +196,7 @@ ifeq ($(BUILD_MODE),DEBUG)
     endif
 else
     ifeq ($(PLATFORM),PLATFORM_WEB)
-        CFLAGS += -Os
+        CFLAGS += -O3
     else
         CFLAGS += -s -O1
     endif
@@ -233,7 +233,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
     # --profiling                # include information for code profiling
     # --memory-init-file 0       # to avoid an external memory initialization code file (.mem)
     # --preload-file resources   # specify a resources folder for data compilation
-    CFLAGS += -s USE_GLFW=3 -s FORCE_FILESYSTEM=1 -s EMTERPRETIFY=1 -s EMTERPRETIFY_ASYNC=1 --preload-file $(dir $<)resources@resources
+    CFLAGS += -s USE_GLFW=3 -s FORCE_FILESYSTEM=1 -s ASYNCIFY --preload-file $(dir $<)resources@resources
 
     # NOTE: Simple raylib examples are compiled to be interpreter by emterpreter, that way,
     # we can compile same code for ALL platforms with no change required, but, working on bigger

+ 8 - 5
lib.mod/raylib/examples/core/core_storage_values.c

@@ -12,7 +12,10 @@
 #include "raylib.h"
 
 // NOTE: Storage positions must start with 0, directly related to file memory layout
-typedef enum { STORAGE_SCORE = 0, STORAGE_HISCORE } StorageData;
+typedef enum {
+    STORAGE_POSITION_SCORE      = 0,
+    STORAGE_POSITION_HISCORE    = 1
+} StorageData;
 
 int main(void)
 {
@@ -43,14 +46,14 @@ int main(void)
 
         if (IsKeyPressed(KEY_ENTER))
         {
-            StorageSaveValue(STORAGE_SCORE, score);
-            StorageSaveValue(STORAGE_HISCORE, hiscore);
+            SaveStorageValue(STORAGE_POSITION_SCORE, score);
+            SaveStorageValue(STORAGE_POSITION_HISCORE, hiscore);
         }
         else if (IsKeyPressed(KEY_SPACE))
         {
             // NOTE: If requested position could not be found, value 0 is returned
-            score = StorageLoadValue(STORAGE_SCORE);
-            hiscore = StorageLoadValue(STORAGE_HISCORE);
+            score = LoadStorageValue(STORAGE_POSITION_SCORE);
+            hiscore = LoadStorageValue(STORAGE_POSITION_HISCORE);
         }
 
         framesCounter++;

+ 3 - 3
lib.mod/raylib/examples/models/resources/shaders/glsl330/irradiance.fs

@@ -15,7 +15,7 @@ in vec3 fragPosition;
 uniform samplerCube environmentMap;
 
 // Constant values
-const float PI = 3.14159265359f;
+const float PI = 3.14159265359;
 
 // Output fragment color
 out vec4 finalColor;
@@ -31,8 +31,8 @@ void main()
     vec3 right = cross(up, normal);
     up = cross(normal, right);
 
-    float sampleDelta = 0.025f;
-    float nrSamples = 0.0f; 
+    float sampleDelta = 0.025;
+    float nrSamples = 0.0; 
 
     for (float phi = 0.0; phi < 2.0*PI; phi += sampleDelta)
     {

+ 1 - 1
lib.mod/raylib/examples/models/resources/shaders/glsl330/pbr.vs

@@ -34,7 +34,7 @@ void main()
     mat3 normalMatrix = transpose(inverse(mat3(matModel)));
 
     // Calculate fragment position based on model transformations
-    fragPosition = vec3(matModel*vec4(vertexPosition, 1.0f));
+    fragPosition = vec3(matModel*vec4(vertexPosition, 1.0));
 
     // Send vertex attributes to fragment shader
     fragTexCoord = vertexTexCoord;

+ 4 - 4
lib.mod/raylib/examples/models/resources/shaders/glsl330/prefilter.fs

@@ -18,7 +18,7 @@ uniform samplerCube environmentMap;
 uniform float roughness;
 
 // Constant values
-const float PI = 3.14159265359f;
+const float PI = 3.14159265359;
 
 // Output fragment color
 out vec4 finalColor;
@@ -35,7 +35,7 @@ float DistributionGGX(vec3 N, vec3 H, float roughness)
     float NdotH = max(dot(N, H), 0.0);
     float NdotH2 = NdotH*NdotH;
 
-    float nom   = a2;
+    float nom = a2;
     float denom = (NdotH2*(a2 - 1.0) + 1.0);
     denom = PI*denom*denom;
 
@@ -49,7 +49,7 @@ float RadicalInverse_VdC(uint bits)
      bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
      bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
      bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
-     return float(bits) * 2.3283064365386963e-10; // / 0x100000000
+     return float(bits)*2.3283064365386963e-10; // / 0x100000000
 }
 
 vec2 Hammersley(uint i, uint N)
@@ -60,7 +60,7 @@ vec2 Hammersley(uint i, uint N)
 vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)
 {
 	float a = roughness*roughness;
-	float phi = 2.0 * PI * Xi.x;
+	float phi = 2.0*PI*Xi.x;
 	float cosTheta = sqrt((1.0 - Xi.y)/(1.0 + (a*a - 1.0)*Xi.y));
 	float sinTheta = sqrt(1.0 - cosTheta*cosTheta);
 

+ 154 - 167
lib.mod/raylib/examples/network/network_ping_pong.c

@@ -1,79 +1,72 @@
 /*******************************************************************************************
- *
- *   raylib [network] example - Client/Server ping-pong
- *
- *   Welcome to raylib!
- *
- *   To test examples, just press F6 and execute raylib_compile_execute script
- *   Note that compiled executable is placed in the same folder as .c file
- *
- *   You can find all basic examples on C:\raylib\raylib\examples folder or
- *   raylib official webpage: www.raylib.com
- *
- *   Enjoy using raylib. :)
- *
- *   This example has been created using raylib 2.0 (www.raylib.com)
- *   raylib is licensed under an unmodified zlib/libpng license (View raylib.h
- *for details)
- *
- *   Copyright (c) 2013-2016 Ramon Santamaria (@raysan5)
- *
- ********************************************************************************************/
+*
+*   raylib [network] example - Client/Server ping-pong
+*
+*   This example has been created using raylib 3.0 (www.raylib.com)
+*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
+*
+*   Copyright (c) 2019-2020 Jak Barnes (@syphonx) and Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
 
 #include "raylib.h"
+
+#define RNET_IMPLEMENTATION
 #include "rnet.h"
 
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-
-float         elapsed          = 0.0f;
-float         delay            = 1.0f;
-bool          ping             = false;
-bool          pong             = false;
-bool          connected        = false;
-bool          client_connected = false;
-const char *  pingmsg          = "Ping!";
-const char *  pongmsg          = "Pong!";
-int           msglen           = 0;
-SocketConfig  server_cfg       = {.host = "127.0.0.1", .port = "4950", .type = SOCKET_TCP, .server = true, .nonblocking = true};
-SocketConfig  client_cfg       = {.host = "127.0.0.1", .port = "4950", .type = SOCKET_TCP, .nonblocking = true};
-SocketConfig  connection_cfg   = {.nonblocking = true};
-SocketResult *server_res       = NULL;
-SocketResult *client_res       = NULL;
-SocketSet *   socket_set       = NULL;
-Socket *      connection       = NULL;
-char          recvBuffer[512];
+float elapsed = 0.0f;
+float delay = 1.0f;
+bool ping = false;
+bool pong = false;
+bool connected = false;
+bool clientConnected = false;
+const char *pingmsg = "Ping!";
+const char *pongmsg = "Pong!";
+int msglen = 0;
+SocketConfig serverConfig = { .host = "127.0.0.1", .port = "4950", .type = SOCKET_TCP, .server = true, .nonblocking = true };
+SocketConfig clientConfig = { .host = "127.0.0.1", .port = "4950", .type = SOCKET_TCP, .nonblocking = true };
+SocketConfig connectionConfig = { .nonblocking = true };
+SocketResult *serverResult = NULL;
+SocketResult *clientResult = NULL;
+SocketSet *socketSet = NULL;
+Socket *connection = NULL;
+char receiveBuffer[512] = { 0 };
 
 // Attempt to connect to the network (Either TCP, or UDP)
-void NetworkConnect()
+static void NetworkConnect(void)
 {
     // If the server is configured as UDP, ignore connection requests
-    if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
-        ping      = true;
+    if ((serverConfig.type == SOCKET_UDP) && (clientConfig.type == SOCKET_UDP))
+    {
+        ping = true;
         connected = true;
-    } else {
+    } 
+    else 
+    {
         // If the client is connected, run the server code to check for a connection
-        if (client_connected) {
-            int active = CheckSockets(socket_set, 0);
-            if (active != 0) {
-                TraceLog(LOG_DEBUG,
-                         "There are currently %d socket(s) with data to be processed.", active);
-            }
-            if (active > 0) {
-                if ((connection = SocketAccept(server_res->socket, &connection_cfg)) != NULL) {
-                    AddSocket(socket_set, connection);
-                    ping      = true;
+        if (clientConnected) 
+        {
+            int active = CheckSockets(socketSet, 0);
+            if (active != 0) TraceLog(LOG_INFO, "There are currently %d socket(s) with data to be processed.", active);
+
+            if (active > 0) 
+            {
+                if ((connection = SocketAccept(serverResult->socket, &connectionConfig)) != NULL)
+                {
+                    AddSocket(socketSet, connection);
                     connected = true;
+                    ping = true;
                 }
             }
-        } else {
+        } 
+        else
+        {
             // Check if we're connected every _delay_ seconds
             elapsed += GetFrameTime();
-            if (elapsed > delay) {
-                if (IsSocketConnected(client_res->socket)) {
-                    client_connected = true;
-                }
+            if (elapsed > delay)
+            {
+                if (IsSocketConnected(clientResult->socket)) clientConnected = true;
+                
                 elapsed = 0.0f;
             }
         }
@@ -82,144 +75,138 @@ void NetworkConnect()
 
 // Once connected to the network, check the sockets for pending information
 // and when information is ready, send either a Ping or a Pong.
-void NetworkUpdate()
+static void UpdateNetwork(void)
 {
-    // CheckSockets
-    //
-    // If any of the sockets in the socket_set are pending (received data, or requests)
-    // then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
-    int active = CheckSockets(socket_set, 0);
-    if (active != 0) {
-        TraceLog(LOG_DEBUG,
-                 "There are currently %d socket(s) with data to be processed.", active);
-    }
+    // CheckSockets, if any of the sockets in the socketSet are pending (received data, or requests)
+    // then mark the socket as being ready. You can check this with IsSocketReady(clientResult->socket)
+    int active = CheckSockets(socketSet, 0);
+    if (active != 0) TraceLog(LOG_DEBUG, "There are currently %d socket(s) with data to be processed.", active);
 
-    // IsSocketReady
-    //
-    // If the socket is ready, attempt to receive data from the socket
+    // IsSocketReady, if the socket is ready, attempt to receive data from the socket
     int bytesRecv = 0;
-    if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
-        if (IsSocketReady(client_res->socket)) {
-            bytesRecv = SocketReceive(client_res->socket, recvBuffer, msglen);
-        }
-        if (IsSocketReady(server_res->socket)) {
-            bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen);
-        }
-    } else {
-        if (IsSocketReady(connection)) {
-            bytesRecv = SocketReceive(connection, recvBuffer, msglen);
-        }
-    }
+    if ((serverConfig.type == SOCKET_UDP) && (clientConfig.type == SOCKET_UDP))
+    {
+        if (IsSocketReady(clientResult->socket)) bytesRecv = SocketReceive(clientResult->socket, receiveBuffer, msglen);
+        if (IsSocketReady(serverResult->socket)) bytesRecv = SocketReceive(serverResult->socket, receiveBuffer, msglen);
+    } 
+    else if (IsSocketReady(connection)) bytesRecv = SocketReceive(connection, receiveBuffer, msglen);
 
     // If we received data, was that data a "Ping!" or a "Pong!"
-    if (bytesRecv > 0) {
-        if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
-        if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
+    if (bytesRecv > 0)
+    {
+        if (strcmp(receiveBuffer, pingmsg) == 0) { pong = true; }
+        if (strcmp(receiveBuffer, pongmsg) == 0) { ping = true; }
     }
 
     // After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
     elapsed += GetFrameTime();
-    if (elapsed > delay) {
-        if (ping) {
+    if (elapsed > delay)
+    {
+        if (ping)
+        {
             ping = false;
-            if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
-                SocketSend(client_res->socket, pingmsg, msglen);
-            } else {
-                SocketSend(client_res->socket, pingmsg, msglen);
-            }
-        } else if (pong) {
+            if (serverConfig.type == SOCKET_UDP && clientConfig.type == SOCKET_UDP) SocketSend(clientResult->socket, pingmsg, msglen);
+            else SocketSend(clientResult->socket, pingmsg, msglen);
+        } 
+        else if (pong)
+        {
             pong = false;
-            if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
-                SocketSend(client_res->socket, pongmsg, msglen);
-            } else {
-                SocketSend(client_res->socket, pongmsg, msglen);
-            }
+            if (serverConfig.type == SOCKET_UDP && clientConfig.type == SOCKET_UDP) SocketSend(clientResult->socket, pongmsg, msglen);
+            else SocketSend(clientResult->socket, pongmsg, msglen);
         }
+        
         elapsed = 0.0f;
     }
 }
 
-int main()
+int main(void)
 {
-    // Setup
-    int screenWidth  = 800;
-    int screenHeight = 450;
-    InitWindow(
-        screenWidth, screenHeight, "raylib [network] example - ping pong");
-    SetTargetFPS(60);
-    SetTraceLogLevel(LOG_DEBUG);
-
-    // Networking
-    InitNetwork();
-
-    // Create the server
-    //
-    // Performs
-    //     getaddrinfo
-    //     socket
-    //     setsockopt
-    //     bind
-    //     listen
-    server_res = AllocSocketResult();
-    if (!SocketCreate(&server_cfg, server_res)) {
-        TraceLog(LOG_WARNING, "Failed to open server: status %d, errno %d",
-                 server_res->status, server_res->socket->status);
-    } else {
-        if (!SocketBind(&server_cfg, server_res)) {
-            TraceLog(LOG_WARNING, "Failed to bind server: status %d, errno %d",
-                     server_res->status, server_res->socket->status);
-        } else {
-            if (!(server_cfg.type == SOCKET_UDP)) {
-                if (!SocketListen(&server_cfg, server_res)) {
-                    TraceLog(LOG_WARNING,
-                             "Failed to start listen server: status %d, errno %d",
-                             server_res->status, server_res->socket->status);
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [network] example - ping pong");
+
+    InitNetworkDevice();    // Init network communications
+
+    //  Create the server: getaddrinfo + socket + setsockopt + bind + listen
+    serverResult = LoadSocketResult();
+    if (!SocketCreate(&serverConfig, serverResult)) 
+    {
+        TraceLog(LOG_WARNING, "Failed to open server: status %d, errno %d", serverResult->status, serverResult->socket->status);
+    }
+    else
+    {
+        if (!SocketBind(&serverConfig, serverResult))
+        {
+            TraceLog(LOG_WARNING, "Failed to bind server: status %d, errno %d", serverResult->status, serverResult->socket->status);
+        } 
+        else
+        {
+            if (!(serverConfig.type == SOCKET_UDP))
+            {
+                if (!SocketListen(&serverConfig, serverResult))
+                {
+                    TraceLog(LOG_WARNING, "Failed to start listen server: status %d, errno %d", serverResult->status, serverResult->socket->status);
                 }
             }
         }
     }
 
-    // Create the client
-    //
-    // Performs
-    //     getaddrinfo
-    //     socket
-    //     setsockopt
-    //     connect (TCP only)
-    client_res = AllocSocketResult();
-    if (!SocketCreate(&client_cfg, client_res)) {
-        TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d",
-                 client_res->status, client_res->socket->status);
-    } else {
-        if (!(client_cfg.type == SOCKET_UDP)) {
-            if (!SocketConnect(&client_cfg, client_res)) {
-                TraceLog(LOG_WARNING,
-                         "Failed to connect to server: status %d, errno %d",
-                         client_res->status, client_res->socket->status);
+    // Create the client: getaddrinfo + socket + setsockopt + connect (TCP only)
+    clientResult = LoadSocketResult();
+    if (!SocketCreate(&clientConfig, clientResult)) 
+    {
+        TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d", clientResult->status, clientResult->socket->status);
+    }
+    else
+    {
+        if (!(clientConfig.type == SOCKET_UDP))
+        {
+            if (!SocketConnect(&clientConfig, clientResult))
+            {
+                TraceLog(LOG_WARNING, "Failed to connect to server: status %d, errno %d", clientResult->status, clientResult->socket->status);
             }
         }
     }
 
-    // Create & Add sockets to the socket set
-    socket_set = AllocSocketSet(3);
-    msglen     = strlen(pingmsg) + 1;
-    memset(recvBuffer, '\0', sizeof(recvBuffer));
-    AddSocket(socket_set, server_res->socket);
-    AddSocket(socket_set, client_res->socket);
+    // Create and add sockets to the socket set
+    socketSet = LoadSocketSet(3);
+
+    AddSocket(socketSet, serverResult->socket);
+    AddSocket(socketSet, clientResult->socket);
+
+    SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
+    //--------------------------------------------------------------------------------------
 
     // Main game loop
-    while (!WindowShouldClose()) {
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        if (connected) UpdateNetwork();
+        //else NetworkConnect();
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
         BeginDrawing();
-        ClearBackground(RAYWHITE);
-        if (connected) {
-            NetworkUpdate();
-        } else {
-            NetworkConnect();
-        }
+
+            ClearBackground(RAYWHITE);
+            
+            // TODO: Draw relevant connection info
+
         EndDrawing();
+        //----------------------------------------------------------------------------------
     }
 
-    // Cleanup
-    CloseWindow();
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseNetworkDevice();   // Close network communication
+    
+    CloseWindow();          // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
     return 0;
 }

+ 55 - 57
lib.mod/raylib/examples/network/network_resolve_host.c

@@ -1,80 +1,78 @@
 /*******************************************************************************************
- *
- *   raylib [network] example - Resolve Host
- *
- *   Welcome to raylib!
- *
- *   To test examples, just press F6 and execute raylib_compile_execute script
- *   Note that compiled executable is placed in the same folder as .c file
- *
- *   You can find all basic examples on C:\raylib\raylib\examples folder or
- *   raylib official webpage: www.raylib.com
- *
- *   Enjoy using raylib. :)
- *
- *   This example has been created using raylib 2.0 (www.raylib.com)
- *   raylib is licensed under an unmodified zlib/libpng license (View raylib.h
- *for details)
- *
- *   Copyright (c) 2013-2016 Ramon Santamaria (@raysan5)
- *
- ********************************************************************************************/
+*
+*   raylib [network] example - Resolve Host
+*
+*   This example has been created using raylib 3.0 (www.raylib.com)
+*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
+*
+*   Copyright (c) 2019-2020 Jak Barnes (@syphonx) and Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
 
-#include "raylib.h" 
-#include "rnet.h"
+#include "raylib.h"
 
-char     buffer[ADDRESS_IPV6_ADDRSTRLEN];
-uint16_t port = 0;
+#define RNET_IMPLEMENTATION
+#include "rnet.h"
 
-int main()
+int main(void)
 {
-    // Setup
-    int screenWidth  = 800;
-    int screenHeight = 450;
-    InitWindow(
-        screenWidth, screenHeight, "raylib [network] example - ping pong");
-    SetTargetFPS(60);
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
 
-    SetTraceLogLevel(LOG_DEBUG);
+    InitWindow(screenWidth, screenHeight, "raylib [network] example - resolve host");
+    
+    InitNetworkDevice();    // Init network communications
+    
+    char buffer[ADDRESS_IPV6_ADDRSTRLEN];
+    unsigned short port = 0;
 
-    // Networking
-    InitNetwork();
-     
-    AddressInformation* addr = AllocAddressList(1);
-    int count = ResolveHost(
-        NULL,
-        "5210",
-        ADDRESS_TYPE_IPV4,
-        0                               // Uncomment any of these flags
-        //  ADDRESS_INFO_NUMERICHOST    // or try them in conjunction to
-        //  ADDRESS_INFO_NUMERICSERV    // specify custom behaviour from 
-        //  ADDRESS_INFO_DNS_ONLY       // the function getaddrinfo()
-        //  ADDRESS_INFO_ALL            //
-        //  ADDRESS_INFO_FQDN           // e.g. ADDRESS_INFO_CANONNAME | ADDRESS_INFO_NUMERICSERV
-        ,
-        addr
-    );
+    AddressInformation *address = LoadAddressList(1);
+    
+    // Address info flags
+    //  ADDRESS_INFO_NUMERICHOST    // or try them in conjunction to
+    //  ADDRESS_INFO_NUMERICSERV    // specify custom behaviour from 
+    //  ADDRESS_INFO_DNS_ONLY       // the function getaddrinfo()
+    //  ADDRESS_INFO_ALL            //
+    //  ADDRESS_INFO_FQDN           // e.g. ADDRESS_INFO_CANONNAME | ADDRESS_INFO_NUMERICSERV
+    int count = ResolveHost(NULL, "5210", ADDRESS_TYPE_IPV4, 0, address);
 
     if (count > 0)
     {
-        GetAddressHostAndPort(addr[0], buffer, &port);
-        TraceLog(LOG_INFO, "Resolved to ip %s::%d\n", buffer, port);
+        GetAddressHostAndPort(address[0], buffer, &port);
+        TraceLog(LOG_INFO, "Resolved to ip %s::%d", buffer, port);
     }
 
+    SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
+    //--------------------------------------------------------------------------------------
+
     // Main game loop
-    while (!WindowShouldClose())
+    while (!WindowShouldClose())    // Detect window close button or ESC key
     {
+        // Update
+        //----------------------------------------------------------------------------------
+        // TODO: Update your variables here
+        //----------------------------------------------------------------------------------
+
         // Draw
+        //----------------------------------------------------------------------------------
         BeginDrawing();
 
-        // Clear
-        ClearBackground(RAYWHITE);
+            ClearBackground(RAYWHITE);
+
+            // TODO: Draw relevant connection info
 
-        // End draw
         EndDrawing();
+        //----------------------------------------------------------------------------------
     }
 
-    // Cleanup
-    CloseWindow();
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseNetworkDevice();   // Close network communication
+    
+    CloseWindow();          // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
     return 0;
 }

+ 120 - 129
lib.mod/raylib/examples/network/network_tcp_client.c

@@ -1,151 +1,142 @@
 /*******************************************************************************************
- *
- *   raylib [network] example - TCP Client
- *
- *   Welcome to raylib!
- *
- *   To test examples, just press F6 and execute raylib_compile_execute script
- *   Note that compiled executable is placed in the same folder as .c file
- *
- *   You can find all basic examples on C:\raylib\raylib\examples folder or
- *   raylib official webpage: www.raylib.com
- *
- *   Enjoy using raylib. :)
- *
- *   This example has been created using raylib 2.0 (www.raylib.com)
- *   raylib is licensed under an unmodified zlib/libpng license (View raylib.h
- *for details)
- *
- *   Copyright (c) 2013-2016 Ramon Santamaria (@raysan5)
- *
- ********************************************************************************************/
+*
+*   raylib [network] example - TCP Client
+*
+*   This example has been created using raylib 3.0 (www.raylib.com)
+*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
+*
+*   Copyright (c) 2019-2020 Jak Barnes (@syphonx) and Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
 
 #include "raylib.h"
+
+#define RNET_IMPLEMENTATION
 #include "rnet.h"
 
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-
-float         elapsed    = 0.0f;
-float         delay      = 1.0f;
-bool          ping       = false;
-bool          pong       = false;
-bool          connected  = false;
-const char *  pingmsg    = "Ping!";
-const char *  pongmsg    = "Pong!";
-int           msglen     = 0;
-SocketConfig  client_cfg = {.host = "127.0.0.1", .port = "4950", .type = SOCKET_TCP, .nonblocking = true};
-SocketResult *client_res = NULL;
-SocketSet *   socket_set = NULL;
-char          recvBuffer[512];
-
-// Attempt to connect to the network (Either TCP, or UDP)
-void NetworkConnect()
+int main(void)
 {
-    // Check if we're connected every _delay_ seconds
-    elapsed += GetFrameTime();
-    if (elapsed > delay) {
-        if (IsSocketConnected(client_res->socket)) { connected = true; }
-        elapsed = 0.0f;
-    }
-}
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
 
-// Once connected to the network, check the sockets for pending information
-// and when information is ready, send either a Ping or a Pong.
-void NetworkUpdate()
-{
-    // CheckSockets
-    //
-    // If any of the sockets in the socket_set are pending (received data, or requests)
-    // then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
-    int active = CheckSockets(socket_set, 0);
-    if (active != 0) {
-        TraceLog(LOG_DEBUG,
-                 "There are currently %d socket(s) with data to be processed.", active);
-    }
+    InitWindow(screenWidth, screenHeight, "raylib [network] example - tcp client");
 
-    // IsSocketReady
-    //
-    // If the socket is ready, attempt to receive data from the socket
-    int bytesRecv = 0;
-    if (IsSocketReady(client_res->socket)) {
-        bytesRecv = SocketReceive(client_res->socket, recvBuffer, msglen);
-    }
+    InitNetworkDevice();    // Init network communications
+    
+    const char *pingmsg = "Ping!";
+    const char *pongmsg = "Pong!";
+    
+    bool ping = false;
+    bool pong = false;
+    float elapsed = 0.0f;
+    float delay = 1.0f;
+    bool connected = false;
 
-    // If we received data, was that data a "Ping!" or a "Pong!"
-    if (bytesRecv > 0) {
-        if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
-        if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
-    }
+    SocketConfig clientConfig = {
+        .host = "127.0.0.1", 
+        .port = "4950", 
+        .type = SOCKET_TCP, 
+        .nonblocking = true
+    };
+    
+    SocketSet *socketSet = NULL;
+    SocketResult *clientResult = NULL;
+    char receiveBuffer[512] = { 0 };
 
-    // After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
-    elapsed += GetFrameTime();
-    if (elapsed > delay) {
-        if (ping) {
-            ping = false;
-            SocketSend(client_res->socket, pingmsg, msglen);
-        } else if (pong) {
-            pong = false;
-            SocketSend(client_res->socket, pongmsg, msglen);
+    // Create the client: getaddrinfo + socket + setsockopt + connect (TCP only)
+    clientResult = LoadSocketResult();
+    if (!SocketCreate(&clientConfig, clientResult)) TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d", clientResult->status, clientResult->socket->status);
+    else 
+    {
+        if (!(clientConfig.type == SOCKET_UDP)) 
+        {
+            if (!SocketConnect(&clientConfig, clientResult)) TraceLog(LOG_WARNING, "Failed to connect to server: status %d, errno %d", clientResult->status, clientResult->socket->status);
         }
-        elapsed = 0.0f;
     }
-}
 
-int main()
-{
-    // Setup
-    int screenWidth  = 800;
-    int screenHeight = 450;
-    InitWindow(
-        screenWidth, screenHeight, "raylib [network] example - tcp client");
-    SetTargetFPS(60);
-    SetTraceLogLevel(LOG_DEBUG);
-
-    // Networking
-    InitNetwork();
-
-    // Create the client
-    //
-    //  Performs
-    //      getaddrinfo
-    //      socket
-    //      setsockopt
-    //      connect (TCP only)
-    client_res = AllocSocketResult();
-    if (!SocketCreate(&client_cfg, client_res)) {
-        TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d",
-                 client_res->status, client_res->socket->status);
-    } else {
-        if (!(client_cfg.type == SOCKET_UDP)) {
-            if (!SocketConnect(&client_cfg, client_res)) {
-                TraceLog(LOG_WARNING,
-                         "Failed to connect to server: status %d, errno %d",
-                         client_res->status, client_res->socket->status);
-            }
-        }
-    }
+    // Create and add sockets to the socket set
+    socketSet = LoadSocketSet(1);
+    AddSocket(socketSet, clientResult->socket);
 
-    //  Create & Add sockets to the socket set
-    socket_set = AllocSocketSet(1);
-    msglen     = strlen(pingmsg) + 1;
-    memset(recvBuffer, '\0', sizeof(recvBuffer));
-    AddSocket(socket_set, client_res->socket);
+    SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
+    //--------------------------------------------------------------------------------------
 
     // Main game loop
-    while (!WindowShouldClose()) {
-        BeginDrawing();
-        ClearBackground(RAYWHITE);
-        if (connected) {
-            NetworkUpdate();
-        } else {
-            NetworkConnect();
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        if (connected)
+        {
+            // Once connected to the network, check the sockets for pending information
+            // and when information is ready, send either a Ping or a Pong.
+
+            // CheckSockets, if any of the sockets in the socketSet are pending (received data, or requests)
+            // then mark the socket as being ready. You can check this with IsSocketReady(clientResult->socket)
+            int active = CheckSockets(socketSet, 0);
+            if (active != 0) TraceLog(LOG_DEBUG, "There are currently %d socket(s) with data to be processed.", active);
+
+            // IsSocketReady, if the socket is ready, attempt to receive data from the socket
+            int bytesRecv = 0;
+            if (IsSocketReady(clientResult->socket)) bytesRecv = SocketReceive(clientResult->socket, receiveBuffer, strlen(pingmsg) + 1);
+
+            // If we received data, was that data a "Ping!" or a "Pong!"
+            if (bytesRecv > 0) 
+            {
+                if (strcmp(receiveBuffer, pingmsg) == 0) { pong = true; }
+                if (strcmp(receiveBuffer, pongmsg) == 0) { ping = true; }
+            }
+
+            // After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
+            elapsed += GetFrameTime();
+            if (elapsed > delay) 
+            {
+                if (ping) 
+                {
+                    ping = false;
+                    SocketSend(clientResult->socket, pingmsg, strlen(pingmsg) + 1);
+                }
+                else if (pong) 
+                {
+                    pong = false;
+                    SocketSend(clientResult->socket, pongmsg, strlen(pingmsg) + 1);
+                }
+                
+                elapsed = 0.0f;
+            }
+        }
+        else
+        {
+            // Check if we're connected every delay seconds
+            elapsed += GetFrameTime();
+            if (elapsed > delay)
+            {
+                if (IsSocketConnected(clientResult->socket)) { connected = true; }
+                elapsed = 0.0f;
+            }
         }
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+            
+            // TODO: Draw relevant connection info
+
         EndDrawing();
+        //----------------------------------------------------------------------------------
     }
 
-    // Cleanup
-    CloseWindow();
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseNetworkDevice();   // Close network communication
+    
+    CloseWindow();          // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
     return 0;
 }

+ 138 - 141
lib.mod/raylib/examples/network/network_tcp_server.c

@@ -1,165 +1,162 @@
 /*******************************************************************************************
- *
- *   raylib [network] example - TCP Server
- *
- *   Welcome to raylib!
- *
- *   To test examples, just press F6 and execute raylib_compile_execute script
- *   Note that compiled executable is placed in the same folder as .c file
- *
- *   You can find all basic examples on C:\raylib\raylib\examples folder or
- *   raylib official webpage: www.raylib.com
- *
- *   Enjoy using raylib. :)
- *
- *   This example has been created using raylib 2.0 (www.raylib.com)
- *   raylib is licensed under an unmodified zlib/libpng license (View raylib.h
- *for details)
- *
- *   Copyright (c) 2013-2016 Ramon Santamaria (@raysan5)
- *
- ********************************************************************************************/
+*
+*   raylib [network] example - TCP Server
+*
+*   This example has been created using raylib 3.0 (www.raylib.com)
+*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
+*
+*   Copyright (c) 2019-2020 Jak Barnes (@syphonx) and Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
 
 #include "raylib.h"
+
+#define RNET_IMPLEMENTATION
 #include "rnet.h"
 
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-
-float         elapsed        = 0.0f;
-float         delay          = 1.0f;
-bool          ping           = false;
-bool          pong           = false;
-bool          connected      = false;
-const char *  pingmsg        = "Ping!";
-const char *  pongmsg        = "Pong!";
-int           msglen         = 0;
-SocketConfig  server_cfg     = {.host = "127.0.0.1", .port = "4950", .type = SOCKET_TCP, .server = true, .nonblocking = true};
-SocketConfig  connection_cfg = {.nonblocking = true};
-SocketResult *server_res     = NULL;
-SocketSet *   socket_set     = NULL;
-Socket *      connection     = NULL;
-char          recvBuffer[512];
-
-// Attempt to connect to the network (Either TCP, or UDP)
-void NetworkConnect()
+int main(void)
 {
-    int active = CheckSockets(socket_set, 0);
-    if (active != 0) {
-        TraceLog(LOG_DEBUG,
-                 "There are currently %d socket(s) with data to be processed.", active);
-    }
-    if (active > 0) {
-        if ((connection = SocketAccept(server_res->socket, &connection_cfg)) != NULL) {
-            AddSocket(socket_set, connection);
-            ping      = true;
-            connected = true;
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [network] example - tcp server");
+
+    InitNetworkDevice();    // Init network communications
+    
+    const char *pingmsg = "Ping!";
+    const char *pongmsg = "Pong!";
+    
+    bool ping = false;
+    bool pong = false;
+    float elapsed = 0.0f;
+    float delay = 1.0f;
+    bool connected = false;
+
+    SocketConfig serverConfig = {
+        .host = "127.0.0.1", 
+        .port = "4950", 
+        .type = SOCKET_TCP,
+        .server = true,
+        .nonblocking = true
+    };
+    
+    SocketConfig connectionConfig = { .nonblocking = true };
+    
+    Socket *connection = NULL;
+    SocketSet *socketSet = NULL;
+    SocketResult *serverResult = NULL;
+    char receiveBuffer[512] = { 0 };
+    
+    //  Create the server: getaddrinfo + socket + setsockopt + bind + listen
+    serverResult = LoadSocketResult();
+    if (!SocketCreate(&serverConfig, serverResult)) 
+    {
+        TraceLog(LOG_WARNING, "Failed to open server: status %d, errno %d", serverResult->status, serverResult->socket->status);
+    } 
+    else
+    {
+        if (!SocketBind(&serverConfig, serverResult))
+        {
+            TraceLog(LOG_WARNING, "Failed to bind server: status %d, errno %d", serverResult->status, serverResult->socket->status);
+        } 
+        else
+        {
+            if (!(serverConfig.type == SOCKET_UDP))
+            {
+                if (!SocketListen(&serverConfig, serverResult)) TraceLog(LOG_WARNING, "Failed to start listen server: status %d, errno %d", serverResult->status, serverResult->socket->status);
+            }
         }
     }
-}
 
-// Once connected to the network, check the sockets for pending information
-// and when information is ready, send either a Ping or a Pong.
-void NetworkUpdate()
-{
-    // CheckSockets
-    //
-    // If any of the sockets in the socket_set are pending (received data, or requests)
-    // then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
-    int active = CheckSockets(socket_set, 0);
-    if (active != 0) {
-        TraceLog(LOG_DEBUG,
-                 "There are currently %d socket(s) with data to be processed.", active);
-    }
+    // Create and add sockets to the socket set
+    socketSet = LoadSocketSet(2);
+    AddSocket(socketSet, serverResult->socket);
 
-    // IsSocketReady
-    //
-    // If the socket is ready, attempt to receive data from the socket
-    int bytesRecv = 0;
-    if (IsSocketReady(connection)) {
-        bytesRecv = SocketReceive(connection, recvBuffer, msglen);
-    }
+    SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
+    //--------------------------------------------------------------------------------------
 
-    // If we received data, was that data a "Ping!" or a "Pong!"
-    if (bytesRecv > 0) {
-        if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
-        if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
-    }
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        if (connected)
+        {
+            // Once connected to the network, check the sockets for pending information
+            // and when information is ready, send either a Ping or a Pong.
 
-    // After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
-    elapsed += GetFrameTime();
-    if (elapsed > delay) {
-        if (ping) {
-            ping = false;
-            SocketSend(connection, pingmsg, msglen);
-        } else if (pong) {
-            pong = false;
-            SocketSend(connection, pongmsg, msglen);
-        }
-        elapsed = 0.0f;
-    }
-}
+            // CheckSockets, if any of the sockets in the socketSet are pending (received data, or requests)
+            // then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
+            int active = CheckSockets(socketSet, 0);
+            if (active != 0) TraceLog(LOG_DEBUG, "There are currently %d socket(s) with data to be processed.", active);
 
-int main()
-{
-    // Setup
-    int screenWidth  = 800;
-    int screenHeight = 450;
-    InitWindow(
-        screenWidth, screenHeight, "raylib [network] example - tcp server");
-    SetTargetFPS(60);
-    SetTraceLogLevel(LOG_DEBUG);
-
-    // Networking
-    InitNetwork();
-
-    //  Create the server
-    //
-    //  Performs
-    //      getaddrinfo
-    //      socket
-    //      setsockopt
-    //      bind
-    //      listen
-    server_res = AllocSocketResult();
-    if (!SocketCreate(&server_cfg, server_res)) {
-        TraceLog(LOG_WARNING, "Failed to open server: status %d, errno %d",
-                 server_res->status, server_res->socket->status);
-    } else {
-        if (!SocketBind(&server_cfg, server_res)) {
-            TraceLog(LOG_WARNING, "Failed to bind server: status %d, errno %d",
-                     server_res->status, server_res->socket->status);
-        } else {
-            if (!(server_cfg.type == SOCKET_UDP)) {
-                if (!SocketListen(&server_cfg, server_res)) {
-                    TraceLog(LOG_WARNING,
-                             "Failed to start listen server: status %d, errno %d",
-                             server_res->status, server_res->socket->status);
+            // IsSocketReady, if the socket is ready, attempt to receive data from the socket
+            int bytesRecv = 0;
+            if (IsSocketReady(connection)) bytesRecv = SocketReceive(connection, receiveBuffer, strlen(pingmsg) + 1);
+
+            // If we received data, was that data a "Ping!" or a "Pong!"
+            if (bytesRecv > 0)
+            {
+                if (strcmp(receiveBuffer, pingmsg) == 0) { pong = true; }
+                if (strcmp(receiveBuffer, pongmsg) == 0) { ping = true; }
+            }
+
+            // After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
+            elapsed += GetFrameTime();
+            if (elapsed > delay)
+            {
+                if (ping) 
+                {
+                    ping = false;
+                    SocketSend(connection, pingmsg, strlen(pingmsg) + 1);
+                } 
+                else if (pong)
+                {
+                    pong = false;
+                    SocketSend(connection, pongmsg, strlen(pingmsg) + 1);
                 }
+                
+                elapsed = 0.0f;
             }
         }
-    }
+        else
+        {
+            // Attempt to connect to the network (Either TCP, or UDP)
+            int active = CheckSockets(socketSet, 0);
+            if (active != 0) TraceLog(LOG_DEBUG, "There are currently %d socket(s) with data to be processed.", active);
 
-    //  Create & Add sockets to the socket set
-    socket_set = AllocSocketSet(2);
-    msglen     = strlen(pingmsg) + 1;
-    memset(recvBuffer, '\0', sizeof(recvBuffer));
-    AddSocket(socket_set, server_res->socket);
+            if (active > 0) 
+            {
+                if ((connection = SocketAccept(serverResult->socket, &connectionConfig)) != NULL) 
+                {
+                    AddSocket(socketSet, connection);
+                    connected = true;
+                    ping = true;
+                }
+            }
+        }
+        //----------------------------------------------------------------------------------
 
-    // Main game loop
-    while (!WindowShouldClose()) {
+        // Draw
+        //----------------------------------------------------------------------------------
         BeginDrawing();
-        ClearBackground(RAYWHITE);
-        if (connected) {
-            NetworkUpdate();
-        } else {
-            NetworkConnect();
-        }
+
+            ClearBackground(RAYWHITE);
+            
+            // TODO: Draw relevant connection info
+
         EndDrawing();
+        //----------------------------------------------------------------------------------
     }
 
-    // Cleanup
-    CloseWindow();
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseNetworkDevice();   // Close network communication
+    
+    CloseWindow();          // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
     return 0;
 }

+ 64 - 48
lib.mod/raylib/examples/network/network_test.c

@@ -1,48 +1,39 @@
 /*******************************************************************************************
- *
- *   raylib [network] example - Network Test
- *
- *   Welcome to raylib!
- *
- *   To test examples, just press F6 and execute raylib_compile_execute script
- *   Note that compiled executable is placed in the same folder as .c file
- *
- *   You can find all basic examples on C:\raylib\raylib\examples folder or
- *   raylib official webpage: www.raylib.com
- *
- *   Enjoy using raylib. :)
- *
- *   This example has been created using raylib 2.0 (www.raylib.com)
- *   raylib is licensed under an unmodified zlib/libpng license (View raylib.h
- *for details)
- *
- *   Copyright (c) 2013-2016 Ramon Santamaria (@raysan5)
- *
- ********************************************************************************************/
+*
+*   raylib [network] example - Network Test
+*
+*   This example has been created using raylib 3.0 (www.raylib.com)
+*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
+*
+*   Copyright (c) 2019-2020 Jak Barnes (@syphonx) and Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
 
 #include "raylib.h"
+
+#define RNET_IMPLEMENTATION
 #include "rnet.h"
 
 #include <assert.h>
 
 void test_network_initialise()
 {
-    assert(InitNetwork() == true);
+    assert(InitNetworkDevice() == true);
 }
 
 void test_socket_result()
 {
-    SocketResult *result = AllocSocketResult();
+    SocketResult *result = LoadSocketResult();
     assert(result != NULL);
-    FreeSocketResult(&result);
+    UnloadSocketResult(&result);
     assert(result == NULL);
 }
 
 void test_socket()
 {
-    Socket *socket = AllocSocket();
+    Socket *socket = LoadSocket();
     assert(socket != NULL);
-    FreeSocket(&socket);
+    UnloadSocket(&socket);
     assert(socket == NULL);
 }
 
@@ -50,8 +41,8 @@ void test_resolve_ip()
 {
     const char *host = "8.8.8.8";
     const char *port = "8080";
-    char        ip[ADDRESS_IPV6_ADDRSTRLEN];
-    char        service[ADDRESS_MAXSERV];
+    char ip[ADDRESS_IPV6_ADDRSTRLEN];
+    char service[ADDRESS_MAXSERV];
 
     memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN);
     ResolveIP(host, port, NAME_INFO_NUMERICHOST, ip, service);
@@ -91,9 +82,9 @@ void test_resolve_ip()
 
 void test_resolve_host()
 {
-    const char *        address = "localhost";
-    const char *        port    = "80";
-    AddressInformation *addr    = AllocAddressList(3);
+    const char *address = "localhost";
+    const char *port = "80";
+    AddressInformation *addr = LoadAddressList(3);
     int count = ResolveHost(address, port, ADDRESS_TYPE_ANY, 0, addr); 
 
     assert(GetAddressFamily(addr[0]) == ADDRESS_TYPE_IPV6);
@@ -113,36 +104,61 @@ void test_address_list()
 
 void test_socket_create()
 {
-    SocketConfig  server_cfg = {.host = "127.0.0.1", .port = "8080", .server = true, .nonblocking = true};
-    Socket *      socket     = AllocSocket();
-    SocketResult *server_res = AllocSocketResult();
-    SocketSet *   socket_set = AllocSocketSet(1);
+    SocketConfig server_cfg = { .host = "127.0.0.1", .port = "8080", .server = true, .nonblocking = true };
+    Socket *socket = LoadSocket();
+    SocketResult *server_res = LoadSocketResult();
+    SocketSet *socket_set = LoadSocketSet(1);
+
     assert(SocketCreate(&server_cfg, server_res));
     assert(AddSocket(socket_set, server_res->socket));
     assert(SocketListen(&server_cfg, server_res));
 }
 
-int main()
+int main(void)
 {
-    int screenWidth  = 800;
-    int screenHeight = 450;
-    InitWindow(
-        screenWidth, screenHeight, "raylib [network] example - network test");
-    SetTargetFPS(60);
-
-    // Run the tests
-    test_network_initialise();
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [network] example - network test");
+    
+    InitNetworkDevice();    // Init network communications
+    
+    // Run some tests
     test_resolve_host();
-    // test_socket_create();
+    //test_socket_create();
+    //test_resolve_ip();
+
+    SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
+    //--------------------------------------------------------------------------------------
 
     // Main game loop
-    while (!WindowShouldClose()) {
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        // TODO: Update your variables here
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
         BeginDrawing();
-        ClearBackground(RAYWHITE);
-        DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
+
+            ClearBackground(RAYWHITE);
+            
+            // TODO: Draw relevant connection info
+
         EndDrawing();
+        //----------------------------------------------------------------------------------
     }
-    CloseWindow();
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseNetworkDevice();   // Close network communication
+    
+    CloseWindow();          // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
 
     return 0;
 }

+ 104 - 108
lib.mod/raylib/examples/network/network_udp_client.c

@@ -1,128 +1,124 @@
 /*******************************************************************************************
- *
- *   raylib [network] example - UDP Client
- *
- *   Welcome to raylib!
- *
- *   To test examples, just press F6 and execute raylib_compile_execute script
- *   Note that compiled executable is placed in the same folder as .c file
- *
- *   You can find all basic examples on C:\raylib\raylib\examples folder or
- *   raylib official webpage: www.raylib.com
- *
- *   Enjoy using raylib. :)
- *
- *   This example has been created using raylib 2.0 (www.raylib.com)
- *   raylib is licensed under an unmodified zlib/libpng license (View raylib.h
- *for details)
- *
- *   Copyright (c) 2013-2016 Ramon Santamaria (@raysan5)
- *
- ********************************************************************************************/
+*
+*   raylib [network] example - UDP Client
+*
+*   This example has been created using raylib 3.0 (www.raylib.com)
+*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
+*
+*   Copyright (c) 2019-2020 Jak Barnes (@syphonx) and Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
 
 #include "raylib.h"
+
+#define RNET_IMPLEMENTATION
 #include "rnet.h"
 
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-
-float         elapsed = 0.0f;
-float         delay   = 1.0f;
-bool          ping    = false;
-bool          pong    = false;
-const char *  pingmsg = "Ping!";
-const char *  pongmsg = "Pong!";
-int           msglen  = 0;
-SocketConfig  client_cfg = {.host = "127.0.0.1", .port = "4950",  .type = SOCKET_UDP, .nonblocking = true};
-SocketResult *client_res = NULL;
-SocketSet *   socket_set = NULL;
-char          recvBuffer[512];
-
-// Once connected to the network, check the sockets for pending information
-// and when information is ready, send either a Ping or a Pong.
-void NetworkUpdate()
+int main(void)
 {
-    // CheckSockets
-    //
-    // If any of the sockets in the socket_set are pending (received data, or requests)
-    // then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
-    int active = CheckSockets(socket_set, 0);
-    if (active != 0) {
-        TraceLog(LOG_DEBUG,
-                 "There are currently %d socket(s) with data to be processed.", active);
-    }
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
 
-    // IsSocketReady
-    //
-    // If the socket is ready, attempt to receive data from the socket
-    int bytesRecv = 0;
-    if (IsSocketReady(client_res->socket)) {
-        bytesRecv = SocketReceive(client_res->socket, recvBuffer, msglen);
-    }
+    InitWindow(screenWidth, screenHeight, "raylib [network] example - udp client");
 
-    // If we received data, was that data a "Ping!" or a "Pong!"
-    if (bytesRecv > 0) {
-        if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
-        if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
-    }
+    InitNetworkDevice();    // Init network communications
+       
+    const char *pingmsg = "Ping!";
+    const char *pongmsg = "Pong!";
+    
+    bool ping = true;
+    bool pong = false;
+    float elapsed = 0.0f;
+    float delay = 1.0f;
 
-    // After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
-    elapsed += GetFrameTime();
-    if (elapsed > delay) {
-        if (ping) {
-            ping = false;
-            SocketSend(client_res->socket, pingmsg, msglen);
-        } else if (pong) {
-            pong = false;
-            SocketSend(client_res->socket, pongmsg, msglen);
-        }
-        elapsed = 0.0f;
-    }
-}
+    SocketConfig clientConfig = {
+        .host = "127.0.0.1", 
+        .port = "4950", 
+        .type = SOCKET_UDP, 
+        .nonblocking = true
+    };
+    
+    SocketResult *clientResult = NULL;
+    SocketSet *socketSet = NULL;
+    char receiveBuffer[512] = { 0 };
 
-int main()
-{
-    // Setup
-    int screenWidth  = 800;
-    int screenHeight = 450;
-    InitWindow(
-        screenWidth, screenHeight, "raylib [network] example - udp client");
-    SetTargetFPS(60);
-    SetTraceLogLevel(LOG_DEBUG);
-
-    // Networking
-    InitNetwork();
-
-    // Create the client
-    //
-    //  Performs
-    //      getaddrinfo
-    //      socket
-    //      setsockopt
-    //      connect (TCP only)
-    client_res = AllocSocketResult();
-    if (!SocketCreate(&client_cfg, client_res)) {
-        TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d",
-                 client_res->status, client_res->socket->status);
+    // Create the client: getaddrinfo + socket + setsockopt + connect (TCP only)
+    clientResult = LoadSocketResult();
+    if (!SocketCreate(&clientConfig, clientResult))
+    {
+        TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d", clientResult->status, clientResult->socket->status);
     }
 
-    //  Create & Add sockets to the socket set
-    socket_set = AllocSocketSet(1);
-    msglen     = strlen(pingmsg) + 1;
-    ping       = true;
-    memset(recvBuffer, '\0', sizeof(recvBuffer));
-    AddSocket(socket_set, client_res->socket);
+    //  Create and add sockets to the socket set
+    socketSet = LoadSocketSet(1);
+    AddSocket(socketSet, clientResult->socket);
+
+    SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
+    //--------------------------------------------------------------------------------------
 
     // Main game loop
-    while (!WindowShouldClose()) {
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        // Once connected to the network, check the sockets for pending information
+        // and when information is ready, send either a Ping or a Pong.
+
+        // CheckSockets, if any of the sockets in the socketSet are pending (received data, or requests)
+        // then mark the socket as being ready. You can check this with IsSocketReady(clientResult->socket)
+        int active = CheckSockets(socketSet, 0);
+        if (active != 0) TraceLog(LOG_INFO, "There are currently %d socket(s) with data to be processed.", active);
+
+        // IsSocketReady, if the socket is ready, attempt to receive data from the socket
+        int bytesRecv = 0;
+        if (IsSocketReady(clientResult->socket)) bytesRecv = SocketReceive(clientResult->socket, receiveBuffer, strlen(pingmsg) + 1);
+
+        // If we received data, was that data a "Ping!" or a "Pong!"
+        if (bytesRecv > 0) 
+        {
+            if (strcmp(receiveBuffer, pingmsg) == 0) { pong = true; }
+            if (strcmp(receiveBuffer, pongmsg) == 0) { ping = true; }
+        }
+
+        // After each delay has expired, send a response "Ping!" for a "Pong!" and vice-versa
+        elapsed += GetFrameTime();
+        if (elapsed > delay)
+        {
+            if (ping) 
+            {
+                ping = false;
+                SocketSend(clientResult->socket, pingmsg, strlen(pingmsg) + 1);
+            } 
+            else if (pong)
+            {
+                pong = false;
+                SocketSend(clientResult->socket, pongmsg, strlen(pongmsg) + 1);
+            }
+            
+            elapsed = 0.0f;
+        }
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
         BeginDrawing();
-        ClearBackground(RAYWHITE);
-        NetworkUpdate();
+
+            ClearBackground(RAYWHITE);
+            
+            // TODO: Draw relevant connection info
+
         EndDrawing();
+        //----------------------------------------------------------------------------------
     }
 
-    // Cleanup
-    CloseWindow();
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseNetworkDevice();   // Close network communication
+    
+    CloseWindow();          // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
     return 0;
 }

+ 110 - 116
lib.mod/raylib/examples/network/network_udp_server.c

@@ -1,134 +1,128 @@
 /*******************************************************************************************
- *
- *   raylib [network] example - UDP Server
- *
- *   Welcome to raylib!
- *
- *   To test examples, just press F6 and execute raylib_compile_execute script
- *   Note that compiled executable is placed in the same folder as .c file
- *
- *   You can find all basic examples on C:\raylib\raylib\examples folder or
- *   raylib official webpage: www.raylib.com
- *
- *   Enjoy using raylib. :)
- *
- *   This example has been created using raylib 2.0 (www.raylib.com)
- *   raylib is licensed under an unmodified zlib/libpng license (View raylib.h
- *for details)
- *
- *   Copyright (c) 2013-2016 Ramon Santamaria (@raysan5)
- *
- ********************************************************************************************/
+*
+*   raylib [network] example - UDP Server
+*
+*   This example has been created using raylib 3.0 (www.raylib.com)
+*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
+*
+*   Copyright (c) 2019-2020 Jak Barnes (@syphonx) and Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
 
 #include "raylib.h"
+
+#define RNET_IMPLEMENTATION
 #include "rnet.h"
 
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-
-float         elapsed    = 0.0f;
-float         delay      = 1.0f;
-bool          ping       = false;
-bool          pong       = false;
-const char *  pingmsg    = "Ping!";
-const char *  pongmsg    = "Pong!";
-int           msglen     = 0;
-SocketConfig  server_cfg = {.host = "127.0.0.1", .port = "4950", .server = true, .type = SOCKET_UDP, .nonblocking = true};
-SocketResult *server_res = NULL;
-SocketSet *   socket_set = NULL;
-char          recvBuffer[512];
-
-// Once connected to the network, check the sockets for pending information
-// and when information is ready, send either a Ping or a Pong.
-void NetworkUpdate()
+int main(void)
 {
-    // CheckSockets
-    //
-    // If any of the sockets in the socket_set are pending (received data, or requests)
-    // then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
-    int active = CheckSockets(socket_set, 0);
-    if (active != 0) {
-        TraceLog(LOG_DEBUG,
-                 "There are currently %d socket(s) with data to be processed.", active);
-    }
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
 
-    // IsSocketReady
-    //
-    // If the socket is ready, attempt to receive data from the socket
-    //  int bytesRecv = 0;
-    //  if (IsSocketReady(server_res->socket)) {
-    //      bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen);
-    //  }
-    int bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen);
-
-    // If we received data, was that data a "Ping!" or a "Pong!"
-    if (bytesRecv > 0) {
-        if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
-        if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
-    }
+    InitWindow(screenWidth, screenHeight, "raylib [network] example - udp server");
 
-    // After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
-    elapsed += GetFrameTime();
-    if (elapsed > delay) {
-        if (ping) {
-            ping = false;
-            SocketSend(server_res->socket, pingmsg, msglen);
-        } else if (pong) {
-            pong = false;
-            SocketSend(server_res->socket, pongmsg, msglen);
-        }
-        elapsed = 0.0f;
-    }
-}
+    InitNetworkDevice();    // Init network communications
+    
+    const char *pingmsg = "Ping!";
+    const char *pongmsg = "Pong!";
+    
+    bool ping = false;
+    bool pong = false;
+    float elapsed = 0.0f;
+    float delay = 1.0f;
 
-int main()
-{
-    // Setup
-    int screenWidth  = 800;
-    int screenHeight = 450;
-    InitWindow(
-        screenWidth, screenHeight, "raylib [network] example - udp server");
-    SetTargetFPS(60);
-    SetTraceLogLevel(LOG_DEBUG);
-
-    // Networking
-    InitNetwork();
-
-    //  Create the server
-    //
-    //  Performs
-    //      getaddrinfo
-    //      socket
-    //      setsockopt
-    //      bind
-    //      listen
-    server_res = AllocSocketResult();
-    if (!SocketCreate(&server_cfg, server_res)) {
-        TraceLog(LOG_WARNING, "Failed to open server: status %d, errno %d",
-                 server_res->status, server_res->socket->status);
-    } else {
-        if (!SocketBind(&server_cfg, server_res)) {
-            TraceLog(LOG_WARNING, "Failed to bind server: status %d, errno %d",
-                     server_res->status, server_res->socket->status);
-        }
-    }
+    SocketConfig serverConfig = {
+        .host = "127.0.0.1", 
+        .port = "4950", 
+        .server = true, 
+        .type = SOCKET_UDP, 
+        .nonblocking = true
+    };
+    
+    SocketResult *serverResult = NULL;
+    SocketSet *socketSet = NULL;
+    char receiveBuffer[512] = { 0 };
+
+    //  Create the server: getaddrinfo + socket + setsockopt + bind + listen
+    serverResult = LoadSocketResult();
+    
+    if (!SocketCreate(&serverConfig, serverResult)) TraceLog(LOG_WARNING, "Failed to open server: status %d, errno %d", serverResult->status, serverResult->socket->status);
+    else if (!SocketBind(&serverConfig, serverResult)) TraceLog(LOG_WARNING, "Failed to bind server: status %d, errno %d", serverResult->status, serverResult->socket->status);
+
+    //  Create and add sockets to the socket set
+    socketSet = LoadSocketSet(1);
+    AddSocket(socketSet, serverResult->socket);
 
-    //  Create & Add sockets to the socket set
-    socket_set = AllocSocketSet(1);
-    msglen     = strlen(pingmsg) + 1;
-    memset(recvBuffer, '\0', sizeof(recvBuffer));
-    AddSocket(socket_set, server_res->socket);
+    SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
+    //--------------------------------------------------------------------------------------
 
     // Main game loop
-    while (!WindowShouldClose()) {
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        // Once connected to the network, check the sockets for pending information
+        // and when information is ready, send either a Ping or a Pong.
+        
+        // CheckSockets, if any of the sockets in the set are pending (received data, or requests)
+        // then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
+        int active = CheckSockets(socketSet, 0);
+        if (active != 0) TraceLog(LOG_INFO, "There are currently %d socket(s) with data to be processed.", active);
+
+        // IsSocketReady, if the socket is ready, attempt to receive data from the socket
+        //  int bytesRecv = 0;
+        //  if (IsSocketReady(serverResult->socket)) {
+        //      bytesRecv = SocketReceive(serverResult->socket, receiveBuffer, msglen);
+        //  }
+        int bytesRecv = SocketReceive(serverResult->socket, receiveBuffer, strlen(pingmsg) + 1);
+
+        // If we received data, is that data a "Ping!" or a "Pong!"?
+        if (bytesRecv > 0) 
+        {
+            if (strcmp(receiveBuffer, pingmsg) == 0) { pong = true; }
+            if (strcmp(receiveBuffer, pongmsg) == 0) { ping = true; }
+        }
+
+        // After each delay has expired, send a response "Ping!" for a "Pong!" and vice-versa
+        elapsed += GetFrameTime();
+        
+        if (elapsed > delay)
+        {
+            if (ping) 
+            {
+                ping = false;
+                SocketSend(serverResult->socket, pingmsg, strlen(pingmsg) + 1);
+            } 
+            else if (pong) 
+            {
+                pong = false;
+                SocketSend(serverResult->socket, pongmsg, strlen(pongmsg) + 1);
+            }
+            
+            elapsed = 0.0f;
+        }
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
         BeginDrawing();
-        ClearBackground(RAYWHITE);
-        NetworkUpdate();
+
+            ClearBackground(RAYWHITE);
+
+            // TODO: Draw relevant connection info
+
         EndDrawing();
+        //----------------------------------------------------------------------------------
     }
 
-    // Cleanup
-    CloseWindow();
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseNetworkDevice();   // Close network communication
+    
+    CloseWindow();          // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
     return 0;
 }

+ 10 - 8
lib.mod/raylib/examples/others/rlgl_standalone.c

@@ -54,6 +54,8 @@
 
 #include <GLFW/glfw3.h>         // Windows/Context and inputs management
 
+#include <stdio.h>              // Required for: printf()
+
 #define RED        (Color){ 230, 41, 55, 255 }     // Red
 #define RAYWHITE   (Color){ 245, 245, 245, 255 }   // My own White (raylib logo)
 #define DARKGRAY   (Color){ 80, 80, 80, 255 }      // Dark Gray
@@ -61,8 +63,8 @@
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
 //----------------------------------------------------------------------------------
-static void ErrorCallback(int error, const char* description);
-static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
+static void ErrorCallback(int error, const char *description);
+static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods);
 
 // Drawing functions (uses rlgl functionality)
 static void DrawGrid(int slices, float spacing);
@@ -86,10 +88,10 @@ int main(void)
     
     if (!glfwInit())
     {
-        TraceLog(LOG_WARNING, "GLFW3: Can not initialize GLFW");
+        printf("GLFW3: Can not initialize GLFW\n");
         return 1;
     }
-    else TraceLog(LOG_INFO, "GLFW3: GLFW initialized successfully");
+    else printf("GLFW3: GLFW initialized successfully\n");
     
     glfwWindowHint(GLFW_SAMPLES, 4);
     glfwWindowHint(GLFW_DEPTH_BITS, 16);
@@ -105,7 +107,7 @@ int main(void)
         glfwTerminate();
         return 2;
     }
-    else TraceLog(LOG_INFO, "GLFW3: Window created successfully");
+    else printf("GLFW3: Window created successfully\n");
     
     glfwSetWindowPos(window, 200, 200);
     
@@ -215,13 +217,13 @@ int main(void)
 //----------------------------------------------------------------------------------
 
 // GLFW3: Error callback
-static void ErrorCallback(int error, const char* description)
+static void ErrorCallback(int error, const char *description)
 {
-    TraceLog(LOG_ERROR, description);
+    fprintf(stderr, description);
 }
 
 // GLFW3: Keyboard callback
-static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
+static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
 {
     if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
     {

+ 0 - 1
lib.mod/raylib/examples/shaders/resources/shaders/glsl100/base.fs

@@ -11,7 +11,6 @@ uniform sampler2D texture0;
 uniform vec4 colDiffuse;
 
 // NOTE: Add here your custom variables
-uniform vec2 resolution = vec2(800, 450);
 
 void main()
 {

+ 59 - 0
lib.mod/raylib/examples/shaders/resources/shaders/glsl100/base_lighting.vs

@@ -0,0 +1,59 @@
+#version 100
+
+// Input vertex attributes
+attribute vec3 vertexPosition;
+attribute vec2 vertexTexCoord;
+attribute vec3 vertexNormal;
+attribute vec4 vertexColor;
+
+// Input uniform values
+uniform mat4 mvp;
+uniform mat4 matModel;
+
+// Output vertex attributes (to fragment shader)
+varying vec3 fragPosition;
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+varying vec3 fragNormal;
+
+// NOTE: Add here your custom variables
+
+// https://github.com/glslify/glsl-inverse
+mat3 inverse(mat3 m)
+{
+  float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];
+  float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];
+  float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];
+
+  float b01 = a22*a11 - a12*a21;
+  float b11 = -a22*a10 + a12*a20;
+  float b21 = a21*a10 - a11*a20;
+
+  float det = a00*b01 + a01*b11 + a02*b21;
+
+  return mat3(b01, (-a22*a01 + a02*a21), (a12*a01 - a02*a11),
+              b11, (a22*a00 - a02*a20), (-a12*a00 + a02*a10),
+              b21, (-a21*a00 + a01*a20), (a11*a00 - a01*a10))/det;
+}
+
+// https://github.com/glslify/glsl-transpose
+mat3 transpose(mat3 m)
+{
+  return mat3(m[0][0], m[1][0], m[2][0],
+              m[0][1], m[1][1], m[2][1],
+              m[0][2], m[1][2], m[2][2]);
+}
+
+void main()
+{
+    // Send vertex attributes to fragment shader
+    fragPosition = vec3(matModel*vec4(vertexPosition, 1.0));
+    fragTexCoord = vertexTexCoord;
+    fragColor = vertexColor;
+
+    mat3 normalMatrix = transpose(inverse(mat3(matModel)));
+    fragNormal = normalize(normalMatrix*vertexNormal);
+
+    // Calculate final vertex position
+    gl_Position = mvp*vec4(vertexPosition, 1.0);
+}

+ 94 - 0
lib.mod/raylib/examples/shaders/resources/shaders/glsl100/fog.fs

@@ -0,0 +1,94 @@
+#version 100
+
+precision mediump float;
+
+// Input vertex attributes (from vertex shader)
+varying vec3 fragPosition;
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+varying vec3 fragNormal;
+
+// Input uniform values
+uniform sampler2D texture0;
+uniform vec4 colDiffuse;
+
+// NOTE: Add here your custom variables
+
+#define     MAX_LIGHTS              4
+#define     LIGHT_DIRECTIONAL       0
+#define     LIGHT_POINT             1
+
+struct MaterialProperty {
+    vec3 color;
+    int useSampler;
+    sampler2D sampler;
+};
+
+struct Light {
+    int enabled;
+    int type;
+    vec3 position;
+    vec3 target;
+    vec4 color;
+};
+
+// Input lighting values
+uniform Light lights[MAX_LIGHTS];
+uniform vec4 ambient;
+uniform vec3 viewPos;
+uniform float fogDensity;
+
+void main()
+{
+    // Texel color fetching from texture sampler
+    vec4 texelColor = texture2D(texture0, fragTexCoord);
+    vec3 lightDot = vec3(0.0);
+    vec3 normal = normalize(fragNormal);
+    vec3 viewD = normalize(viewPos - fragPosition);
+    vec3 specular = vec3(0.0);
+
+    // NOTE: Implement here your fragment shader code
+
+    for (int i = 0; i < MAX_LIGHTS; i++)
+    {
+        if (lights[i].enabled == 1)
+        {
+            vec3 light = vec3(0.0);
+            
+            if (lights[i].type == LIGHT_DIRECTIONAL) light = -normalize(lights[i].target - lights[i].position);
+            if (lights[i].type == LIGHT_POINT) light = normalize(lights[i].position - fragPosition);
+
+            float NdotL = max(dot(normal, light), 0.0);
+            lightDot += lights[i].color.rgb*NdotL;
+
+            float specCo = 0.0;
+            if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16.0); // Shine: 16.0
+            specular += specCo;
+        }
+    }
+
+    vec4 finalColor = (texelColor*((colDiffuse + vec4(specular,1))*vec4(lightDot, 1.0)));
+    finalColor += texelColor*(ambient/10.0);
+    
+    // Gamma correction
+    finalColor = pow(finalColor, vec4(1.0/2.2));
+    
+    // Fog calculation
+    float dist = length(viewPos - fragPosition);
+
+    // these could be parameters...
+    const vec4 fogColor = vec4(0.5, 0.5, 0.5, 1.0);
+    //const float fogDensity = 0.16;
+
+    // Exponential fog
+    float fogFactor = 1.0/exp((dist*fogDensity)*(dist*fogDensity));
+
+    // Linear fog (less nice)
+    //const float fogStart = 2.0;
+    //const float fogEnd = 10.0;
+    //float fogFactor = (fogEnd - dist)/(fogEnd - fogStart);
+
+    fogFactor = clamp(fogFactor, 0.0, 1.0);
+
+    gl_FragColor = mix(fogColor, finalColor, fogFactor);
+}

+ 81 - 0
lib.mod/raylib/examples/shaders/resources/shaders/glsl100/lighting.fs

@@ -0,0 +1,81 @@
+#version 100
+
+precision mediump float;
+
+// Input vertex attributes (from vertex shader)
+varying vec3 fragPosition;
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+varying vec3 fragNormal;
+
+// Input uniform values
+uniform sampler2D texture0;
+uniform vec4 colDiffuse;
+
+// NOTE: Add here your custom variables
+
+#define     MAX_LIGHTS              4
+#define     LIGHT_DIRECTIONAL       0
+#define     LIGHT_POINT             1
+
+struct MaterialProperty {
+    vec3 color;
+    int useSampler;
+    sampler2D sampler;
+};
+
+struct Light {
+    int enabled;
+    int type;
+    vec3 position;
+    vec3 target;
+    vec4 color;
+};
+
+// Input lighting values
+uniform Light lights[MAX_LIGHTS];
+uniform vec4 ambient;
+uniform vec3 viewPos;
+
+void main()
+{
+    // Texel color fetching from texture sampler
+    vec4 texelColor = texture2D(texture0, fragTexCoord);
+    vec3 lightDot = vec3(0.0);
+    vec3 normal = normalize(fragNormal);
+    vec3 viewD = normalize(viewPos - fragPosition);
+    vec3 specular = vec3(0.0);
+
+    // NOTE: Implement here your fragment shader code
+
+    for (int i = 0; i < MAX_LIGHTS; i++)
+    {
+        if (lights[i].enabled == 1)
+        {
+            vec3 light = vec3(0.0);
+            
+            if (lights[i].type == LIGHT_DIRECTIONAL) 
+            {
+                light = -normalize(lights[i].target - lights[i].position);
+            }
+            
+            if (lights[i].type == LIGHT_POINT) 
+            {
+                light = normalize(lights[i].position - fragPosition);
+            }
+            
+            float NdotL = max(dot(normal, light), 0.0);
+            lightDot += lights[i].color.rgb*NdotL;
+
+            float specCo = 0.0;
+            if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16.0); // 16 refers to shine
+            specular += specCo;
+        }
+    }
+
+    vec4 finalColor = (texelColor*((colDiffuse + vec4(specular, 1.0))*vec4(lightDot, 1.0)));
+    finalColor += texelColor*(ambient/10.0);
+    
+    // Gamma correction
+    gl_FragColor = pow(finalColor, vec4(1.0/2.2));
+}

+ 24 - 0
lib.mod/raylib/examples/shaders/resources/shaders/glsl100/mask.fs

@@ -0,0 +1,24 @@
+#version 100
+
+precision mediump float;
+
+// Input vertex attributes (from vertex shader)
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+// Input uniform values
+uniform sampler2D texture0;
+uniform sampler2D mask;
+uniform vec4 colDiffuse;
+uniform int frame;
+
+// NOTE: Add here your custom variables
+
+void main()
+{
+    vec4 maskColour = texture2D(mask, fragTexCoord + vec2(sin(-float(frame)/150.0)/10.0, cos(-float(frame)/170.0)/10.0));
+    if (maskColour.r < 0.25) discard;
+    vec4 texelColor = texture2D(texture0, fragTexCoord + vec2(sin(float(frame)/90.0)/8.0, cos(float(frame)/60.0)/8.0));
+
+    gl_FragColor = texelColor*maskColour;
+}

+ 1 - 1
lib.mod/raylib/examples/shaders/resources/shaders/glsl330/basic_lighting.vs → lib.mod/raylib/examples/shaders/resources/shaders/glsl330/base_lighting.vs

@@ -21,7 +21,7 @@ out vec3 fragNormal;
 void main()
 {
     // Send vertex attributes to fragment shader
-    fragPosition = vec3(matModel*vec4(vertexPosition, 1.0f));
+    fragPosition = vec3(matModel*vec4(vertexPosition, 1.0));
     fragTexCoord = vertexTexCoord;
     fragColor = vertexColor;
     

+ 8 - 12
lib.mod/raylib/examples/shaders/resources/shaders/glsl330/fog.fs

@@ -55,25 +55,21 @@ void main()
         if (lights[i].enabled == 1)
         {
             vec3 light = vec3(0.0);
-            if (lights[i].type == LIGHT_DIRECTIONAL) {
-                light = -normalize(lights[i].target - lights[i].position);
-            }
-            if (lights[i].type == LIGHT_POINT) {
-                light = normalize(lights[i].position - fragPosition);
-            }
+            
+            if (lights[i].type == LIGHT_DIRECTIONAL) light = -normalize(lights[i].target - lights[i].position);
+            if (lights[i].type == LIGHT_POINT) light = normalize(lights[i].position - fragPosition);
+
             float NdotL = max(dot(normal, light), 0.0);
-            lightDot += lights[i].color.rgb * NdotL;
+            lightDot += lights[i].color.rgb*NdotL;
 
             float specCo = 0.0;
-            if(NdotL > 0.0)
-                specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16);//16 =shine
+            if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16.0); // Shine: 16.0
             specular += specCo;
-
         }
     }
 
-    finalColor =  (texelColor * ((colDiffuse+vec4(specular,1)) * vec4(lightDot, 1.0)));
-    finalColor += texelColor * (ambient/10.0);
+    finalColor = (texelColor*((colDiffuse + vec4(specular,1))*vec4(lightDot, 1.0)));
+    finalColor += texelColor*(ambient/10.0);
     
     // Gamma correction
     finalColor = pow(finalColor, vec4(1.0/2.2));

+ 0 - 32
lib.mod/raylib/examples/shaders/resources/shaders/glsl330/fog.vs

@@ -1,32 +0,0 @@
-#version 330
-
-// Input vertex attributes
-in vec3 vertexPosition;
-in vec2 vertexTexCoord;
-in vec3 vertexNormal;
-in vec4 vertexColor;
-
-// Input uniform values
-uniform mat4 mvp;
-uniform mat4 matModel;
-
-// Output vertex attributes (to fragment shader)
-out vec2 fragTexCoord;
-out vec4 fragColor;
-out vec3 fragPosition;
-out vec3 fragNormal;
-
-// NOTE: Add here your custom variables
-
-void main()
-{
-    // Send vertex attributes to fragment shader
-    fragTexCoord = vertexTexCoord;
-    fragColor = vertexColor;
-    fragPosition = vec3(matModel*vec4(vertexPosition, 1.0f));
-    mat3 normalMatrix = transpose(inverse(mat3(matModel)));
-    fragNormal = normalize(normalMatrix*vertexNormal);
-
-    // Calculate final vertex position
-    gl_Position = mvp*vec4(vertexPosition, 1.0);
-}

+ 1 - 1
lib.mod/raylib/examples/shaders/resources/shaders/glsl330/basic_lighting.fs → lib.mod/raylib/examples/shaders/resources/shaders/glsl330/lighting.fs

@@ -69,7 +69,7 @@ void main()
             lightDot += lights[i].color.rgb*NdotL;
 
             float specCo = 0.0;
-            if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16); // 16 refers to shine
+            if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16.0); // 16 refers to shine
             specular += specCo;
         }
     }

+ 4 - 3
lib.mod/raylib/examples/shaders/resources/shaders/glsl330/mask.fs

@@ -2,6 +2,7 @@
 
 // Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
 // Input uniform values
 uniform sampler2D texture0;
@@ -13,9 +14,9 @@ out vec4 finalColor;
 
 void main()
 {
-    vec4 maskColour = texture(mask, fragTexCoord+vec2(sin(-frame/150.0)/10.0,cos(-frame/170.0)/10.0));
+    vec4 maskColour = texture(mask, fragTexCoord + vec2(sin(-frame/150.0)/10.0, cos(-frame/170.0)/10.0));
     if (maskColour.r < 0.25) discard;
-    vec4 texelColor = texture(texture0, fragTexCoord+vec2(sin(frame/90.0)/8.0,cos(frame/60.0)/8.0));
+    vec4 texelColor = texture(texture0, fragTexCoord + vec2(sin(frame/90.0)/8.0, cos(frame/60.0)/8.0));
 
-    finalColor = texelColor * maskColour;
+    finalColor = texelColor*maskColour;
 }

+ 0 - 21
lib.mod/raylib/examples/shaders/resources/shaders/glsl330/mask.vs

@@ -1,21 +0,0 @@
-#version 330
-
-// Input vertex attributes
-in vec3 vertexPosition;
-in vec2 vertexTexCoord;
-
-// Input uniform values
-uniform mat4 mvp;
-uniform mat4 matModel;
-
-// Output vertex attributes (to fragment shader)
-out vec2 fragTexCoord;
-
-void main()
-{
-    // Send vertex attributes to fragment shader
-    fragTexCoord = vertexTexCoord;
-
-    // Calculate final vertex position
-    gl_Position = mvp*vec4(vertexPosition, 1.0);
-}

+ 3 - 7
lib.mod/raylib/examples/shaders/rlights.h

@@ -68,17 +68,11 @@ typedef enum {
 extern "C" {            // Prevents name mangling of functions
 #endif
 
-//----------------------------------------------------------------------------------
-// Global Variables Definition
-//----------------------------------------------------------------------------------
-int lightsCount = 0;    // Current amount of created lights
-
 //----------------------------------------------------------------------------------
 // Module Functions Declaration
 //----------------------------------------------------------------------------------
 Light CreateLight(int type, Vector3 position, Vector3 target, Color color, Shader shader);   // Create a light and get shader locations
 void UpdateLightValues(Shader shader, Light light);         // Send light properties to shader
-//void InitLightLocations(Shader shader, Light *light);     // Init light shader locations
 
 #ifdef __cplusplus
 }
@@ -110,7 +104,7 @@ void UpdateLightValues(Shader shader, Light light);         // Send light proper
 //----------------------------------------------------------------------------------
 // Global Variables Definition
 //----------------------------------------------------------------------------------
-// ...
+static int lightsCount = 0;    // Current amount of created lights
 
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
@@ -142,6 +136,8 @@ Light CreateLight(int type, Vector3 position, Vector3 target, Color color, Shade
         char posName[32] = "lights[x].position\0";
         char targetName[32] = "lights[x].target\0";
         char colorName[32] = "lights[x].color\0";
+        
+        // Set location name [x] depending on lights count
         enabledName[7] = '0' + lightsCount;
         typeName[7] = '0' + lightsCount;
         posName[7] = '0' + lightsCount;

+ 6 - 6
lib.mod/raylib/examples/shaders/shaders_basic_lighting.c

@@ -69,8 +69,8 @@ int main(void)
     modelB.materials[0].maps[MAP_DIFFUSE].texture = texture;
     modelC.materials[0].maps[MAP_DIFFUSE].texture = texture;
 
-    Shader shader = LoadShader("resources/shaders/glsl330/basic_lighting.vs", 
-                               "resources/shaders/glsl330/basic_lighting.fs");
+    Shader shader = LoadShader(FormatText("resources/shaders/glsl%i/base_lighting.vs", GLSL_VERSION), 
+                               FormatText("resources/shaders/glsl%i/lighting.fs", GLSL_VERSION));
     
     // Get some shader loactions
     shader.locs[LOC_MATRIX_MODEL] = GetShaderLocation(shader, "matModel");
@@ -112,7 +112,7 @@ int main(void)
         UpdateCamera(&camera);              // Update camera
 
         // Make the lights do differing orbits
-        angle -= 0.02;
+        angle -= 0.02f;
         lights[0].position.x = cosf(angle)*4.0f;
         lights[0].position.z = sinf(angle)*4.0f;
         lights[1].position.x = cosf(-angle*0.6f)*4.0f;
@@ -128,8 +128,8 @@ int main(void)
         UpdateLightValues(shader, lights[3]);
 
         // Rotate the torus
-        modelA.transform = MatrixMultiply(modelA.transform, MatrixRotateX(-0.025));
-        modelA.transform = MatrixMultiply(modelA.transform, MatrixRotateZ(0.012));
+        modelA.transform = MatrixMultiply(modelA.transform, MatrixRotateX(-0.025f));
+        modelA.transform = MatrixMultiply(modelA.transform, MatrixRotateZ(0.012f));
 
         // Update the light shader with the camera view position
         float cameraPos[3] = { camera.position.x, camera.position.y, camera.position.z };
@@ -161,7 +161,7 @@ int main(void)
 
             DrawFPS(10, 10);
             
-            DrawText("Keys RGB & W toggle lights", 10, 30, 20, DARKGRAY);
+            DrawText("Use keys RGBW to toggle lights", 10, 30, 20, DARKGRAY);
 
         EndDrawing();
         //----------------------------------------------------------------------------------

+ 8 - 1
lib.mod/raylib/examples/shaders/shaders_fog.c

@@ -32,6 +32,12 @@
 #define RLIGHTS_IMPLEMENTATION
 #include "rlights.h"
 
+#if defined(PLATFORM_DESKTOP)
+    #define GLSL_VERSION            330
+#else   // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB
+    #define GLSL_VERSION            100
+#endif
+
 int main(void)
 {
     // Initialization
@@ -61,7 +67,8 @@ int main(void)
     modelC.materials[0].maps[MAP_DIFFUSE].texture = texture;
 
     // Load shader and set up some uniforms
-    Shader shader = LoadShader("resources/shaders/glsl330/fog.vs", "resources/shaders/glsl330/fog.fs");
+    Shader shader = LoadShader(FormatText("resources/shaders/glsl%i/base_lighting.vs", GLSL_VERSION), 
+                               FormatText("resources/shaders/glsl%i/fog.fs", GLSL_VERSION));
     shader.locs[LOC_MATRIX_MODEL] = GetShaderLocation(shader, "matModel");
     shader.locs[LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos");
 

+ 9 - 3
lib.mod/raylib/examples/shaders/shaders_simple_mask.c

@@ -21,6 +21,12 @@
 #include "raylib.h"
 #include "raymath.h"
 
+#if defined(PLATFORM_DESKTOP)
+    #define GLSL_VERSION            330
+#else   // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB
+    #define GLSL_VERSION            100
+#endif
+
 int main(void)
 {
     // Initialization
@@ -50,8 +56,8 @@ int main(void)
     Model model3 = LoadModelFromMesh(sphere);
 
     // Load the shader
-    Shader shader = LoadShader("resources/shaders/glsl330/mask.vs", "resources/shaders/glsl330/mask.fs");
-
+    Shader shader = LoadShader(0, FormatText("resources/shaders/glsl%i/mask.fs", GLSL_VERSION));
+    
     // Load and apply the diffuse texture (colour map)
     Texture texDiffuse = LoadTexture("resources/plasma.png");
     model1.materials[0].maps[MAP_DIFFUSE].texture = texDiffuse;
@@ -66,7 +72,7 @@ int main(void)
     shader.locs[LOC_MAP_EMISSION] = GetShaderLocation(shader, "mask");
 
     // Frame is incremented each frame to animate the shader
-    int shaderFrame = GetShaderLocation(shader, "framesCounter");
+    int shaderFrame = GetShaderLocation(shader, "frame");
 
     // Apply the shader to the two models
     model1.materials[0].shader = shader;

+ 3 - 3
lib.mod/raylib/examples/textures/textures_mouse_painting.c

@@ -106,7 +106,7 @@ int main(void)
             EndTextureMode();
         }
 
-        if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+        if (IsMouseButtonDown(MOUSE_LEFT_BUTTON) || (GetGestureDetected() == GESTURE_DRAG))
         {
             // Paint circle into render texture
             // NOTE: To avoid discontinuous circles, we could store
@@ -166,7 +166,7 @@ int main(void)
             // Draw drawing circle for reference
             if (mousePos.y > 50) 
             {
-                if (IsMouseButtonDown(MOUSE_RIGHT_BUTTON)) DrawCircleLines(mousePos.x, mousePos.y, brushSize, colors[colorSelected]);
+                if (IsMouseButtonDown(MOUSE_RIGHT_BUTTON)) DrawCircleLines(mousePos.x, mousePos.y, brushSize, GRAY);
                 else DrawCircle(GetMouseX(), GetMouseY(), brushSize, colors[colorSelected]);
             }
             
@@ -194,7 +194,7 @@ int main(void)
                 DrawRectangle(0, 150, GetScreenWidth(), 80, BLACK);
                 DrawText("IMAGE SAVED:  my_amazing_texture_painting.png", 150, 180, 20, RAYWHITE);
             }
-            
+
         EndDrawing();
         //----------------------------------------------------------------------------------
     }

+ 227 - 74
lib.mod/raylib/projects/Notepad++/raylib_npp_parser/raylib_npp.xml

@@ -102,6 +102,9 @@
                 <Param name="int monitor" />
             </Overload>
         </KeyWord>
+        <KeyWord name="GetWindowPosition" func="yes">
+            <Overload retVal="Vector2" descr="Get window position XY on monitor"></Overload>
+        </KeyWord>
         <KeyWord name="GetMonitorName" func="yes">
             <Overload retVal="const char" descr="Get the human-readable, UTF-8 encoded name of the primary monitor">
                 <Param name="int monitor" />
@@ -169,6 +172,17 @@
         <KeyWord name="EndTextureMode" func="yes">
             <Overload retVal="void" descr="Ends drawing to render texture"></Overload>
         </KeyWord>
+        <KeyWord name="BeginScissorMode" func="yes">
+            <Overload retVal="void" descr="Begin scissor mode (define screen area for following drawing)">
+                <Param name="int x" />
+                <Param name="int y" />
+                <Param name="int width" />
+                <Param name="int height" />
+            </Overload>
+        </KeyWord>
+        <KeyWord name="EndScissorMode" func="yes">
+            <Overload retVal="void" descr="End scissor mode"></Overload>
+        </KeyWord>
 
         <!-- Screen-space-related functions -->
         <KeyWord name="GetMouseRay" func="yes">
@@ -177,15 +191,40 @@
                 <Param name="Camera camera" />
             </Overload>
         </KeyWord>
+        <KeyWord name="GetCameraMatrix" func="yes">
+            <Overload retVal="Matrix" descr="Returns camera transform matrix (view matrix)">
+                <Param name="Camera camera" />
+            </Overload>
+        </KeyWord>
+        <KeyWord name="GetCameraMatrix2D" func="yes">
+            <Overload retVal="Matrix" descr="Returns camera 2d transform matrix">
+                <Param name="Camera2D camera" />
+            </Overload>
+        </KeyWord>
         <KeyWord name="GetWorldToScreen" func="yes">
             <Overload retVal="Vector2" descr="Returns the screen space position for a 3d world space position">
                 <Param name="Vector3 position" />
                 <Param name="Camera camera" />
             </Overload>
         </KeyWord>
-        <KeyWord name="GetCameraMatrix" func="yes">
-            <Overload retVal="Matrix" descr="Returns camera transform matrix (view matrix)">
+        <KeyWord name="GetWorldToScreenEx" func="yes">
+            <Overload retVal="Vector2" descr="Returns size position for a 3d world space position">
+                <Param name="Vector3 position" />
                 <Param name="Camera camera" />
+                <Param name="int width" />
+                <Param name="int height" />
+            </Overload>
+        </KeyWord>
+        <KeyWord name="GetWorldToScreen2D" func="yes">
+            <Overload retVal="Vector2" descr="Returns the screen space position for a 2d camera world space position">
+                <Param name="Vector2 position" />
+                <Param name="Camera2D camera" />
+            </Overload>
+        </KeyWord>
+        <KeyWord name="GetScreenToWorld2D" func="yes">
+            <Overload retVal="Vector2" descr="Returns the world space position for a 2d camera screen space position">
+                <Param name="Vector2 position" />
+                <Param name="Camera2D camera" />
             </Overload>
         </KeyWord>
 
@@ -216,6 +255,11 @@
                 <Param name="Color color" />
             </Overload>
         </KeyWord>
+        <KeyWord name="ColorFromNormalized" func="yes">
+            <Overload retVal="Color" descr="Returns color from normalized values [0..1]">
+                <Param name="Vector4 normalized" />
+            </Overload>
+        </KeyWord>
         <KeyWord name="ColorToHSV" func="yes">
             <Overload retVal="Vector3" descr="Returns HSV values for a Color">
                 <Param name="Color color" />
@@ -241,7 +285,7 @@
         <!-- Misc. functions -->
         <KeyWord name="SetConfigFlags" func="yes">
             <Overload retVal="void" descr="Setup window configuration flags (view FLAGS)">
-                <Param name="unsigned char flags" />
+                <Param name="unsigned int flags" />
             </Overload>
         </KeyWord>
         <KeyWord name="SetTraceLogLevel" func="yes">
@@ -290,6 +334,11 @@
                 <Param name="const char *ext" />
             </Overload>
         </KeyWord>
+        <KeyWord name="DirectoryExists" func="yes">
+            <Overload retVal="bool" descr="Check if a directory path exists">
+                <Param name="const char *dirPath" />
+            </Overload>
+        </KeyWord>
         <KeyWord name="GetExtension" func="yes">
             <Overload retVal="const char" descr="Get pointer to extension for a filename string">
                 <Param name="const char *fileName" />
@@ -301,13 +350,18 @@
             </Overload>
         </KeyWord>
         <KeyWord name="GetFileNameWithoutExt" func="yes">
-            <Overload retVal="const char" descr="Get filename string without extension (memory should be freed)">
+            <Overload retVal="const char" descr="Get filename string without extension (uses static string)">
                 <Param name="const char *filePath" />
             </Overload>
         </KeyWord>
         <KeyWord name="GetDirectoryPath" func="yes">
-            <Overload retVal="const char" descr="Get full path for a given fileName (uses static string)">
-                <Param name="const char *fileName" />
+            <Overload retVal="const char" descr="Get full path for a given fileName with path (uses static string)">
+                <Param name="const char *filePath" />
+            </Overload>
+        </KeyWord>
+        <KeyWord name="GetPrevDirectoryPath" func="yes">
+            <Overload retVal="const char" descr="Get previous directory path for a given path (uses static string)">
+                <Param name="const char *dirPath" />
             </Overload>
         </KeyWord>
         <KeyWord name="GetWorkingDirectory" func="yes">
@@ -344,6 +398,21 @@
             </Overload>
         </KeyWord>
 
+        <KeyWord name="char *CompressData" func="yes">
+            <Overload retVal="unsigned" descr="Compress data (DEFLATE algorythm)">
+                <Param name="unsigned char *data" />
+                <Param name="int dataLength" />
+                <Param name="int *compDataLength" />
+            </Overload>
+        </KeyWord>
+        <KeyWord name="char *DecompressData" func="yes">
+            <Overload retVal="unsigned" descr="Decompress data (DEFLATE algorythm)">
+                <Param name="unsigned char *compData" />
+                <Param name="int compDataLength" />
+                <Param name="int *dataLength" />
+            </Overload>
+        </KeyWord>
+
         <!-- Persistent storage management -->
         <KeyWord name="StorageSaveValue" func="yes">
             <Overload retVal="void" descr="Save integer value to storage file (to defined position)">
@@ -703,6 +772,24 @@
                 <Param name="Color color" />
             </Overload>
         </KeyWord>
+        <KeyWord name="DrawEllipse" func="yes">
+            <Overload retVal="void" descr="Draw ellipse">
+                <Param name="int centerX" />
+                <Param name="int centerY" />
+                <Param name="float radiusH" />
+                <Param name="float radiusV" />
+                <Param name="Color color" />
+            </Overload>
+        </KeyWord>
+        <KeyWord name="DrawEllipseLines" func="yes">
+            <Overload retVal="void" descr="Draw ellipse outline">
+                <Param name="int centerX" />
+                <Param name="int centerY" />
+                <Param name="float radiusH" />
+                <Param name="float radiusV" />
+                <Param name="Color color" />
+            </Overload>
+        </KeyWord>
         <KeyWord name="DrawRing" func="yes">
             <Overload retVal="void" descr="Draw ring">
                 <Param name="Vector2 center" />
@@ -818,7 +905,7 @@
             </Overload>
         </KeyWord>
         <KeyWord name="DrawTriangle" func="yes">
-            <Overload retVal="void" descr="Draw a color-filled triangle">
+            <Overload retVal="void" descr="Draw a color-filled triangle (vertex in counter-clockwise order!)">
                 <Param name="Vector2 v1" />
                 <Param name="Vector2 v2" />
                 <Param name="Vector2 v3" />
@@ -826,7 +913,7 @@
             </Overload>
         </KeyWord>
         <KeyWord name="DrawTriangleLines" func="yes">
-            <Overload retVal="void" descr="Draw triangle outline">
+            <Overload retVal="void" descr="Draw triangle outline (vertex in counter-clockwise order!)">
                 <Param name="Vector2 v1" />
                 <Param name="Vector2 v2" />
                 <Param name="Vector2 v3" />
@@ -834,12 +921,19 @@
             </Overload>
         </KeyWord>
         <KeyWord name="DrawTriangleFan" func="yes">
-            <Overload retVal="void" descr="Draw a triangle fan defined by points">
+            <Overload retVal="void" descr="Draw a triangle fan defined by points (first vertex is the center)">
                 <Param name="Vector2 *points" />
                 <Param name="int numPoints" />
                 <Param name="Color color" />
             </Overload>
         </KeyWord>
+        <KeyWord name="DrawTriangleStrip" func="yes">
+            <Overload retVal="void" descr="Draw a triangle strip defined by points">
+                <Param name="Vector2 *points" />
+                <Param name="int pointsCount" />
+                <Param name="Color color" />
+            </Overload>
+        </KeyWord>
         <KeyWord name="DrawPoly" func="yes">
             <Overload retVal="void" descr="Draw a regular polygon (Vector version)">
                 <Param name="Vector2 center" />
@@ -849,11 +943,13 @@
                 <Param name="Color color" />
             </Overload>
         </KeyWord>
-
-        <KeyWord name="SetShapesTexture" func="yes">
-            <Overload retVal="void" descr="Define default texture used to draw shapes">
-                <Param name="Texture2D texture" />
-                <Param name="Rectangle source" />
+        <KeyWord name="DrawPolyLines" func="yes">
+            <Overload retVal="void" descr="Draw a polygon outline of n sides">
+                <Param name="Vector2 center" />
+                <Param name="int sides" />
+                <Param name="float radius" />
+                <Param name="float rotation" />
+                <Param name="Color color" />
             </Overload>
         </KeyWord>
 
@@ -995,6 +1091,12 @@
                 <Param name="Image image" />
             </Overload>
         </KeyWord>
+        <KeyWord name="GetImageAlphaBorder" func="yes">
+            <Overload retVal="Rectangle" descr="Get image alpha border rectangle">
+                <Param name="Image image" />
+                <Param name="float threshold" />
+            </Overload>
+        </KeyWord>
         <KeyWord name="GetPixelDataSize" func="yes">
             <Overload retVal="int" descr="Get pixel data size in bytes (image or texture)">
                 <Param name="int width" />
@@ -1023,6 +1125,12 @@
                 <Param name="Image image" />
             </Overload>
         </KeyWord>
+        <KeyWord name="ImageFromImage" func="yes">
+            <Overload retVal="Image" descr="Create an image from another image piece">
+                <Param name="Image image" />
+                <Param name="Rectangle rec" />
+            </Overload>
+        </KeyWord>
         <KeyWord name="ImageToPOT" func="yes">
             <Overload retVal="void" descr="Convert image to POT (power-of-two)">
                 <Param name="Image *image" />
@@ -1127,11 +1235,12 @@
             </Overload>
         </KeyWord>
         <KeyWord name="ImageDraw" func="yes">
-            <Overload retVal="void" descr="Draw a source image within a destination image">
+            <Overload retVal="void" descr="Draw a source image within a destination image (tint applied to source)">
                 <Param name="Image *dst" />
                 <Param name="Image src" />
                 <Param name="Rectangle srcRec" />
                 <Param name="Rectangle dstRec" />
+                <Param name="Color tint" />
             </Overload>
         </KeyWord>
         <KeyWord name="ImageDrawRectangle" func="yes">
@@ -1413,7 +1522,8 @@
         </KeyWord>
         <KeyWord name="GenImageFontAtlas" func="yes">
             <Overload retVal="Image" descr="Generate image font atlas using chars info">
-                <Param name="CharInfo *chars" />
+                <Param name="const CharInfo *chars" />
+                <Param name="Rectangle **recs" />
                 <Param name="int charsCount" />
                 <Param name="int fontSize" />
                 <Param name="int padding" />
@@ -1463,17 +1573,14 @@
                 <Param name="Color tint" />
             </Overload>
         </KeyWord>
-        <KeyWord name="DrawTextRecEx" func="yes">
-            <Overload retVal="void" descr="Draw text using font inside rectangle limits with support for text selection">
+        <!--RLAPI void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint); // Draw text using font inside rectangle limits with support for text selection -->
+        <KeyWord name="DrawTextCodepoint" func="yes">
+            <Overload retVal="void" descr="Draw one character (codepoint)">
                 <Param name="Font font" />
-                <Param name="const char *text" />
-                <Param name="Rectangle rec" />
-                <Param name="float fontSize" />
-                <Param name="float spacing" />
-                <Param name="bool wordWrap" />
+                <Param name="int codepoint" />
+                <Param name="Vector2 position" />
+                <Param name="float scale" />
                 <Param name="Color tint" />
-                <Param name="int selectStart" />
-                <Param name="int selecFont" />
             </Overload>
         </KeyWord>
 
@@ -1495,18 +1602,18 @@
         <KeyWord name="GetGlyphIndex" func="yes">
             <Overload retVal="int" descr="Get index position for a unicode character on font">
                 <Param name="Font font" />
-                <Param name="int character" />
-            </Overload>
-        </KeyWord>
-        <KeyWord name="GetNextCodepoint" func="yes">
-            <Overload retVal="int" descr="Returns next codepoint in a UTF8 encoded string">
-                <Param name="const char *text" />
-                <Param name="int *count" />
+                <Param name="int codepoint" />
             </Overload>
         </KeyWord>
 
-        <!-- Text strings management functions -->
+        <!-- Text strings management functions (no utf8 strings, only byte chars) -->
         <!-- NOTE: Some strings allocate memory internally for returned strings, just be careful! -->
+        <KeyWord name="TextCopy" func="yes">
+            <Overload retVal="int" descr="Copy one string to another, returns bytes copied">
+                <Param name="char *dst" />
+                <Param name="const char *src" />
+            </Overload>
+        </KeyWord>
         <KeyWord name="TextIsEqual" func="yes">
             <Overload retVal="bool" descr="Check if two text string are equal">
                 <Param name="const char *text1" />
@@ -1518,11 +1625,6 @@
                 <Param name="const char *text" />
             </Overload>
         </KeyWord>
-        <KeyWord name="int TextCountCodepoints" func="yes">
-            <Overload retVal="unsigned" descr="Get total number of characters (codepoints) in a UTF8 encoded string">
-                <Param name="const char *text" />
-            </Overload>
-        </KeyWord>
         <KeyWord name="TextFormat" func="yes">
             <Overload retVal="const char" descr="Text formatting with variables (sprintf style)">
                 <Param name="const char *text" />
@@ -1537,14 +1639,14 @@
             </Overload>
         </KeyWord>
         <KeyWord name="TextReplace" func="yes">
-            <Overload retVal="const char" descr="Replace text string (memory should be freed!)">
+            <Overload retVal="char" descr="Replace text string (memory must be freed!)">
                 <Param name="char *text" />
                 <Param name="const char *replace" />
                 <Param name="const char *by" />
             </Overload>
         </KeyWord>
         <KeyWord name="TextInsert" func="yes">
-            <Overload retVal="const char" descr="Insert text in a position (memory should be freed!)">
+            <Overload retVal="char" descr="Insert text in a position (memory must be freed!)">
                 <Param name="const char *text" />
                 <Param name="const char *insert" />
                 <Param name="int position" />
@@ -1597,6 +1699,37 @@
                 <Param name="const char *text" />
             </Overload>
         </KeyWord>
+        <KeyWord name="TextToUtf8" func="yes">
+            <Overload retVal="char" descr="Encode text codepoint into utf8 text (memory must be freed!)">
+                <Param name="int *codepoints" />
+                <Param name="int length" />
+            </Overload>
+        </KeyWord>
+
+        <!-- UTF8 text strings management functions -->
+        <KeyWord name="GetCodepoints" func="yes">
+            <Overload retVal="int" descr="Get all codepoints in a string, codepoints count returned by parameters">
+                <Param name="const char *text" />
+                <Param name="int *count" />
+            </Overload>
+        </KeyWord>
+        <KeyWord name="GetCodepointsCount" func="yes">
+            <Overload retVal="int" descr="Get total number of characters (codepoints) in a UTF8 encoded string">
+                <Param name="const char *text" />
+            </Overload>
+        </KeyWord>
+        <KeyWord name="GetNextCodepoint" func="yes">
+            <Overload retVal="int" descr="Returns next codepoint in a UTF8 encoded string; 0x3f('?') is returned on failure">
+                <Param name="const char *text" />
+                <Param name="int *bytesProcessed" />
+            </Overload>
+        </KeyWord>
+        <KeyWord name="CodepointToUtf8" func="yes">
+            <Overload retVal="const char" descr="Encode codepoint into utf8 text (char array length returned as parameter)">
+                <Param name="int codepoint" />
+                <Param name="int *byteLength" />
+            </Overload>
+        </KeyWord>
 
         <!-------------------------------------------------------------------------------------- -->
         <!-- Basic 3d Shapes Drawing Functions (Module: models) -->
@@ -1610,6 +1743,12 @@
                 <Param name="Color color" />
             </Overload>
         </KeyWord>
+        <KeyWord name="DrawPoint3D" func="yes">
+            <Overload retVal="void" descr="Draw a point in 3D space, actually a small line">
+                <Param name="Vector3 position" />
+                <Param name="Color color" />
+            </Overload>
+        </KeyWord>
         <KeyWord name="DrawCircle3D" func="yes">
             <Overload retVal="void" descr="Draw a circle in 3D world space">
                 <Param name="Vector3 center" />
@@ -1730,7 +1869,6 @@
                 <Param name="Vector3 position" />
             </Overload>
         </KeyWord>
-        <!--DrawTorus(), DrawTeapot() could be useful? -->
 
         <!-------------------------------------------------------------------------------------- -->
         <!-- Model 3d Loading and Drawing Functions (Module: models) -->
@@ -1768,7 +1906,7 @@
         </KeyWord>
         <KeyWord name="UnloadMesh" func="yes">
             <Overload retVal="void" descr="Unload mesh from memory (RAM and/or VRAM)">
-                <Param name="Mesh *mesh" />
+                <Param name="Mesh mesh" />
             </Overload>
         </KeyWord>
 
@@ -1998,22 +2136,22 @@
         <KeyWord name="CheckCollisionBoxSphere" func="yes">
             <Overload retVal="bool" descr="Detect collision between box and sphere">
                 <Param name="BoundingBox box" />
-                <Param name="Vector3 centerSphere" />
-                <Param name="float radiusSphere" />
+                <Param name="Vector3 center" />
+                <Param name="float radius" />
             </Overload>
         </KeyWord>
         <KeyWord name="CheckCollisionRaySphere" func="yes">
             <Overload retVal="bool" descr="Detect collision between ray and sphere">
                 <Param name="Ray ray" />
-                <Param name="Vector3 spherePosition" />
-                <Param name="float sphereRadius" />
+                <Param name="Vector3 center" />
+                <Param name="float radius" />
             </Overload>
         </KeyWord>
         <KeyWord name="CheckCollisionRaySphereEx" func="yes">
             <Overload retVal="bool" descr="Detect collision between ray and sphere, returns collision point">
                 <Param name="Ray ray" />
-                <Param name="Vector3 spherePosition" />
-                <Param name="float sphereRadius" />
+                <Param name="Vector3 center" />
+                <Param name="float radius" />
                 <Param name="Vector3 *collisionPoint" />
             </Overload>
         </KeyWord>
@@ -2026,7 +2164,7 @@
         <KeyWord name="GetCollisionRayModel" func="yes">
             <Overload retVal="RayHitInfo" descr="Get collision info between ray and model">
                 <Param name="Ray ray" />
-                <Param name="Model *model" />
+                <Param name="Model model" />
             </Overload>
         </KeyWord>
         <KeyWord name="GetCollisionRayTriangle" func="yes">
@@ -2063,8 +2201,8 @@
         </KeyWord>
         <KeyWord name="LoadShaderCode" func="yes">
             <Overload retVal="Shader" descr="Load shader from code strings and bind default locations">
-                <Param name="char *vsCode" />
-                <Param name="char *fsCode" />
+                <Param name="const char *vsCode" />
+                <Param name="const char *fsCode" />
             </Overload>
         </KeyWord>
         <KeyWord name="UnloadShader" func="yes">
@@ -2079,6 +2217,18 @@
         <KeyWord name="GetTextureDefault" func="yes">
             <Overload retVal="Texture2D" descr="Get default texture"></Overload>
         </KeyWord>
+        <KeyWord name="GetShapesTexture" func="yes">
+            <Overload retVal="Texture2D" descr="Get texture to draw shapes"></Overload>
+        </KeyWord>
+        <KeyWord name="GetShapesTextureRec" func="yes">
+            <Overload retVal="Rectangle" descr="Get texture rectangle to draw shapes"></Overload>
+        </KeyWord>
+        <KeyWord name="SetShapesTexture" func="yes">
+            <Overload retVal="void" descr="Define default texture used to draw shapes">
+                <Param name="Texture2D texture" />
+                <Param name="Rectangle source" />
+            </Overload>
+        </KeyWord>
 
         <!-- Shader configuration functions -->
         <KeyWord name="GetShaderLocation" func="yes">
@@ -2129,17 +2279,18 @@
             </Overload>
         </KeyWord>
         <KeyWord name="GetMatrixModelview" func="yes">
-            <Overload retVal="Matrix" descr="Get internal modelview matrix">
-                <Param name="Matrix view" />
-            </Overload>
+            <Overload retVal="Matrix" descr="Get internal modelview matrix"></Overload>
+        </KeyWord>
+        <KeyWord name="GetMatrixProjection" func="yes">
+            <Overload retVal="Matrix" descr="Get internal projection matrix"></Overload>
         </KeyWord>
 
         <!-- Texture maps generation (PBR) -->
         <!-- NOTE: Required shaders should be provided -->
         <KeyWord name="GenTextureCubemap" func="yes">
-            <Overload retVal="Texture2D" descr="Generate cubemap texture from HDR texture">
+            <Overload retVal="Texture2D" descr="Generate cubemap texture from 2D texture">
                 <Param name="Shader shader" />
-                <Param name="Texture2D skyHDR" />
+                <Param name="Texture2D map" />
                 <Param name="int size" />
             </Overload>
         </KeyWord>
@@ -2181,17 +2332,6 @@
         <KeyWord name="EndBlendMode" func="yes">
             <Overload retVal="void" descr="End blending mode (reset to default: alpha blending)"></Overload>
         </KeyWord>
-        <KeyWord name="BeginScissorMode" func="yes">
-            <Overload retVal="void" descr="Begin scissor mode (define screen area for following drawing)">
-                <Param name="int x" />
-                <Param name="int y" />
-                <Param name="int width" />
-                <Param name="int height" />
-            </Overload>
-        </KeyWord>
-        <KeyWord name="EndScissorMode" func="yes">
-            <Overload retVal="void" descr="End scissor mode"></Overload>
-        </KeyWord>
 
         <!-- VR control functions -->
         <KeyWord name="InitVrSimulator" func="yes">
@@ -2206,7 +2346,7 @@
             </Overload>
         </KeyWord>
         <KeyWord name="SetVrConfiguration" func="yes">
-            <Overload retVal="void" descr="Set stereo rendering configuration parameters ">
+            <Overload retVal="void" descr="Set stereo rendering configuration parameters">
                 <Param name="VrDeviceInfo info" />
                 <Param name="Shader distortion" />
             </Overload>
@@ -2250,9 +2390,6 @@
                 <Param name="const char *fileName" />
             </Overload>
         </KeyWord>
-        <KeyWord name="LoadWaveEx" func="yes">
-            <Overload retVal="Wave" descr="Load wave data from raw array data"></Overload>
-        </KeyWord>
         <KeyWord name="LoadSound" func="yes">
             <Overload retVal="Sound" descr="Load sound from file">
                 <Param name="const char *fileName" />
@@ -2299,6 +2436,11 @@
                 <Param name="Sound sound" />
             </Overload>
         </KeyWord>
+        <KeyWord name="StopSound" func="yes">
+            <Overload retVal="void" descr="Stop playing a sound">
+                <Param name="Sound sound" />
+            </Overload>
+        </KeyWord>
         <KeyWord name="PauseSound" func="yes">
             <Overload retVal="void" descr="Pause a sound">
                 <Param name="Sound sound" />
@@ -2309,11 +2451,17 @@
                 <Param name="Sound sound" />
             </Overload>
         </KeyWord>
-        <KeyWord name="StopSound" func="yes">
-            <Overload retVal="void" descr="Stop playing a sound">
+        <KeyWord name="PlaySoundMulti" func="yes">
+            <Overload retVal="void" descr="Play a sound (using multichannel buffer pool)">
                 <Param name="Sound sound" />
             </Overload>
         </KeyWord>
+        <KeyWord name="StopSoundMulti" func="yes">
+            <Overload retVal="void" descr="Stop any sound playing (using multichannel buffer pool)"></Overload>
+        </KeyWord>
+        <KeyWord name="GetSoundsPlaying" func="yes">
+            <Overload retVal="int" descr="Get number of sounds playing in the multichannel"></Overload>
+        </KeyWord>
         <KeyWord name="IsSoundPlaying" func="yes">
             <Overload retVal="bool" descr="Check if a sound is currently playing">
                 <Param name="Sound sound" />
@@ -2447,7 +2595,7 @@
                 <Param name="AudioStream stream" />
             </Overload>
         </KeyWord>
-        <KeyWord name="IsAudioBufferProcessed" func="yes">
+        <KeyWord name="IsAudioStreamProcessed" func="yes">
             <Overload retVal="bool" descr="Check if any audio stream buffers requires refill">
                 <Param name="AudioStream stream" />
             </Overload>
@@ -2489,3 +2637,8 @@
                 <Param name="float pitch" />
             </Overload>
         </KeyWord>
+        <KeyWord name="SetAudioStreamBufferSizeDefault" func="yes">
+            <Overload retVal="void" descr="Default size for new audio streams">
+                <Param name="int size" />
+            </Overload>
+        </KeyWord>

+ 62 - 34
lib.mod/raylib/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h

@@ -27,6 +27,7 @@ RLAPI int GetMonitorWidth(int monitor);                           // Get primary
 RLAPI int GetMonitorHeight(int monitor);                          // Get primary monitor height
 RLAPI int GetMonitorPhysicalWidth(int monitor);                   // Get primary monitor physical width in millimetres
 RLAPI int GetMonitorPhysicalHeight(int monitor);                  // Get primary monitor physical height in millimetres
+RLAPI Vector2 GetWindowPosition(void);                            // Get window position XY on monitor
 RLAPI const char *GetMonitorName(int monitor);                    // Get the human-readable, UTF-8 encoded name of the primary monitor
 RLAPI const char *GetClipboardText(void);                         // Get clipboard text content
 RLAPI void SetClipboardText(const char *text);                    // Set clipboard text content
@@ -48,11 +49,17 @@ RLAPI void BeginMode3D(Camera3D camera);                          // Initializes
 RLAPI void EndMode3D(void);                                       // Ends 3D mode and returns to default 2D orthographic mode
 RLAPI void BeginTextureMode(RenderTexture2D target);              // Initializes render texture for drawing
 RLAPI void EndTextureMode(void);                                  // Ends drawing to render texture
+RLAPI void BeginScissorMode(int x, int y, int width, int height); // Begin scissor mode (define screen area for following drawing)
+RLAPI void EndScissorMode(void);                                  // End scissor mode
 
 // Screen-space-related functions
 RLAPI Ray GetMouseRay(Vector2 mousePosition, Camera camera);      // Returns a ray trace from mouse position
-RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera);  // Returns the screen space position for a 3d world space position
 RLAPI Matrix GetCameraMatrix(Camera camera);                      // Returns camera transform matrix (view matrix)
+RLAPI Matrix GetCameraMatrix2D(Camera2D camera);                  // Returns camera 2d transform matrix
+RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera);  // Returns the screen space position for a 3d world space position
+RLAPI Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int height); // Returns size position for a 3d world space position
+RLAPI Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera); // Returns the screen space position for a 2d camera world space position
+RLAPI Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera); // Returns the world space position for a 2d camera screen space position
 
 // Timing-related functions
 RLAPI void SetTargetFPS(int fps);                                 // Set target FPS (maximum)
@@ -63,13 +70,14 @@ RLAPI double GetTime(void);                                       // Returns ela
 // Color-related functions
 RLAPI int ColorToInt(Color color);                                // Returns hexadecimal value for a Color
 RLAPI Vector4 ColorNormalize(Color color);                        // Returns color normalized as float [0..1]
+RLAPI Color ColorFromNormalized(Vector4 normalized);              // Returns color from normalized values [0..1]
 RLAPI Vector3 ColorToHSV(Color color);                            // Returns HSV values for a Color
 RLAPI Color ColorFromHSV(Vector3 hsv);                            // Returns a Color from HSV values
 RLAPI Color GetColor(int hexValue);                               // Returns a Color struct from hexadecimal value
 RLAPI Color Fade(Color color, float alpha);                       // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
 
 // Misc. functions
-RLAPI void SetConfigFlags(unsigned char flags);                   // Setup window configuration flags (view FLAGS)
+RLAPI void SetConfigFlags(unsigned int flags);                    // Setup window configuration flags (view FLAGS)
 RLAPI void SetTraceLogLevel(int logType);                         // Set the current threshold (minimum) log level
 RLAPI void SetTraceLogExit(int logType);                          // Set the exit threshold (minimum) log level
 RLAPI void SetTraceLogCallback(TraceLogCallback callback);        // Set a trace log callback to enable custom logging
@@ -80,10 +88,12 @@ RLAPI int GetRandomValue(int min, int max);                       // Returns a r
 // Files management functions
 RLAPI bool FileExists(const char *fileName);                      // Check if file exists
 RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension
+RLAPI bool DirectoryExists(const char *dirPath);                  // Check if a directory path exists
 RLAPI const char *GetExtension(const char *fileName);             // Get pointer to extension for a filename string
 RLAPI const char *GetFileName(const char *filePath);              // Get pointer to filename for a path string
-RLAPI const char *GetFileNameWithoutExt(const char *filePath);    // Get filename string without extension (memory should be freed)
-RLAPI const char *GetDirectoryPath(const char *fileName);         // Get full path for a given fileName (uses static string)
+RLAPI const char *GetFileNameWithoutExt(const char *filePath);    // Get filename string without extension (uses static string)
+RLAPI const char *GetDirectoryPath(const char *filePath);         // Get full path for a given fileName with path (uses static string)
+RLAPI const char *GetPrevDirectoryPath(const char *dirPath);      // Get previous directory path for a given path (uses static string)
 RLAPI const char *GetWorkingDirectory(void);                      // Get current working directory (uses static string)
 RLAPI char **GetDirectoryFiles(const char *dirPath, int *count);  // Get filenames in a directory path (memory should be freed)
 RLAPI void ClearDirectoryFiles(void);                             // Clear directory files paths buffers (free memory)
@@ -93,6 +103,9 @@ RLAPI char **GetDroppedFiles(int *count);                         // Get dropped
 RLAPI void ClearDroppedFiles(void);                               // Clear dropped files paths buffer (free memory)
 RLAPI long GetFileModTime(const char *fileName);                  // Get file modification time (last write time)
 
+RLAPI unsigned char *CompressData(unsigned char *data, int dataLength, int *compDataLength);        // Compress data (DEFLATE algorythm)
+RLAPI unsigned char *DecompressData(unsigned char *compData, int compDataLength, int *dataLength);  // Decompress data (DEFLATE algorythm)
+
 // Persistent storage management
 RLAPI void StorageSaveValue(int position, int value);             // Save integer value to storage file (to defined position)
 RLAPI int StorageLoadValue(int position);                         // Load integer value from storage file (from defined position)
@@ -183,6 +196,8 @@ RLAPI void DrawCircleSectorLines(Vector2 center, float radius, int startAngle, i
 RLAPI void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2);       // Draw a gradient-filled circle
 RLAPI void DrawCircleV(Vector2 center, float radius, Color color);                                       // Draw a color-filled circle (Vector version)
 RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color);                         // Draw circle outline
+RLAPI void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color);             // Draw ellipse
+RLAPI void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color);        // Draw ellipse outline
 RLAPI void DrawRing(Vector2 center, float innerRadius, float outerRadius, int startAngle, int endAngle, int segments, Color color); // Draw ring
 RLAPI void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, int startAngle, int endAngle, int segments, Color color);    // Draw ring outline
 RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color);                        // Draw a color-filled rectangle
@@ -196,12 +211,12 @@ RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color c
 RLAPI void DrawRectangleLinesEx(Rectangle rec, int lineThick, Color color);                              // Draw rectangle outline with extended parameters
 RLAPI void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color);              // Draw rectangle with rounded edges
 RLAPI void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, int lineThick, Color color); // Draw rectangle with rounded edges outline
-RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color);                                // Draw a color-filled triangle
-RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color);                           // Draw triangle outline
-RLAPI void DrawTriangleFan(Vector2 *points, int numPoints, Color color);                                 // Draw a triangle fan defined by points
+RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color);                                // Draw a color-filled triangle (vertex in counter-clockwise order!)
+RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color);                           // Draw triangle outline (vertex in counter-clockwise order!)
+RLAPI void DrawTriangleFan(Vector2 *points, int numPoints, Color color);                                 // Draw a triangle fan defined by points (first vertex is the center)
+RLAPI void DrawTriangleStrip(Vector2 *points, int pointsCount, Color color);                             // Draw a triangle strip defined by points
 RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color);               // Draw a regular polygon (Vector version)
-
-RLAPI void SetShapesTexture(Texture2D texture, Rectangle source);                                        // Define default texture used to draw shapes
+RLAPI void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color);          // Draw a polygon outline of n sides
 
 // Basic shapes collision detection functions
 RLAPI bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2);                                           // Check collision between two rectangles
@@ -232,6 +247,7 @@ RLAPI void UnloadTexture(Texture2D texture);
 RLAPI void UnloadRenderTexture(RenderTexture2D target);                                                  // Unload render texture from GPU memory (VRAM)
 RLAPI Color *GetImageData(Image image);                                                                  // Get pixel data from image as a Color struct array
 RLAPI Vector4 *GetImageDataNormalized(Image image);                                                      // Get pixel data from image as Vector4 array (float normalized)
+RLAPI Rectangle GetImageAlphaBorder(Image image, float threshold);                                       // Get image alpha border rectangle
 RLAPI int GetPixelDataSize(int width, int height, int format);                                           // Get pixel data size in bytes (image or texture)
 RLAPI Image GetTextureData(Texture2D texture);                                                           // Get pixel data from GPU texture and return an Image
 RLAPI Image GetScreenData(void);                                                                         // Get pixel data from screen buffer and return an Image (screenshot)
@@ -239,6 +255,7 @@ RLAPI void UpdateTexture(Texture2D texture, const void *pixels);
 
 // Image manipulation functions
 RLAPI Image ImageCopy(Image image);                                                                      // Create an image duplicate (useful for transformations)
+RLAPI Image ImageFromImage(Image image, Rectangle rec);                                                  // Create an image from another image piece
 RLAPI void ImageToPOT(Image *image, Color fillColor);                                                    // Convert image to POT (power-of-two)
 RLAPI void ImageFormat(Image *image, int newFormat);                                                     // Convert image data to desired format
 RLAPI void ImageAlphaMask(Image *image, Image alphaMask);                                                // Apply alpha mask to image
@@ -254,7 +271,7 @@ RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp);
 RLAPI Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount);                    // Extract color palette from image to maximum size (memory should be freed)
 RLAPI Image ImageText(const char *text, int fontSize, Color color);                                      // Create an image from text (default font)
 RLAPI Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint);         // Create an image from text (custom sprite font)
-RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec);                         // Draw a source image within a destination image
+RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint);             // Draw a source image within a destination image (tint applied to source)
 RLAPI void ImageDrawRectangle(Image *dst, Rectangle rec, Color color);                                   // Draw rectangle within an image
 RLAPI void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color);                   // Draw rectangle lines within an image
 RLAPI void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color);     // Draw text (default font) within an image (destination)
@@ -304,7 +321,7 @@ RLAPI Font LoadFont(const char *fileName);
 RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCount);  // Load font from file with extended parameters
 RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar);                        // Load font from Image (XNA style)
 RLAPI CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int charsCount, int type); // Load font data for further use
-RLAPI Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int padding, int packMethod);  // Generate image font atlas using chars info
+RLAPI Image GenImageFontAtlas(const CharInfo *chars, Rectangle **recs, int charsCount, int fontSize, int padding, int packMethod);  // Generate image font atlas using chars info
 RLAPI void UnloadFont(Font font);                                                           // Unload Font from GPU memory (VRAM)
 
 // Text drawing functions
@@ -312,24 +329,23 @@ RLAPI void DrawFPS(int posX, int posY);
 RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color);       // Draw text (using default font)
 RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint);                // Draw text using font and additional parameters
 RLAPI void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint);   // Draw text using font inside rectangle limits
-RLAPI void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectText, Color selectBack);    // Draw text using font inside rectangle limits with support for text selection
+//RLAPI void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint); // Draw text using font inside rectangle limits with support for text selection
+RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float scale, Color tint);   // Draw one character (codepoint)
 
 // Text misc. functions
 RLAPI int MeasureText(const char *text, int fontSize);                                      // Measure string width for default font
 RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing);    // Measure string size for Font
-RLAPI int GetGlyphIndex(Font font, int character);                                          // Get index position for a unicode character on font
-RLAPI int GetNextCodepoint(const char *text, int *count);                                   // Returns next codepoint in a UTF8 encoded string
-                                                                                            // NOTE: 0x3f(`?`) is returned on failure, `count` will hold the total number of bytes processed
+RLAPI int GetGlyphIndex(Font font, int codepoint);                                          // Get index position for a unicode character on font
 
-// Text strings management functions
+// Text strings management functions (no utf8 strings, only byte chars)
 // NOTE: Some strings allocate memory internally for returned strings, just be careful!
+RLAPI int TextCopy(char *dst, const char *src);                                             // Copy one string to another, returns bytes copied
 RLAPI bool TextIsEqual(const char *text1, const char *text2);                               // Check if two text string are equal
 RLAPI unsigned int TextLength(const char *text);                                            // Get text length, checks for '\0' ending
-RLAPI unsigned int TextCountCodepoints(const char *text);                                   // Get total number of characters (codepoints) in a UTF8 encoded string
 RLAPI const char *TextFormat(const char *text, ...);                                        // Text formatting with variables (sprintf style)
 RLAPI const char *TextSubtext(const char *text, int position, int length);                  // Get a piece of a text string
-RLAPI const char *TextReplace(char *text, const char *replace, const char *by);             // Replace text string (memory should be freed!)
-RLAPI const char *TextInsert(const char *text, const char *insert, int position);           // Insert text in a position (memory should be freed!)
+RLAPI char *TextReplace(char *text, const char *replace, const char *by);                   // Replace text string (memory must be freed!)
+RLAPI char *TextInsert(const char *text, const char *insert, int position);                 // Insert text in a position (memory must be freed!)
 RLAPI const char *TextJoin(const char **textList, int count, const char *delimiter);        // Join text strings with delimiter
 RLAPI const char **TextSplit(const char *text, char delimiter, int *count);                 // Split text into multiple strings
 RLAPI void TextAppend(char *text, const char *append, int *position);                       // Append text at specific position and move cursor!
@@ -338,6 +354,13 @@ RLAPI const char *TextToUpper(const char *text);                      // Get upp
 RLAPI const char *TextToLower(const char *text);                      // Get lower case version of provided string
 RLAPI const char *TextToPascal(const char *text);                     // Get Pascal case notation version of provided string
 RLAPI int TextToInteger(const char *text);                            // Get integer value from text (negative values not supported)
+RLAPI char *TextToUtf8(int *codepoints, int length);                  // Encode text codepoint into utf8 text (memory must be freed!)
+
+// UTF8 text strings management functions
+RLAPI int *GetCodepoints(const char *text, int *count);               // Get all codepoints in a string, codepoints count returned by parameters
+RLAPI int GetCodepointsCount(const char *text);                       // Get total number of characters (codepoints) in a UTF8 encoded string
+RLAPI int GetNextCodepoint(const char *text, int *bytesProcessed);    // Returns next codepoint in a UTF8 encoded string; 0x3f('?') is returned on failure
+RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength);    // Encode codepoint into utf8 text (char array length returned as parameter)
 
 //------------------------------------------------------------------------------------
 // Basic 3d Shapes Drawing Functions (Module: models)
@@ -345,6 +368,7 @@ RLAPI int TextToInteger(const char *text);                            // Get int
 
 // Basic geometric 3D shapes drawing functions
 RLAPI void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color);                                    // Draw a line in 3D world space
+RLAPI void DrawPoint3D(Vector3 position, Color color);                                                   // Draw a point in 3D space, actually a small line
 RLAPI void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color); // Draw a circle in 3D world space
 RLAPI void DrawCube(Vector3 position, float width, float height, float length, Color color);             // Draw cube
 RLAPI void DrawCubeV(Vector3 position, Vector3 size, Color color);                                       // Draw cube (Vector version)
@@ -360,7 +384,6 @@ RLAPI void DrawPlane(Vector3 centerPos, Vector2 size, Color color);
 RLAPI void DrawRay(Ray ray, Color color);                                                                // Draw a ray line
 RLAPI void DrawGrid(int slices, float spacing);                                                          // Draw a grid (centered at (0, 0, 0))
 RLAPI void DrawGizmo(Vector3 position);                                                                  // Draw simple gizmo
-//DrawTorus(), DrawTeapot() could be useful?
 
 //------------------------------------------------------------------------------------
 // Model 3d Loading and Drawing Functions (Module: models)
@@ -374,7 +397,7 @@ RLAPI void UnloadModel(Model model);
 // Mesh loading/unloading functions
 RLAPI Mesh *LoadMeshes(const char *fileName, int *meshCount);                                           // Load meshes from model file
 RLAPI void ExportMesh(Mesh mesh, const char *fileName);                                                 // Export mesh data to file
-RLAPI void UnloadMesh(Mesh *mesh);                                                                      // Unload mesh from memory (RAM and/or VRAM)
+RLAPI void UnloadMesh(Mesh mesh);                                                                       // Unload mesh from memory (RAM and/or VRAM)
 
 // Material loading/unloading functions
 RLAPI Material *LoadMaterials(const char *fileName, int *materialCount);                                // Load materials from model file
@@ -418,11 +441,11 @@ RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRe
 // Collision detection functions
 RLAPI bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB);       // Detect collision between two spheres
 RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2);                                     // Detect collision between two bounding boxes
-RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float radiusSphere);          // Detect collision between box and sphere
-RLAPI bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius);                // Detect collision between ray and sphere
-RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, Vector3 *collisionPoint); // Detect collision between ray and sphere, returns collision point
+RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius);                      // Detect collision between box and sphere
+RLAPI bool CheckCollisionRaySphere(Ray ray, Vector3 center, float radius);                              // Detect collision between ray and sphere
+RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 center, float radius, Vector3 *collisionPoint);   // Detect collision between ray and sphere, returns collision point
 RLAPI bool CheckCollisionRayBox(Ray ray, BoundingBox box);                                              // Detect collision between ray and box
-RLAPI RayHitInfo GetCollisionRayModel(Ray ray, Model *model);                                           // Get collision info between ray and model
+RLAPI RayHitInfo GetCollisionRayModel(Ray ray, Model model);                                            // Get collision info between ray and model
 RLAPI RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3);                  // Get collision info between ray and triangle
 RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight);                                    // Get collision info between ray and ground plane (Y-normal plane)
 
@@ -434,11 +457,14 @@ RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight);
 // Shader loading/unloading functions
 RLAPI char *LoadText(const char *fileName);                               // Load chars array from text file
 RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName);  // Load shader from files and bind default locations
-RLAPI Shader LoadShaderCode(char *vsCode, char *fsCode);                  // Load shader from code strings and bind default locations
+RLAPI Shader LoadShaderCode(const char *vsCode, const char *fsCode);                  // Load shader from code strings and bind default locations
 RLAPI void UnloadShader(Shader shader);                                   // Unload shader from GPU memory (VRAM)
 
 RLAPI Shader GetShaderDefault(void);                                      // Get default shader
 RLAPI Texture2D GetTextureDefault(void);                                  // Get default texture
+RLAPI Texture2D GetShapesTexture(void);                                   // Get texture to draw shapes
+RLAPI Rectangle GetShapesTextureRec(void);                                // Get texture rectangle to draw shapes
+RLAPI void SetShapesTexture(Texture2D texture, Rectangle source);         // Define default texture used to draw shapes
 
 // Shader configuration functions
 RLAPI int GetShaderLocation(Shader shader, const char *uniformName);      // Get shader uniform location
@@ -448,11 +474,12 @@ RLAPI void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat);
 RLAPI void SetShaderValueTexture(Shader shader, int uniformLoc, Texture2D texture); // Set shader uniform value for texture
 RLAPI void SetMatrixProjection(Matrix proj);                              // Set a custom projection matrix (replaces internal projection matrix)
 RLAPI void SetMatrixModelview(Matrix view);                               // Set a custom modelview matrix (replaces internal modelview matrix)
-RLAPI Matrix GetMatrixModelview();                                        // Get internal modelview matrix
+RLAPI Matrix GetMatrixModelview(void);                                    // Get internal modelview matrix
+RLAPI Matrix GetMatrixProjection(void);                                   // Get internal projection matrix
 
 // Texture maps generation (PBR)
 // NOTE: Required shaders should be provided
-RLAPI Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size);       // Generate cubemap texture from HDR texture
+RLAPI Texture2D GenTextureCubemap(Shader shader, Texture2D map, int size);          // Generate cubemap texture from 2D texture
 RLAPI Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size);   // Generate irradiance texture using cubemap data
 RLAPI Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size);    // Generate prefilter texture using cubemap data
 RLAPI Texture2D GenTextureBRDF(Shader shader, int size);                  // Generate BRDF texture
@@ -462,14 +489,12 @@ RLAPI void BeginShaderMode(Shader shader);                                // Beg
 RLAPI void EndShaderMode(void);                                           // End custom shader drawing (use default shader)
 RLAPI void BeginBlendMode(int mode);                                      // Begin blending mode (alpha, additive, multiplied)
 RLAPI void EndBlendMode(void);                                            // End blending mode (reset to default: alpha blending)
-RLAPI void BeginScissorMode(int x, int y, int width, int height);         // Begin scissor mode (define screen area for following drawing)
-RLAPI void EndScissorMode(void);                                          // End scissor mode
 
 // VR control functions
 RLAPI void InitVrSimulator(void);                       // Init VR simulator for selected device parameters
 RLAPI void CloseVrSimulator(void);                      // Close VR simulator for current device
 RLAPI void UpdateVrTracking(Camera *camera);            // Update VR tracking (position and orientation) and camera
-RLAPI void SetVrConfiguration(VrDeviceInfo info, Shader distortion);      // Set stereo rendering configuration parameters 
+RLAPI void SetVrConfiguration(VrDeviceInfo info, Shader distortion);      // Set stereo rendering configuration parameters
 RLAPI bool IsVrSimulatorReady(void);                    // Detect if VR simulator is ready
 RLAPI void ToggleVrMode(void);                          // Enable/Disable VR experience
 RLAPI void BeginVrDrawing(void);                        // Begin VR simulator stereo rendering
@@ -487,7 +512,6 @@ RLAPI void SetMasterVolume(float volume);                             // Set mas
 
 // Wave/Sound loading/unloading functions
 RLAPI Wave LoadWave(const char *fileName);                            // Load wave data from file
-RLAPI Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from raw array data
 RLAPI Sound LoadSound(const char *fileName);                          // Load sound from file
 RLAPI Sound LoadSoundFromWave(Wave wave);                             // Load sound from wave data
 RLAPI void UpdateSound(Sound sound, const void *data, int samplesCount);// Update sound buffer with new data
@@ -498,9 +522,12 @@ RLAPI void ExportWaveAsCode(Wave wave, const char *fileName);         // Export
 
 // Wave/Sound management functions
 RLAPI void PlaySound(Sound sound);                                    // Play a sound
+RLAPI void StopSound(Sound sound);                                    // Stop playing a sound
 RLAPI void PauseSound(Sound sound);                                   // Pause a sound
 RLAPI void ResumeSound(Sound sound);                                  // Resume a paused sound
-RLAPI void StopSound(Sound sound);                                    // Stop playing a sound
+RLAPI void PlaySoundMulti(Sound sound);                               // Play a sound (using multichannel buffer pool)
+RLAPI void StopSoundMulti(void);                                      // Stop any sound playing (using multichannel buffer pool)
+RLAPI int GetSoundsPlaying(void);                                     // Get number of sounds playing in the multichannel
 RLAPI bool IsSoundPlaying(Sound sound);                               // Check if a sound is currently playing
 RLAPI void SetSoundVolume(Sound sound, float volume);                 // Set volume for a sound (1.0 is max level)
 RLAPI void SetSoundPitch(Sound sound, float pitch);                   // Set pitch for a sound (1.0 is base level)
@@ -528,7 +555,7 @@ RLAPI float GetMusicTimePlayed(Music music);                          // Get cur
 RLAPI AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Init audio stream (to stream raw audio pcm data)
 RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount); // Update audio stream buffers with data
 RLAPI void CloseAudioStream(AudioStream stream);                      // Close audio stream and free memory
-RLAPI bool IsAudioBufferProcessed(AudioStream stream);                // Check if any audio stream buffers requires refill
+RLAPI bool IsAudioStreamProcessed(AudioStream stream);                // Check if any audio stream buffers requires refill
 RLAPI void PlayAudioStream(AudioStream stream);                       // Play audio stream
 RLAPI void PauseAudioStream(AudioStream stream);                      // Pause audio stream
 RLAPI void ResumeAudioStream(AudioStream stream);                     // Resume audio stream
@@ -536,3 +563,4 @@ RLAPI bool IsAudioStreamPlaying(AudioStream stream);                  // Check i
 RLAPI void StopAudioStream(AudioStream stream);                       // Stop audio stream
 RLAPI void SetAudioStreamVolume(AudioStream stream, float volume);    // Set volume for audio stream (1.0 is max level)
 RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch);      // Set pitch for audio stream (1.0 is base level)
+RLAPI void SetAudioStreamBufferSizeDefault(int size);                 // Default size for new audio streams

+ 18 - 16
lib.mod/raylib/src/Makefile

@@ -42,8 +42,8 @@
 .PHONY: all clean install uninstall
 
 # Define required raylib variables
-RAYLIB_VERSION     = 2.5.0
-RAYLIB_API_VERSION = 251
+RAYLIB_VERSION     = 3.0.0
+RAYLIB_API_VERSION = 300
 
 # See below for alternatives.
 RAYLIB_PATH        = ..
@@ -148,9 +148,9 @@ endif
 ifeq ($(PLATFORM),PLATFORM_WEB)
     # Emscripten required variables
     EMSDK_PATH         ?= C:/emsdk
-    EMSCRIPTEN_PATH    ?= $(EMSDK_PATH)/fastcomp/emscripten
-    CLANG_PATH          = $(EMSDK_PATH)/fastcomp/bin
-    PYTHON_PATH         = $(EMSDK_PATH)/python/2.7.13.1_64bit/python-2.7.13.amd64
+    EMSCRIPTEN_PATH    ?= $(EMSDK_PATH)/upstream/emscripten
+    CLANG_PATH          = $(EMSDK_PATH)/upstream/bin
+    PYTHON_PATH         = $(EMSDK_PATH)/python/3.7.4_64bit
     NODE_PATH           = $(EMSDK_PATH)/node/12.9.1_64bit/bin
     export PATH         = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH);C:\raylib\MinGW\bin:$$(PATH)
 endif
@@ -291,9 +291,16 @@ endif
 
 ifeq ($(RAYLIB_BUILD_MODE),DEBUG)
     CFLAGS += -g
+    ifeq ($(PLATFORM),PLATFORM_WEB)
+        CFLAGS += -s ASSERTIONS=1 --profiling
+    endif
 endif
 ifeq ($(RAYLIB_BUILD_MODE),RELEASE)
-    CFLAGS += -O1
+    ifeq ($(PLATFORM),PLATFORM_WEB)
+        CFLAGS += -Os
+    else
+        CFLAGS += -s -O1
+    endif
 endif
 
 # Additional flags for compiler (if desired)
@@ -311,18 +318,12 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
     # -s ALLOW_MEMORY_GROWTH=1   # to allow memory resizing -> WARNING: Audio buffers could FAIL!
     # -s TOTAL_MEMORY=16777216   # to specify heap memory size (default = 16MB)
     # -s USE_PTHREADS=1          # multithreading support
-    # -s WASM=0                  # disable Web Assembly, emitted by default
-    # -s EMTERPRETIFY=1          # enable emscripten code interpreter (very slow)
-    # -s EMTERPRETIFY_ASYNC=1    # support synchronous loops by emterpreter
     # -s FORCE_FILESYSTEM=1      # force filesystem to load/save files data
     # -s ASSERTIONS=1            # enable runtime checks for common memory allocation errors (-O1 and above turn it off)
     # --profiling                # include information for code profiling
     # --memory-init-file 0       # to avoid an external memory initialization code file (.mem)
     # --preload-file resources   # specify a resources folder for data compilation
     CFLAGS += -s USE_GLFW=3
-    ifeq ($(RAYLIB_BUILD_MODE),DEBUG)
-        CFLAGS += -s ASSERTIONS=1 --profiling
-    endif
 endif
 ifeq ($(PLATFORM),PLATFORM_ANDROID)
     # Compiler flags for arquitecture
@@ -477,7 +478,7 @@ endif
 raylib: $(OBJS)
 ifeq ($(PLATFORM),PLATFORM_WEB)
     # Compile raylib for web.
-	emcc -O1 $(OBJS) -o $(RAYLIB_RELEASE_PATH)/libraylib.bc
+	$(CC) -O1 $(OBJS) -o $(RAYLIB_RELEASE_PATH)/libraylib.bc
 	@echo "raylib library generated (libraylib.bc)!"
 else
     ifeq ($(RAYLIB_LIBTYPE),SHARED)
@@ -571,10 +572,11 @@ raudio.o : raudio.c raylib.h
 
 # Compile raygui module
 # NOTE: raygui header should be distributed with raylib.h
-raygui.o : raygui.c raygui.h
-	@echo #define RAYGUI_IMPLEMENTATION > raygui.c
-	@echo #include "$(RAYLIB_MODULE_RAYGUI_PATH)/raygui.h" > raygui.c
+raygui.o : raygui.c raygui.h gui_textbox_extended.h ricons.h
 	$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) -DRAYGUI_IMPLEMENTATION
+raygui.c:
+	echo '#define RAYGUI_IMPLEMENTATION' > raygui.c
+	echo '#include "$(RAYLIB_MODULE_RAYGUI_PATH)/raygui.h"' >> raygui.c
 
 # Compile physac module
 # NOTE: physac header should be distributed with raylib.h

+ 9 - 6
lib.mod/raylib/src/config.h

@@ -53,13 +53,15 @@
 // Wait for events passively (sleeping while no events) instead of polling them actively every frame
 //#define SUPPORT_EVENTS_WAITING      1
 // Allow automatic screen capture of current screen pressing F12, defined in KeyCallback()
-#define SUPPORT_SCREEN_CAPTURE      1
+//#define SUPPORT_SCREEN_CAPTURE      1
 // Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback()
-#define SUPPORT_GIF_RECORDING       1
+//#define SUPPORT_GIF_RECORDING       1
 // Allow scale all the drawn content to match the high-DPI equivalent size (only PLATFORM_DESKTOP)
 //#define SUPPORT_HIGH_DPI            1
 // Support CompressData() and DecompressData() functions
-#define SUPPORT_COMPRESSION_API     1
+#define SUPPORT_COMPRESSION_API       1
+// Support saving binary data automatically to a generated storage.data file. This file is managed internally.
+#define SUPPORT_DATA_STORAGE          1
 
 //------------------------------------------------------------------------------------
 // Module: rlgl - Configuration Flags
@@ -84,15 +86,16 @@
 #define SUPPORT_FILEFORMAT_PNG      1
 //#define SUPPORT_FILEFORMAT_BMP    1
 //#define SUPPORT_FILEFORMAT_TGA    1
-//#define SUPPORT_FILEFORMAT_JPG    1
-#define SUPPORT_FILEFORMAT_GIF    1
+#define SUPPORT_FILEFORMAT_JPG    1
+#define SUPPORT_FILEFORMAT_GIF      1
 //#define SUPPORT_FILEFORMAT_PSD    1
 #define SUPPORT_FILEFORMAT_DDS    1
-#define SUPPORT_FILEFORMAT_HDR      1
+#define SUPPORT_FILEFORMAT_HDR    1
 //#define SUPPORT_FILEFORMAT_KTX    1
 //#define SUPPORT_FILEFORMAT_ASTC   1
 //#define SUPPORT_FILEFORMAT_PKM    1
 //#define SUPPORT_FILEFORMAT_PVR    1
+
 // Support image export functionality (.png, .bmp, .tga, .jpg)
 #define SUPPORT_IMAGE_EXPORT        1
 // Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop...

+ 291 - 201
lib.mod/raylib/src/core.c

@@ -82,6 +82,9 @@
 *       provided by stb_image and stb_image_write libraries, so, those libraries must be enabled on textures module
 *       for linkage
 *
+*   #define SUPPORT_DATA_STORAGE
+*       Support saving binary data automatically to a generated storage.data file. This file is managed internally.
+*
 *   DEPENDENCIES:
 *       rglfw    - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX. FreeBSD, OpenBSD, NetBSD, DragonFly)
 *       raymath  - 3D math functionality (Vector2, Vector3, Matrix, Quaternion)
@@ -152,7 +155,6 @@
 #endif
 
 #include <stdlib.h>             // Required for: srand(), rand(), atexit()
-#include <stdio.h>              // Required for: FILE, fopen(), fseek(), fread(), fwrite(), fclose() [Used in StorageSaveValue()/StorageLoadValue()]
 #include <string.h>             // Required for: strrchr(), strcmp(), strlen()
 #include <time.h>               // Required for: time() [Used in InitTimer()]
 #include <math.h>               // Required for: tan() [Used in BeginMode3D()]
@@ -219,33 +221,33 @@
     #include <android/window.h>             // Defines AWINDOW_FLAG_FULLSCREEN and others
     #include <android_native_app_glue.h>    // Defines basic app state struct and manages activity
 
-    #include <EGL/egl.h>        // Khronos EGL library - Native platform display device control functions
-    #include <GLES2/gl2.h>      // Khronos OpenGL ES 2.0 library
+    #include <EGL/egl.h>            // Khronos EGL library - Native platform display device control functions
+    #include <GLES2/gl2.h>          // Khronos OpenGL ES 2.0 library
 #endif
 
 #if defined(PLATFORM_RPI)
-    #include <fcntl.h>          // POSIX file control definitions - open(), creat(), fcntl()
-    #include <unistd.h>         // POSIX standard function definitions - read(), close(), STDIN_FILENO
-    #include <termios.h>        // POSIX terminal control definitions - tcgetattr(), tcsetattr()
-    #include <pthread.h>        // POSIX threads management (inputs reading)
-    #include <dirent.h>         // POSIX directory browsing
+    #include <fcntl.h>              // POSIX file control definitions - open(), creat(), fcntl()
+    #include <unistd.h>             // POSIX standard function definitions - read(), close(), STDIN_FILENO
+    #include <termios.h>            // POSIX terminal control definitions - tcgetattr(), tcsetattr()
+    #include <pthread.h>            // POSIX threads management (inputs reading)
+    #include <dirent.h>             // POSIX directory browsing
 
-    #include <sys/ioctl.h>      // UNIX System call for device-specific input/output operations - ioctl()
-    #include <linux/kd.h>       // Linux: KDSKBMODE, K_MEDIUMRAM constants definition
-    #include <linux/input.h>    // Linux: Keycodes constants definition (KEY_A, ...)
-    #include <linux/joystick.h> // Linux: Joystick support library
+    #include <sys/ioctl.h>          // UNIX System call for device-specific input/output operations - ioctl()
+    #include <linux/kd.h>           // Linux: KDSKBMODE, K_MEDIUMRAM constants definition
+    #include <linux/input.h>        // Linux: Keycodes constants definition (KEY_A, ...)
+    #include <linux/joystick.h>     // Linux: Joystick support library
 
-    #include "bcm_host.h"       // Raspberry Pi VideoCore IV access functions
+    #include "bcm_host.h"           // Raspberry Pi VideoCore IV access functions
 
-    #include "EGL/egl.h"        // Khronos EGL library - Native platform display device control functions
-    #include "EGL/eglext.h"     // Khronos EGL library - Extensions
-    #include "GLES2/gl2.h"      // Khronos OpenGL ES 2.0 library
+    #include "EGL/egl.h"            // Khronos EGL library - Native platform display device control functions
+    #include "EGL/eglext.h"         // Khronos EGL library - Extensions
+    #include "GLES2/gl2.h"          // Khronos OpenGL ES 2.0 library
 #endif
 
 #if defined(PLATFORM_UWP)
-    #include "EGL/egl.h"        // Khronos EGL library - Native platform display device control functions
-    #include "EGL/eglext.h"     // Khronos EGL library - Extensions
-    #include "GLES2/gl2.h"      // Khronos OpenGL ES 2.0 library
+    #include "EGL/egl.h"            // Khronos EGL library - Native platform display device control functions
+    #include "EGL/eglext.h"         // Khronos EGL library - Extensions
+    #include "GLES2/gl2.h"          // Khronos OpenGL ES 2.0 library
 #endif
 
 #if defined(PLATFORM_WEB)
@@ -283,34 +285,36 @@
 #endif
 
 #define MAX_GAMEPADS              4         // Max number of gamepads supported
-#define MAX_GAMEPAD_BUTTONS       32        // Max bumber of buttons supported (per gamepad)
 #define MAX_GAMEPAD_AXIS          8         // Max number of axis supported (per gamepad)
+#define MAX_GAMEPAD_BUTTONS       32        // Max bumber of buttons supported (per gamepad)
 
 #define MAX_CHARS_QUEUE           16        // Max number of characters in the input queue
 
-#define STORAGE_FILENAME        "storage.data"
+#if defined(SUPPORT_DATA_STORAGE)
+    #define STORAGE_DATA_FILE     "storage.data"
+#endif
 
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
 #if defined(PLATFORM_RPI)
 typedef struct {
-    pthread_t threadId;                         // Event reading thread id
-    int fd;                                     // File descriptor to the device it is assigned to
-    int eventNum;                               // Number of 'event<N>' device
-    Rectangle absRange;                         // Range of values for absolute pointing devices (touchscreens)
-    int touchSlot;                              // Hold the touch slot number of the currently being sent multitouch block
-    bool isMouse;                               // True if device supports relative X Y movements
-    bool isTouch;                               // True if device supports absolute X Y movements and has BTN_TOUCH
-    bool isMultitouch;                          // True if device supports multiple absolute movevents and has BTN_TOUCH
-    bool isKeyboard;                            // True if device has letter keycodes
-    bool isGamepad;                             // True if device has gamepad buttons
+    pthread_t threadId;             // Event reading thread id
+    int fd;                         // File descriptor to the device it is assigned to
+    int eventNum;                   // Number of 'event<N>' device
+    Rectangle absRange;             // Range of values for absolute pointing devices (touchscreens)
+    int touchSlot;                  // Hold the touch slot number of the currently being sent multitouch block
+    bool isMouse;                   // True if device supports relative X Y movements
+    bool isTouch;                   // True if device supports absolute X Y movements and has BTN_TOUCH
+    bool isMultitouch;              // True if device supports multiple absolute movevents and has BTN_TOUCH
+    bool isKeyboard;                // True if device has letter keycodes
+    bool isGamepad;                 // True if device has gamepad buttons
 } InputEventWorker;
 
-typedef struct{
-    int Contents[8];
-    char Head;
-    char Tail;
+typedef struct {
+    int contents[8];                // Key events FIFO contents (8 positions)
+    char head;                      // Key events FIFO head position
+    char tail;                      // Key events FIFO tail position
 } KeyEventFifo;
 #endif
 
@@ -394,18 +398,18 @@ typedef struct CoreData {
 #if defined(PLATFORM_WEB)
             bool cursorLockRequired;        // Ask for cursor pointer lock on next click
 #endif
-#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP)
             char currentButtonState[3];     // Registers current mouse button state
             char previousButtonState[3];    // Registers previous mouse button state
             int currentWheelMove;           // Registers current mouse wheel variation
             int previousWheelMove;          // Registers previous mouse wheel variation
-#endif
 #if defined(PLATFORM_RPI)
             char currentButtonStateEvdev[3];    // Holds the new mouse state for the next polling event to grab (Can't be written directly due to multithreading, app could miss the update)
 #endif
         } Mouse;
         struct {
-            Vector2 position[MAX_TOUCH_POINTS]; // Touch position on screen
+            Vector2 position[MAX_TOUCH_POINTS];         // Touch position on screen
+            char currentTouchState[MAX_TOUCH_POINTS];   // Registers current touch state
+            char previousTouchState[MAX_TOUCH_POINTS];  // Registers previous touch state
         } Touch;
         struct {
             int lastButtonPressed;          // Register last gamepad button pressed
@@ -441,7 +445,7 @@ typedef struct CoreData {
 //----------------------------------------------------------------------------------
 static CoreData CORE = { 0 };               // Global CORE context
 
-static char **dirFilesPath;                 // Store directory files paths as strings
+static char **dirFilesPath = NULL;          // Store directory files paths as strings
 static int dirFilesCount = 0;               // Count directory files strings
 
 #if defined(SUPPORT_SCREEN_CAPTURE)
@@ -473,8 +477,6 @@ static void SwapBuffers(void);                          // Copy back buffer to f
 static void InitTimer(void);                            // Initialize timer
 static void Wait(float ms);                             // Wait for some milliseconds (stop program execution)
 
-static bool GetKeyStatus(int key);                      // Returns if a key has been pressed
-static bool GetMouseButtonStatus(int button);           // Returns if a mouse button has been pressed
 static int GetGamepadButton(int button);                // Get gamepad button generic to all platforms
 static int GetGamepadAxis(int axis);                    // Get gamepad axis generic to all platforms
 static void PollInputEvents(void);                      // Register user events
@@ -498,7 +500,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
 #endif
 
 #if defined(PLATFORM_WEB)
-static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *e, void *userData);
+static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData);
 static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData);
 static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
 static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
@@ -683,7 +685,7 @@ void InitWindow(int width, int height, const char *title)
     // NOTE: External functions (defined in module: text)
     LoadFontDefault();
     Rectangle rec = GetFontDefault().recs[95];
-    // NOTE: We setup a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering	
+    // NOTE: We setup a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering
     SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 });
 #endif
 #if defined(PLATFORM_DESKTOP) && defined(SUPPORT_HIGH_DPI)
@@ -703,7 +705,8 @@ void InitWindow(int width, int height, const char *title)
 #endif
 
 #if defined(PLATFORM_WEB)
-    emscripten_set_fullscreenchange_callback(0, 0, 1, EmscriptenFullscreenChangeCallback);
+    // Detect fullscreen change events
+    emscripten_set_fullscreenchange_callback("#canvas", NULL, 1, EmscriptenFullscreenChangeCallback);
 
     // Support keyboard events
     emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
@@ -867,9 +870,9 @@ bool IsWindowHidden(void)
 // Toggle fullscreen mode (only PLATFORM_DESKTOP)
 void ToggleFullscreen(void)
 {
-#if defined(PLATFORM_DESKTOP)
     CORE.Window.fullscreen = !CORE.Window.fullscreen;          // Toggle fullscreen flag
 
+#if defined(PLATFORM_DESKTOP)
     // NOTE: glfwSetWindowMonitor() doesn't work properly (bugs)
     if (CORE.Window.fullscreen)
     {
@@ -893,7 +896,10 @@ void ToggleFullscreen(void)
     }
     else glfwSetWindowMonitor(CORE.Window.handle, NULL, CORE.Window.position.x, CORE.Window.position.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
 #endif
-
+#if defined(PLATFORM_WEB)
+    if (CORE.Window.fullscreen) EM_ASM(Module.requestFullscreen(false, false););
+    else EM_ASM(document.exitFullscreen(););
+#endif
 #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
     TRACELOG(LOG_WARNING, "Could not toggle to windowed mode");
 #endif
@@ -971,6 +977,14 @@ void SetWindowSize(int width, int height)
 #if defined(PLATFORM_DESKTOP)
     glfwSetWindowSize(CORE.Window.handle, width, height);
 #endif
+#if defined(PLATFORM_WEB)
+    emscripten_set_canvas_size(width, height);  // DEPRECATED!
+
+    // TODO: Below functions should be used to replace previous one but
+    // they do not seem to work properly
+    //emscripten_set_canvas_element_size("canvas", width, height);
+    //emscripten_set_element_css_size("canvas", width, height);
+#endif
 }
 
 // Show the window
@@ -1611,9 +1625,30 @@ void SetTargetFPS(int fps)
 }
 
 // Returns current FPS
+// NOTE: We calculate an average framerate
 int GetFPS(void)
 {
-    return (int)roundf(1.0f/GetFrameTime());
+    #define FPS_CAPTURE_FRAMES_COUNT    30      // 30 captures
+    #define FPS_AVERAGE_TIME_SECONDS   0.5f     // 500 millisecondes
+    #define FPS_STEP (FPS_AVERAGE_TIME_SECONDS/FPS_CAPTURE_FRAMES_COUNT)
+
+    static int index = 0;
+    static float history[FPS_CAPTURE_FRAMES_COUNT] = { 0 };
+    static float average = 0, last = 0;
+    float fpsFrame = GetFrameTime();
+
+    if (fpsFrame == 0) return 0;
+
+    if ((GetTime() - last) > FPS_STEP)
+    {
+        last = GetTime();
+        index = (index + 1)%FPS_CAPTURE_FRAMES_COUNT;
+        average -= history[index];
+        history[index] = fpsFrame/FPS_CAPTURE_FRAMES_COUNT;
+        average += history[index];
+    }
+
+    return (int)roundf(1.0f/average);
 }
 
 // Returns time in seconds for last frame drawn
@@ -1681,8 +1716,8 @@ Color ColorFromNormalized(Vector4 normalized)
 // NOTE: Hue is returned as degrees [0..360]
 Vector3 ColorToHSV(Color color)
 {
+    Vector3 hsv = { 0 };
     Vector3 rgb = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
-    Vector3 hsv = { 0.0f, 0.0f, 0.0f };
     float min, max, delta;
 
     min = rgb.x < rgb.y? rgb.x : rgb.y;
@@ -2147,80 +2182,84 @@ unsigned char *DecompressData(unsigned char *compData, int compDataLength, int *
 
 // Save integer value to storage file (to defined position)
 // NOTE: Storage positions is directly related to file memory layout (4 bytes each integer)
-void StorageSaveValue(int position, int value)
+void SaveStorageValue(int position, int value)
 {
-    FILE *storageFile = NULL;
-
+#if defined(SUPPORT_DATA_STORAGE)
     char path[512] = { 0 };
 #if defined(PLATFORM_ANDROID)
     strcpy(path, CORE.Android.internalDataPath);
     strcat(path, "/");
-    strcat(path, STORAGE_FILENAME);
+    strcat(path, STORAGE_DATA_FILE);
 #else
-    strcpy(path, STORAGE_FILENAME);
+    strcpy(path, STORAGE_DATA_FILE);
 #endif
 
-    // Try open existing file to append data
-    storageFile = fopen(path, "rb+");
+    int dataSize = 0;
+    unsigned char *fileData = LoadFileData(path, &dataSize);
 
-    // If file doesn't exist, create a new storage data file
-    if (!storageFile) storageFile = fopen(path, "wb");
-
-    if (!storageFile) TRACELOG(LOG_WARNING, "Storage data file could not be created");
-    else
+    if (fileData != NULL)
     {
-        // Get file size
-        fseek(storageFile, 0, SEEK_END);
-        int fileSize = ftell(storageFile);  // Size in bytes
-        fseek(storageFile, 0, SEEK_SET);
-
-        if (fileSize < (position*sizeof(int))) TRACELOG(LOG_WARNING, "Storage position could not be found");
+        if (dataSize <= (position*sizeof(int)))
+        {
+            // Increase data size up to position and store value
+            dataSize = (position + 1)*sizeof(int);
+            fileData = (unsigned char *)RL_REALLOC(fileData, dataSize);
+            int *dataPtr = (int *)fileData;
+            dataPtr[position] = value;
+        }
         else
         {
-            fseek(storageFile, (position*sizeof(int)), SEEK_SET);
-            fwrite(&value, 1, sizeof(int), storageFile);
+            // Replace value on selected position
+            int *dataPtr = (int *)fileData;
+            dataPtr[position] = value;
         }
 
-        fclose(storageFile);
+        SaveFileData(path, fileData, dataSize);
+        RL_FREE(fileData);
+    }
+    else
+    {
+        dataSize = (position + 1)*sizeof(int);
+        fileData = (unsigned char *)RL_MALLOC(dataSize);
+        int *dataPtr = (int *)fileData;
+        dataPtr[position] = value;
+
+        SaveFileData(path, fileData, dataSize);
+        RL_FREE(fileData);
     }
+#endif
 }
 
 // Load integer value from storage file (from defined position)
 // NOTE: If requested position could not be found, value 0 is returned
-int StorageLoadValue(int position)
+int LoadStorageValue(int position)
 {
     int value = 0;
-
+#if defined(SUPPORT_DATA_STORAGE)
     char path[512] = { 0 };
 #if defined(PLATFORM_ANDROID)
     strcpy(path, CORE.Android.internalDataPath);
     strcat(path, "/");
-    strcat(path, STORAGE_FILENAME);
+    strcat(path, STORAGE_DATA_FILE);
 #else
-    strcpy(path, STORAGE_FILENAME);
+    strcpy(path, STORAGE_DATA_FILE);
 #endif
 
-    // Try open existing file to append data
-    FILE *storageFile = fopen(path, "rb");
+    int dataSize = 0;
+    unsigned char *fileData = LoadFileData(path, &dataSize);
 
-    if (!storageFile) TRACELOG(LOG_WARNING, "Storage data file could not be found");
-    else
+    if (fileData != NULL)
     {
-        // Get file size
-        fseek(storageFile, 0, SEEK_END);
-        int fileSize = ftell(storageFile);      // Size in bytes
-        fseek(storageFile, 0, SEEK_SET);        // Reset file pointer
-
-        if (fileSize < (position*4)) TRACELOG(LOG_WARNING, "Storage position could not be found");
+        if (dataSize < (position*4)) TRACELOG(LOG_WARNING, "Storage position could not be found");
         else
         {
-            fseek(storageFile, (position*4), SEEK_SET);
-            fread(&value, 4, 1, storageFile);   // Read 1 element of 4 bytes size
+            int *dataPtr = (int *)fileData;
+            value = dataPtr[position];
         }
 
-        fclose(storageFile);
+        RL_FREE(fileData);
     }
-
+#endif
     return value;
 }
 
@@ -2239,17 +2278,21 @@ void OpenURL(const char *url)
     }
     else
     {
+#if defined(PLATFORM_DESKTOP)
         char *cmd = (char *)RL_CALLOC(strlen(url) + 10, sizeof(char));
-
-#if defined(_WIN32)
+    #if defined(_WIN32)
         sprintf(cmd, "explorer %s", url);
-#elif defined(__linux__)
+    #elif defined(__linux__)
         sprintf(cmd, "xdg-open '%s'", url); // Alternatives: firefox, x-www-browser
-#elif defined(__APPLE__)
+    #elif defined(__APPLE__)
         sprintf(cmd, "open '%s'", url);
-#endif
+    #endif
         system(cmd);
         RL_FREE(cmd);
+#endif
+#if defined(PLATFORM_WEB)
+        emscripten_run_script(TextFormat("window.open('%s', '_blank')", url));
+#endif
     }
 }
 
@@ -2261,7 +2304,7 @@ bool IsKeyPressed(int key)
 {
     bool pressed = false;
 
-    if ((CORE.Input.Keyboard.currentKeyState[key] != CORE.Input.Keyboard.previousKeyState[key]) && (CORE.Input.Keyboard.currentKeyState[key] == 1)) pressed = true;
+    if ((CORE.Input.Keyboard.previousKeyState[key] == 0) && (CORE.Input.Keyboard.currentKeyState[key] == 1)) pressed = true;
     else pressed = false;
 
     return pressed;
@@ -2270,7 +2313,7 @@ bool IsKeyPressed(int key)
 // Detect if a key is being pressed (key held down)
 bool IsKeyDown(int key)
 {
-    if (GetKeyStatus(key) == 1) return true;
+    if (CORE.Input.Keyboard.currentKeyState[key] == 1) return true;
     else return false;
 }
 
@@ -2279,7 +2322,7 @@ bool IsKeyReleased(int key)
 {
     bool released = false;
 
-    if ((CORE.Input.Keyboard.currentKeyState[key] != CORE.Input.Keyboard.previousKeyState[key]) && (CORE.Input.Keyboard.currentKeyState[key] == 0)) released = true;
+    if ((CORE.Input.Keyboard.previousKeyState[key] == 1) && (CORE.Input.Keyboard.currentKeyState[key] == 0)) released = true;
     else released = false;
 
     return released;
@@ -2288,7 +2331,7 @@ bool IsKeyReleased(int key)
 // Detect if a key is NOT being pressed (key not held down)
 bool IsKeyUp(int key)
 {
-    if (GetKeyStatus(key) == 0) return true;
+    if (CORE.Input.Keyboard.currentKeyState[key] == 0) return true;
     else return false;
 }
 
@@ -2457,9 +2500,10 @@ bool IsMouseButtonPressed(int button)
 #if defined(PLATFORM_ANDROID)
     if (IsGestureDetected(GESTURE_TAP)) pressed = true;
 #else
-    // NOTE: On PLATFORM_DESKTOP and PLATFORM_WEB IsMouseButtonPressed() is equivalent to GESTURE_TAP
-    if (((CORE.Input.Mouse.currentButtonState[button] != CORE.Input.Mouse.previousButtonState[button]) &&
-         (CORE.Input.Mouse.currentButtonState[button] == 1)) || IsGestureDetected(GESTURE_TAP))  pressed = true;
+    if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) pressed = true;
+
+    // Map touches to mouse buttons checking
+    if ((CORE.Input.Touch.currentTouchState[button] == 1) && (CORE.Input.Touch.previousTouchState[button] == 0)) pressed = true;
 #endif
 
     return pressed;
@@ -2473,8 +2517,10 @@ bool IsMouseButtonDown(int button)
 #if defined(PLATFORM_ANDROID)
     if (IsGestureDetected(GESTURE_HOLD)) down = true;
 #else
-    // NOTE: On PLATFORM_DESKTOP and PLATFORM_WEB IsMouseButtonDown() is equivalent to GESTURE_HOLD or GESTURE_DRAG
-    if ((GetMouseButtonStatus(button) == 1) || IsGestureDetected(GESTURE_HOLD) || IsGestureDetected(GESTURE_DRAG)) down = true;
+    if (CORE.Input.Mouse.currentButtonState[button] == 1) down = true;
+
+    // Map touches to mouse buttons checking
+    if (CORE.Input.Touch.currentTouchState[button] == 1) down = true;
 #endif
 
     return down;
@@ -2485,9 +2531,15 @@ bool IsMouseButtonReleased(int button)
 {
     bool released = false;
 
-#if !defined(PLATFORM_ANDROID)
-    if ((CORE.Input.Mouse.currentButtonState[button] != CORE.Input.Mouse.previousButtonState[button]) &&
-        (CORE.Input.Mouse.currentButtonState[button] == 0)) released = true;
+#if defined(PLATFORM_ANDROID)
+    #if defined(SUPPORT_GESTURES_SYSTEM)
+        released = GetGestureDetected() == GESTURE_TAP;
+    #endif
+#else
+    if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) released = true;
+    
+    // Map touches to mouse buttons checking
+    if ((CORE.Input.Touch.currentTouchState[button] == 0) && (CORE.Input.Touch.previousTouchState[button] == 1)) released = true;
 #endif
 
     return released;
@@ -2499,7 +2551,10 @@ bool IsMouseButtonUp(int button)
     bool up = false;
 
 #if !defined(PLATFORM_ANDROID)
-    if (GetMouseButtonStatus(button) == 0) up = true;
+    if (CORE.Input.Mouse.currentButtonState[button] == 0) up = true;
+    
+    // Map touches to mouse buttons checking
+    if (CORE.Input.Touch.currentTouchState[button] == 0) up = true;
 #endif
 
     return up;
@@ -2528,12 +2583,13 @@ int GetMouseY(void)
 // Returns mouse position XY
 Vector2 GetMousePosition(void)
 {
-    Vector2 position = { 0.0f, 0.0f };
+    Vector2 position = { 0 };
 
 #if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB)
     position = GetTouchPosition(0);
 #else
-    position = (Vector2){ (CORE.Input.Mouse.position.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x, (CORE.Input.Mouse.position.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y };
+    position.x = (CORE.Input.Mouse.position.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x;
+    position.y = (CORE.Input.Mouse.position.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y;
 #endif
 
     return position;
@@ -2632,7 +2688,6 @@ Vector2 GetTouchPosition(int index)
     // TODO: GLFW is not supporting multi-touch input just yet
     // https://www.codeproject.com/Articles/668404/Programming-for-Multi-Touch
     // https://docs.microsoft.com/en-us/windows/win32/wintouch/getting-started-with-multi-touch-messages
-
     if (index == 0) position = GetMousePosition();
 #endif
 
@@ -3402,36 +3457,6 @@ static void Wait(float ms)
 #endif
 }
 
-// Get one key state
-static bool GetKeyStatus(int key)
-{
-#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
-    return glfwGetKey(CORE.Window.handle, key);
-#elif defined(PLATFORM_ANDROID)
-    // NOTE: Android supports up to 260 keys
-    if (key < 0 || key > 260) return false;
-    else return CORE.Input.Keyboard.currentKeyState[key];
-#elif defined(PLATFORM_RPI) || defined(PLATFORM_UWP)
-    // NOTE: Keys states are filled in PollInputEvents()
-    if (key < 0 || key > 511) return false;
-    else return CORE.Input.Keyboard.currentKeyState[key];
-#endif
-}
-
-// Get one mouse button state
-static bool GetMouseButtonStatus(int button)
-{
-#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
-    return glfwGetMouseButton(CORE.Window.handle, button);
-#elif defined(PLATFORM_ANDROID)
-    // TODO: Check for virtual mouse?
-    return false;
-#elif defined(PLATFORM_RPI) || defined(PLATFORM_UWP)
-    // NOTE: Mouse buttons states are filled in PollInputEvents()
-    return CORE.Input.Mouse.currentButtonState[button];
-#endif
-}
-
 // Get gamepad button generic to all platforms
 static int GetGamepadButton(int button)
 {
@@ -3545,15 +3570,15 @@ static void PollInputEvents(void)
 
 #if defined(PLATFORM_RPI)
     // Register previous keys states
-    for (int i = 0; i < 512; i++)CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i];
+    for (int i = 0; i < 512; i++) CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i];
 
     // Grab a keypress from the evdev fifo if avalable
-    if (CORE.Input.Keyboard.lastKeyPressed.Head != CORE.Input.Keyboard.lastKeyPressed.Tail)
+    if (CORE.Input.Keyboard.lastKeyPressed.head != CORE.Input.Keyboard.lastKeyPressed.tail)
     {
-        CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = CORE.Input.Keyboard.lastKeyPressed.Contents[CORE.Input.Keyboard.lastKeyPressed.Tail];    // Read the key from the buffer
+        CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = CORE.Input.Keyboard.lastKeyPressed.contents[CORE.Input.Keyboard.lastKeyPressed.tail];    // Read the key from the buffer
         CORE.Input.Keyboard.keyPressedQueueCount++;
 
-        CORE.Input.Keyboard.lastKeyPressed.Tail = (CORE.Input.Keyboard.lastKeyPressed.Tail + 1) & 0x07;           // Increment the tail pointer forwards and binary wraparound after 7 (fifo is 8 elements long)
+        CORE.Input.Keyboard.lastKeyPressed.tail = (CORE.Input.Keyboard.lastKeyPressed.tail + 1) & 0x07;           // Increment the tail pointer forwards and binary wraparound after 7 (fifo is 8 elements long)
     }
 
     // Register previous mouse states
@@ -3581,6 +3606,7 @@ static void PollInputEvents(void)
     // Register previous mouse states
     CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove;
     CORE.Input.Mouse.currentWheelMove = 0;
+
     for (int i = 0; i < 3; i++) CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i];
 
     // Loop over pending messages
@@ -3721,16 +3747,7 @@ static void PollInputEvents(void)
 #endif  // PLATFORM_UWP
 
 #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
-    // Mouse input polling
-    double mouseX;
-    double mouseY;
-
-    glfwGetCursorPos(CORE.Window.handle, &mouseX, &mouseY);
-
-    CORE.Input.Mouse.position.x = (float)mouseX;
-    CORE.Input.Mouse.position.y = (float)mouseY;
-
-    // Keyboard input polling (automatically managed by GLFW3 through callback)
+    // Keyboard/Mouse input polling (automatically managed by GLFW3 through callback)
 
     // Register previous keys states
     for (int i = 0; i < 512; i++) CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i];
@@ -3738,8 +3755,12 @@ static void PollInputEvents(void)
     // Register previous mouse states
     for (int i = 0; i < 3; i++) CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i];
 
+    // Register previous mouse wheel state
     CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove;
     CORE.Input.Mouse.currentWheelMove = 0;
+
+    // Register previous touch states
+    for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i];
 #endif
 
 #if defined(PLATFORM_DESKTOP)
@@ -3965,23 +3986,30 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
         }
 #endif  // SUPPORT_SCREEN_CAPTURE
     }
-    else CORE.Input.Keyboard.currentKeyState[key] = action;
+    else 
+    {
+        // WARNING: GLFW could return GLFW_REPEAT, we need to consider it as 1
+        // to work properly with our implementation (IsKeyDown/IsKeyUp checks)
+        if (action == GLFW_RELEASE) CORE.Input.Keyboard.currentKeyState[key] = 0;
+        else CORE.Input.Keyboard.currentKeyState[key] = 1;
+    }
 }
 
 // GLFW3 Mouse Button Callback, runs on mouse button pressed
 static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods)
 {
-    CORE.Input.Mouse.previousButtonState[button] = CORE.Input.Mouse.currentButtonState[button];
+    // WARNING: GLFW could only return GLFW_PRESS (1) or GLFW_RELEASE (0) for now, 
+    // but future releases may add more actions (i.e. GLFW_REPEAT)
     CORE.Input.Mouse.currentButtonState[button] = action;
-
+    
 #if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
     // Process mouse events as touches to be able to use mouse-gestures
     GestureEvent gestureEvent = { 0 };
 
     // Register touch actions
-    if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_DOWN;
-    else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_UP;
-
+    if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) gestureEvent.touchAction = TOUCH_DOWN;
+    else if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) gestureEvent.touchAction = TOUCH_UP;
+    
     // NOTE: TOUCH_MOVE event is registered in MouseCursorPosCallback()
 
     // Assign a pointer ID
@@ -4005,6 +4033,10 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int
 // GLFW3 Cursor Position Callback, runs on mouse move
 static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
 {
+    CORE.Input.Mouse.position.x = (float)x;
+    CORE.Input.Mouse.position.y = (float)y;
+    CORE.Input.Touch.position[0] = CORE.Input.Mouse.position;
+    
 #if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
     // Process mouse events as touches to be able to use mouse-gestures
     GestureEvent gestureEvent = { 0 };
@@ -4018,9 +4050,7 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
     gestureEvent.pointCount = 1;
 
     // Register touch points position, only one point registered
-    gestureEvent.position[0] = (Vector2){ (float)x, (float)y };
-
-    CORE.Input.Touch.position[0] = gestureEvent.position[0];
+    gestureEvent.position[0] = CORE.Input.Touch.position[0];
 
     // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height
     gestureEvent.position[0].x /= (float)GetScreenWidth();
@@ -4139,7 +4169,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
                     // NOTE: External function (defined in module: text)
                     LoadFontDefault();
                     Rectangle rec = GetFontDefault().recs[95];
-                    // NOTE: We setup a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering	
+                    // NOTE: We setup a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering
                     SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 });
                 #endif
 
@@ -4204,37 +4234,84 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
 {
     // If additional inputs are required check:
     // https://developer.android.com/ndk/reference/group/input
+    // https://developer.android.com/training/game-controllers/controller-input
 
     int type = AInputEvent_getType(event);
+    int source = AInputEvent_getSource(event);
 
     if (type == AINPUT_EVENT_TYPE_MOTION)
     {
-        // Get first touch position
-        CORE.Input.Touch.position[0].x = AMotionEvent_getX(event, 0);
-        CORE.Input.Touch.position[0].y = AMotionEvent_getY(event, 0);
+        if ((source & AINPUT_SOURCE_JOYSTICK) == AINPUT_SOURCE_JOYSTICK || (source & AINPUT_SOURCE_GAMEPAD) == AINPUT_SOURCE_GAMEPAD)
+        {
+            // Get first touch position
+            CORE.Input.Touch.position[0].x = AMotionEvent_getX(event, 0);
+            CORE.Input.Touch.position[0].y = AMotionEvent_getY(event, 0);
+
+            // Get second touch position
+            CORE.Input.Touch.position[1].x = AMotionEvent_getX(event, 1);
+            CORE.Input.Touch.position[1].y = AMotionEvent_getY(event, 1);
 
-        // Get second touch position
-        CORE.Input.Touch.position[1].x = AMotionEvent_getX(event, 1);
-        CORE.Input.Touch.position[1].y = AMotionEvent_getY(event, 1);
+            int32_t keycode = AKeyEvent_getKeyCode(event);
+            if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN)
+            {
+                CORE.Input.Keyboard.currentKeyState[keycode] = 1;   // Key down
 
-        // Useful functions for gamepad inputs:
-        //AMotionEvent_getAction()
-        //AMotionEvent_getAxisValue()
-        //AMotionEvent_getButtonState()
+                CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = keycode;
+                CORE.Input.Keyboard.keyPressedQueueCount++;
+            }
+            else CORE.Input.Keyboard.currentKeyState[keycode] = 0;  // Key up
 
-        // Gamepad dpad button presses capturing
-        // TODO: That's weird, key input (or button)
-        // shouldn't come as a TYPE_MOTION event...
-        int32_t keycode = AKeyEvent_getKeyCode(event);
-        if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN)
-        {
-            CORE.Input.Keyboard.currentKeyState[keycode] = 1;  // Key down
+            // Stop processing gamepad buttons
+            return 1;
+        }
 
-            CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = keycode;
-            CORE.Input.Keyboard.keyPressedQueueCount++;
+        int32_t action = AMotionEvent_getAction(event);
+        unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
+
+        // Simple touch position
+        if (flags == AMOTION_EVENT_ACTION_DOWN)
+        {
+            // Get first touch position
+            CORE.Input.Touch.position[0].x = AMotionEvent_getX(event, 0);
+            CORE.Input.Touch.position[0].y = AMotionEvent_getY(event, 0);
         }
-        else CORE.Input.Keyboard.currentKeyState[keycode] = 0;  // Key up
 
+#if defined(SUPPORT_GESTURES_SYSTEM)
+        GestureEvent gestureEvent;
+
+        // Register touch actions
+        if (flags == AMOTION_EVENT_ACTION_DOWN) gestureEvent.touchAction = TOUCH_DOWN;
+        else if (flags == AMOTION_EVENT_ACTION_UP) gestureEvent.touchAction = TOUCH_UP;
+        else if (flags == AMOTION_EVENT_ACTION_MOVE) gestureEvent.touchAction = TOUCH_MOVE;
+
+        // Register touch points count
+        // NOTE: Documentation says pointerCount is Always >= 1,
+        // but in practice it can be 0 or over a million
+        gestureEvent.pointCount = AMotionEvent_getPointerCount(event);
+
+        // Only enable gestures for 1-3 touch points
+        if ((gestureEvent.pointCount > 0) && (gestureEvent.pointCount < 4))
+        {
+            // Register touch points id
+            // NOTE: Only two points registered
+            gestureEvent.pointerId[0] = AMotionEvent_getPointerId(event, 0);
+            gestureEvent.pointerId[1] = AMotionEvent_getPointerId(event, 1);
+
+            // Register touch points position
+            gestureEvent.position[0] = (Vector2){ AMotionEvent_getX(event, 0), AMotionEvent_getY(event, 0) };
+            gestureEvent.position[1] = (Vector2){ AMotionEvent_getX(event, 1), AMotionEvent_getY(event, 1) };
+
+            // Normalize gestureEvent.position[x] for screenWidth and screenHeight
+            gestureEvent.position[0].x /= (float)GetScreenWidth();
+            gestureEvent.position[0].y /= (float)GetScreenHeight();
+
+            gestureEvent.position[1].x /= (float)GetScreenWidth();
+            gestureEvent.position[1].y /= (float)GetScreenHeight();
+
+            // Gesture data is sent to gestures system for processing
+            ProcessGestureEvent(gestureEvent);
+        }
+#endif
     }
     else if (type == AINPUT_EVENT_TYPE_KEY)
     {
@@ -4271,11 +4348,28 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
             // Set default OS behaviour
             return 0;
         }
+
+        return 0;
     }
 
     int32_t action = AMotionEvent_getAction(event);
     unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
 
+    // Support only simple touch position
+    if (flags == AMOTION_EVENT_ACTION_DOWN)
+    {
+        // Get first touch position
+        CORE.Input.Touch.position[0].x = AMotionEvent_getX(event, 0);
+        CORE.Input.Touch.position[0].y = AMotionEvent_getY(event, 0);
+    }
+    else if (flags == AMOTION_EVENT_ACTION_UP)
+    {
+        // Get first touch position
+        CORE.Input.Touch.position[0].x = 0;
+        CORE.Input.Touch.position[0].y = 0;
+    }
+    else return 0; // TODO: Not sure what else should be handled
+
 #if defined(SUPPORT_GESTURES_SYSTEM)
     GestureEvent gestureEvent = { 0 };
 
@@ -4311,17 +4405,6 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
         // Gesture data is sent to gestures system for processing
         ProcessGestureEvent(gestureEvent);
     }
-#else
-    // Support only simple touch position
-    if (flags == AMOTION_EVENT_ACTION_DOWN)
-    {
-        // Get first touch position
-        CORE.Input.Touch.position[0].x = AMotionEvent_getX(event, 0);
-        CORE.Input.Touch.position[0].y = AMotionEvent_getY(event, 0);
-
-        CORE.Input.Touch.position[0].x /= (float)GetScreenWidth();
-        CORE.Input.Touch.position[0].y /= (float)GetScreenHeight();
-    }
 #endif
 
     return 0;
@@ -4329,7 +4412,6 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
 #endif
 
 #if defined(PLATFORM_WEB)
-
 // Register fullscreen change events
 static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData)
 {
@@ -4342,10 +4424,12 @@ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const Emscripte
 
     if (event->isFullscreen)
     {
+        CORE.Window.fullscreen = true;
         TRACELOG(LOG_INFO, "Canvas scaled to fullscreen. ElementSize: (%ix%i), ScreenSize(%ix%i)", event->elementWidth, event->elementHeight, event->screenWidth, event->screenHeight);
     }
     else
     {
+        CORE.Window.fullscreen = false;
         TRACELOG(LOG_INFO, "Canvas scaled to windowed. ElementSize: (%ix%i), ScreenSize(%ix%i)", event->elementWidth, event->elementHeight, event->screenWidth, event->screenHeight);
     }
 
@@ -4391,6 +4475,12 @@ static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent
 // Register touch input events
 static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
 {
+    for (int i = 0; i < touchEvent->numTouches; i++) 
+    {
+        if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) CORE.Input.Touch.currentTouchState[i] = 1;
+        else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) CORE.Input.Touch.currentTouchState[i] = 0;
+    }
+
 #if defined(SUPPORT_GESTURES_SYSTEM)
     GestureEvent gestureEvent = { 0 };
 
@@ -4533,7 +4623,7 @@ static void ProcessKeyboard(void)
 
     // Reset pressed keys array (it will be filled below)
     for (int i = 0; i < 512; i++) CORE.Input.Keyboard.currentKeyState[i] = 0;
-
+    
     // Check keys from event input workers (This is the new keyboard reading method)
     //for (int i = 0; i < 512; i++) CORE.Input.Keyboard.currentKeyState[i] = CORE.Input.Keyboard.currentKeyStateEvdev[i];
 
@@ -4660,11 +4750,11 @@ static void InitEvdevInput(void)
         CORE.Input.Touch.position[i].x = -1;
         CORE.Input.Touch.position[i].y = -1;
     }
-    
+
     // Reset keypress buffer
-    CORE.Input.Keyboard.lastKeyPressed.Head = 0;
-    CORE.Input.Keyboard.lastKeyPressed.Tail = 0;
-    
+    CORE.Input.Keyboard.lastKeyPressed.head = 0;
+    CORE.Input.Keyboard.lastKeyPressed.tail = 0;
+
     // Reset keyboard key state
     for (int i = 0; i < 512; i++) CORE.Input.Keyboard.currentKeyState[i] = 0;
 
@@ -5026,8 +5116,8 @@ static void *EventThread(void *arg)
                         if (event.value > 0)
                         {
                             // Add the key int the fifo
-                            CORE.Input.Keyboard.lastKeyPressed.Contents[CORE.Input.Keyboard.lastKeyPressed.Head] = keycode;   // Put the data at the front of the fifo snake
-                            CORE.Input.Keyboard.lastKeyPressed.Head = (CORE.Input.Keyboard.lastKeyPressed.Head + 1) & 0x07;   // Increment the head pointer forwards and binary wraparound after 7 (fifo is 8 elements long)
+                            CORE.Input.Keyboard.lastKeyPressed.contents[CORE.Input.Keyboard.lastKeyPressed.head] = keycode;   // Put the data at the front of the fifo snake
+                            CORE.Input.Keyboard.lastKeyPressed.head = (CORE.Input.Keyboard.lastKeyPressed.head + 1) & 0x07;   // Increment the head pointer forwards and binary wraparound after 7 (fifo is 8 elements long)
                             // TODO: This fifo is not fully threadsafe with multiple writers, so multiple keyboards hitting a key at the exact same time could miss a key (double write to head before it was incremented)
                         }
                         */

+ 655 - 75
lib.mod/raylib/src/external/miniaudio.h

@@ -105,14 +105,18 @@ Other less major API changes have also been made in version 0.10.
 
 `ma_device_set_stop_callback()` has been removed. You now must set the stop callback via the device config just like the data callback.
 
-`ma_sine_wave_read_f32()` and `ma_sine_wave_read_f32_ex()` have been removed and replaced with `ma_sine_wave_process_pcm_frames()` which supports outputting
-PCM frames in any format (specified by a parameter).
+The `ma_sine_wave` API has been replaced with a more general API called `ma_waveform`. This supports generation of different types of waveforms, including
+sine, square, triangle and sawtooth. Use `ma_waveform_init()` in place of `ma_sine_wave_init()` to initialize the waveform object. This takes the same
+parameters, except an additional `ma_waveform_type` value which you would set to `ma_waveform_type_sine`. Use `ma_waveform_read_pcm_frames()` in place of
+`ma_sine_wave_read_f32()` and `ma_sine_wave_read_f32_ex()`.
 
 `ma_convert_frames()` and `ma_convert_frames_ex()` have been changed. Both of these functions now take a new parameter called `frameCountOut` which specifies
 the size of the output buffer in PCM frames. This has been added for safety. In addition to this, the parameters for `ma_convert_frames_ex()` have changed to
 take a pointer to a `ma_data_converter_config` object to specify the input and output formats to convert between. This was done to make it make it more
 flexible, to prevent the parameter list getting too long, and to prevent API breakage whenever a new conversion property is added.
 
+`ma_calculate_frame_count_after_src()` has been renamed to `ma_calculate_frame_count_after_resampling()` for consistency with the new `ma_resampler` API.
+
 
 Biquad and Low-Pass Filters
 ---------------------------
@@ -125,6 +129,13 @@ filters together. Low-pass filtering is achieved via the `ma_lpf` API. Since the
 point and 16-bit signed integer formats.
 
 
+Sine, Square, Triangle and Sawtooth Waveforms
+---------------------------------------------
+Previously miniaudio supported only sine wave generation. This has now been generalized to support sine, square, triangle and sawtooth waveforms. The old
+`ma_sine_wave` API has been removed and replaced with the `ma_waveform` API. Use `ma_waveform_init()` to initialize the waveform. Here you specify tyhe type of
+waveform you want to generated. You then read data using `ma_waveform_read_pcm_frames()`.
+
+
 Miscellaneous Changes
 ---------------------
 Internal functions have all been made static where possible. If you get warnings about unused functions, please submit a bug report.
@@ -975,9 +986,9 @@ and will result in an error.
 
 
 
-Low-Pass Filtering
-==================
-Low-pass filtering is achieved with the `ma_lpf` API. Example:
+Low-Pass, High-Pass and Band-Pass Filtering
+===========================================
+Low-pass, high-pass and band-pass filtering is achieved with the `ma_lpf`, `ma_hpf` and `ma_bpf` APIs respective. Low-pass filter example:
 
     ```c
     ma_lpf_config config = ma_lpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency);
@@ -1000,7 +1011,7 @@ Filtering can be applied in-place by passing in the same pointer for both the in
     ma_lpf_process_pcm_frames(&lpf, pMyData, pMyData, frameCount);
     ```
 
-The low-pass filter is implemented as a biquad filter. If you need to increase the filter order, simply chain multiple low-pass filters together.
+These filters are implemented as a biquad filter. If you need to increase the filter order, simply chain multiple filters together.
 
     ```c
     for (iFilter = 0; iFilter < filterCount; iFilter += 1) {
@@ -1012,6 +1023,30 @@ If you need to change the configuration of the filter, but need to maintain the
 useful if you need to change the sample rate and/or cutoff frequency dynamically while maintaing smooth transitions. Note that changing the format or channel
 count after initialization is invalid and will result in an error.
 
+The example code above is for low-pass filters, but the same applies for high-pass and band-pass filters, only you should use the `ma_hpf` and `ma_bpf` APIs
+instead.
+
+
+
+Waveforms
+=========
+miniaudio supports generation of sine, square, triangle and sawtooth waveforms. This is achieved with the `ma_waveform` API. Example:
+
+    ```c
+    ma_waveform waveform;
+    ma_result result = ma_waveform_init(ma_waveform_type_sine, amplitude, frequency, sampleRate, &waveform);
+    if (result != MA_SUCCESS) {
+        // Error.
+    }
+
+    ...
+
+    ma_waveform_read_pcm_frames(&waveform, pOutput, frameCount, FORMAT, CHANNELS);
+    ```
+
+The amplitude, frequency and sample rate can be changed dynamically with `ma_waveform_set_amplitude()`, `ma_waveform_set_frequency()` and
+`ma_waveform_set_sample_rate()` respectively.
+
 
 
 Ring Buffers
@@ -1445,17 +1480,10 @@ typedef int ma_result;
 #define MA_SAMPLE_RATE_352800                          352800
 #define MA_SAMPLE_RATE_384000                          384000
 
-#define MA_MIN_PCM_SAMPLE_SIZE_IN_BYTES                1   /* For simplicity, miniaudio does not support PCM samples that are not byte aligned. */
-#define MA_MAX_PCM_SAMPLE_SIZE_IN_BYTES                8
 #define MA_MIN_CHANNELS                                1
 #define MA_MAX_CHANNELS                                32
 #define MA_MIN_SAMPLE_RATE                             MA_SAMPLE_RATE_8000
 #define MA_MAX_SAMPLE_RATE                             MA_SAMPLE_RATE_384000
-#define MA_SRC_SINC_MIN_WINDOW_WIDTH                   2
-#define MA_SRC_SINC_MAX_WINDOW_WIDTH                   32
-#define MA_SRC_SINC_DEFAULT_WINDOW_WIDTH               32
-#define MA_SRC_SINC_LOOKUP_TABLE_RESOLUTION            8
-#define MA_SRC_INPUT_BUFFER_SIZE_IN_SAMPLES            256
 
 typedef enum
 {
@@ -1598,6 +1626,58 @@ ma_result ma_lpf_process_pcm_frames(ma_lpf* pLPF, void* pFramesOut, const void*
 ma_uint32 ma_lpf_get_latency(ma_lpf* pLPF);
 
 
+/**************************************************************************************************************************************************************
+
+High-Pass Filtering
+
+**************************************************************************************************************************************************************/
+typedef struct
+{
+    ma_format format;
+    ma_uint32 channels;
+    ma_uint32 sampleRate;
+    double cutoffFrequency;
+} ma_hpf_config;
+
+ma_hpf_config ma_hpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency);
+
+typedef struct
+{
+    ma_biquad bq;   /* The high-pass filter is implemented as a biquad filter. */
+} ma_hpf;
+
+ma_result ma_hpf_init(const ma_hpf_config* pConfig, ma_hpf* pHPF);
+ma_result ma_hpf_reinit(const ma_hpf_config* pConfig, ma_hpf* pHPF);
+ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
+ma_uint32 ma_hpf_get_latency(ma_hpf* pHPF);
+
+
+/**************************************************************************************************************************************************************
+
+Band-Pass Filtering
+
+**************************************************************************************************************************************************************/
+typedef struct
+{
+    ma_format format;
+    ma_uint32 channels;
+    ma_uint32 sampleRate;
+    double cutoffFrequency;
+} ma_bpf_config;
+
+ma_bpf_config ma_bpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency);
+
+typedef struct
+{
+    ma_biquad bq;   /* The band-pass filter is implemented as a biquad filter. */
+} ma_bpf;
+
+ma_result ma_bpf_init(const ma_bpf_config* pConfig, ma_bpf* pBPF);
+ma_result ma_bpf_reinit(const ma_bpf_config* pConfig, ma_bpf* pBPF);
+ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
+ma_uint32 ma_bpf_get_latency(ma_bpf* pBPF);
+
+
 /************************************************************************************************************************************************************
 *************************************************************************************************************************************************************
 
@@ -3238,6 +3318,8 @@ struct ma_device
             /*SLRecordItf*/ ma_ptr pAudioRecorder;
             /*SLAndroidSimpleBufferQueueItf*/ ma_ptr pBufferQueuePlayback;
             /*SLAndroidSimpleBufferQueueItf*/ ma_ptr pBufferQueueCapture;
+            ma_bool32 isDrainingCapture;
+            ma_bool32 isDrainingPlayback;
             ma_uint32 currentBufferIndexPlayback;
             ma_uint32 currentBufferIndexCapture;
             ma_uint8* pBufferPlayback;      /* This is malloc()'d and is used for storing audio data. Typed as ma_uint8 for easy offsetting. */
@@ -4717,16 +4799,28 @@ ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config
 Generation
 
 ************************************************************************************************************************************************************/
+typedef enum
+{
+    ma_waveform_type_sine,
+    ma_waveform_type_square,
+    ma_waveform_type_triangle,
+    ma_waveform_type_sawtooth
+} ma_waveform_type;
+
 typedef struct
 {
+    ma_waveform_type type;
     double amplitude;
-    double periodsPerSecond;
-    double delta;
+    double frequency;
+    double deltaTime;
     double time;
-} ma_sine_wave;
+} ma_waveform;
 
-ma_result ma_sine_wave_init(double amplitude, double period, ma_uint32 sampleRate, ma_sine_wave* pSineWave);
-ma_uint64 ma_sine_wave_read_pcm_frames(ma_sine_wave* pSineWave, void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels);
+ma_result ma_waveform_init(ma_waveform_type type, double amplitude, double frequency, ma_uint32 sampleRate, ma_waveform* pWaveform);
+ma_uint64 ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels);
+ma_result ma_waveform_set_amplitude(ma_waveform* pWaveform, double amplitude);
+ma_result ma_waveform_set_frequency(ma_waveform* pWaveform, double frequency);
+ma_result ma_waveform_set_sample_rate(ma_waveform* pWaveform, ma_uint32 sampleRate);
 
 #ifdef __cplusplus
 }
@@ -4897,6 +4991,7 @@ IMPLEMENTATION
     #endif
 #endif
 
+/* Begin globally disabled warnings. */
 #if defined(_MSC_VER)
     #pragma warning(push)
     #pragma warning(disable:4752)   /* found Intel(R) Advanced Vector Extensions; consider using /arch:AVX */
@@ -5302,6 +5397,7 @@ Standard Library Stuff
 #define ma_countof(x)               (sizeof(x) / sizeof(x[0]))
 #define ma_max(x, y)                (((x) > (y)) ? (x) : (y))
 #define ma_min(x, y)                (((x) < (y)) ? (x) : (y))
+#define ma_abs(x)                   (((x) > 0) ? (x) : -(x))
 #define ma_clamp(x, lo, hi)         (ma_max(lo, ma_min(x, hi)))
 #define ma_offset_ptr(p, offset)    (((ma_uint8*)(p)) + (offset))
 
@@ -5318,10 +5414,10 @@ static MA_INLINE double ma_cos(double x)
     return ma_sin((MA_PI*0.5) - x);
 }
 
-static MA_INLINE double ma_log2(double x)
+static MA_INLINE double ma_log(double x)
 {
-    /* TODO: Implement custom log2(x). */
-    return log2(x);
+    /* TODO: Implement custom log(x). */
+    return log(x);
 }
 
 static MA_INLINE double ma_pow(double x, double y)
@@ -5332,7 +5428,7 @@ static MA_INLINE double ma_pow(double x, double y)
 
 static MA_INLINE double ma_log10(double x)
 {
-    return ma_log2(x) * 0.30102999566398119521;
+    return ma_log(x) * 0.43429448190325182765;
 }
 
 static MA_INLINE float ma_powf(float x, float y)
@@ -5346,8 +5442,6 @@ static MA_INLINE float ma_log10f(float x)
 }
 
 
-
-
 /*
 Return Values:
   0:  Success
@@ -6063,17 +6157,23 @@ static ma_result ma_allocation_callbacks_init_copy(ma_allocation_callbacks* pDst
 }
 
 
-ma_uint64 ma_calculate_frame_count_after_src(ma_uint32 sampleRateOut, ma_uint32 sampleRateIn, ma_uint64 frameCountIn)
+ma_uint64 ma_calculate_frame_count_after_resampling(ma_uint32 sampleRateOut, ma_uint32 sampleRateIn, ma_uint64 frameCountIn)
 {
-    double    srcRatio       = (double)sampleRateOut / sampleRateIn;
-    double    frameCountOutF = (ma_int64)frameCountIn * srcRatio; /* Cast to int64 required for VC6. */
-    ma_uint64 frameCountOut  = (ma_uint64)frameCountOutF;
+    /* For robustness we're going to use a resampler object to calculate this since that already has a way of calculating this. */
+    ma_result result;
+    ma_uint64 frameCountOut;
+    ma_resampler_config config;
+    ma_resampler resampler;
 
-    /* If the output frame count is fractional, make sure we add an extra frame to ensure there's enough room for that last sample. */
-    if ((frameCountOutF - (ma_int64)frameCountOut) > 0.0) {
-        frameCountOut += 1;
+    config = ma_resampler_config_init(ma_format_s16, 1, sampleRateIn, sampleRateOut, ma_resample_algorithm_linear);
+    result = ma_resampler_init(&config, &resampler);
+    if (result != MA_SUCCESS) {
+        return 0;
     }
 
+    frameCountOut = ma_resampler_get_expected_output_frame_count(&resampler, frameCountIn);
+
+    ma_resampler_uninit(&resampler);
     return frameCountOut;
 }
 
@@ -6270,7 +6370,7 @@ const char* ma_log_level_to_string(ma_uint32 logLevel)
 }
 
 /* Posts a log message. */
-static void ma_log(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message)
+static void ma_post_log_message(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message)
 {
     if (pContext == NULL) {
         return;
@@ -6304,7 +6404,7 @@ static ma_result ma_context_post_error(ma_context* pContext, ma_device* pDevice,
         }
     }
 
-    ma_log(pContext, pDevice, logLevel, message);
+    ma_post_log_message(pContext, pDevice, logLevel, message);
     return resultCode;
 }
 
@@ -6438,7 +6538,7 @@ ma_handle ma_dlopen(ma_context* pContext, const char* filename)
     if (pContext != NULL) {
         char message[256];
         ma_strappend(message, sizeof(message), "Loading library: ", filename);
-        ma_log(pContext, NULL, MA_LOG_LEVEL_VERBOSE, message);
+        ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_VERBOSE, message);
     }
 #endif
 
@@ -6466,7 +6566,7 @@ ma_handle ma_dlopen(ma_context* pContext, const char* filename)
     if (handle == NULL) {
         char message[256];
         ma_strappend(message, sizeof(message), "Failed to load library: ", filename);
-        ma_log(pContext, NULL, MA_LOG_LEVEL_INFO, message);
+        ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_INFO, message);
     }
 #endif
 
@@ -6493,7 +6593,7 @@ ma_proc ma_dlsym(ma_context* pContext, ma_handle handle, const char* symbol)
     if (pContext != NULL) {
         char message[256];
         ma_strappend(message, sizeof(message), "Loading symbol: ", symbol);
-        ma_log(pContext, NULL, MA_LOG_LEVEL_VERBOSE, message);
+        ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_VERBOSE, message);
     }
 #endif
 
@@ -6514,7 +6614,7 @@ ma_proc ma_dlsym(ma_context* pContext, ma_handle handle, const char* symbol)
     if (handle == NULL) {
         char message[256];
         ma_strappend(message, sizeof(message), "Failed to load symbol: ", symbol);
-        ma_log(pContext, NULL, MA_LOG_LEVEL_WARNING, message);
+        ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_WARNING, message);
     }
 #endif
 
@@ -13945,10 +14045,25 @@ static ma_result ma_device_stop__winmm(ma_device* pDevice)
     }
 
     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
+        ma_uint32 iPeriod;
+        WAVEHDR* pWAVEHDR;
+
         if (pDevice->winmm.hDevicePlayback == NULL) {
             return MA_INVALID_ARGS;
         }
 
+        /* We need to drain the device. To do this we just loop over each header and if it's locked just wait for the event. */
+        pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback;
+        for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; iPeriod += 1) {
+            if (pWAVEHDR[iPeriod].dwUser == 1) { /* 1 = locked. */
+                if (WaitForSingleObject((HANDLE)pDevice->winmm.hEventPlayback, INFINITE) != WAIT_OBJECT_0) {
+                    break;  /* An error occurred so just abandon ship and stop the device without draining. */
+                }
+
+                pWAVEHDR[iPeriod].dwUser = 0;
+            }
+        }
+
         resultMM = ((MA_PFN_waveOutReset)pDevice->pContext->winmm.waveOutReset)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
         if (resultMM != MMSYSERR_NOERROR) {
             ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] WARNING: Failed to reset playback device.", ma_result_from_MMRESULT(resultMM));
@@ -19381,7 +19496,7 @@ static ma_result ma_device_init__jack(ma_context* pContext, const ma_device_conf
     }
 
     if (pDevice->type == ma_device_type_duplex) {
-        ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_src(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods);
+        ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods);
         result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->pContext->allocationCallbacks, &pDevice->jack.duplexRB);
         if (result != MA_SUCCESS) {
             ma_device_uninit__jack(pDevice);
@@ -22285,7 +22400,7 @@ static ma_result ma_device_init__coreaudio(ma_context* pContext, const ma_device
 
     /* Need a ring buffer for duplex mode. */
     if (pConfig->deviceType == ma_device_type_duplex) {
-        ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_src(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods);
+        ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods);
         ma_result result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->pContext->allocationCallbacks, &pDevice->coreaudio.duplexRB);
         if (result != MA_SUCCESS) {
             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[Core Audio] Failed to initialize ring buffer.", result);
@@ -22342,7 +22457,9 @@ static ma_result ma_device_start__coreaudio(ma_device* pDevice)
 static ma_result ma_device_stop__coreaudio(ma_device* pDevice)
 {
     MA_ASSERT(pDevice != NULL);
-    
+
+    /* It's not clear from the documentation whether or not AudioOutputUnitStop() actually drains the device or not. */
+
     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
         OSStatus status = ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
         if (status != noErr) {
@@ -23305,6 +23422,16 @@ static ma_result ma_device_stop__sndio(ma_device* pDevice)
 {
     MA_ASSERT(pDevice != NULL);
 
+    /*
+    From the documentation:
+
+        The sio_stop() function puts the audio subsystem in the same state as before sio_start() is called. It stops recording, drains the play buffer and then
+        stops playback. If samples to play are queued but playback hasn't started yet then playback is forced immediately; playback will actually stop once the
+        buffer is drained. In no case are samples in the play buffer discarded.
+
+    Therefore, sio_stop() performs all of the necessary draining for us.
+    */
+
     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
         ((ma_sio_stop_proc)pDevice->pContext->sndio.sio_stop)((struct ma_sio_hdl*)pDevice->sndio.handleCapture);
     }
@@ -24268,14 +24395,24 @@ static ma_result ma_device_stop__audio4(ma_device* pDevice)
     MA_ASSERT(pDevice != NULL);
 
     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
-        ma_result result = ma_device_stop_fd__audio4(pDevice, pDevice->audio4.fdCapture);
+        ma_result result;
+
+        result = ma_device_stop_fd__audio4(pDevice, pDevice->audio4.fdCapture);
         if (result != MA_SUCCESS) {
             return result;
         }
     }
 
     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
-        ma_result result = ma_device_stop_fd__audio4(pDevice, pDevice->audio4.fdPlayback);
+        ma_result result;
+
+        /* Drain the device first. If this fails we'll just need to flush without draining. Unfortunately draining isn't available on newer version of OpenBSD. */
+    #if !defined(MA_AUDIO4_USE_NEW_API)
+        ioctl(pDevice->audio4.fdPlayback, AUDIO_DRAIN, 0);
+    #endif
+
+        /* Here is where the device is stopped immediately. */
+        result = ma_device_stop_fd__audio4(pDevice, pDevice->audio4.fdPlayback);
         if (result != MA_SUCCESS) {
             return result;
         }
@@ -25709,7 +25846,7 @@ static ma_result ma_device_init__aaudio(ma_context* pContext, const ma_device_co
     }
 
     if (pConfig->deviceType == ma_device_type_duplex) {
-        ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_src(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames) * pDevice->capture.internalPeriods;
+        ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames) * pDevice->capture.internalPeriods;
         ma_result result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->pContext->allocationCallbacks, &pDevice->aaudio.duplexRB);
         if (result != MA_SUCCESS) {
             if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
@@ -25775,6 +25912,14 @@ static ma_result ma_device_stop_stream__aaudio(ma_device* pDevice, ma_AAudioStre
 
     MA_ASSERT(pDevice != NULL);
 
+    /*
+    From the AAudio documentation:
+
+        The stream will stop after all of the data currently buffered has been played.
+
+    This maps with miniaudio's requirement that device's be drained which means we don't need to implement any draining logic.
+    */
+
     resultAA = ((MA_PFN_AAudioStream_requestStop)pDevice->pContext->aaudio.AAudioStream_requestStop)(pStream);
     if (resultAA != MA_AAUDIO_OK) {
         return ma_result_from_aaudio(resultAA);
@@ -26328,6 +26473,11 @@ static void ma_buffer_queue_callback_capture__opensl_android(SLAndroidSimpleBuff
         return;
     }
 
+    /* Don't do anything if the device is being drained. */
+    if (pDevice->opensl.isDrainingCapture) {
+        return;
+    }
+
     periodSizeInBytes = pDevice->capture.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
     pBuffer = pDevice->opensl.pBufferCapture + (pDevice->opensl.currentBufferIndexCapture * periodSizeInBytes);
 
@@ -26361,6 +26511,11 @@ static void ma_buffer_queue_callback_playback__opensl_android(SLAndroidSimpleBuf
         return;
     }
 
+    /* Don't do anything if the device is being drained. */
+    if (pDevice->opensl.isDrainingPlayback) {
+        return;
+    }
+
     periodSizeInBytes = pDevice->playback.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
     pBuffer = pDevice->opensl.pBufferPlayback + (pDevice->opensl.currentBufferIndexPlayback * periodSizeInBytes);
 
@@ -26723,7 +26878,7 @@ static ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_co
     }
 
     if (pConfig->deviceType == ma_device_type_duplex) {
-        ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_src(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames) * pDevice->capture.internalPeriods;
+        ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames) * pDevice->capture.internalPeriods;
         ma_result result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->pContext->allocationCallbacks, &pDevice->opensl.duplexRB);
         if (result != MA_SUCCESS) {
             ma_device_uninit__opensl(pDevice);
@@ -26803,6 +26958,40 @@ static ma_result ma_device_start__opensl(ma_device* pDevice)
     return MA_SUCCESS;
 }
 
+static ma_result ma_device_drain__opensl(ma_device* pDevice, ma_device_type deviceType)
+{
+    SLAndroidSimpleBufferQueueItf pBufferQueue;
+
+    MA_ASSERT(deviceType == ma_device_type_capture || deviceType == ma_device_type_playback);
+
+    if (pDevice->type == ma_device_type_capture) {
+        pBufferQueue = (SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture;
+        pDevice->opensl.isDrainingCapture  = MA_TRUE;
+    } else {
+        pBufferQueue = (SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback;
+        pDevice->opensl.isDrainingPlayback = MA_TRUE;
+    }
+
+    for (;;) {
+        SLAndroidSimpleBufferQueueState state;
+
+        MA_OPENSL_BUFFERQUEUE(pBufferQueue)->GetState(pBufferQueue, &state);
+        if (state.count == 0) {
+            break;
+        }
+
+        ma_sleep(10);
+    }
+
+    if (pDevice->type == ma_device_type_capture) {
+        pDevice->opensl.isDrainingCapture  = MA_FALSE;
+    } else {
+        pDevice->opensl.isDrainingPlayback = MA_FALSE;
+    }
+
+    return MA_SUCCESS;
+}
+
 static ma_result ma_device_stop__opensl(ma_device* pDevice)
 {
     SLresult resultSL;
@@ -26815,9 +27004,9 @@ static ma_result ma_device_stop__opensl(ma_device* pDevice)
         return MA_INVALID_OPERATION;
     }
 
-    /* TODO: Wait until all buffers have been processed. Hint: Maybe SLAndroidSimpleBufferQueue::GetState() could be used in a loop? */
-
     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
+        ma_device_drain__opensl(pDevice, ma_device_type_capture);
+
         resultSL = MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED);
         if (resultSL != SL_RESULT_SUCCESS) {
             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal capture device.", MA_FAILED_TO_STOP_BACKEND_DEVICE);
@@ -26827,6 +27016,8 @@ static ma_result ma_device_stop__opensl(ma_device* pDevice)
     }
 
     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
+        ma_device_drain__opensl(pDevice, ma_device_type_playback);
+
         resultSL = MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_STOPPED);
         if (resultSL != SL_RESULT_SUCCESS) {
             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal playback device.", MA_FAILED_TO_STOP_BACKEND_DEVICE);
@@ -27334,7 +27525,7 @@ static ma_result ma_device_init__webaudio(ma_context* pContext, const ma_device_
     the external sample rate.
     */
     if (pConfig->deviceType == ma_device_type_duplex) {
-        ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_src(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames) * 2;
+        ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames) * 2;
         result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->pContext->allocationCallbacks, &pDevice->webaudio.duplexRB);
         if (result != MA_SUCCESS) {
             if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
@@ -27384,6 +27575,16 @@ static ma_result ma_device_stop__webaudio(ma_device* pDevice)
 {
     MA_ASSERT(pDevice != NULL);
 
+    /*
+    From the WebAudio API documentation for AudioContext.suspend():
+
+        Suspends the progression of AudioContext's currentTime, allows any current context processing blocks that are already processed to be played to the
+        destination, and then allows the system to release its claim on audio hardware.
+
+    I read this to mean that "any current context processing blocks" are processed by suspend() - i.e. They they are drained. We therefore shouldn't need to
+    do any kind of explicit draining.
+    */
+
     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
         EM_ASM({
             miniaudio.get_device_by_index($0).webaudio.suspend();
@@ -29084,6 +29285,226 @@ ma_uint32 ma_lpf_get_latency(ma_lpf* pLPF)
 }
 
 
+/**************************************************************************************************************************************************************
+
+High-Pass Filtering
+
+**************************************************************************************************************************************************************/
+ma_hpf_config ma_hpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency)
+{
+    ma_hpf_config config;
+    
+    MA_ZERO_OBJECT(&config);
+    config.format = format;
+    config.channels = channels;
+    config.sampleRate = sampleRate;
+    config.cutoffFrequency = cutoffFrequency;
+
+    return config;
+}
+
+static MA_INLINE ma_biquad_config ma_hpf__get_biquad_config(const ma_hpf_config* pConfig)
+{
+    ma_biquad_config bqConfig;
+    double q;
+    double w;
+    double s;
+    double c;
+    double a;
+
+    MA_ASSERT(pConfig != NULL);
+
+    q = 0.707107;
+    w = 2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate;
+    s = ma_sin(w);
+    c = ma_cos(w);
+    a = s / (2*q);
+
+    bqConfig.b0 =  (1 + c) / 2;
+    bqConfig.b1 = -(1 + c);
+    bqConfig.b2 =  (1 + c) / 2;
+    bqConfig.a0 =   1 + a;
+    bqConfig.a1 =  -2 * c;
+    bqConfig.a2 =   1 - a;
+
+    bqConfig.format   = pConfig->format;
+    bqConfig.channels = pConfig->channels;
+
+    return bqConfig;
+}
+
+ma_result ma_hpf_init(const ma_hpf_config* pConfig, ma_hpf* pHPF)
+{
+    ma_result result;
+    ma_biquad_config bqConfig;
+
+    if (pHPF == NULL) {
+        return MA_INVALID_ARGS;
+    }
+
+    MA_ZERO_OBJECT(pHPF);
+
+    if (pConfig == NULL) {
+        return MA_INVALID_ARGS;
+    }
+
+    bqConfig = ma_hpf__get_biquad_config(pConfig);
+    result = ma_biquad_init(&bqConfig, &pHPF->bq);
+    if (result != MA_SUCCESS) {
+        return result;
+    }
+
+    return MA_SUCCESS;
+}
+
+ma_result ma_hpf_reinit(const ma_hpf_config* pConfig, ma_hpf* pHPF)
+{
+    ma_result result;
+    ma_biquad_config bqConfig;
+
+    if (pHPF == NULL || pConfig == NULL) {
+        return MA_INVALID_ARGS;
+    }
+
+    bqConfig = ma_hpf__get_biquad_config(pConfig);
+    result = ma_biquad_reinit(&bqConfig, &pHPF->bq);
+    if (result != MA_SUCCESS) {
+        return result;
+    }
+
+    return MA_SUCCESS;
+}
+
+ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
+{
+    if (pHPF == NULL) {
+        return MA_INVALID_ARGS;
+    }
+
+    return ma_biquad_process_pcm_frames(&pHPF->bq, pFramesOut, pFramesIn, frameCount);
+}
+
+ma_uint32 ma_hpf_get_latency(ma_hpf* pHPF)
+{
+    if (pHPF == NULL) {
+        return 0;
+    }
+
+    return ma_biquad_get_latency(&pHPF->bq);
+}
+
+
+/**************************************************************************************************************************************************************
+
+Band-Pass Filtering
+
+**************************************************************************************************************************************************************/
+ma_bpf_config ma_bpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency)
+{
+    ma_bpf_config config;
+    
+    MA_ZERO_OBJECT(&config);
+    config.format = format;
+    config.channels = channels;
+    config.sampleRate = sampleRate;
+    config.cutoffFrequency = cutoffFrequency;
+
+    return config;
+}
+
+
+static MA_INLINE ma_biquad_config ma_bpf__get_biquad_config(const ma_bpf_config* pConfig)
+{
+    ma_biquad_config bqConfig;
+    double q;
+    double w;
+    double s;
+    double c;
+    double a;
+
+    MA_ASSERT(pConfig != NULL);
+
+    q = 0.707107;
+    w = 2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate;
+    s = ma_sin(w);
+    c = ma_cos(w);
+    a = s / (2*q);
+
+    bqConfig.b0 =  q * a;
+    bqConfig.b1 =  0;
+    bqConfig.b2 = -q * a;
+    bqConfig.a0 =  1 + a;
+    bqConfig.a1 = -2 * c;
+    bqConfig.a2 =  1 - a;
+
+    bqConfig.format   = pConfig->format;
+    bqConfig.channels = pConfig->channels;
+
+    return bqConfig;
+}
+
+ma_result ma_bpf_init(const ma_bpf_config* pConfig, ma_bpf* pBPF)
+{
+    ma_result result;
+    ma_biquad_config bqConfig;
+
+    if (pBPF == NULL) {
+        return MA_INVALID_ARGS;
+    }
+
+    MA_ZERO_OBJECT(pBPF);
+
+    if (pConfig == NULL) {
+        return MA_INVALID_ARGS;
+    }
+
+    bqConfig = ma_bpf__get_biquad_config(pConfig);
+    result = ma_biquad_init(&bqConfig, &pBPF->bq);
+    if (result != MA_SUCCESS) {
+        return result;
+    }
+
+    return MA_SUCCESS;
+}
+
+ma_result ma_bpf_reinit(const ma_bpf_config* pConfig, ma_bpf* pBPF)
+{
+    ma_result result;
+    ma_biquad_config bqConfig;
+
+    if (pBPF == NULL || pConfig == NULL) {
+        return MA_INVALID_ARGS;
+    }
+
+    bqConfig = ma_bpf__get_biquad_config(pConfig);
+    result = ma_biquad_reinit(&bqConfig, &pBPF->bq);
+    if (result != MA_SUCCESS) {
+        return result;
+    }
+
+    return MA_SUCCESS;
+}
+
+ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
+{
+    if (pBPF == NULL) {
+        return MA_INVALID_ARGS;
+    }
+
+    return ma_biquad_process_pcm_frames(&pBPF->bq, pFramesOut, pFramesIn, frameCount);
+}
+
+ma_uint32 ma_bpf_get_latency(ma_bpf* pBPF)
+{
+    if (pBPF == NULL) {
+        return 0;
+    }
+
+    return ma_biquad_get_latency(&pBPF->bq);
+}
+
+
+
 /**************************************************************************************************************************************************************
 
 Resampling
@@ -37515,7 +37936,12 @@ ma_uint64 ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder)
     }
 
     if (pDecoder->onGetLengthInPCMFrames) {
-        return pDecoder->onGetLengthInPCMFrames(pDecoder);
+        ma_uint64 nativeLengthInPCMFrames = pDecoder->onGetLengthInPCMFrames(pDecoder);
+        if (pDecoder->internalSampleRate == pDecoder->outputSampleRate) {
+            return nativeLengthInPCMFrames;
+        } else {
+            return ma_calculate_frame_count_after_resampling(pDecoder->outputSampleRate, pDecoder->internalSampleRate, nativeLengthInPCMFrames);
+        }
     }
 
     return 0;
@@ -37750,61 +38176,215 @@ ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config
 Generation
 
 **************************************************************************************************************************************************************/
-ma_result ma_sine_wave_init(double amplitude, double periodsPerSecond, ma_uint32 sampleRate, ma_sine_wave* pSineWave)
+ma_result ma_waveform_init(ma_waveform_type type, double amplitude, double frequency, ma_uint32 sampleRate, ma_waveform* pWaveform)
 {
-    if (pSineWave == NULL) {
+    if (pWaveform == NULL) {
         return MA_INVALID_ARGS;
     }
-    MA_ZERO_OBJECT(pSineWave);
 
-    if (amplitude == 0 || periodsPerSecond == 0) {
+    MA_ZERO_OBJECT(pWaveform);
+
+    pWaveform->type      = type;
+    pWaveform->amplitude = amplitude;
+    pWaveform->frequency = frequency;
+    pWaveform->deltaTime = 1.0 / sampleRate;
+    pWaveform->time      = 0;
+
+    return MA_SUCCESS;
+}
+
+ma_result ma_waveform_set_amplitude(ma_waveform* pWaveform, double amplitude)
+{
+    if (pWaveform == NULL) {
         return MA_INVALID_ARGS;
     }
 
-    if (amplitude > 1) {
-        amplitude = 1;
-    }
-    if (amplitude < -1) {
-        amplitude = -1;
+    pWaveform->amplitude = amplitude;
+    return MA_SUCCESS;
+}
+
+ma_result ma_waveform_set_frequency(ma_waveform* pWaveform, double frequency)
+{
+    if (pWaveform == NULL) {
+        return MA_INVALID_ARGS;
     }
 
-    pSineWave->amplitude = amplitude;
-    pSineWave->periodsPerSecond = periodsPerSecond;
-    pSineWave->delta = MA_TAU_D / sampleRate;
-    pSineWave->time = 0;
+    pWaveform->frequency = frequency;
+    return MA_SUCCESS;
+}
 
+ma_result ma_waveform_set_sample_rate(ma_waveform* pWaveform, ma_uint32 sampleRate)
+{
+    if (pWaveform == NULL) {
+        return MA_INVALID_ARGS;
+    }
+
+    pWaveform->deltaTime = 1.0 / sampleRate;
     return MA_SUCCESS;
 }
 
-ma_uint64 ma_sine_wave_read_pcm_frames(ma_sine_wave* pSineWave, void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels)
+static float ma_waveform_sine_f32(double time, double frequency, double amplitude)
+{
+    return (float)(ma_sin(MA_TAU_D * time * frequency) * amplitude);
+}
+
+static float ma_waveform_square_f32(double time, double frequency, double amplitude)
+{
+    double t = time * frequency;
+    double f = t - (ma_uint64)t;
+    double r;
+    
+    if (f < 0.5) {
+        r =  amplitude;
+    } else {
+        r = -amplitude;
+    }
+
+    return (float)r;
+}
+
+static float ma_waveform_triangle_f32(double time, double frequency, double amplitude)
+{
+    double t = time * frequency;
+    double f = t - (ma_uint64)t;
+    double r;
+
+    r = 2 * ma_abs(2 * (f - 0.5)) - 1;
+
+    return (float)(r * amplitude);
+}
+
+static float ma_waveform_sawtooth_f32(double time, double frequency, double amplitude)
+{
+    double t = time * frequency;
+    double f = t - (ma_uint64)t;
+    double r;
+
+    r = 2 * (f - 0.5);
+
+    return (float)(r * amplitude);
+}
+
+static void ma_waveform_read_pcm_frames__sine(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels)
+{
+    ma_uint64 iFrame;
+    ma_uint64 iChannel;
+    ma_uint32 bpf = ma_get_bytes_per_frame(format, channels);
+    ma_uint32 bps = ma_get_bytes_per_sample(format);
+
+    MA_ASSERT(pWaveform  != NULL);
+    MA_ASSERT(pFramesOut != NULL);
+
+    for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
+        float s = ma_waveform_sine_f32(pWaveform->time, pWaveform->frequency, pWaveform->amplitude);
+        pWaveform->time += pWaveform->deltaTime;
+
+        for (iChannel = 0; iChannel < channels; iChannel += 1) {
+            ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), format, &s, ma_format_f32, 1, ma_dither_mode_none);
+        }
+    }
+}
+
+static void ma_waveform_read_pcm_frames__square(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels)
+{
+    ma_uint64 iFrame;
+    ma_uint64 iChannel;
+    ma_uint32 bpf = ma_get_bytes_per_frame(format, channels);
+    ma_uint32 bps = ma_get_bytes_per_sample(format);
+
+    MA_ASSERT(pWaveform  != NULL);
+    MA_ASSERT(pFramesOut != NULL);
+
+    for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
+        float s = ma_waveform_square_f32(pWaveform->time, pWaveform->frequency, pWaveform->amplitude);
+        pWaveform->time += pWaveform->deltaTime;
+
+        for (iChannel = 0; iChannel < channels; iChannel += 1) {
+            ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), format, &s, ma_format_f32, 1, ma_dither_mode_none);
+        }
+    }
+}
+
+static void ma_waveform_read_pcm_frames__triangle(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels)
+{
+    ma_uint64 iFrame;
+    ma_uint64 iChannel;
+    ma_uint32 bpf = ma_get_bytes_per_frame(format, channels);
+    ma_uint32 bps = ma_get_bytes_per_sample(format);
+
+    MA_ASSERT(pWaveform  != NULL);
+    MA_ASSERT(pFramesOut != NULL);
+
+    for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
+        float s = ma_waveform_triangle_f32(pWaveform->time, pWaveform->frequency, pWaveform->amplitude);
+        pWaveform->time += pWaveform->deltaTime;
+
+        for (iChannel = 0; iChannel < channels; iChannel += 1) {
+            ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), format, &s, ma_format_f32, 1, ma_dither_mode_none);
+        }
+    }
+}
+
+static void ma_waveform_read_pcm_frames__sawtooth(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels)
+{
+    ma_uint64 iFrame;
+    ma_uint64 iChannel;
+    ma_uint32 bpf = ma_get_bytes_per_frame(format, channels);
+    ma_uint32 bps = ma_get_bytes_per_sample(format);
+
+    MA_ASSERT(pWaveform  != NULL);
+    MA_ASSERT(pFramesOut != NULL);
+
+    for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
+        float s = ma_waveform_sawtooth_f32(pWaveform->time, pWaveform->frequency, pWaveform->amplitude);
+        pWaveform->time += pWaveform->deltaTime;
+
+        for (iChannel = 0; iChannel < channels; iChannel += 1) {
+            ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), format, &s, ma_format_f32, 1, ma_dither_mode_none);
+        }
+    }
+}
+
+ma_uint64 ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels)
 {
-    if (pSineWave == NULL) {
+    if (pWaveform == NULL) {
         return 0;
     }
 
     if (pFramesOut != NULL) {
-        ma_uint64 iFrame;
-        for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
-            ma_uint64 iChannel;
-            float s;
+        switch (pWaveform->type)
+        {
+            case ma_waveform_type_sine:
+            {
+                ma_waveform_read_pcm_frames__sine(pWaveform, pFramesOut, frameCount, format, channels);
+            } break;
 
-            s = (float)(ma_sin(pSineWave->time * pSineWave->periodsPerSecond) * pSineWave->amplitude);
-            pSineWave->time += pSineWave->delta;
+            case ma_waveform_type_square:
+            {
+                ma_waveform_read_pcm_frames__square(pWaveform, pFramesOut, frameCount, format, channels);
+            } break;
 
-            for (iChannel = 0; iChannel < channels; iChannel += 1) {
-                ma_uint32 bpf = ma_get_bytes_per_frame(format, channels);
-                ma_uint32 bps = ma_get_bytes_per_sample(format);
+            case ma_waveform_type_triangle:
+            {
+                ma_waveform_read_pcm_frames__triangle(pWaveform, pFramesOut, frameCount, format, channels);
+            } break;
 
-                ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), format, &s, ma_format_f32, 1, ma_dither_mode_none);
-            }
+            case ma_waveform_type_sawtooth:
+            {
+                ma_waveform_read_pcm_frames__sawtooth(pWaveform, pFramesOut, frameCount, format, channels);
+            } break;
+
+            default: return 0;
         }
     } else {
-        pSineWave->time += pSineWave->delta * (ma_int64)frameCount; /* Cast to int64 required for VC6. Won't affect anything in practice. */
+        pWaveform->time += pWaveform->deltaTime * (ma_int64)frameCount; /* Cast to int64 required for VC6. Won't affect anything in practice. */
     }
 
     return frameCount;
 }
 
+
+/* End globally disabled warnings. */
 #if defined(_MSC_VER)
     #pragma warning(pop)
 #endif

+ 2 - 2
lib.mod/raylib/src/external/tinyobj_loader_c.h

@@ -748,7 +748,7 @@ static int tinyobj_parse_and_index_mtl_file(tinyobj_material_t **materials_out,
 
   fp = fopen(filename, "r");
   if (!fp) {
-    fprintf(stderr, "TINYOBJ: Error reading file '%s': %s (%d)\n", filename, strerror(errno), errno);
+    //fprintf(stderr, "TINYOBJ: Error reading file '%s': %s (%d)\n", filename, strerror(errno), errno);     // @raysan5: commented
     return TINYOBJ_ERROR_FILE_OPERATION;
   }
 
@@ -1321,7 +1321,7 @@ int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes,
 
     if (ret != TINYOBJ_SUCCESS) {
       /* warning. */
-      fprintf(stderr, "TINYOBJ: Failed to parse material file '%s': %d\n", filename, ret);
+      //fprintf(stderr, "TINYOBJ: Failed to parse material file '%s': %d\n", filename, ret);     // @raysan5: commented
     }
 
     TINYOBJ_FREE(filename);

+ 54 - 45
lib.mod/raylib/src/models.c

@@ -45,10 +45,10 @@
 
 #include "utils.h"          // Required for: fopen() Android mapping
 
-#include <stdlib.h>         // Required for: malloc(), free(), fabs()
+#include <stdlib.h>         // Required for: malloc(), free()
 #include <stdio.h>          // Required for: FILE, fopen(), fclose()
 #include <string.h>         // Required for: strncmp() [Used in LoadModelAnimations()], strlen() [Used in LoadTextureFromCgltfImage()]
-#include <math.h>           // Required for: sinf(), cosf(), sqrtf()
+#include <math.h>           // Required for: sinf(), cosf(), sqrtf(), fabsf()
 
 #include "rlgl.h"           // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
 
@@ -2513,9 +2513,9 @@ void DrawBoundingBox(BoundingBox box, Color color)
 {
     Vector3 size;
 
-    size.x = (float)fabs(box.max.x - box.min.x);
-    size.y = (float)fabs(box.max.y - box.min.y);
-    size.z = (float)fabs(box.max.z - box.min.z);
+    size.x = fabsf(box.max.x - box.min.x);
+    size.y = fabsf(box.max.y - box.min.y);
+    size.z = fabsf(box.max.z - box.min.z);
 
     Vector3 center = { box.min.x + size.x/2.0f, box.min.y + size.y/2.0f, box.min.z + size.z/2.0f };
 
@@ -2761,7 +2761,7 @@ RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight)
 
     RayHitInfo result = { 0 };
 
-    if (fabs(ray.direction.y) > EPSILON)
+    if (fabsf(ray.direction.y) > EPSILON)
     {
         float distance = (ray.position.y - groundHeight)/-ray.direction.y;
 
@@ -3377,9 +3377,9 @@ static unsigned char *DecodeBase64(char *input, int *size)
 }
 
 // Load texture from cgltf_image
-static Texture LoadTextureFromCgltfImage(cgltf_image *image, const char *texPath, Color tint)
+static Image LoadImageFromCgltfImage(cgltf_image *image, const char *texPath, Color tint)
 {
-    Texture texture = { 0 };
+    Image rimage = { 0 };
 
     if (image->uri)
     {
@@ -3406,22 +3406,18 @@ static Texture LoadTextureFromCgltfImage(cgltf_image *image, const char *texPath
                 int w, h;
                 unsigned char *raw = stbi_load_from_memory(data, size, &w, &h, NULL, 4);
 
-                Image rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
+                rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
 
                 // TODO: Tint shouldn't be applied here!
                 ImageColorTint(&rimage, tint);
-                texture = LoadTextureFromImage(rimage);
-                UnloadImage(rimage);
             }
         }
         else
         {
-            Image rimage = LoadImage(TextFormat("%s/%s", texPath, image->uri));
+            rimage = LoadImage(TextFormat("%s/%s", texPath, image->uri));
 
             // TODO: Tint shouldn't be applied here!
             ImageColorTint(&rimage, tint);
-            texture = LoadTextureFromImage(rimage);
-            UnloadImage(rimage);
         }
     }
     else if (image->buffer_view)
@@ -3440,41 +3436,36 @@ static Texture LoadTextureFromCgltfImage(cgltf_image *image, const char *texPath
         unsigned char *raw = stbi_load_from_memory(data, image->buffer_view->size, &w, &h, NULL, 4);
         free(data);
 
-        Image rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
+        rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
         free(raw);
 
         // TODO: Tint shouldn't be applied here!
         ImageColorTint(&rimage, tint);
-        texture = LoadTextureFromImage(rimage);
-        UnloadImage(rimage);
     }
     else
     {
-        Image rimage = LoadImageEx(&tint, 1, 1);
-        texture = LoadTextureFromImage(rimage);
-        UnloadImage(rimage);
+        rimage = LoadImageEx(&tint, 1, 1);
     }
 
-    return texture;
+    return rimage;
 }
 
-// Load glTF mesh data
+// LoadGLTF loads in model data from given filename, supporting both .gltf and .glb
 static Model LoadGLTF(const char *fileName)
 {
     /***********************************************************************************
 
-        Function implemented by Wilhem Barbier (@wbrbr)
+        Function implemented by Wilhem Barbier(@wbrbr), with modifications by Tyler Bezera(@gamerfiend)
 
         Features:
           - Supports .gltf and .glb files
           - Supports embedded (base64) or external textures
-          - Loads the albedo/diffuse texture (other maps could be added)
+          - Loads all raylib supported material textures, values and colors
           - Supports multiple mesh per model and multiple primitives per model
 
         Some restrictions (not exhaustive):
           - Triangle-only meshes
           - Not supported node hierarchies or transforms
-          - Only loads the diffuse texture... but not too hard to support other maps (normal, roughness/metalness...)
           - Only supports unsigned short indices (no byte/unsigned int)
           - Only supports float for texture coordinates (no byte/unsigned short)
 
@@ -3547,44 +3538,62 @@ static Model LoadGLTF(const char *fileName)
             //Ensure material follows raylib support for PBR (metallic/roughness flow)
             if (data->materials[i].has_pbr_metallic_roughness)
             {
-                float roughness = data->materials[i].pbr_metallic_roughness.roughness_factor;
-                float metallic = data->materials[i].pbr_metallic_roughness.metallic_factor;
+                tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0] * 255);
+                tint.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1] * 255);
+                tint.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2] * 255);
+                tint.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3] * 255);
 
-                // NOTE: Material name not used for the moment
-                //if (model.materials[i].name && data->materials[i].name) strcpy(model.materials[i].name, data->materials[i].name);
-
-                // TODO: REview: shouldn't these be *255 ???
-                tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255);
-                tint.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255);
-                tint.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255);
-                tint.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255);
-
-                model.materials[i].maps[MAP_ROUGHNESS].color = tint;
+                model.materials[i].maps[MAP_ALBEDO].color = tint;
 
                 if (data->materials[i].pbr_metallic_roughness.base_color_texture.texture)
                 {
-                    model.materials[i].maps[MAP_ALBEDO].texture = LoadTextureFromCgltfImage(data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image, texPath, tint);
+                    Image albedo = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image, texPath, tint);
+                    model.materials[i].maps[MAP_ALBEDO].texture = LoadTextureFromImage(albedo);
+                    UnloadImage(albedo);
                 }
 
-                // NOTE: Tint isn't need for other textures.. pass null or clear?
-                // Just set as white, multiplying by white has no effect
+                //Set tint to white after it's been used by Albedo
                 tint = WHITE;
 
                 if (data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture)
                 {
-                    model.materials[i].maps[MAP_ROUGHNESS].texture = LoadTextureFromCgltfImage(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture->image, texPath, tint);
+                    Image metallicRoughness = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture->image, texPath, tint);
+                    model.materials[i].maps[MAP_ROUGHNESS].texture = LoadTextureFromImage(metallicRoughness);
+
+                    float roughness = data->materials[i].pbr_metallic_roughness.roughness_factor;
+                    model.materials[i].maps[MAP_ROUGHNESS].value = roughness;
+
+                    float metallic = data->materials[i].pbr_metallic_roughness.metallic_factor;
+                    model.materials[i].maps[MAP_METALNESS].value = metallic;
+
+                    UnloadImage(metallicRoughness);
                 }
-                model.materials[i].maps[MAP_ROUGHNESS].value = roughness;
-                model.materials[i].maps[MAP_METALNESS].value = metallic;
+
+
 
                 if (data->materials[i].normal_texture.texture)
                 {
-                    model.materials[i].maps[MAP_NORMAL].texture = LoadTextureFromCgltfImage(data->materials[i].normal_texture.texture->image, texPath, tint);
+                    Image normalImage = LoadImageFromCgltfImage(data->materials[i].normal_texture.texture->image, texPath, tint);
+                    model.materials[i].maps[MAP_NORMAL].texture = LoadTextureFromImage(normalImage);
+                    UnloadImage(normalImage);
                 }
 
                 if (data->materials[i].occlusion_texture.texture)
                 {
-                    model.materials[i].maps[MAP_OCCLUSION].texture = LoadTextureFromCgltfImage(data->materials[i].occlusion_texture.texture->image, texPath, tint);
+                    Image occulsionImage = LoadImageFromCgltfImage(data->materials[i].occlusion_texture.texture->image, texPath, tint);
+                    model.materials[i].maps[MAP_OCCLUSION].texture = LoadTextureFromImage(occulsionImage);
+                    UnloadImage(occulsionImage);
+                }
+
+                if (data->materials[i].emissive_texture.texture)
+                {
+                    Image emissiveImage = LoadImageFromCgltfImage(data->materials[i].emissive_texture.texture->image, texPath, tint);
+                    model.materials[i].maps[MAP_EMISSION].texture = LoadTextureFromImage(emissiveImage);
+                    tint.r = (unsigned char)(data->materials[i].emissive_factor[0] * 255);
+                    tint.g = (unsigned char)(data->materials[i].emissive_factor[1] * 255);
+                    tint.b = (unsigned char)(data->materials[i].emissive_factor[2] * 255);
+                    model.materials[i].maps[MAP_EMISSION].color = tint;
+                    UnloadImage(emissiveImage);
                 }
             }
         }

+ 99 - 138
lib.mod/raylib/src/raudio.c

@@ -79,8 +79,8 @@
 #endif
 
 #if defined(_WIN32)
-// @raysan5: To avoid conflicting windows.h symbols with raylib, so flags are defined
-// WARNING: Those flags avoid inclusion of some Win32 headers that could be required 
+// To avoid conflicting windows.h symbols with raylib, some flags are defined
+// WARNING: Those flags avoid inclusion of some Win32 headers that could be required
 // by user at some point and won't be included...
 //-------------------------------------------------------------------------------------
 
@@ -149,7 +149,7 @@ typedef struct tagBITMAPINFOHEADER {
 #include <mmreg.h>
 #include <mmsystem.h>
 
-// @raysan5: Some required types defined for MSVC/TinyC compiler
+// Some required types defined for MSVC/TinyC compiler
 #if defined(_MSC_VER) || defined(__TINYC__)
     #include "propidl.h"
 #endif
@@ -157,14 +157,18 @@ typedef struct tagBITMAPINFOHEADER {
 
 #define MA_NO_JACK
 #define MINIAUDIO_IMPLEMENTATION
-#include "external/miniaudio.h" // miniaudio library
-#undef PlaySound                // Win32 API: windows.h > mmsystem.h defines PlaySound macro
+#include "external/miniaudio.h"         // miniaudio library
+#undef PlaySound                        // Win32 API: windows.h > mmsystem.h defines PlaySound macro
 
-#include <stdlib.h>             // Required for: malloc(), free()
-#include <stdio.h>              // Required for: FILE, fopen(), fclose(), fread()
+#include <stdlib.h>                     // Required for: malloc(), free()
+#include <stdio.h>                      // Required for: FILE, fopen(), fclose(), fread()
 
 #if defined(RAUDIO_STANDALONE)
-    #include <string.h>         // Required for: strcmp() [Used in IsFileExtension()]
+    #include <string.h>                 // Required for: strcmp() [Used in IsFileExtension()]
+
+    #if !defined(TRACELOG)
+        #define TRACELOG(level, ...) (void)0
+    #endif
 #endif
 
 #if defined(SUPPORT_FILEFORMAT_OGG)
@@ -200,17 +204,9 @@ typedef struct tagBITMAPINFOHEADER {
 //----------------------------------------------------------------------------------
 // Defines and Macros
 //----------------------------------------------------------------------------------
-// NOTE: Music buffer size is defined by number of samples, independent of sample size and channels number
-// After some math, considering a sampleRate of 48000, a buffer refill rate of 1/60 seconds and a
-// standard double-buffering system, a 4096 samples buffer has been chosen, it should be enough
-// In case of music-stalls, just increase this number
-#if !defined(AUDIO_BUFFER_SIZE)
-    #define AUDIO_BUFFER_SIZE 4096      // PCM data samples (i.e. 16bit, Mono: 8Kb)
-#endif
-
-#define DEVICE_FORMAT       ma_format_f32
-#define DEVICE_CHANNELS     2
-#define DEVICE_SAMPLE_RATE  44100
+#define AUDIO_DEVICE_FORMAT         ma_format_f32
+#define AUDIO_DEVICE_CHANNELS       2
+#define AUDIO_DEVICE_SAMPLE_RATE    44100
 
 #define MAX_AUDIO_BUFFER_POOL_CHANNELS 16
 
@@ -286,6 +282,7 @@ typedef struct AudioData {
     struct {
         AudioBuffer *first;         // Pointer to first AudioBuffer in the list
         AudioBuffer *last;          // Pointer to last AudioBuffer in the list
+        int defaultSize;            // Default audio buffer size for audio streams
     } Buffer;
     struct {
         AudioBuffer *pool[MAX_AUDIO_BUFFER_POOL_CHANNELS];      // Multichannel AudioBuffer pointers pool
@@ -297,7 +294,14 @@ typedef struct AudioData {
 //----------------------------------------------------------------------------------
 // Global Variables Definition
 //----------------------------------------------------------------------------------
-static AudioData AUDIO = { 0 };     // Global CORE context
+static AudioData AUDIO = {          // Global AUDIO context
+
+    // NOTE: Music buffer size is defined by number of samples, independent of sample size and channels number
+    // After some math, considering a sampleRate of 48000, a buffer refill rate of 1/60 seconds and a
+    // standard double-buffering system, a 4096 samples buffer has been chosen, it should be enough
+    // In case of music-stalls, just increase this number
+    .Buffer.defaultSize = 4096
+};
 
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
@@ -325,15 +329,16 @@ static Wave LoadMP3(const char *fileName);              // Load MP3 file
 
 #if defined(RAUDIO_STANDALONE)
 bool IsFileExtension(const char *fileName, const char *ext);// Check file extension
-void TRACELOG(int msgType, const char *text, ...);      // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
+void TraceLog(int msgType, const char *text, ...);      // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
 #endif
 
 //----------------------------------------------------------------------------------
 // AudioBuffer management functions declaration
 // NOTE: Those functions are not exposed by raylib... for the moment
 //----------------------------------------------------------------------------------
-AudioBuffer *InitAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 sizeInFrames, int usage);
-void CloseAudioBuffer(AudioBuffer *buffer);
+AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 sizeInFrames, int usage);
+void UnloadAudioBuffer(AudioBuffer *buffer);
+
 bool IsAudioBufferPlaying(AudioBuffer *buffer);
 void PlayAudioBuffer(AudioBuffer *buffer);
 void StopAudioBuffer(AudioBuffer *buffer);
@@ -367,12 +372,12 @@ void InitAudioDevice(void)
     // NOTE: Using the default device. Format is floating point because it simplifies mixing.
     ma_device_config config = ma_device_config_init(ma_device_type_playback);
     config.playback.pDeviceID = NULL;  // NULL for the default playback AUDIO.System.device.
-    config.playback.format    = DEVICE_FORMAT;
-    config.playback.channels  = DEVICE_CHANNELS;
+    config.playback.format    = AUDIO_DEVICE_FORMAT;
+    config.playback.channels  = AUDIO_DEVICE_CHANNELS;
     config.capture.pDeviceID  = NULL;  // NULL for the default capture AUDIO.System.device.
     config.capture.format     = ma_format_s16;
     config.capture.channels   = 1;
-    config.sampleRate         = DEVICE_SAMPLE_RATE;
+    config.sampleRate         = AUDIO_DEVICE_SAMPLE_RATE;
     config.dataCallback       = OnSendAudioDataToDevice;
     config.pUserData          = NULL;
 
@@ -410,7 +415,7 @@ void InitAudioDevice(void)
     TRACELOG(LOG_INFO, "Audio format: %s -> %s", ma_get_format_name(AUDIO.System.device.playback.format), ma_get_format_name(AUDIO.System.device.playback.internalFormat));
     TRACELOG(LOG_INFO, "Audio channels: %d -> %d", AUDIO.System.device.playback.channels, AUDIO.System.device.playback.internalChannels);
     TRACELOG(LOG_INFO, "Audio sample rate: %d -> %d", AUDIO.System.device.sampleRate, AUDIO.System.device.playback.internalSampleRate);
-    TRACELOG(LOG_INFO, "Audio buffer size: %d", AUDIO.System.device.playback.internalPeriodSizeInFrames*AUDIO.System.device.playback.internalPeriods);
+    TRACELOG(LOG_INFO, "Audio periods size: %d", AUDIO.System.device.playback.internalPeriodSizeInFrames*AUDIO.System.device.playback.internalPeriods);
 
     InitAudioBufferPool();
     TRACELOG(LOG_INFO, "Audio multichannel pool size: %i", MAX_AUDIO_BUFFER_POOL_CHANNELS);
@@ -451,27 +456,27 @@ void SetMasterVolume(float volume)
 //----------------------------------------------------------------------------------
 
 // Initialize a new audio buffer (filled with silence)
-AudioBuffer *InitAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 sizeInFrames, int usage)
+AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 sizeInFrames, int usage)
 {
     AudioBuffer *audioBuffer = (AudioBuffer *)RL_CALLOC(1, sizeof(AudioBuffer));
 
     if (audioBuffer == NULL)
     {
-        TRACELOG(LOG_ERROR, "InitAudioBuffer() : Failed to allocate memory for audio buffer");
+        TRACELOG(LOG_ERROR, "LoadAudioBuffer() : Failed to allocate memory for audio buffer");
         return NULL;
     }
 
     audioBuffer->data = RL_CALLOC(sizeInFrames*channels*ma_get_bytes_per_sample(format), 1);
 
     // Audio data runs through a format converter
-    ma_data_converter_config converterConfig = ma_data_converter_config_init(format, DEVICE_FORMAT, channels, DEVICE_CHANNELS, sampleRate, DEVICE_SAMPLE_RATE);
+    ma_data_converter_config converterConfig = ma_data_converter_config_init(format, AUDIO_DEVICE_FORMAT, channels, AUDIO_DEVICE_CHANNELS, sampleRate, AUDIO_DEVICE_SAMPLE_RATE);
     converterConfig.resampling.allowDynamicSampleRate = true;        // Required for pitch shifting
 
     ma_result result = ma_data_converter_init(&converterConfig, &audioBuffer->converter);
 
     if (result != MA_SUCCESS)
     {
-        TRACELOG(LOG_ERROR, "InitAudioBuffer() : Failed to create data conversion pipeline");
+        TRACELOG(LOG_ERROR, "LoadAudioBuffer() : Failed to create data conversion pipeline");
         RL_FREE(audioBuffer);
         return NULL;
     }
@@ -498,7 +503,7 @@ AudioBuffer *InitAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam
 }
 
 // Delete an audio buffer
-void CloseAudioBuffer(AudioBuffer *buffer)
+void UnloadAudioBuffer(AudioBuffer *buffer)
 {
     if (buffer != NULL)
     {
@@ -507,7 +512,6 @@ void CloseAudioBuffer(AudioBuffer *buffer)
         RL_FREE(buffer->data);
         RL_FREE(buffer);
     }
-    else TRACELOG(LOG_ERROR, "CloseAudioBuffer() : No audio buffer");
 }
 
 // Check if an audio buffer is playing
@@ -516,7 +520,6 @@ bool IsAudioBufferPlaying(AudioBuffer *buffer)
     bool result = false;
 
     if (buffer != NULL) result = (buffer->playing && !buffer->paused);
-    else TRACELOG(LOG_WARNING, "IsAudioBufferPlaying() : No audio buffer");
 
     return result;
 }
@@ -532,7 +535,6 @@ void PlayAudioBuffer(AudioBuffer *buffer)
         buffer->paused = false;
         buffer->frameCursorPos = 0;
     }
-    else TRACELOG(LOG_ERROR, "PlayAudioBuffer() : No audio buffer");
 }
 
 // Stop an audio buffer
@@ -550,28 +552,24 @@ void StopAudioBuffer(AudioBuffer *buffer)
             buffer->isSubBufferProcessed[1] = true;
         }
     }
-    else TRACELOG(LOG_ERROR, "StopAudioBuffer() : No audio buffer");
 }
 
 // Pause an audio buffer
 void PauseAudioBuffer(AudioBuffer *buffer)
 {
     if (buffer != NULL) buffer->paused = true;
-    else TRACELOG(LOG_ERROR, "PauseAudioBuffer() : No audio buffer");
 }
 
 // Resume an audio buffer
 void ResumeAudioBuffer(AudioBuffer *buffer)
 {
     if (buffer != NULL) buffer->paused = false;
-    else TRACELOG(LOG_ERROR, "ResumeAudioBuffer() : No audio buffer");
 }
 
 // Set volume for an audio buffer
 void SetAudioBufferVolume(AudioBuffer *buffer, float volume)
 {
     if (buffer != NULL) buffer->volume = volume;
-    else TRACELOG(LOG_WARNING, "SetAudioBufferVolume() : No audio buffer");
 }
 
 // Set pitch for an audio buffer
@@ -590,7 +588,6 @@ void SetAudioBufferPitch(AudioBuffer *buffer, float pitch)
 
         ma_data_converter_set_rate(&buffer->converter, buffer->converter.config.sampleRateIn, newOutputSampleRate);
     }
-    else TRACELOG(LOG_WARNING, "SetAudioBufferPitch() : No audio buffer");
 }
 
 // Track audio buffer to linked list next position
@@ -687,19 +684,19 @@ Sound LoadSoundFromWave(Wave wave)
         ma_format formatIn  = ((wave.sampleSize == 8)? ma_format_u8 : ((wave.sampleSize == 16)? ma_format_s16 : ma_format_f32));
         ma_uint32 frameCountIn = wave.sampleCount/wave.channels;
 
-        ma_uint32 frameCount = (ma_uint32)ma_convert_frames(NULL, 0, DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, frameCountIn, formatIn, wave.channels, wave.sampleRate);
+        ma_uint32 frameCount = (ma_uint32)ma_convert_frames(NULL, 0, AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO_DEVICE_SAMPLE_RATE, NULL, frameCountIn, formatIn, wave.channels, wave.sampleRate);
         if (frameCount == 0) TRACELOG(LOG_WARNING, "LoadSoundFromWave() : Failed to get frame count for format conversion");
 
-        AudioBuffer *audioBuffer = InitAudioBuffer(DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, frameCount, AUDIO_BUFFER_USAGE_STATIC);
+        AudioBuffer *audioBuffer = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO_DEVICE_SAMPLE_RATE, frameCount, AUDIO_BUFFER_USAGE_STATIC);
         if (audioBuffer == NULL) TRACELOG(LOG_WARNING, "LoadSoundFromWave() : Failed to create audio buffer");
 
-        frameCount = (ma_uint32)ma_convert_frames(audioBuffer->data, frameCount, DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, wave.data, frameCountIn, formatIn, wave.channels, wave.sampleRate);
+        frameCount = (ma_uint32)ma_convert_frames(audioBuffer->data, frameCount, AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO_DEVICE_SAMPLE_RATE, wave.data, frameCountIn, formatIn, wave.channels, wave.sampleRate);
         if (frameCount == 0) TRACELOG(LOG_WARNING, "LoadSoundFromWave() : Format conversion failed");
 
-        sound.sampleCount = frameCount*DEVICE_CHANNELS;
-        sound.stream.sampleRate = DEVICE_SAMPLE_RATE;
+        sound.sampleCount = frameCount*AUDIO_DEVICE_CHANNELS;
+        sound.stream.sampleRate = AUDIO_DEVICE_SAMPLE_RATE;
         sound.stream.sampleSize = 32;
-        sound.stream.channels = DEVICE_CHANNELS;
+        sound.stream.channels = AUDIO_DEVICE_CHANNELS;
         sound.stream.buffer = audioBuffer;
     }
 
@@ -717,7 +714,7 @@ void UnloadWave(Wave wave)
 // Unload sound
 void UnloadSound(Sound sound)
 {
-    CloseAudioBuffer(sound.stream.buffer);
+    UnloadAudioBuffer(sound.stream.buffer);
 
     TRACELOG(LOG_INFO, "Unloaded sound data from RAM");
 }
@@ -725,16 +722,13 @@ void UnloadSound(Sound sound)
 // Update sound buffer with new data
 void UpdateSound(Sound sound, const void *data, int samplesCount)
 {
-    AudioBuffer *audioBuffer = sound.stream.buffer;
-
-    if (audioBuffer != NULL)
+    if (sound.stream.buffer != NULL)
     {
-        StopAudioBuffer(audioBuffer);
+        StopAudioBuffer(sound.stream.buffer);
 
         // TODO: May want to lock/unlock this since this data buffer is read at mixing time
-        memcpy(audioBuffer->data, data, samplesCount*ma_get_bytes_per_frame(audioBuffer->converter.config.formatIn, audioBuffer->converter.config.channelsIn));
+        memcpy(sound.stream.buffer->data, data, samplesCount*ma_get_bytes_per_frame(sound.stream.buffer->converter.config.formatIn, sound.stream.buffer->converter.config.channelsIn));
     }
-    else TRACELOG(LOG_ERROR, "UpdateSound() : Invalid sound - no audio buffer");
 }
 
 // Export wave data to file
@@ -750,9 +744,8 @@ void ExportWave(Wave wave, const char *fileName)
     {
         // Export raw sample data (without header)
         // NOTE: It's up to the user to track wave parameters
-        FILE *rawFile = fopen(fileName, "wb");
-        success = fwrite(wave.data, wave.sampleCount*wave.channels*wave.sampleSize/8, 1, rawFile);
-        fclose(rawFile);
+        SaveFileData(fileName, wave.data, wave.sampleCount*wave.channels*wave.sampleSize/8);
+        success = true;
     }
 
     if (success) TRACELOG(LOG_INFO, "Wave exported successfully: %s", fileName);
@@ -837,13 +830,12 @@ void PlaySoundMulti(Sound sound)
     // If no none playing pool members can be index choose the oldest
     if (index == -1)
     {
-        TRACELOG(LOG_WARNING,"pool age %i ended a sound early no room in buffer pool", AUDIO.MultiChannel.poolCounter);
+        TRACELOG(LOG_WARNING, "Pool age %i ended a sound early no room in buffer pool", AUDIO.MultiChannel.poolCounter);
 
         if (oldIndex == -1)
         {
             // Shouldn't be able to get here... but just in case something odd happens!
-            TRACELOG(LOG_ERROR,"sound buffer pool couldn't determine oldest buffer not playing sound");
-
+            TRACELOG(LOG_ERROR, "Sound buffer pool could not determine oldest buffer not playing sound");
             return;
         }
 
@@ -854,7 +846,7 @@ void PlaySoundMulti(Sound sound)
     }
 
     // Experimentally mutex lock doesn't seem to be needed this makes sense
-    // as AUDIO.MultiChannel.pool[index] isn't playing and the only stuff we're copying
+    // as pool[index] isn't playing and the only stuff we're copying
     // shouldn't be changing...
 
     AUDIO.MultiChannel.channels[index] = AUDIO.MultiChannel.poolCounter;
@@ -938,7 +930,7 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels)
     ma_uint32 frameCount = (ma_uint32)ma_convert_frames(NULL, 0, formatOut, channels, sampleRate, NULL, frameCountIn, formatIn, wave->channels, wave->sampleRate);
     if (frameCount == 0)
     {
-        TRACELOG(LOG_ERROR, "WaveFormat() : Failed to get frame count for format conversion.");
+        TRACELOG(LOG_WARNING, "WaveFormat() : Failed to get frame count for format conversion.");
         return;
     }
 
@@ -947,7 +939,7 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels)
     frameCount = (ma_uint32)ma_convert_frames(data, frameCount, formatOut, channels, sampleRate, wave->data, frameCountIn, formatIn, wave->channels, wave->sampleRate);
     if (frameCount == 0)
     {
-        TRACELOG(LOG_ERROR, "WaveFormat() : Format conversion failed.");
+        TRACELOG(LOG_WARNING, "WaveFormat() : Format conversion failed.");
         return;
     }
 
@@ -1111,7 +1103,6 @@ Music LoadMusicStream(const char *fileName)
     else if (IsFileExtension(fileName, ".mod"))
     {
         jar_mod_context_t *ctxMod = RL_MALLOC(sizeof(jar_mod_context_t));
-        music.ctxData = ctxMod;
 
         jar_mod_init(ctxMod);
         int result = jar_mod_load_file(ctxMod, fileName);
@@ -1125,6 +1116,8 @@ Music LoadMusicStream(const char *fileName)
             music.sampleCount = (unsigned int)jar_mod_max_samples(ctxMod)*2;
             music.loopCount = 0;   // Infinite loop by default
             musicLoaded = true;
+
+            music.ctxData = ctxMod;
         }
     }
 #endif
@@ -1189,20 +1182,16 @@ void UnloadMusicStream(Music music)
 // Start music playing (open stream)
 void PlayMusicStream(Music music)
 {
-    AudioBuffer *audioBuffer = music.stream.buffer;
-
-    if (audioBuffer != NULL)
+    if (music.stream.buffer != NULL)
     {
         // For music streams, we need to make sure we maintain the frame cursor position
         // This is a hack for this section of code in UpdateMusicStream()
         // NOTE: In case window is minimized, music stream is stopped, just make sure to
         // play again on window restore: if (IsMusicPlaying(music)) PlayMusicStream(music);
-        ma_uint32 frameCursorPos = audioBuffer->frameCursorPos;
+        ma_uint32 frameCursorPos = music.stream.buffer->frameCursorPos;
         PlayAudioStream(music.stream);  // WARNING: This resets the cursor position.
-        audioBuffer->frameCursorPos = frameCursorPos;
+        music.stream.buffer->frameCursorPos = frameCursorPos;
     }
-    else TRACELOG(LOG_ERROR, "PlayMusicStream() : No audio buffer");
-
 }
 
 // Pause music playing
@@ -1246,6 +1235,8 @@ void StopMusicStream(Music music)
 // Update (re-fill) music buffers if data already processed
 void UpdateMusicStream(Music music)
 {
+    if (music.stream.buffer == NULL) return;
+
     bool streamEnding = false;
 
     unsigned int subBufferSizeInFrames = music.stream.buffer->sizeInFrames/2;
@@ -1387,9 +1378,12 @@ float GetMusicTimePlayed(Music music)
 {
     float secondsPlayed = 0.0f;
 
-    //ma_uint32 frameSizeInBytes = ma_get_bytes_per_sample(music.stream.buffer->dsp.formatConverterIn.config.formatIn)*music.stream.buffer->dsp.formatConverterIn.config.channels;
-    unsigned int samplesPlayed = music.stream.buffer->totalFramesProcessed*music.stream.channels;
-    secondsPlayed = (float)samplesPlayed/(music.stream.sampleRate*music.stream.channels);
+    if (music.stream.buffer != NULL)
+    {
+        //ma_uint32 frameSizeInBytes = ma_get_bytes_per_sample(music.stream.buffer->dsp.formatConverterIn.config.formatIn)*music.stream.buffer->dsp.formatConverterIn.config.channels;
+        unsigned int samplesPlayed = music.stream.buffer->totalFramesProcessed*music.stream.channels;
+        secondsPlayed = (float)samplesPlayed / (music.stream.sampleRate*music.stream.channels);
+    }
 
     return secondsPlayed;
 }
@@ -1407,18 +1401,19 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
 
     // The size of a streaming buffer must be at least double the size of a period
     unsigned int periodSize = AUDIO.System.device.playback.internalPeriodSizeInFrames;
-    unsigned int subBufferSize = AUDIO_BUFFER_SIZE;
+    unsigned int subBufferSize = AUDIO.Buffer.defaultSize;     // Default buffer size (audio stream)
 
     if (subBufferSize < periodSize) subBufferSize = periodSize;
 
-    stream.buffer = InitAudioBuffer(formatIn, stream.channels, stream.sampleRate, subBufferSize*2, AUDIO_BUFFER_USAGE_STREAM);
+    // Create a double audio buffer of defined size
+    stream.buffer = LoadAudioBuffer(formatIn, stream.channels, stream.sampleRate, subBufferSize*2, AUDIO_BUFFER_USAGE_STREAM);
 
     if (stream.buffer != NULL)
     {
         stream.buffer->looping = true;    // Always loop for streaming buffers
-        TRACELOG(LOG_INFO, "Audio stream loaded successfully (%i Hz, %i bit, %s)", stream.sampleRate, stream.sampleSize, (stream.channels == 1)? "Mono" : "Stereo");
+        TRACELOG(LOG_INFO, "Audio stream initialized successfully (%i Hz, %i bit, %s)", stream.sampleRate, stream.sampleSize, (stream.channels == 1)? "Mono" : "Stereo");
     }
-    else TRACELOG(LOG_ERROR, "InitAudioStream() : Failed to create audio buffer");
+    else TRACELOG(LOG_ERROR, "Audio stream could not be created: Failed to load audio buffer");
 
     return stream;
 }
@@ -1426,7 +1421,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
 // Close audio stream and free memory
 void CloseAudioStream(AudioStream stream)
 {
-    CloseAudioBuffer(stream.buffer);
+    UnloadAudioBuffer(stream.buffer);
 
     TRACELOG(LOG_INFO, "Unloaded audio stream data");
 }
@@ -1436,32 +1431,30 @@ void CloseAudioStream(AudioStream stream)
 // NOTE 2: To unqueue a buffer it needs to be processed: IsAudioStreamProcessed()
 void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount)
 {
-    AudioBuffer *audioBuffer = stream.buffer;
-
-    if (audioBuffer != NULL)
+    if (stream.buffer != NULL)
     {
-        if (audioBuffer->isSubBufferProcessed[0] || audioBuffer->isSubBufferProcessed[1])
+        if (stream.buffer->isSubBufferProcessed[0] || stream.buffer->isSubBufferProcessed[1])
         {
             ma_uint32 subBufferToUpdate = 0;
 
-            if (audioBuffer->isSubBufferProcessed[0] && audioBuffer->isSubBufferProcessed[1])
+            if (stream.buffer->isSubBufferProcessed[0] && stream.buffer->isSubBufferProcessed[1])
             {
                 // Both buffers are available for updating.
                 // Update the first one and make sure the cursor is moved back to the front.
                 subBufferToUpdate = 0;
-                audioBuffer->frameCursorPos = 0;
+                stream.buffer->frameCursorPos = 0;
             }
             else
             {
                 // Just update whichever sub-buffer is processed.
-                subBufferToUpdate = (audioBuffer->isSubBufferProcessed[0])? 0 : 1;
+                subBufferToUpdate = (stream.buffer->isSubBufferProcessed[0])? 0 : 1;
             }
 
-            ma_uint32 subBufferSizeInFrames = audioBuffer->sizeInFrames/2;
-            unsigned char *subBuffer = audioBuffer->data + ((subBufferSizeInFrames*stream.channels*(stream.sampleSize/8))*subBufferToUpdate);
+            ma_uint32 subBufferSizeInFrames = stream.buffer->sizeInFrames/2;
+            unsigned char *subBuffer = stream.buffer->data + ((subBufferSizeInFrames*stream.channels*(stream.sampleSize/8))*subBufferToUpdate);
 
             // TODO: Get total frames processed on this buffer... DOES NOT WORK.
-            audioBuffer->totalFramesProcessed += subBufferSizeInFrames;
+            stream.buffer->totalFramesProcessed += subBufferSizeInFrames;
 
             // Does this API expect a whole buffer to be updated in one go?
             // Assuming so, but if not will need to change this logic.
@@ -1479,23 +1472,18 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount)
 
                 if (leftoverFrameCount > 0) memset(subBuffer + bytesToWrite, 0, leftoverFrameCount*stream.channels*(stream.sampleSize/8));
 
-                audioBuffer->isSubBufferProcessed[subBufferToUpdate] = false;
+                stream.buffer->isSubBufferProcessed[subBufferToUpdate] = false;
             }
             else TRACELOG(LOG_ERROR, "UpdateAudioStream() : Attempting to write too many frames to buffer");
         }
         else TRACELOG(LOG_ERROR, "UpdateAudioStream() : Audio buffer not available for updating");
     }
-    else TRACELOG(LOG_ERROR, "UpdateAudioStream() : No audio buffer");
 }
 
 // Check if any audio stream buffers requires refill
 bool IsAudioStreamProcessed(AudioStream stream)
 {
-    if (stream.buffer == NULL)
-    {
-        TRACELOG(LOG_ERROR, "IsAudioStreamProcessed() : No audio buffer");
-        return false;
-    }
+    if (stream.buffer == NULL) return false;
 
     return (stream.buffer->isSubBufferProcessed[0] || stream.buffer->isSubBufferProcessed[1]);
 }
@@ -1530,16 +1518,24 @@ void StopAudioStream(AudioStream stream)
     StopAudioBuffer(stream.buffer);
 }
 
+// Set volume for audio stream (1.0 is max level)
 void SetAudioStreamVolume(AudioStream stream, float volume)
 {
     SetAudioBufferVolume(stream.buffer, volume);
 }
 
+// Set pitch for audio stream (1.0 is base level)
 void SetAudioStreamPitch(AudioStream stream, float pitch)
 {
     SetAudioBufferPitch(stream.buffer, pitch);
 }
 
+// Default size for new audio streams
+void SetAudioStreamBufferSizeDefault(int size)
+{
+    AUDIO.Buffer.defaultSize = size;
+}
+
 //----------------------------------------------------------------------------------
 // Module specific Functions Definition
 //----------------------------------------------------------------------------------
@@ -1559,11 +1555,7 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer,
     ma_uint32 subBufferSizeInFrames = (audioBuffer->sizeInFrames > 1)? audioBuffer->sizeInFrames/2 : audioBuffer->sizeInFrames;
     ma_uint32 currentSubBufferIndex = audioBuffer->frameCursorPos/subBufferSizeInFrames;
 
-    if (currentSubBufferIndex > 1)
-    {
-        TRACELOGD("Frame cursor position moved too far forward in audio stream");
-        return 0;
-    }
+    if (currentSubBufferIndex > 1) return 0;
 
     // Another thread can update the processed state of buffers so
     // we just take a copy here to try and avoid potential synchronization problems
@@ -1646,7 +1638,7 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer,
 // Reads audio data from an AudioBuffer object in device format. Returned data will be in a format appropriate for mixing.
 static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, float *framesOut, ma_uint32 frameCount)
 {
-    // What's going on here is that we're continuously converting data from the AudioBuffer's internal format to the mixing format, which 
+    // What's going on here is that we're continuously converting data from the AudioBuffer's internal format to the mixing format, which
     // should be defined by the output format of the data converter. We do this until frameCount frames have been output. The important
     // detail to remember here is that we never, ever attempt to read more input data than is required for the specified number of output
     // frames. This can be achieved with ma_data_converter_get_required_input_frame_count().
@@ -1670,7 +1662,7 @@ static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, f
         ma_uint64 inputFramesProcessedThisIteration = ReadAudioBufferFramesInInternalFormat(audioBuffer, inputBuffer, (ma_uint32)inputFramesToProcessThisIteration);    /* Safe cast. */
         ma_uint64 outputFramesProcessedThisIteration = outputFramesToProcessThisIteration;
         ma_data_converter_process_pcm_frames(&audioBuffer->converter, inputBuffer, &inputFramesProcessedThisIteration, runningFramesOut, &outputFramesProcessedThisIteration);
-        
+
         totalOutputFramesProcessed += (ma_uint32)outputFramesProcessedThisIteration; /* Safe cast. */
 
         if (inputFramesProcessedThisIteration < inputFramesToProcessThisIteration)
@@ -1711,13 +1703,7 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const
 
             while (1)
             {
-                if (framesRead > frameCount)
-                {
-                    TRACELOGD("Mixed too many frames from audio buffer");
-                    break;
-                }
-
-                if (framesRead == frameCount) break;
+                if (framesRead >= frameCount) break;
 
                 // Just read as much data as we can from the stream
                 ma_uint32 framesToRead = (frameCount - framesRead);
@@ -1727,9 +1713,9 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const
                     float tempBuffer[1024]; // 512 frames for stereo
 
                     ma_uint32 framesToReadRightNow = framesToRead;
-                    if (framesToReadRightNow > sizeof(tempBuffer)/sizeof(tempBuffer[0])/DEVICE_CHANNELS)
+                    if (framesToReadRightNow > sizeof(tempBuffer)/sizeof(tempBuffer[0])/AUDIO_DEVICE_CHANNELS)
                     {
-                        framesToReadRightNow = sizeof(tempBuffer)/sizeof(tempBuffer[0])/DEVICE_CHANNELS;
+                        framesToReadRightNow = sizeof(tempBuffer)/sizeof(tempBuffer[0])/AUDIO_DEVICE_CHANNELS;
                     }
 
                     ma_uint32 framesJustRead = ReadAudioBufferFramesInMixingFormat(audioBuffer, tempBuffer, framesToReadRightNow);
@@ -1800,7 +1786,7 @@ static void InitAudioBufferPool(void)
     // Dummy buffers
     for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
     {
-        AUDIO.MultiChannel.pool[i] = InitAudioBuffer(DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, 0, AUDIO_BUFFER_USAGE_STATIC);
+        AUDIO.MultiChannel.pool[i] = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO_DEVICE_SAMPLE_RATE, 0, AUDIO_BUFFER_USAGE_STATIC);
     }
 }
 
@@ -2044,9 +2030,7 @@ static Wave LoadOGG(const char *fileName)
         wave.data = (short *)RL_MALLOC(wave.sampleCount*wave.channels*sizeof(short));
 
         // NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!)
-        int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, (short *)wave.data, wave.sampleCount*wave.channels);
-        TRACELOGD("[%s] Samples obtained: %i", fileName, numSamplesOgg);
-
+        stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, (short *)wave.data, wave.sampleCount*wave.channels);
         TRACELOG(LOG_INFO, "[%s] OGG file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
 
         stb_vorbis_close(oggFile);
@@ -2122,29 +2106,6 @@ bool IsFileExtension(const char *fileName, const char *ext)
 
     return result;
 }
-
-// Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
-void TRACELOG(int msgType, const char *text, ...)
-{
-    va_list args;
-    va_start(args, text);
-
-    switch (msgType)
-    {
-        case LOG_INFO: fprintf(stdout, "INFO: "); break;
-        case LOG_ERROR: fprintf(stdout, "ERROR: "); break;
-        case LOG_WARNING: fprintf(stdout, "WARNING: "); break;
-        case LOG_DEBUG: fprintf(stdout, "DEBUG: "); break;
-        default: break;
-    }
-
-    vfprintf(stdout, text, args);
-    fprintf(stdout, "\n");
-
-    va_end(args);
-
-    if (msgType == LOG_ERROR) exit(1);
-}
 #endif
 
 #undef AudioBuffer

+ 1 - 0
lib.mod/raylib/src/raudio.h

@@ -189,6 +189,7 @@ bool IsAudioStreamPlaying(AudioStream stream);                  // Check if audi
 void StopAudioStream(AudioStream stream);                       // Stop audio stream
 void SetAudioStreamVolume(AudioStream stream, float volume);    // Set volume for audio stream (1.0 is max level)
 void SetAudioStreamPitch(AudioStream stream, float pitch);      // Set pitch for audio stream (1.0 is base level)
+void SetAudioStreamBufferSizeDefault(int size);                 // Default size for new audio streams
 
 #ifdef __cplusplus
 }

+ 11 - 6
lib.mod/raylib/src/raylib.h

@@ -107,10 +107,10 @@
     #define RL_CALLOC(n,sz)     calloc(n,sz)
 #endif
 #ifndef RL_REALLOC
-    #define RL_REALLOC(n,sz)    realloc(n,sz)
+    #define RL_REALLOC(ptr,sz)  realloc(ptr,sz)
 #endif
 #ifndef RL_FREE
-    #define RL_FREE(p)          free(p)
+    #define RL_FREE(ptr)        free(ptr)
 #endif
 
 // NOTE: MSC C++ compiler does not support compound literals (C99 feature)
@@ -156,6 +156,7 @@
 #define FormatText  TextFormat
 #define SubText     TextSubtext
 #define ShowWindow  UnhideWindow
+#define LoadText    LoadFileText
 
 //----------------------------------------------------------------------------------
 // Structures Definition
@@ -949,6 +950,10 @@ RLAPI void TakeScreenshot(const char *fileName);                  // Takes a scr
 RLAPI int GetRandomValue(int min, int max);                       // Returns a random value between min and max (both included)
 
 // Files management functions
+RLAPI unsigned char *LoadFileData(const char *fileName, int *bytesRead);     // Load file data as byte array (read)
+RLAPI void SaveFileData(const char *fileName, void *data, int bytesToWrite); // Save data to file from byte array (write)
+RLAPI char *LoadFileText(const char *fileName);                   // Load text data from file (read), returns a '\0' terminated string
+RLAPI void SaveFileText(const char *fileName, char *text);        // Save text data to file (write), string must be '\0' terminated
 RLAPI bool FileExists(const char *fileName);                      // Check if file exists
 RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension
 RLAPI bool DirectoryExists(const char *dirPath);                  // Check if a directory path exists
@@ -970,8 +975,8 @@ RLAPI unsigned char *CompressData(unsigned char *data, int dataLength, int *comp
 RLAPI unsigned char *DecompressData(unsigned char *compData, int compDataLength, int *dataLength);  // Decompress data (DEFLATE algorythm)
 
 // Persistent storage management
-RLAPI void StorageSaveValue(int position, int value);             // Save integer value to storage file (to defined position)
-RLAPI int StorageLoadValue(int position);                         // Load integer value from storage file (from defined position)
+RLAPI void SaveStorageValue(int position, int value);             // Save integer value to storage file (to defined position)
+RLAPI int LoadStorageValue(int position);                         // Load integer value from storage file (from defined position)
 
 RLAPI void OpenURL(const char *url);                              // Open URL with default system browser (if available)
 
@@ -1320,9 +1325,8 @@ RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight);
 //------------------------------------------------------------------------------------
 
 // Shader loading/unloading functions
-RLAPI char *LoadText(const char *fileName);                               // Load chars array from text file
 RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName);  // Load shader from files and bind default locations
-RLAPI Shader LoadShaderCode(const char *vsCode, const char *fsCode);                  // Load shader from code strings and bind default locations
+RLAPI Shader LoadShaderCode(const char *vsCode, const char *fsCode);      // Load shader from code strings and bind default locations
 RLAPI void UnloadShader(Shader shader);                                   // Unload shader from GPU memory (VRAM)
 
 RLAPI Shader GetShaderDefault(void);                                      // Get default shader
@@ -1428,6 +1432,7 @@ RLAPI bool IsAudioStreamPlaying(AudioStream stream);                  // Check i
 RLAPI void StopAudioStream(AudioStream stream);                       // Stop audio stream
 RLAPI void SetAudioStreamVolume(AudioStream stream, float volume);    // Set volume for audio stream (1.0 is max level)
 RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch);      // Set pitch for audio stream (1.0 is base level)
+RLAPI void SetAudioStreamBufferSizeDefault(int size);                 // Default size for new audio streams
 
 //------------------------------------------------------------------------------------
 // Network (Module: network)

+ 15 - 7
lib.mod/raylib/src/raymath.h

@@ -268,6 +268,14 @@ RMDEF Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount)
     return result;
 }
 
+// Rotate Vector by float in Degrees.
+RMDEF Vector2 Vector2Rotate(Vector2 v, float degs)
+{
+    float rads = degs*DEG2RAD;
+    Vector2 result = {v.x * cosf(rads) - v.y * sinf(rads) , v.x * sinf(rads) + v.y * cosf(rads) };
+    return result;
+}
+
 //----------------------------------------------------------------------------------
 // Module Functions Definition - Vector3 math
 //----------------------------------------------------------------------------------
@@ -1135,8 +1143,8 @@ RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
     else if (cosHalfTheta > 0.95f) result = QuaternionNlerp(q1, q2, amount);
     else
     {
-        float halfTheta = (float) acos(cosHalfTheta);
-        float sinHalfTheta = (float) sqrt(1.0f - cosHalfTheta*cosHalfTheta);
+        float halfTheta = acosf(cosHalfTheta);
+        float sinHalfTheta = sqrtf(1.0f - cosHalfTheta*cosHalfTheta);
 
         if (fabs(sinHalfTheta) < 0.001f)
         {
@@ -1191,7 +1199,7 @@ RMDEF Quaternion QuaternionFromMatrix(Matrix mat)
 
     if (trace > 0.0f)
     {
-        float s = (float)sqrt(trace + 1)*2.0f;
+        float s = sqrtf(trace + 1)*2.0f;
         float invS = 1.0f/s;
 
         result.w = s*0.25f;
@@ -1215,7 +1223,7 @@ RMDEF Quaternion QuaternionFromMatrix(Matrix mat)
         }
         else if (m11 > m22)
         {
-            float s = (float)sqrt(1.0f + m11 - m00 - m22)*2.0f;
+            float s = sqrtf(1.0f + m11 - m00 - m22)*2.0f;
             float invS = 1.0f/s;
 
             result.w = (mat.m8 - mat.m2)*invS;
@@ -1225,7 +1233,7 @@ RMDEF Quaternion QuaternionFromMatrix(Matrix mat)
         }
         else
         {
-            float s = (float)sqrt(1.0f + m22 - m00 - m11)*2.0f;
+            float s = sqrtf(1.0f + m22 - m00 - m11)*2.0f;
             float invS = 1.0f/s;
 
             result.w = (mat.m1 - mat.m4)*invS;
@@ -1317,8 +1325,8 @@ RMDEF void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle
     Vector3 resAxis = { 0.0f, 0.0f, 0.0f };
     float resAngle = 0.0f;
 
-    resAngle = 2.0f*(float)acos(q.w);
-    float den = (float)sqrt(1.0f - q.w*q.w);
+    resAngle = 2.0f*acosf(q.w);
+    float den = sqrtf(1.0f - q.w*q.w);
 
     if (den > 0.0001f)
     {

+ 48 - 74
lib.mod/raylib/src/rlgl.h

@@ -76,15 +76,7 @@
     #endif
 
     // Support TRACELOG macros
-    #if defined(RLGL_SUPPORT_TRACELOG)
-        #define TRACELOG(level, ...) TraceLog(level, __VA_ARGS__)
-
-        #if defined(RLGL_SUPPORT_TRACELOG_DEBUG)
-            #define TRACELOGD(...) TraceLog(LOG_DEBUG, __VA_ARGS__)
-        #else
-            #define TRACELOGD(...) (void)0
-        #endif
-    #else
+    #if !defined(TRACELOG)
         #define TRACELOG(level, ...) (void)0
         #define TRACELOGD(...) (void)0
     #endif
@@ -554,9 +546,8 @@ RLAPI void rlUnloadMesh(Mesh mesh);                                       // Unl
 // NOTE: This functions are useless when using OpenGL 1.1
 //------------------------------------------------------------------------------------
 // Shader loading/unloading functions
-RLAPI char *LoadText(const char *fileName);                               // Load chars array from text file
 RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName);  // Load shader from files and bind default locations
-RLAPI Shader LoadShaderCode(const char *vsCode, const char *fsCode);                  // Load shader from code strings and bind default locations
+RLAPI Shader LoadShaderCode(const char *vsCode, const char *fsCode);      // Load shader from code strings and bind default locations
 RLAPI void UnloadShader(Shader shader);                                   // Unload shader from GPU memory (VRAM)
 
 RLAPI Shader GetShaderDefault(void);                                      // Get default shader
@@ -596,7 +587,7 @@ RLAPI void ToggleVrMode(void);                          // Enable/Disable VR exp
 RLAPI void BeginVrDrawing(void);                        // Begin VR simulator stereo rendering
 RLAPI void EndVrDrawing(void);                          // End VR simulator stereo rendering
 
-RLAPI void TRACELOG(int msgType, const char *text, ...);      // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
+RLAPI char *LoadFileText(const char *fileName);         // Load chars array from text file
 RLAPI int GetPixelDataSize(int width, int height, int format);// Get pixel data size in bytes (image or texture)
 #endif
 
@@ -614,21 +605,19 @@ RLAPI int GetPixelDataSize(int width, int height, int format);// Get pixel data
 
 #if defined(RLGL_IMPLEMENTATION)
 
-#if !defined(RLGL_STANDALONE)
+#if defined(RLGL_STANDALONE)
+    #include <stdio.h>              // Required for: fopen(), fseek(), fread(), fclose() [LoadFileText]
+#else
     // Check if config flags have been externally provided on compilation line
     #if !defined(EXTERNAL_CONFIG_FLAGS)
         #include "config.h"         // Defines module configuration flags
     #endif
+    #include "raymath.h"            // Required for: Vector3 and Matrix functions
 #endif
 
-#include <stdlib.h>                 // Required for: malloc(), free(), fabs()
-#include <stdio.h>                  // Required for: fopen(), fseek(), fread(), fclose() [LoadText]
+#include <stdlib.h>                 // Required for: malloc(), free()
 #include <string.h>                 // Required for: strcmp(), strlen() [Used in rlglInit(), on extensions loading]
-#include <math.h>                   // Required for: atan2f()
-
-#if !defined(RLGL_STANDALONE)
-    #include "raymath.h"            // Required for: Vector3 and Matrix functions
-#endif
+#include <math.h>                   // Required for: atan2f(), fabs()
 
 #if defined(GRAPHICS_API_OPENGL_11)
     #if defined(__APPLE__)
@@ -676,10 +665,6 @@ RLAPI int GetPixelDataSize(int width, int height, int format);// Get pixel data
     #include <GLES2/gl2ext.h>           // OpenGL ES 2.0 extensions library
 #endif
 
-#if defined(RLGL_STANDALONE)
-    #include <stdarg.h>                 // Required for: va_list, va_start(), vfprintf(), va_end() [Used in TraceLog()]
-#endif
-
 //----------------------------------------------------------------------------------
 // Defines and Macros
 //----------------------------------------------------------------------------------
@@ -2997,38 +2982,6 @@ Shader GetShaderDefault(void)
 #endif
 }
 
-// Load text data from file
-// NOTE: text chars array should be freed manually
-char *LoadText(const char *fileName)
-{
-    FILE *textFile = NULL;
-    char *text = NULL;
-
-    if (fileName != NULL)
-    {
-        textFile = fopen(fileName,"rt");
-
-        if (textFile != NULL)
-        {
-            fseek(textFile, 0, SEEK_END);
-            int size = ftell(textFile);
-            fseek(textFile, 0, SEEK_SET);
-
-            if (size > 0)
-            {
-                text = (char *)RL_MALLOC(sizeof(char)*(size + 1));
-                int count = fread(text, sizeof(char), size, textFile);
-                text[count] = '\0';
-            }
-
-            fclose(textFile);
-        }
-        else TRACELOG(LOG_WARNING, "[%s] Text file could not be opened", fileName);
-    }
-
-    return text;
-}
-
 // Load shader from files and bind default locations
 // NOTE: If shader string is NULL, using default vertex/fragment shaders
 Shader LoadShader(const char *vsFileName, const char *fsFileName)
@@ -3040,8 +2993,8 @@ Shader LoadShader(const char *vsFileName, const char *fsFileName)
     char *vShaderStr = NULL;
     char *fShaderStr = NULL;
 
-    if (vsFileName != NULL) vShaderStr = LoadText(vsFileName);
-    if (fsFileName != NULL) fShaderStr = LoadText(fsFileName);
+    if (vsFileName != NULL) vShaderStr = LoadFileText(vsFileName);
+    if (fsFileName != NULL) fShaderStr = LoadFileText(fsFileName);
 
     shader = LoadShaderCode(vShaderStr, fShaderStr);
 
@@ -3664,7 +3617,7 @@ void SetVrConfiguration(VrDeviceInfo hmd, Shader distortion)
 
     // Compute distortion scale parameters
     // NOTE: To get lens max radius, lensShift must be normalized to [-1..1]
-    float lensRadius = (float)fabs(-1.0f - 4.0f*lensShift);
+    float lensRadius = fabsf(-1.0f - 4.0f*lensShift);
     float lensRadiusSq = lensRadius*lensRadius;
     float distortionScale = hmd.lensDistortionValues[0] +
                             hmd.lensDistortionValues[1]*lensRadiusSq +
@@ -4645,27 +4598,48 @@ static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight)
 #endif
 
 #if defined(RLGL_STANDALONE)
-// Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
-void TraceLog(int msgType, const char *text, ...)
+// Load text data from file, returns a '\0' terminated string
+// NOTE: text chars array should be freed manually
+char *LoadFileText(const char *fileName)
 {
-    va_list args;
-    va_start(args, text);
+    char *text = NULL;
 
-    switch (msgType)
+    if (fileName != NULL)
     {
-        case LOG_INFO: fprintf(stdout, "INFO: "); break;
-        case LOG_ERROR: fprintf(stdout, "ERROR: "); break;
-        case LOG_WARNING: fprintf(stdout, "WARNING: "); break;
-        case LOG_DEBUG: fprintf(stdout, "DEBUG: "); break;
-        default: break;
-    }
+        FILE *textFile = fopen(fileName, "rt");
+
+        if (textFile != NULL)
+        {
+            // WARNING: When reading a file as 'text' file,
+            // text mode causes carriage return-linefeed translation...
+            // ...but using fseek() should return correct byte-offset
+            fseek(textFile, 0, SEEK_END);
+            int size = ftell(textFile);
+            fseek(textFile, 0, SEEK_SET);
+
+            if (size > 0)
+            {
+                text = (char *)RL_MALLOC(sizeof(char)*(size + 1));
+                int count = fread(text, sizeof(char), size, textFile);
 
-    vfprintf(stdout, text, args);
-    fprintf(stdout, "\n");
+                // WARNING: \r\n is converted to \n on reading, so,
+                // read bytes count gets reduced by the number of lines
+                if (count < size) text = RL_REALLOC(text, count + 1);
 
-    va_end(args);
+                // Zero-terminate the string
+                text[count] = '\0';
+                
+                TRACELOG(LOG_INFO, "[%s] Text file loaded successfully", fileName);
+            }
+            else TRACELOG(LOG_WARNING, "[%s] Text file could not be read", fileName);
+
+            fclose(textFile);
+        }
+        else TRACELOG(LOG_WARNING, "[%s] Text file could not be opened", fileName);
+    }
+    else TRACELOG(LOG_WARNING, "File name provided is not valid");
 
-    if (msgType == LOG_ERROR) exit(1);
+    return text;
 }
 
 // Get pixel data size in bytes (image or texture)

+ 0 - 2024
lib.mod/raylib/src/rnet.c.review

@@ -1,2024 +0,0 @@
-/*********************************************************************************************
-*
-*   rnet - A simple and easy-to-use network module for raylib
-*
-*   FEATURES:
-*       - Provides a simple and (hopefully) easy to use wrapper around the Berkeley socket API
-*
-*   DEPENDENCIES:
-*       raylib.h    - TraceLog
-*       rnet.h      - platform-specific network includes
-*
-*   CONTRIBUTORS:
-*       Jak Barnes (github: @syphonx) (Feb. 2019) - Initial version
-*
-*
-*   LICENSE: zlib/libpng
-*
-*   Copyright (c) 2019 Jak Barnes (github: @syphonx) and Ramon Santamaria (@raysan5)
-*
-*   This software is provided "as-is", without any express or implied warranty. In no event
-*   will the authors be held liable for any damages arising from the use of this software.
-*
-*   Permission is granted to anyone to use this software for any purpose, including commercial
-*   applications, and to alter it and redistribute it freely, subject to the following restrictions:
-*
-*     1. The origin of this software must not be misrepresented; you must not claim that you
-*     wrote the original software. If you use this software in a product, an acknowledgment
-*     in the product documentation would be appreciated but is not required.
-*
-*     2. Altered source versions must be plainly marked as such, and must not be misrepresented
-*     as being the original software.
-*
-*     3. This notice may not be removed or altered from any source distribution.
-*
-**********************************************************************************************/
-
-//----------------------------------------------------------------------------------
-// Check if config flags have been externally provided on compilation line
-//----------------------------------------------------------------------------------
-
-#include "rnet.h"
-
-#include "raylib.h"
-
-#include <assert.h>         // Required for: assert()
-#include <stdio.h>          // Required for: FILE, fopen(), fclose(), fread()
-#include <stdlib.h>         // Required for: malloc(), free()
-#include <string.h>         // Required for: strcmp(), strncmp()
-
-//----------------------------------------------------------------------------------
-// Module defines
-//----------------------------------------------------------------------------------
-
-#define NET_DEBUG_ENABLED (1)
-
-//----------------------------------------------------------------------------------
-// Types and Structures Definition
-//----------------------------------------------------------------------------------
-
-typedef struct _SocketAddress
-{
-    struct sockaddr address;
-} _SocketAddress;
-
-typedef struct _SocketAddressIPv4
-{
-    struct sockaddr_in address;
-} _SocketAddressIPv4;
-
-typedef struct _SocketAddressIPv6
-{
-    struct sockaddr_in6 address;
-} _SocketAddressIPv6;
-
-typedef struct _SocketAddressStorage
-{
-    struct sockaddr_storage address;
-} _SocketAddressStorage;
-
-typedef struct _AddressInformation
-{
-    struct addrinfo addr;
-} _AddressInformation;
-
-
-
-//----------------------------------------------------------------------------------
-// Global module forward declarations
-//----------------------------------------------------------------------------------
-
-static void PrintSocket(struct sockaddr_storage *addr, const int family, const int socktype, const int protocol);
-static const char *SocketAddressToString(struct sockaddr_storage *sockaddr);
-static bool IsIPv4Address(const char *ip);
-static bool IsIPv6Address(const char *ip);
-static void *GetSocketPortPtr(struct sockaddr_storage *sa);
-static void *GetSocketAddressPtr(struct sockaddr_storage *sa);
-static bool IsSocketValid(Socket *sock);
-static void SocketSetLastError(int err);
-static int SocketGetLastError();
-static char *SocketGetLastErrorString();
-static char *SocketErrorCodeToString(int err);
-static bool SocketSetDefaults(SocketConfig *config);
-static bool InitSocket(Socket *sock, struct addrinfo *addr);
-static bool CreateSocket(SocketConfig *config, SocketResult *outresult);
-static bool SocketSetBlocking(Socket *sock);
-static bool SocketSetNonBlocking(Socket *sock);
-static bool SocketSetOptions(SocketConfig *config, Socket *sock);
-static void SocketSetHints(SocketConfig *config, struct addrinfo *hints);
-
-//----------------------------------------------------------------------------------
-// Global module implementation
-//----------------------------------------------------------------------------------
-
-// Print socket information
-static void PrintSocket(struct sockaddr_storage *addr, const int family, const int socktype, const int protocol)
-{
-    switch (family)
-    {
-        case AF_UNSPEC: { TraceLog(LOG_DEBUG, "\tFamily: Unspecified");
-        }
-        break;
-        case AF_INET:
-        {
-            TraceLog(LOG_DEBUG, "\tFamily: AF_INET (IPv4)");
-            TraceLog(LOG_INFO, "\t- IPv4 address %s", SocketAddressToString(addr));
-        }
-        break;
-        case AF_INET6:
-        {
-            TraceLog(LOG_DEBUG, "\tFamily: AF_INET6 (IPv6)");
-            TraceLog(LOG_INFO, "\t- IPv6 address %s", SocketAddressToString(addr));
-        }
-        break;
-        case AF_NETBIOS:
-        {
-            TraceLog(LOG_DEBUG, "\tFamily: AF_NETBIOS (NetBIOS)");
-        }
-        break;
-        default: { TraceLog(LOG_DEBUG, "\tFamily: Other %ld", family);
-        }
-        break;
-    }
-    TraceLog(LOG_DEBUG, "\tSocket type:");
-    switch (socktype)
-    {
-        case 0: TraceLog(LOG_DEBUG, "\t- Unspecified"); break;
-        case SOCK_STREAM:
-            TraceLog(LOG_DEBUG, "\t- SOCK_STREAM (stream)");
-            break;
-        case SOCK_DGRAM:
-            TraceLog(LOG_DEBUG, "\t- SOCK_DGRAM (datagram)");
-            break;
-        case SOCK_RAW: TraceLog(LOG_DEBUG, "\t- SOCK_RAW (raw)"); break;
-        case SOCK_RDM:
-            TraceLog(LOG_DEBUG, "\t- SOCK_RDM (reliable message datagram)");
-            break;
-        case SOCK_SEQPACKET:
-            TraceLog(LOG_DEBUG, "\t- SOCK_SEQPACKET (pseudo-stream packet)");
-            break;
-        default: TraceLog(LOG_DEBUG, "\t- Other %ld", socktype); break;
-    }
-    TraceLog(LOG_DEBUG, "\tProtocol:");
-    switch (protocol)
-    {
-        case 0: TraceLog(LOG_DEBUG, "\t- Unspecified"); break;
-        case IPPROTO_TCP: TraceLog(LOG_DEBUG, "\t- IPPROTO_TCP (TCP)"); break;
-        case IPPROTO_UDP: TraceLog(LOG_DEBUG, "\t- IPPROTO_UDP (UDP)"); break;
-        default: TraceLog(LOG_DEBUG, "\t- Other %ld", protocol); break;
-    }
-}
-
-// Convert network ordered socket address to human readable string (127.0.0.1)
-static const char *SocketAddressToString(struct sockaddr_storage *sockaddr)
-{
-    //static const char* ipv6[INET6_ADDRSTRLEN];
-    assert(sockaddr != NULL);
-    assert(sockaddr->ss_family == AF_INET || sockaddr->ss_family == AF_INET6);
-    switch (sockaddr->ss_family)
-    {
-        case AF_INET:
-        {
-            //struct sockaddr_in *s = ((struct sockaddr_in *) sockaddr);
-            //return inet_ntop(AF_INET, &s->sin_addr, ipv6, INET_ADDRSTRLEN);       // TODO.
-        }
-        break;
-        case AF_INET6:
-        {
-            //struct sockaddr_in6 *s = ((struct sockaddr_in6 *) sockaddr);
-            //return inet_ntop(AF_INET6, &s->sin6_addr, ipv6, INET6_ADDRSTRLEN);    // TODO.
-        }
-        break;
-    }
-    return NULL;
-}
-
-// Check if the null terminated string ip is a valid IPv4 address
-static bool IsIPv4Address(const char *ip)
-{
-    /*
-    struct sockaddr_in sa;
-    int result = inet_pton(AF_INET, ip, &(sa.sin_addr));    // TODO.
-    return (result != 0);
-    */
-    return false;
-}
-
-// Check if the null terminated string ip is a valid IPv6 address
-static bool IsIPv6Address(const char *ip)
-{
-    /*
-    struct sockaddr_in6 sa;
-    int result = inet_pton(AF_INET6, ip, &(sa.sin6_addr));    // TODO.
-    return result != 0;
-    */
-    return false;
-}
-
-// Return a pointer to the port from the correct address family (IPv4, or IPv6)
-static void *GetSocketPortPtr(struct sockaddr_storage *sa)
-{
-    if (sa->ss_family == AF_INET)
-    {
-        return &(((struct sockaddr_in *) sa)->sin_port);
-    }
-
-    return &(((struct sockaddr_in6 *) sa)->sin6_port);
-}
-
-// Return a pointer to the address from the correct address family (IPv4, or IPv6)
-static void *GetSocketAddressPtr(struct sockaddr_storage *sa)
-{
-    if (sa->ss_family == AF_INET)
-    {
-        return &(((struct sockaddr_in *) sa)->sin_addr);
-    }
-
-    return &(((struct sockaddr_in6 *) sa)->sin6_addr);
-}
-
-// Is the socket in a valid state?
-static bool IsSocketValid(Socket *sock)
-{
-    if (sock != NULL)
-    {
-        return (sock->channel != INVALID_SOCKET);
-    }
-    return false;
-}
-
-// Sets the error code that can be retrieved through the WSAGetLastError function.
-static void SocketSetLastError(int err)
-{
-#if defined(_WIN32)
-    WSASetLastError(err);
-#else
-    errno = err;
-#endif
-}
-
-// Returns the error status for the last Sockets operation that failed
-static int SocketGetLastError()
-{
-#if defined(_WIN32)
-    return WSAGetLastError();
-#else
-    return errno;
-#endif
-}
-
-// Returns a human-readable string representing the last error message
-static char *SocketGetLastErrorString()
-{
-    return SocketErrorCodeToString(SocketGetLastError());
-}
-
-// Returns a human-readable string representing the error message (err)
-static char *SocketErrorCodeToString(int err)
-{
-#if defined(_WIN32)
-    static char gaiStrErrorBuffer[GAI_STRERROR_BUFFER_SIZE];
-    sprintf(gaiStrErrorBuffer, "%s", gai_strerror(err));
-    return gaiStrErrorBuffer;
-#else
-    return gai_strerror(err);
-#endif
-}
-
-// Set the defaults in the supplied SocketConfig if they're not already set
-static bool SocketSetDefaults(SocketConfig *config)
-{
-    if (config->backlog_size == 0)
-    {
-        config->backlog_size = SOCKET_MAX_QUEUE_SIZE;
-    }
-
-    return true;
-}
-
-// Create the socket channel
-static bool InitSocket(Socket *sock, struct addrinfo *addr)
-{
-    switch (sock->type)
-    {
-        case SOCKET_TCP:
-            if (addr->ai_family == AF_INET)
-            {
-                sock->channel = socket(AF_INET, SOCK_STREAM, 0);
-            }
-            else
-            {
-                sock->channel = socket(AF_INET6, SOCK_STREAM, 0);
-            }
-            break;
-        case SOCKET_UDP:
-            if (addr->ai_family == AF_INET)
-            {
-                sock->channel = socket(AF_INET, SOCK_DGRAM, 0);
-            }
-            else
-            {
-                sock->channel = socket(AF_INET6, SOCK_DGRAM, 0);
-            }
-            break;
-        default: 
-            TraceLog(LOG_WARNING, "Invalid socket type specified.");
-            break;
-    }
-    return IsSocketValid(sock);
-}
-
-//    CreateSocket() - Interally called by CreateSocket()
-//
-//    This here is the bread and butter of the socket API, This function will
-//    attempt to open a socket, bind and listen to it based on the config passed in
-//
-//    SocketConfig* config - Configuration for which socket to open
-//    SocketResult* result - The results of this function (if any, including errors)
-//
-//    e.g.
-//    SocketConfig server_config = {                SocketConfig client_config = {
-//        .host        = "127.0.0.1",                .host = "127.0.0.1",
-//        .port        = 8080,                    .port = 8080,
-//        .server      = true,                };
-//        .nonblocking = true,
-//    };
-//    SocketResult server_res;                SocketResult client_res;
-static bool CreateSocket(SocketConfig *config, SocketResult *outresult)
-{
-    bool             success = true;
-    int              addrstatus;
-    struct addrinfo  hints; // Address flags (IPV4, IPV6, UDP?)
-    struct addrinfo *res;   // A pointer to the resulting address list
-    outresult->socket->channel = INVALID_SOCKET;
-    outresult->status          = RESULT_FAILURE;
-
-    // Set the socket type
-    outresult->socket->type = config->type;
-
-    //    Set the hints based on information in the config
-    //
-    //    AI_CANONNAME    Causes the ai_canonname of the result to the filled  out with the host's canonical (real) name.
-    //    AI_PASSIVE:        Causes the result's IP address to be filled out with INADDR_ANY (IPv4)or in6addr_any (IPv6);
-    //    Note:    This causes a subsequent call to bind() to auto-fill the IP address
-    //            of the struct sockaddr with the address of the current host.
-    //
-    SocketSetHints(config, &hints);
-
-    // Populate address information
-    addrstatus = getaddrinfo(config->host, // e.g. "www.example.com" or IP (Can be null if AI_PASSIVE flag is set
-                             config->port, // e.g. "http" or port number
-                             &hints,       // e.g. SOCK_STREAM/SOCK_DGRAM
-                             &res          // The struct to populate
-    );
-
-    // Did we succeed?
-    if (addrstatus != 0)
-    {
-        outresult->socket->status = SocketGetLastError();
-        TraceLog(LOG_WARNING,
-                 "Socket Error: %s",
-                 SocketErrorCodeToString(outresult->socket->status));
-        SocketSetLastError(0);
-        TraceLog(LOG_WARNING,
-                 "Failed to get resolve host %s:%s: %s",
-                 config->host,
-                 config->port,
-                 SocketGetLastErrorString());
-        return (success = false);
-    }
-    else
-    {
-        char hoststr[NI_MAXHOST];
-        char portstr[NI_MAXSERV];
-        //socklen_t client_len = sizeof(struct sockaddr_storage);
-        //int rc = getnameinfo((struct sockaddr *) res->ai_addr, client_len, hoststr, sizeof(hoststr), portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV);
-        TraceLog(LOG_INFO, "Successfully resolved host %s:%s", hoststr, portstr);
-    }
-
-    // Walk the address information linked-list
-    struct addrinfo *it;
-    for (it = res; it != NULL; it = it->ai_next)
-    {
-        // Initialise the socket
-        if (!InitSocket(outresult->socket, it))
-        {
-            outresult->socket->status = SocketGetLastError();
-            TraceLog(LOG_WARNING,
-                     "Socket Error: %s",
-                     SocketErrorCodeToString(outresult->socket->status));
-            SocketSetLastError(0);
-            continue;
-        }
-
-        // Set socket options
-        if (!SocketSetOptions(config, outresult->socket))
-        {
-            outresult->socket->status = SocketGetLastError();
-            TraceLog(LOG_WARNING,
-                     "Socket Error: %s",
-                     SocketErrorCodeToString(outresult->socket->status));
-            SocketSetLastError(0);
-            freeaddrinfo(res);
-            return (success = false);
-        }
-    }
-
-    if (!IsSocketValid(outresult->socket))
-    {
-        outresult->socket->status = SocketGetLastError();
-        TraceLog(
-            LOG_WARNING, "Socket Error: %s", SocketErrorCodeToString(outresult->status));
-        SocketSetLastError(0);
-        freeaddrinfo(res);
-        return (success = false);
-    }
-
-    if (success)
-    {
-        outresult->status         = RESULT_SUCCESS;
-        outresult->socket->ready  = 0;
-        outresult->socket->status = 0;
-        if (!(config->type == SOCKET_UDP))
-        {
-            outresult->socket->isServer = config->server;
-        }
-        switch (res->ai_addr->sa_family)
-        {
-            case AF_INET:
-            {
-                outresult->socket->addripv4 = (struct _SocketAddressIPv4 *) RNET_MALLOC(
-                    sizeof(*outresult->socket->addripv4));
-                if (outresult->socket->addripv4 != NULL)
-                {
-                    memset(outresult->socket->addripv4, 0,
-                           sizeof(*outresult->socket->addripv4));
-                    if (outresult->socket->addripv4 != NULL)
-                    {
-                        memcpy(&outresult->socket->addripv4->address,
-                               (struct sockaddr_in *) res->ai_addr, sizeof(struct sockaddr_in));
-                        outresult->socket->isIPv6 = false;
-                        char      hoststr[NI_MAXHOST];
-                        char      portstr[NI_MAXSERV];
-                        socklen_t client_len = sizeof(struct sockaddr_storage);
-                        getnameinfo(
-                            (struct sockaddr *) &outresult->socket->addripv4->address, client_len, hoststr, sizeof(hoststr), portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV);
-                        TraceLog(LOG_INFO, "Socket address set to %s:%s", hoststr, portstr);
-                    }
-                }
-            }
-            break;
-            case AF_INET6:
-            {
-                outresult->socket->addripv6 = (struct _SocketAddressIPv6 *) RNET_MALLOC(
-                    sizeof(*outresult->socket->addripv6));
-                if (outresult->socket->addripv6 != NULL)
-                {
-                    memset(outresult->socket->addripv6, 0,
-                           sizeof(*outresult->socket->addripv6));
-                    if (outresult->socket->addripv6 != NULL)
-                    {
-                        memcpy(&outresult->socket->addripv6->address,
-                               (struct sockaddr_in6 *) res->ai_addr, sizeof(struct sockaddr_in6));
-                        outresult->socket->isIPv6 = true;
-                        char      hoststr[NI_MAXHOST];
-                        char      portstr[NI_MAXSERV];
-                        socklen_t client_len = sizeof(struct sockaddr_storage);
-                        getnameinfo(
-                            (struct sockaddr *) &outresult->socket->addripv6->address, client_len, hoststr, sizeof(hoststr), portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV);
-                        TraceLog(LOG_INFO, "Socket address set to %s:%s", hoststr, portstr);
-                    }
-                }
-            }
-            break;
-        }
-    }
-    freeaddrinfo(res);
-    return success;
-}
-
-// Set the state of the Socket sock to blocking
-static bool SocketSetBlocking(Socket *sock)
-{
-    bool ret = true;
-#if defined(_WIN32)
-    unsigned long mode = 0;
-    ret                = ioctlsocket(sock->channel, FIONBIO, &mode);
-#else
-    const int flags = fcntl(sock->channel, F_GETFL, 0);
-    if (!(flags & O_NONBLOCK))
-    {
-        TraceLog(LOG_DEBUG, "Socket was already in blocking mode");
-        return ret;
-    }
-
-    ret = (0 == fcntl(sock->channel, F_SETFL, (flags ^ O_NONBLOCK)));
-#endif
-    return ret;
-}
-
-// Set the state of the Socket sock to non-blocking
-static bool SocketSetNonBlocking(Socket *sock)
-{
-    bool ret = true;
-#if defined(_WIN32)
-    unsigned long mode = 1;
-    ret                = ioctlsocket(sock->channel, FIONBIO, &mode);
-#else
-    const int flags = fcntl(sock->channel, F_GETFL, 0);
-    if ((flags & O_NONBLOCK))
-    {
-        TraceLog(LOG_DEBUG, "Socket was already in non-blocking mode");
-        return ret;
-    }
-    ret = (0 == fcntl(sock->channel, F_SETFL, (flags | O_NONBLOCK)));
-#endif
-    return ret;
-}
-
-// Set options specified in SocketConfig to Socket sock
-static bool SocketSetOptions(SocketConfig *config, Socket *sock)
-{
-    for (int i = 0; i < SOCKET_MAX_SOCK_OPTS; i++)
-    {
-        SocketOpt *opt = &config->sockopts[i];
-        if (opt->id == 0)
-        {
-            break;
-        }
-
-        if (setsockopt(sock->channel, SOL_SOCKET, opt->id, opt->value, opt->valueLen) < 0)
-        {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-// Set "hints" in an addrinfo struct, to be passed to getaddrinfo.
-static void SocketSetHints(SocketConfig *config, struct addrinfo *hints)
-{
-    if (config == NULL || hints == NULL)
-    {
-        return;
-    }
-    memset(hints, 0, sizeof(*hints));
-
-    // Check if the ip supplied in the config is a valid ipv4 ip ipv6 address
-    if (IsIPv4Address(config->host))
-    {
-        hints->ai_family = AF_INET;
-        hints->ai_flags |= AI_NUMERICHOST;
-    }
-    else
-    {
-        if (IsIPv6Address(config->host))
-        {
-            hints->ai_family = AF_INET6;
-            hints->ai_flags |= AI_NUMERICHOST;
-        }
-        else
-        {
-            hints->ai_family = AF_UNSPEC;
-        }
-    }
-
-    if (config->type == SOCKET_UDP)
-    {
-        hints->ai_socktype = SOCK_DGRAM;
-    }
-    else
-    {
-        hints->ai_socktype = SOCK_STREAM;
-    }
-
-    // Set passive unless UDP client
-    if (!(config->type == SOCKET_UDP) || config->server)
-    {
-        hints->ai_flags = AI_PASSIVE;
-    }
-}
-
-//----------------------------------------------------------------------------------
-// Module implementation
-//----------------------------------------------------------------------------------
-
-//    Initialise the network (requires for windows platforms only)
-bool InitNetwork()
-{
-#if defined(_WIN32)
-    WORD    wVersionRequested;
-    WSADATA wsaData;
-    int     err;
-
-    wVersionRequested = MAKEWORD(2, 2);
-    err               = WSAStartup(wVersionRequested, &wsaData);
-    if (err != 0)
-    {
-        TraceLog(LOG_WARNING, "WinSock failed to initialise.");
-        return false;
-    }
-    else
-    {
-        TraceLog(LOG_INFO, "WinSock initialised.");
-    }
-
-    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
-    {
-        TraceLog(LOG_WARNING, "WinSock failed to initialise.");
-        WSACleanup();
-        return false;
-    }
-
-    return true;
-#else
-    return true;
-#endif
-}
-
-//    Cleanup, and close the network
-void CloseNetwork()
-{
-#if defined(_WIN32)
-    WSACleanup();
-#endif
-}
-
-//    Protocol-independent name resolution from an address to an ANSI host name
-//    and from a port number to the ANSI service name.
-//
-//    The flags parameter can be used to customize processing of the getnameinfo function
-//
-//    The following flags are available:
-//
-//    NAME_INFO_DEFAULT        0x00    // No flags set
-//    NAME_INFO_NOFQDN        0x01    // Only return nodename portion for local hosts
-//    NAME_INFO_NUMERICHOST    0x02    // Return numeric form of the host's address
-//    NAME_INFO_NAMEREQD        0x04    // Error if the host's name not in DNS
-//    NAME_INFO_NUMERICSERV    0x08    // Return numeric form of the service (port #)
-//    NAME_INFO_DGRAM            0x10    // Service is a datagram service
-void ResolveIP(const char *ip, const char *port, int flags, char *host, char *serv)
-{
-    // Variables
-    int              status; // Status value to return (0) is success
-    struct addrinfo  hints;  // Address flags (IPV4, IPV6, UDP?)
-    struct addrinfo *res;    // A pointer to the resulting address list
-
-    // Set the hints
-    memset(&hints, 0, sizeof hints);
-    hints.ai_family = AF_UNSPEC; // Either IPv4 or IPv6 (AF_INET, AF_INET6)
-    hints.ai_protocol = 0; // Automatically select correct protocol (IPPROTO_TCP), (IPPROTO_UDP)
-
-    // Populate address information
-    status = getaddrinfo(ip,     // e.g. "www.example.com" or IP
-                         port,   // e.g. "http" or port number
-                         &hints, // e.g. SOCK_STREAM/SOCK_DGRAM
-                         &res    // The struct to populate
-    );
-
-    // Did we succeed?
-    if (status != 0)
-    {
-        TraceLog(LOG_WARNING, "Failed to get resolve host %s:%s: %s", ip, port, gai_strerror(errno));
-    }
-    else
-    {
-        TraceLog(LOG_DEBUG, "Resolving... %s::%s", ip, port);
-    }
-
-    // Attempt to resolve network byte order ip to hostname
-    switch (res->ai_family)
-    {
-        case AF_INET:
-            status = getnameinfo(&*((struct sockaddr *) res->ai_addr),
-                                 sizeof(*((struct sockaddr_in *) res->ai_addr)),
-                                 host,
-                                 NI_MAXHOST,
-                                 serv,
-                                 NI_MAXSERV,
-                                 flags);
-            break;
-        case AF_INET6:
-        /*
-            status = getnameinfo(&*((struct sockaddr_in6 *) res->ai_addr),          // TODO.
-                                 sizeof(*((struct sockaddr_in6 *) res->ai_addr)),
-                                 host, NI_MAXHOST, serv, NI_MAXSERV, flags);
-        */
-            break;
-        default: break;
-    }
-
-    if (status != 0)
-    {
-        TraceLog(LOG_WARNING, "Failed to resolve ip %s: %s", ip, SocketGetLastErrorString());
-    }
-    else
-    {
-        TraceLog(LOG_DEBUG, "Successfully resolved %s::%s to %s", ip, port, host);
-    }
-
-    // Free the pointer to the data returned by addrinfo
-    freeaddrinfo(res);
-}
-
-//    Protocol-independent translation from an ANSI host name to an address
-//
-//    e.g.
-//    const char* address    = "127.0.0.1" (local address)
-//    const char* port    = "80"
-//
-//  Parameters:
-//      const char* address - A pointer to a NULL-terminated ANSI string that contains a host (node) name or a numeric host address string.
-//      const char* service - A pointer to a NULL-terminated ANSI string that contains either a service name or port number represented as a string.
-//
-//    Returns:
-//        The total amount of addresses found, -1 on error
-//
-int ResolveHost(const char *address, const char *service, int addressType, int flags, AddressInformation *outAddr)
-{
-    // Variables
-    int              status; // Status value to return (0) is success
-    struct addrinfo  hints;  // Address flags (IPV4, IPV6, UDP?)
-    struct addrinfo *res;    // will point to the results
-    struct addrinfo *iterator;
-    assert(((address != NULL || address != 0) || (service != NULL || service != 0)));
-    assert(((addressType == AF_INET) || (addressType == AF_INET6) || (addressType == AF_UNSPEC)));
-
-    // Set the hints
-    memset(&hints, 0, sizeof hints);
-    hints.ai_family = addressType; // Either IPv4 or IPv6 (ADDRESS_TYPE_IPV4, ADDRESS_TYPE_IPV6)
-    hints.ai_protocol = 0; // Automatically select correct protocol (IPPROTO_TCP), (IPPROTO_UDP)
-    hints.ai_flags = flags;
-    assert((hints.ai_addrlen == 0) || (hints.ai_addrlen == 0));
-    assert((hints.ai_canonname == 0) || (hints.ai_canonname == 0));
-    assert((hints.ai_addr == 0) || (hints.ai_addr == 0));
-    assert((hints.ai_next == 0) || (hints.ai_next == 0));
-
-    // When the address is NULL, populate the IP for me
-    if (address == NULL)
-    {
-        if ((hints.ai_flags & AI_PASSIVE) == 0)
-        {
-            hints.ai_flags |= AI_PASSIVE;
-        }
-    }
-
-    TraceLog(LOG_INFO, "Resolving host...");
-
-    // Populate address information
-    status = getaddrinfo(address, // e.g. "www.example.com" or IP
-                         service, // e.g. "http" or port number
-                         &hints,  // e.g. SOCK_STREAM/SOCK_DGRAM
-                         &res     // The struct to populate
-    );
-
-    // Did we succeed?
-    if (status != 0)
-    {
-        int error = SocketGetLastError();
-        SocketSetLastError(0);
-        TraceLog(LOG_WARNING, "Failed to get resolve host: %s", SocketErrorCodeToString(error));
-        return -1;
-    }
-    else
-    {
-        TraceLog(LOG_INFO, "Successfully resolved host %s:%s", address, service);
-    }
-
-    // Calculate the size of the address information list
-    int size = 0;
-    for (iterator = res; iterator != NULL; iterator = iterator->ai_next)
-    {
-        size++;
-    }
-
-    // Validate the size is > 0, otherwise return
-    if (size <= 0)
-    {
-        TraceLog(LOG_WARNING, "Error, no addresses found.");
-        return -1;
-    }
-
-    // If not address list was allocated, allocate it dynamically with the known address size
-    if (outAddr == NULL)
-    {
-        outAddr = (AddressInformation *) RNET_MALLOC(size * sizeof(AddressInformation));
-    }
-
-    // Dynamically allocate an array of address information structs
-    if (outAddr != NULL)
-    {
-        int i;
-        for (i = 0; i < size; ++i)
-        {
-            outAddr[i] = AllocAddress();
-            if (outAddr[i] == NULL)
-            {
-                break;
-            }
-        }
-        outAddr[i] = NULL;
-        if (i != size)
-        {
-            outAddr = NULL;
-        }
-    }
-    else
-    {
-        TraceLog(LOG_WARNING,
-                 "Error, failed to dynamically allocate memory for the address list");
-        return -1;
-    }
-
-    // Copy all the address information from res into outAddrList
-    int i = 0;
-    for (iterator = res; iterator != NULL; iterator = iterator->ai_next)
-    {
-        if (i < size)
-        {
-            outAddr[i]->addr.ai_flags    = iterator->ai_flags;
-            outAddr[i]->addr.ai_family   = iterator->ai_family;
-            outAddr[i]->addr.ai_socktype = iterator->ai_socktype;
-            outAddr[i]->addr.ai_protocol = iterator->ai_protocol;
-            outAddr[i]->addr.ai_addrlen  = iterator->ai_addrlen;
-            *outAddr[i]->addr.ai_addr    = *iterator->ai_addr;
-#if NET_DEBUG_ENABLED
-            TraceLog(LOG_DEBUG, "GetAddressInformation");
-            TraceLog(LOG_DEBUG, "\tFlags: 0x%x", iterator->ai_flags);
-            //PrintSocket(outAddr[i]->addr.ai_addr, outAddr[i]->addr.ai_family, outAddr[i]->addr.ai_socktype, outAddr[i]->addr.ai_protocol);
-            TraceLog(LOG_DEBUG, "Length of this sockaddr: %d", outAddr[i]->addr.ai_addrlen);
-            TraceLog(LOG_DEBUG, "Canonical name: %s", iterator->ai_canonname);
-#endif
-            i++;
-        }
-    }
-
-    // Free the pointer to the data returned by addrinfo
-    freeaddrinfo(res);
-
-    // Return the total count of addresses found
-    return size;
-}
-
-//    This here is the bread and butter of the socket API, This function will
-//    attempt to open a socket, bind and listen to it based on the config passed in
-//
-//    SocketConfig* config - Configuration for which socket to open
-//    SocketResult* result - The results of this function (if any, including errors)
-//
-//    e.g.
-//    SocketConfig server_config = {            SocketConfig client_config = {
-//        .host        = "127.0.0.1",                .host = "127.0.0.1",
-//        .port        = 8080,                    .port = 8080,
-//        .server      = true,                };
-//        .nonblocking = true,
-//    };
-//    SocketResult server_res;                SocketResult client_res;
-bool SocketCreate(SocketConfig *config, SocketResult *result)
-{
-    // Socket creation result
-    bool success = true;
-
-    // Make sure we've not received a null config or result pointer
-    if (config == NULL || result == NULL)
-    {
-        return (success = false);
-    }
-
-    // Set the defaults based on the config
-    if (!SocketSetDefaults(config))
-    {
-        TraceLog(LOG_WARNING, "Configuration Error.");
-        success = false;
-    }
-    else
-    {
-        // Create the socket
-        if (CreateSocket(config, result))
-        {
-            if (config->nonblocking)
-            {
-                SocketSetNonBlocking(result->socket);
-            }
-            else
-            {
-                SocketSetBlocking(result->socket);
-            }
-        }
-        else
-        {
-            success = false;
-        }
-    }
-    return success;
-}
-
-// Bind a socket to a local address
-// Note: The bind function is required on an unconnected socket before subsequent calls to the listen function.
-bool SocketBind(SocketConfig *config, SocketResult *result)
-{
-    bool success                       = false;
-    result->status                     = RESULT_FAILURE;
-    struct sockaddr_storage *sock_addr = NULL;
-
-    // Don't bind to a socket that isn't configured as a server
-    if (!IsSocketValid(result->socket) || !config->server)
-    {
-        TraceLog(LOG_WARNING,
-                 "Cannot bind to socket marked as \"Client\" in SocketConfig.");
-        success = false;
-    }
-    else
-    {
-        if (result->socket->isIPv6)
-        {
-            sock_addr = (struct sockaddr_storage *) &result->socket->addripv6->address;
-        }
-        else
-        {
-            sock_addr = (struct sockaddr_storage *) &result->socket->addripv4->address;
-        }
-        if (sock_addr != NULL)
-        {
-            if (bind(result->socket->channel, (struct sockaddr *) sock_addr, sizeof(*sock_addr)) != SOCKET_ERROR)
-            {
-                TraceLog(LOG_INFO, "Successfully bound socket.");
-                success = true;
-            }
-            else
-            {
-                result->socket->status = SocketGetLastError();
-                TraceLog(LOG_WARNING, "Socket Error: %s",
-                         SocketErrorCodeToString(result->socket->status));
-                SocketSetLastError(0);
-                success = false;
-            }
-        }
-    }
-    // Was the bind a success?
-    if (success)
-    {
-        result->status         = RESULT_SUCCESS;
-        result->socket->ready  = 0;
-        result->socket->status = 0;
-        socklen_t sock_len     = sizeof(*sock_addr);
-        if (getsockname(result->socket->channel, (struct sockaddr *) sock_addr, &sock_len) < 0)
-        {
-            TraceLog(LOG_WARNING, "Couldn't get socket address");
-        }
-        else
-        {
-            struct sockaddr_in *s = (struct sockaddr_in *) sock_addr;
-            // result->socket->address.host = s->sin_addr.s_addr;
-            // result->socket->address.port = s->sin_port;
-
-            //
-            result->socket->addripv4
-                = (struct _SocketAddressIPv4 *) RNET_MALLOC(sizeof(*result->socket->addripv4));
-            if (result->socket->addripv4 != NULL)
-            {
-                memset(result->socket->addripv4, 0, sizeof(*result->socket->addripv4));
-            }
-            memcpy(&result->socket->addripv4->address, (struct sockaddr_in *) &s->sin_addr, sizeof(struct sockaddr_in));
-            //
-        }
-    }
-    return success;
-}
-
-// Listens (and queues) incoming connections requests for a bound port.
-bool SocketListen(SocketConfig *config, SocketResult *result)
-{
-    bool success   = false;
-    result->status = RESULT_FAILURE;
-
-    // Don't bind to a socket that isn't configured as a server
-    if (!IsSocketValid(result->socket) || !config->server)
-    {
-        TraceLog(LOG_WARNING,
-                 "Cannot listen on socket marked as \"Client\" in SocketConfig.");
-        success = false;
-    }
-    else
-    {
-        // Don't listen on UDP sockets
-        if (!(config->type == SOCKET_UDP))
-        {
-            if (listen(result->socket->channel, config->backlog_size) != SOCKET_ERROR)
-            {
-                TraceLog(LOG_INFO, "Started listening on socket...");
-                success = true;
-            }
-            else
-            {
-                success = false;
-                result->socket->status = SocketGetLastError();
-                TraceLog(LOG_WARNING, "Socket Error: %s",
-                         SocketErrorCodeToString(result->socket->status));
-                SocketSetLastError(0);
-            }
-        }
-        else
-        {
-            TraceLog(LOG_WARNING,
-                     "Cannot listen on socket marked as \"UDP\" (datagram) in SocketConfig.");
-            success = false;
-        }
-    }
-
-    // Was the listen a success?
-    if (success)
-    {
-        result->status         = RESULT_SUCCESS;
-        result->socket->ready  = 0;
-        result->socket->status = 0;
-    }
-    return success;
-}
-
-// Connect the socket to the destination specified by "host" and "port" in SocketConfig
-bool SocketConnect(SocketConfig *config, SocketResult *result)
-{
-    bool success   = true;
-    result->status = RESULT_FAILURE;
-
-    // Only bind to sockets marked as server
-    if (config->server)
-    {
-        TraceLog(LOG_WARNING,
-                 "Cannot connect to socket marked as \"Server\" in SocketConfig.");
-        success = false;
-    }
-    else
-    {
-        if (IsIPv4Address(config->host))
-        {
-            struct sockaddr_in ip4addr;
-            ip4addr.sin_family = AF_INET;
-            unsigned long hport;
-            hport            = strtoul(config->port, NULL, 0);
-            ip4addr.sin_port = htons(hport);
-            
-            // TODO: Changed the code to avoid the usage of inet_pton and inet_ntop replacing them with getnameinfo (that should have a better support on windows).
-            
-            //inet_pton(AF_INET, config->host, &ip4addr.sin_addr);
-            int connect_result = connect(result->socket->channel, (struct sockaddr *) &ip4addr, sizeof(ip4addr));
-            if (connect_result == SOCKET_ERROR)
-            {
-                result->socket->status = SocketGetLastError();
-                SocketSetLastError(0);
-                switch (result->socket->status)
-                {
-                    case WSAEWOULDBLOCK:
-                    {
-                        success = true;
-                        break;
-                    }
-                    default:
-                    {
-                        TraceLog(LOG_WARNING, "Socket Error: %s",
-                                 SocketErrorCodeToString(result->socket->status));
-                        success = false;
-                        break;
-                    }
-                }
-            }
-            else
-            {
-                TraceLog(LOG_INFO, "Successfully connected to socket.");
-                success = true;
-            }
-        }
-        else
-        {
-            if (IsIPv6Address(config->host))
-            {
-                struct sockaddr_in6 ip6addr;
-                ip6addr.sin6_family = AF_INET6;
-                unsigned long hport;
-                hport             = strtoul(config->port, NULL, 0);
-                ip6addr.sin6_port = htons(hport);
-                //inet_pton(AF_INET6, config->host, &ip6addr.sin6_addr);    // TODO.
-                int connect_result = connect(result->socket->channel, (struct sockaddr *) &ip6addr, sizeof(ip6addr));
-                if (connect_result == SOCKET_ERROR)
-                {
-                    result->socket->status = SocketGetLastError();
-                    SocketSetLastError(0);
-                    switch (result->socket->status)
-                    {
-                        case WSAEWOULDBLOCK:
-                        {
-                            success = true;
-                            break;
-                        }
-                        default:
-                        {
-                            TraceLog(LOG_WARNING, "Socket Error: %s",
-                                     SocketErrorCodeToString(result->socket->status));
-                            success = false;
-                            break;
-                        }
-                    }
-                }
-                else
-                {
-                    TraceLog(LOG_INFO, "Successfully connected to socket.");
-                    success = true;
-                }
-            }
-        }
-    }
-
-    if (success)
-    {
-        result->status         = RESULT_SUCCESS;
-        result->socket->ready  = 0;
-        result->socket->status = 0;
-    }
-
-    return success;
-}
-
-//    Closes an existing socket
-//
-//    SocketChannel socket - The id of the socket to close
-void SocketClose(Socket *sock)
-{
-    if (sock != NULL)
-    {
-        if (sock->channel != INVALID_SOCKET)
-        {
-            closesocket(sock->channel);
-        }
-    }
-}
-
-// Returns the sockaddress for a specific socket in a generic storage struct
-SocketAddressStorage SocketGetPeerAddress(Socket *sock)
-{
-    // TODO.
-    /*
-    if (sock->isServer) return NULL;
-    if (sock->isIPv6) return sock->addripv6;
-    else return sock->addripv4;
-    */
-    
-    return NULL;
-}
-
-// Return the address-type appropriate host portion of a socket address
-char *GetSocketAddressHost(SocketAddressStorage storage)
-{
-    assert(storage->address.ss_family == AF_INET || storage->address.ss_family == AF_INET6);
-    return SocketAddressToString((struct sockaddr_storage *) storage);
-}
-
-// Return the address-type appropriate port(service) portion of a socket address
-short GetSocketAddressPort(SocketAddressStorage storage)
-{
-    //return ntohs(GetSocketPortPtr(storage));      // TODO.
-    
-    return 0;
-}
-
-//    The accept function permits an incoming connection attempt on a socket.
-//
-//    SocketChannel    listener    - The socket to listen for incoming connections on (i.e. server)
-//    SocketResult*    out            - The result of this function (if any, including errors)
-//
-//    e.g.
-//
-//    SocketResult connection;
-//    bool         connected = false;
-//    if (!connected)
-//    {
-//        if (SocketAccept(server_res.socket.channel, &connection))
-//        {
-//            connected = true;
-//        }
-//    }
-Socket *SocketAccept(Socket *server, SocketConfig *config)
-{
-    if (!server->isServer || server->type == SOCKET_UDP)
-    {
-        return NULL;
-    }
-    struct sockaddr_storage sock_addr;
-    socklen_t               sock_alen;
-    Socket *                sock;
-    sock          = AllocSocket();
-    server->ready = 0;
-    sock_alen     = sizeof(sock_addr);
-    sock->channel = accept(server->channel, (struct sockaddr *) &sock_addr, &sock_alen);
-    if (sock->channel == INVALID_SOCKET)
-    {
-        sock->status = SocketGetLastError();
-        TraceLog(LOG_WARNING, "Socket Error: %s", SocketErrorCodeToString(sock->status));
-        SocketSetLastError(0);
-        SocketClose(sock);
-        return NULL;
-    }
-    (config->nonblocking) ? SocketSetNonBlocking(sock) : SocketSetBlocking(sock);
-    sock->isServer = false;
-    sock->ready    = 0;
-    sock->type     = server->type;
-    switch (sock_addr.ss_family)
-    {
-        case AF_INET:
-        {
-            struct sockaddr_in *s = ((struct sockaddr_in *) &sock_addr);
-            sock->addripv4 = (struct _SocketAddressIPv4 *) RNET_MALLOC(sizeof(*sock->addripv4));
-            if (sock->addripv4 != NULL)
-            {
-                memset(sock->addripv4, 0, sizeof(*sock->addripv4));
-                memcpy(&sock->addripv4->address, (struct sockaddr_in *) &s->sin_addr, sizeof(struct sockaddr_in));
-                TraceLog(LOG_INFO, "Server: Got connection from %s::%hu", SocketAddressToString((struct sockaddr_storage *) s),
-                         ntohs(sock->addripv4->address.sin_port));
-            }
-        }
-        break;
-        case AF_INET6:
-        {
-            struct sockaddr_in6 *s = ((struct sockaddr_in6 *) &sock_addr);
-            sock->addripv6 = (struct _SocketAddressIPv6 *) RNET_MALLOC(sizeof(*sock->addripv6));
-            if (sock->addripv6 != NULL)
-            {
-                memset(sock->addripv6, 0, sizeof(*sock->addripv6));
-                memcpy(&sock->addripv6->address, (struct sockaddr_in6 *) &s->sin6_addr, sizeof(struct sockaddr_in6));
-                TraceLog(LOG_INFO, "Server: Got connection from %s::%hu", SocketAddressToString((struct sockaddr_storage *) s),
-                         ntohs(sock->addripv6->address.sin6_port));
-            }
-        }
-        break;
-    }
-    return sock;
-}
-
-// Verify that the channel is in the valid range
-static int ValidChannel(int channel)
-{
-    if ((channel < 0) || (channel >= SOCKET_MAX_UDPCHANNELS))
-    {
-        TraceLog(LOG_WARNING, "Invalid channel");
-        return 0;
-    }
-    return 1;
-}
-
-// Set the socket channel
-int SocketSetChannel(Socket *socket, int channel, const IPAddress *address)
-{
-    struct UDPChannel *binding;
-    if (socket == NULL)
-    {
-        TraceLog(LOG_WARNING, "Passed a NULL socket");
-        return (-1);
-    }
-    if (channel == -1)
-    {
-        for (channel = 0; channel < SOCKET_MAX_UDPCHANNELS; ++channel)
-        {
-            binding = &socket->binding[channel];
-            if (binding->numbound < SOCKET_MAX_UDPADDRESSES)
-            {
-                break;
-            }
-        }
-    }
-    else
-    {
-        if (!ValidChannel(channel))
-        {
-            return (-1);
-        }
-        binding = &socket->binding[channel];
-    }
-    if (binding->numbound == SOCKET_MAX_UDPADDRESSES)
-    {
-        TraceLog(LOG_WARNING, "No room for new addresses");
-        return (-1);
-    }
-    binding->address[binding->numbound++] = *address;
-    return (channel);
-}
-
-// Remove the socket channel
-void SocketUnsetChannel(Socket *socket, int channel)
-{
-    if ((channel >= 0) && (channel < SOCKET_MAX_UDPCHANNELS))
-    {
-        socket->binding[channel].numbound = 0;
-    }
-}
-
-/* Allocate/free a single UDP packet 'size' bytes long.
-   The new packet is returned, or NULL if the function ran out of memory.
- */
-SocketDataPacket *AllocPacket(int size)
-{
-    SocketDataPacket *packet;
-    int               error;
-
-    error  = 1;
-    packet = (SocketDataPacket *) RNET_MALLOC(sizeof(*packet));
-    if (packet != NULL)
-    {
-        packet->maxlen = size;
-        packet->data   = (uint8_t *) RNET_MALLOC(size);
-        if (packet->data != NULL)
-        {
-            error = 0;
-        }
-    }
-    if (error)
-    {
-        FreePacket(packet);
-        packet = NULL;
-    }
-    return (packet);
-}
-
-int ResizePacket(SocketDataPacket *packet, int newsize)
-{
-    uint8_t *newdata;
-
-    newdata = (uint8_t *) RNET_MALLOC(newsize);
-    if (newdata != NULL)
-    {
-        RNET_FREE(packet->data);
-        packet->data   = newdata;
-        packet->maxlen = newsize;
-    }
-    return (packet->maxlen);
-}
-
-void FreePacket(SocketDataPacket *packet)
-{
-    if (packet)
-    {
-        RNET_FREE(packet->data);
-        RNET_FREE(packet);
-    }
-}
-
-/* Allocate/Free a UDP packet vector (array of packets) of 'howmany' packets,
-   each 'size' bytes long.
-   A pointer to the packet array is returned, or NULL if the function ran out
-   of memory.
- */
-SocketDataPacket **AllocPacketList(int howmany, int size)
-{
-    SocketDataPacket **packetV;
-
-    packetV = (SocketDataPacket **) RNET_MALLOC((howmany + 1) * sizeof(*packetV));
-    if (packetV != NULL)
-    {
-        int i;
-        for (i = 0; i < howmany; ++i)
-        {
-            packetV[i] = AllocPacket(size);
-            if (packetV[i] == NULL)
-            {
-                break;
-            }
-        }
-        packetV[i] = NULL;
-
-        if (i != howmany)
-        { 
-            FreePacketList(packetV);
-            packetV = NULL;
-        }
-    }
-    return (packetV);
-}
-
-void FreePacketList(SocketDataPacket **packetV)
-{
-    if (packetV)
-    {
-        int i;
-        for (i = 0; packetV[i]; ++i)
-        {
-            FreePacket(packetV[i]);
-        }
-        RNET_FREE(packetV);
-    }
-}
-
-//    Send 'len' bytes of 'data' over the non-server socket 'sock'
-//
-//    Example
-int SocketSend(Socket *sock, const void *datap, int length)
-{
-    int                  sent    = 0;
-    int                  left    = length;
-    int                  status  = -1;
-    int                  numsent = 0;
-    const unsigned char *data    = (const unsigned char *) datap;
-
-    // Server sockets are for accepting connections only
-    if (sock->isServer)
-    {
-        TraceLog(LOG_WARNING, "Cannot send information on a server socket");
-        return -1;
-    }
-
-    // Which socket are we trying to send data on
-    switch (sock->type)
-    {
-        case SOCKET_TCP:
-        {
-            SocketSetLastError(0);
-            do
-            {
-                length = send(sock->channel, (const char *) data, left, 0);
-                if (length > 0)
-                {
-                    sent += length;
-                    left -= length;
-                    data += length;
-                }
-            } while ((left > 0) && // While we still have bytes left to send
-                     ((length > 0) || // The amount of bytes we actually sent is > 0
-                      (SocketGetLastError() == WSAEINTR)) // The socket was interupted
-            );
-
-            if (length == SOCKET_ERROR)
-            {
-                sock->status = SocketGetLastError();
-                TraceLog(LOG_DEBUG, "Socket Error: %s", SocketErrorCodeToString(sock->status));
-                SocketSetLastError(0);
-            }
-            else
-            {
-                TraceLog(LOG_DEBUG, "Successfully sent \"%s\" (%d bytes)", datap, sent);
-            }
-
-            return sent;
-        }
-        break;
-        case SOCKET_UDP:
-        {
-            SocketSetLastError(0);
-            if (sock->isIPv6)
-            {
-                status = sendto(sock->channel, (const char *) data, left, 0,
-                                (struct sockaddr *) &sock->addripv6->address,
-                                sizeof(sock->addripv6->address));
-            }
-            else
-            {
-                status = sendto(sock->channel, (const char *) data, left, 0,
-                                (struct sockaddr *) &sock->addripv4->address,
-                                sizeof(sock->addripv4->address));
-            }
-            if (sent >= 0)
-            {
-                sock->status = 0;
-                ++numsent;
-                TraceLog(LOG_DEBUG, "Successfully sent \"%s\" (%d bytes)", datap, status);
-            }
-            else
-            {
-                sock->status = SocketGetLastError();
-                TraceLog(LOG_DEBUG, "Socket Error: %s", SocketGetLastErrorString(sock->status));
-                SocketSetLastError(0);
-                return 0;
-            }
-            return numsent;
-        }
-        break;
-        default: break;
-    }
-    return -1;
-}
-
-//    Receive up to 'maxlen' bytes of data over the non-server socket 'sock',
-//    and store them in the buffer pointed to by 'data'.
-//    This function returns the actual amount of data received.  If the return
-//    value is less than or equal to zero, then either the remote connection was
-//    closed, or an unknown socket error occurred.
-int SocketReceive(Socket *sock, void *data, int maxlen)
-{
-    int len = 0;
-    int numrecv = 0;
-    int status = 0;
-    socklen_t sock_len;
-    struct sockaddr_storage sock_addr;
-    //char ip[INET6_ADDRSTRLEN];
-
-    // Server sockets are for accepting connections only
-    if (sock->isServer && sock->type == SOCKET_TCP)
-    {
-        sock->status = SocketGetLastError();
-        TraceLog(LOG_DEBUG, "Socket Error: %s", "Server sockets cannot be used to receive data");
-        SocketSetLastError(0);
-        return 0;
-    }
-
-    // Which socket are we trying to send data on
-    switch (sock->type)
-    {
-        case SOCKET_TCP:
-        {
-            SocketSetLastError(0);
-            do
-            {
-                len = recv(sock->channel, (char *) data, maxlen, 0);
-            } while (SocketGetLastError() == WSAEINTR);
-
-            if (len > 0)
-            {
-                // Who sent the packet?
-                if (sock->type == SOCKET_UDP)
-                {
-                    //TraceLog(LOG_DEBUG, "Received data from: %s", inet_ntop(sock_addr.ss_family, GetSocketAddressPtr((struct sockaddr *) &sock_addr), ip, sizeof(ip)));
-                }
-                
-                ((unsigned char *) data)[len] = '\0'; // Add null terminating character to the end of the stream
-                TraceLog(LOG_DEBUG, "Received \"%s\" (%d bytes)", data, len);
-            }
-            
-            sock->ready = 0;
-            return len;
-        }
-        break;
-        case SOCKET_UDP:
-        {
-            SocketSetLastError(0);
-            sock_len = sizeof(sock_addr);
-            status = recvfrom(sock->channel, // The receving channel
-                              data,   // A pointer to the data buffer to fill
-                              maxlen, // The max length of the data to fill
-                              0,      // Flags
-                              (struct sockaddr *) &sock_addr, // The address of the recevied data
-                              &sock_len // The length of the received data address
-            );
-            if (status >= 0)
-            {
-                ++numrecv;
-            }
-            else
-            {
-                sock->status = SocketGetLastError();
-                switch (sock->status)
-                {
-                    case WSAEWOULDBLOCK: { break;
-                    }
-                    default:
-                    {
-                        TraceLog(LOG_WARNING, "Socket Error: %s", SocketErrorCodeToString(sock->status));
-                        break;
-                    }
-                }
-                SocketSetLastError(0);
-                return 0;
-            }
-            sock->ready = 0;
-            return numrecv;
-        }
-        break;
-    }
-    return -1;
-}
-
-// Does the socket have it's 'ready' flag set?
-bool IsSocketReady(Socket *sock)
-{
-    return (sock != NULL) && (sock->ready);
-}
-
-// Check if the socket is considered connected
-bool IsSocketConnected(Socket *sock)
-{
-#if defined(_WIN32)
-    FD_SET writefds;
-    FD_ZERO(&writefds);
-    FD_SET(sock->channel, &writefds);
-    struct timeval timeout;
-    timeout.tv_sec  = 1;
-    timeout.tv_usec = 1000000000UL;
-    int total       = select(0, NULL, &writefds, NULL, &timeout);
-    if (total == -1)
-    { // Error
-        sock->status = SocketGetLastError();
-        TraceLog(LOG_WARNING, "Socket Error: %s", SocketErrorCodeToString(sock->status));
-        SocketSetLastError(0);
-    }
-    else if (total == 0)
-    { // Timeout
-        return false;
-    }
-    else
-    {
-        if (FD_ISSET(sock->channel, &writefds))
-        {
-            return true;
-        }
-    }
-    return false;
-#else
-    return true;
-#endif
-}
-
-// Allocate and return a SocketResult struct
-SocketResult *AllocSocketResult()
-{
-    struct SocketResult *res;
-    res = (struct SocketResult *) RNET_MALLOC(sizeof(*res));
-    if (res != NULL)
-    {
-        memset(res, 0, sizeof(*res));
-        if ((res->socket = AllocSocket()) == NULL)
-        {
-            RNET_FREE(res);
-            res = NULL;
-        }
-    }
-    return res;
-}
-
-// Free an allocated SocketResult
-void FreeSocketResult(SocketResult **result)
-{
-    if (*result != NULL)
-    {
-        if ((*result)->socket != NULL)
-        {
-            FreeSocket(&((*result)->socket));
-        }
-        RNET_FREE(*result);
-        *result = NULL;
-    }
-}
-
-// Allocate a Socket
-Socket *AllocSocket()
-{
-    // Allocate a socket if one already hasn't been
-    struct Socket *sock;
-    sock = (Socket *) RNET_MALLOC(sizeof(*sock));
-    if (sock != NULL)
-    {
-        memset(sock, 0, sizeof(*sock));
-    }
-    else
-    {
-        TraceLog(
-            LOG_WARNING, "Ran out of memory attempting to allocate a socket");
-        SocketClose(sock);
-        RNET_FREE(sock);
-        sock = NULL;
-    }
-    return sock;
-}
-
-// Free an allocated Socket
-void FreeSocket(Socket **sock)
-{
-    if (*sock != NULL)
-    {
-        RNET_FREE(*sock);
-        *sock = NULL;
-    }
-}
-
-// Allocate a SocketSet
-SocketSet *AllocSocketSet(int max)
-{
-    struct SocketSet *set;
-    int               i;
-
-    set = (struct SocketSet *) RNET_MALLOC(sizeof(*set));
-    if (set != NULL)
-    {
-        set->numsockets = 0;
-        set->maxsockets = max;
-        set->sockets = (struct Socket **) RNET_MALLOC(max * sizeof(*set->sockets));
-        if (set->sockets != NULL)
-        {
-            for (i = 0; i < max; ++i)
-            {
-                set->sockets[i] = NULL;
-            }
-        }
-        else
-        {
-            RNET_FREE(set);
-            set = NULL;
-        }
-    }
-    return (set);
-}
-
-// Free an allocated SocketSet
-void FreeSocketSet(SocketSet *set)
-{
-    if (set)
-    {
-        RNET_FREE(set->sockets);
-        RNET_FREE(set);
-    }
-}
-
-// Add a Socket "sock" to the SocketSet "set"
-int AddSocket(SocketSet *set, Socket *sock)
-{
-    if (sock != NULL)
-    {
-        if (set->numsockets == set->maxsockets)
-        {
-            TraceLog(LOG_DEBUG, "Socket Error: %s", "SocketSet is full");
-            SocketSetLastError(0);
-            return (-1);
-        }
-        set->sockets[set->numsockets++] = (struct Socket *) sock;
-    }
-    else
-    {
-        TraceLog(LOG_DEBUG, "Socket Error: %s", "Socket was null");
-        SocketSetLastError(0);
-        return (-1);
-    }
-    return (set->numsockets);
-}
-
-// Remove a Socket "sock" to the SocketSet "set"
-int RemoveSocket(SocketSet *set, Socket *sock)
-{
-    int i;
-
-    if (sock != NULL)
-    {
-        for (i = 0; i < set->numsockets; ++i)
-        {
-            if (set->sockets[i] == (struct Socket *) sock)
-            {
-                break;
-            }
-        }
-        if (i == set->numsockets)
-        {
-            TraceLog(LOG_DEBUG, "Socket Error: %s", "Socket not found");
-            SocketSetLastError(0);
-            return (-1);
-        }
-        --set->numsockets;
-        for (; i < set->numsockets; ++i)
-        {
-            set->sockets[i] = set->sockets[i + 1];
-        }
-    }
-    return (set->numsockets);
-}
-
-// Check the sockets in the socket set for pending information
-int CheckSockets(SocketSet *set, unsigned int timeout)
-{
-    int            i;
-    SOCKET         maxfd;
-    int            retval;
-    struct timeval tv;
-    fd_set         mask;
-
-    /* Find the largest file descriptor */
-    maxfd = 0;
-    for (i = set->numsockets - 1; i >= 0; --i)
-    {
-        if (set->sockets[i]->channel > maxfd)
-        {
-            maxfd = set->sockets[i]->channel;
-        }
-    }
-
-    // Check the file descriptors for available data
-    do
-    {
-        SocketSetLastError(0);
-
-        // Set up the mask of file descriptors
-        FD_ZERO(&mask);
-        for (i = set->numsockets - 1; i >= 0; --i)
-        {
-            FD_SET(set->sockets[i]->channel, &mask);
-        } // Set up the timeout
-        tv.tv_sec  = timeout / 1000;
-        tv.tv_usec = (timeout % 1000) * 1000;
-
-        /* Look! */
-        retval = select(maxfd + 1, &mask, NULL, NULL, &tv);
-    } while (SocketGetLastError() == WSAEINTR);
-
-    // Mark all file descriptors ready that have data available
-    if (retval > 0)
-    {
-        for (i = set->numsockets - 1; i >= 0; --i)
-        {
-            if (FD_ISSET(set->sockets[i]->channel, &mask))
-            {
-                set->sockets[i]->ready = 1;
-            }
-        }
-    }
-    return (retval);
-} 
-
-// Allocate an AddressInformation
-AddressInformation AllocAddress()
-{
-    AddressInformation addressInfo = NULL;
-    addressInfo = (AddressInformation) RNET_CALLOC(1, sizeof(*addressInfo));
-    if (addressInfo != NULL)
-    {
-        addressInfo->addr.ai_addr = (struct sockaddr *) RNET_CALLOC(1, sizeof(struct sockaddr));
-        if (addressInfo->addr.ai_addr == NULL)
-        {
-            TraceLog(LOG_WARNING,
-                     "Failed to allocate memory for \"struct sockaddr\"");
-        }
-    }
-    else
-    {
-        TraceLog(LOG_WARNING,
-                 "Failed to allocate memory for \"struct AddressInformation\"");
-    }
-    return addressInfo;
-}
-
-// Free an AddressInformation struct
-void FreeAddress(AddressInformation *addressInfo)
-{
-    if (*addressInfo != NULL)
-    {
-        if ((*addressInfo)->addr.ai_addr != NULL)
-        {
-            RNET_FREE((*addressInfo)->addr.ai_addr);
-            (*addressInfo)->addr.ai_addr = NULL;
-        }
-        RNET_FREE(*addressInfo);
-        *addressInfo = NULL;
-    }
-}
-
-// Allocate a list of AddressInformation
-AddressInformation *AllocAddressList(int size)
-{
-    AddressInformation *addr;
-    addr = (AddressInformation *) RNET_MALLOC(size * sizeof(AddressInformation));
-    return addr;
-}
-
-// Opaque datatype accessor addrinfo->ai_family
-int GetAddressFamily(AddressInformation address)
-{
-    return address->addr.ai_family;
-}
-
-// Opaque datatype accessor addrinfo->ai_socktype
-int GetAddressSocketType(AddressInformation address)
-{
-    return address->addr.ai_socktype;
-}
-
-// Opaque datatype accessor addrinfo->ai_protocol
-int GetAddressProtocol(AddressInformation address)
-{
-    return address->addr.ai_protocol;
-}
-
-// Opaque datatype accessor addrinfo->ai_canonname
-char *GetAddressCanonName(AddressInformation address)
-{
-    return address->addr.ai_canonname;
-}
-
-// Opaque datatype accessor addrinfo->ai_addr
-char *GetAddressHostAndPort(AddressInformation address, char *outhost, int *outport)
-{
-    //char *ip[INET6_ADDRSTRLEN];
-    char *result = NULL;
-    struct sockaddr_storage *storage = (struct sockaddr_storage *) address->addr.ai_addr;
-    switch (storage->ss_family)
-    {
-        case AF_INET:
-        {
-            struct sockaddr_in *s = ((struct sockaddr_in *) address->addr.ai_addr);
-            //result = inet_ntop(AF_INET, &s->sin_addr, ip, INET_ADDRSTRLEN);           // TODO.
-            *outport = ntohs(s->sin_port);
-        }
-        break;
-        case AF_INET6:
-        {
-            struct sockaddr_in6 *s = ((struct sockaddr_in6 *) address->addr.ai_addr);
-            //result = inet_ntop(AF_INET6, &s->sin6_addr, ip, INET6_ADDRSTRLEN);          // TODO.
-            *outport = ntohs(s->sin6_port);
-        }
-        break;
-    }
-    if (result == NULL)
-    {
-        TraceLog(LOG_WARNING, "Socket Error: %s", SocketErrorCodeToString(SocketGetLastError()));
-        SocketSetLastError(0);
-    }
-    else
-    {
-        strcpy(outhost, result);
-    }
-    return result;
-}
-
-//
-void PacketSend(Packet *packet)
-{
-    printf("Sending packet (%s) with size %d\n", packet->data, packet->size);
-}
-
-//
-void PacketReceive(Packet *packet)
-{
-    printf("Receiving packet (%s) with size %d\n", packet->data, packet->size);
-}
-
-//
-void PacketWrite16(Packet *packet, uint16_t value)
-{
-    printf("Original: 0x%04" PRIX16 " - %" PRIu16 "\n", value, value);
-    uint8_t *data = packet->data + packet->offs;
-    *data++       = (uint8_t)(value >> 8);
-    *data++       = (uint8_t)(value);
-    packet->size += sizeof(uint16_t);
-    packet->offs += sizeof(uint16_t);
-    printf("Network: 0x%04" PRIX16 " - %" PRIu16 "\n", (uint16_t) *data, (uint16_t) *data);
-}
-
-//
-void PacketWrite32(Packet *packet, uint32_t value)
-{
-    printf("Original: 0x%08" PRIX32 " - %" PRIu32 "\n", value, value);
-    uint8_t *data = packet->data + packet->offs;
-    *data++       = (uint8_t)(value >> 24);
-    *data++       = (uint8_t)(value >> 16);
-    *data++       = (uint8_t)(value >> 8);
-    *data++       = (uint8_t)(value);
-    packet->size += sizeof(uint32_t);
-    packet->offs += sizeof(uint32_t);
-    printf("Network: 0x%08" PRIX32 " - %" PRIu32 "\n",
-           (uint32_t)(((intptr_t) packet->data) - packet->offs),
-           (uint32_t)(((intptr_t) packet->data) - packet->offs));
-}
-
-//
-void PacketWrite64(Packet *packet, uint64_t value)
-{
-    printf("Original: 0x%016" PRIX64 " - %" PRIu64 "\n", value, value);
-    uint8_t *data = packet->data + packet->offs;
-    *data++       = (uint8_t)(value >> 56);
-    *data++       = (uint8_t)(value >> 48);
-    *data++       = (uint8_t)(value >> 40);
-    *data++       = (uint8_t)(value >> 32);
-    *data++       = (uint8_t)(value >> 24);
-    *data++       = (uint8_t)(value >> 16);
-    *data++       = (uint8_t)(value >> 8);
-    *data++       = (uint8_t)(value);
-    packet->size += sizeof(uint64_t);
-    packet->offs += sizeof(uint64_t);
-    printf("Network: 0x%016" PRIX64 " - %" PRIu64 "\n",
-           (uint64_t)(packet->data - packet->offs),
-           (uint64_t)(packet->data - packet->offs));
-}
-
-//
-uint16_t PacketRead16(Packet *packet)
-{
-    uint8_t *data = packet->data + packet->offs;
-    packet->size += sizeof(uint16_t);
-    packet->offs += sizeof(uint16_t);
-    uint16_t value = ((uint16_t) data[0] << 8) | data[1];
-    printf("Original: 0x%04" PRIX16 " - %" PRIu16 "\n", value, value);
-    return value;
-}
-
-//
-uint32_t PacketRead32(Packet *packet)
-{
-    uint8_t *data = packet->data + packet->offs;
-    packet->size += sizeof(uint32_t);
-    packet->offs += sizeof(uint32_t);
-    uint32_t value = ((uint32_t) data[0] << 24) | ((uint32_t) data[1] << 16) | ((uint32_t) data[2] << 8) | data[3];
-    printf("Original: 0x%08" PRIX32 " - %" PRIu32 "\n", value, value);
-    return value;
-}
-
-//
-uint64_t PacketRead64(Packet *packet)
-{
-    uint8_t *data = packet->data + packet->offs;
-    packet->size += sizeof(uint64_t);
-    packet->offs += sizeof(uint64_t);
-    uint64_t value = ((uint64_t) data[0] << 56) | ((uint64_t) data[1] << 48) | ((uint64_t) data[2] << 40) | ((uint64_t) data[3] << 32) | ((uint64_t) data[4] << 24) | ((uint64_t) data[5] << 16) | ((uint64_t) data[6] << 8) | data[7];
-    printf("Original: 0x%016" PRIX64 " - %" PRIu64 "\n", value, value);
-    return value;
-}

+ 1948 - 112
lib.mod/raylib/src/rnet.h

@@ -1,9 +1,9 @@
 /**********************************************************************************************
 *
-*   rnet - Provides cross-platform network defines, macros etc
+*   rnet - A simple and easy-to-use network module for raylib
 *
-*   DEPENDENCIES:
-*       <limits.h>    - Used for cross-platform type specifiers
+*   FEATURES:
+*       - Provides a simple and (hopefully) easy to use wrapper around the Berkeley socket API
 *
 *   INSPIRED BY:
 *       SFML Sockets - https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1Socket.php
@@ -12,14 +12,13 @@
 *       BEEJ - https://beej.us/guide/bgnet/html/single/bgnet.html
 *       Winsock2 - https://docs.microsoft.com/en-us/windows/desktop/api/winsock2
 *
-*
 *   CONTRIBUTORS:
 *       Jak Barnes (github: @syphonx) (Feb. 2019) - Initial version
 *
 *
 *   LICENSE: zlib/libpng
 *
-*   Copyright (c) 2019 Jak Barnes (github: @syphonx) and Ramon Santamaria (@raysan5)
+*   Copyright (c) 2019-2020 Jak Barnes (@syphonx) and Ramon Santamaria (@raysan5)
 *
 *   This software is provided "as-is", without any express or implied warranty. In no event
 *   will the authors be held liable for any damages arising from the use of this software.
@@ -78,15 +77,15 @@
 #define NOMSG             // typedef MSG and associated routines
 #define NOOPENFILE        // OpenFile(), OemToAnsi, AnsiToOem, and OF_*
 #define NOSCROLL          // SB_* and scrolling routines
-#define NOSERVICE          // All Service Controller routines, SERVICE_ equates, etc.
-#define NOSOUND              // Sound driver routines
+#define NOSERVICE         // All Service Controller routines, SERVICE_ equates, etc.
+#define NOSOUND           // Sound driver routines
 #define NOTEXTMETRIC      // typedef TEXTMETRIC and associated routines
 #define NOWH              // SetWindowsHook and WH_*
 #define NOWINOFFSETS      // GWL_*, GCL_*, associated routines
-#define NOCOMM              // COMM driver routines
-#define NOKANJI              // Kanji support stuff.
-#define NOHELP              // Help engine interface.
-#define NOPROFILER          // Profiler interface.
+#define NOCOMM            // COMM driver routines
+#define NOKANJI           // Kanji support stuff.
+#define NOHELP            // Help engine interface.
+#define NOPROFILER        // Profiler interface.
 #define NODEFERWINDOWPOS  // DeferWindowPos routines
 #define NOMCX             // Modem Configuration Extensions
 #define MMNOSOUND
@@ -135,14 +134,14 @@ typedef int socklen_t;
 //----------------------------------------------------------------------------------
 
 // Include system network headers
-#if defined(_WIN32)
+#if defined(_WIN32) // Windows
     #define __USE_W32_SOCKETS
     #define WIN32_LEAN_AND_MEAN
     #include <winsock2.h>
     #include <ws2tcpip.h>
     #include <io.h>
     #define IPTOS_LOWDELAY 0x10
-#else   // Unix
+#else               // Unix
     #include <sys/types.h>
     #include <fcntl.h>
     #include <netinet/in.h>
@@ -178,27 +177,34 @@ typedef int socklen_t;
 //----------------------------------------------------------------------------------
 
 // Network connection related defines
-#define SOCKET_MAX_SET_SIZE                     (32)   // Maximum sockets in a set
-#define SOCKET_MAX_QUEUE_SIZE                   (16)   // Maximum socket queue size
-#define SOCKET_MAX_SOCK_OPTS (4)        // Maximum socket options
-#define SOCKET_MAX_UDPCHANNELS (32)        // Maximum UDP channels
-#define SOCKET_MAX_UDPADDRESSES (4)        // Maximum bound UDP addresses
-
+#define SOCKET_MAX_SET_SIZE         32     // Maximum sockets in a set
+#define SOCKET_MAX_QUEUE_SIZE       16     // Maximum socket queue size
+#define SOCKET_MAX_SOCK_OPTS        4      // Maximum socket options
+#define SOCKET_MAX_UDPCHANNELS      32     // Maximum UDP channels
+#define SOCKET_MAX_UDPADDRESSES     4      // Maximum bound UDP addresses
 
 // Network address related defines
-#define ADDRESS_IPV4_ADDRSTRLEN                 (22)   // IPv4 string length
-#define ADDRESS_IPV6_ADDRSTRLEN                 (65)   // IPv6 string length
-#define ADDRESS_TYPE_ANY                        (0)    // AF_UNSPEC
-#define ADDRESS_TYPE_IPV4                       (2)    // AF_INET
-#define ADDRESS_TYPE_IPV6                       (23)   // AF_INET6
-#define ADDRESS_MAXHOST                         (1025) // Max size of a fully-qualified domain name
-#define ADDRESS_MAXSERV                         (32)   // Max size of a service name
+#define ADDRESS_IPV4_ADDRSTRLEN     22     // IPv4 string length
+#define ADDRESS_IPV6_ADDRSTRLEN     65     // IPv6 string length
+#define ADDRESS_TYPE_ANY            0      // AF_UNSPEC
+#define ADDRESS_TYPE_IPV4           2      // AF_INET
+#define ADDRESS_TYPE_IPV6           23     // AF_INET6
+#define ADDRESS_MAXHOST             1025   // Max size of a fully-qualified domain name
+#define ADDRESS_MAXSERV             32     // Max size of a service name
 
 // Network address related defines
-#define ADDRESS_ANY                             ((unsigned long) 0x00000000)
-#define ADDRESS_LOOPBACK                        (0x7f000001)
-#define ADDRESS_BROADCAST                       ((unsigned long) 0xffffffff)
-#define ADDRESS_NONE                            (0xffffffff)
+#define ADDRESS_ANY                 (unsigned long)0x00000000
+#define ADDRESS_LOOPBACK            0x7f000001
+#define ADDRESS_BROADCAST           (unsigned long)0xffffffff
+#define ADDRESS_NONE                0xffffffff
+
+// Network resolution related defines
+#define NAME_INFO_DEFAULT           0x00   // No flags set
+#define NAME_INFO_NOFQDN            0x01   // Only return nodename portion for local hosts
+#define NAME_INFO_NUMERICHOST       0x02   // Return numeric form of the host's address
+#define NAME_INFO_NAMEREQD          0x04   // Error if the host's name not in DNS
+#define NAME_INFO_NUMERICSERV       0x08   // Return numeric form of the service (port #)
+#define NAME_INFO_DGRAM             0x10   // Service is a datagram service
 
 // Address resolution related defines
 #if defined(_WIN32)
@@ -220,14 +226,6 @@ typedef int socklen_t;
     #define ADDRESS_INFO_RESOLUTION_HANDLE      (0x40000000)  // Request resolution handle
 #endif
 
-// Network resolution related defines
-#define NAME_INFO_DEFAULT                       (0x00) // No flags set
-#define NAME_INFO_NOFQDN                        (0x01) // Only return nodename portion for local hosts
-#define NAME_INFO_NUMERICHOST                   (0x02) // Return numeric form of the host's address
-#define NAME_INFO_NAMEREQD                      (0x04) // Error if the host's name not in DNS
-#define NAME_INFO_NUMERICSERV                   (0x08) // Return numeric form of the service (port #)
-#define NAME_INFO_DGRAM                         (0x10) // Service is a datagram service
-
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
@@ -239,6 +237,11 @@ typedef int socklen_t;
     typedef enum { false, true } bool;
 #endif
 
+typedef enum {
+    SOCKET_TCP = 0,             // SOCK_STREAM
+    SOCKET_UDP = 1              // SOCK_DGRAM
+} SocketType;
+
 // Network typedefs
 typedef uint32_t SocketChannel;
 typedef struct _AddressInformation *AddressInformation;
@@ -249,83 +252,79 @@ typedef struct _SocketAddressStorage *SocketAddressStorage;
 
 // IPAddress definition (in network byte order)
 typedef struct IPAddress {
-    unsigned long  host; /* 32-bit IPv4 host address */
-    unsigned short port; /* 16-bit protocol port */
+    unsigned long host;         // 32-bit IPv4 host address
+    unsigned short port;        // 16-bit protocol port
 } IPAddress;
 
-// An option ID, value, sizeof(value) tuple for setsockopt(2).
-typedef struct SocketOpt {
-    int id;
-    void *value;
-    int valueLen;
-} SocketOpt;
-
-typedef enum {
-    SOCKET_TCP = 0, // SOCK_STREAM
-    SOCKET_UDP = 1  // SOCK_DGRAM
-} SocketType;
-
 typedef struct UDPChannel {
-    int numbound; // The total number of addresses this channel is bound to
+    int numbound;               // The total number of addresses this channel is bound to
     IPAddress address[SOCKET_MAX_UDPADDRESSES]; // The list of remote addresses this channel is bound to
 } UDPChannel;
 
+// An option ID, value, sizeof(value) tuple for setsockopt(2).
+typedef struct SocketOpt {
+    int id;                     // Socked option id
+    int valueLen;               // Socked option value len
+    void *value;                // Socked option value data
+} SocketOpt;
+
 typedef struct Socket {
-    int  ready;    // Is the socket ready? i.e. has information
-    int  status;   // The last status code to have occured using this socket
-    bool isServer; // Is this socket a server socket (i.e. TCP/UDP Listen Server)
-    SocketChannel channel; // The socket handle id
-    SocketType    type;    // Is this socket a TCP or UDP socket?
-    bool          isIPv6;  // Is this socket address an ipv6 address?
+    int ready;                  // Is the socket ready? i.e. has information
+    int status;                 // The last status code to have occured using this socket
+    bool isServer;              // Is this socket a server socket (i.e. TCP/UDP Listen Server)
+    SocketChannel channel;      // The socket handle id
+    SocketType type;            // Is this socket a TCP or UDP socket?
+    
+    bool isIPv6;                // Is this socket address an ipv6 address?
     SocketAddressIPv4 addripv4; // The host/target IPv4 for this socket (in network byte order)
     SocketAddressIPv6 addripv6; // The host/target IPv6 for this socket (in network byte order)
 
     struct UDPChannel binding[SOCKET_MAX_UDPCHANNELS]; // The amount of channels (if UDP) this socket is bound to
 } Socket;
 
-typedef struct SocketSet {
-    int numsockets;
-    int maxsockets;
-    struct Socket **sockets;
-} SocketSet;
+// Configuration for a socket
+typedef struct SocketConfig {
+    SocketType type;            // The type of socket, TCP/UDP
+    char *host;                 // The host address in xxx.xxx.xxx.xxx form
+    char *port;                 // The target port/service in the form "http" or "25565"
+    bool server;                // Listen for incoming clients?
+    bool nonblocking;           // non-blocking operation?
+    int backlog_size;           // set a custom backlog size
+    SocketOpt sockopts[SOCKET_MAX_SOCK_OPTS];
+} SocketConfig;
 
 typedef struct SocketDataPacket {
-    int            channel; // The src/dst channel of the packet
-    unsigned char *data;    // The packet data
-    int            len;     // The length of the packet data
-    int            maxlen;  // The size of the data buffer
-    int            status;  // packet status after sending
-    IPAddress address; // The source/dest address of an incoming/outgoing packet
+    IPAddress address;          // The source/dest address of an incoming/outgoing packet
+    int channel;                // The src/dst channel of the packet
+    int maxlen;                 // The size of the data buffer
+    int status;                 // Packet status after sending
+    unsigned int len;           // The length of the packet data
+    unsigned char *data;        // The packet data
 } SocketDataPacket;
 
-// Configuration for a socket.
-typedef struct SocketConfig {
-    char *     host;   // The host address in xxx.xxx.xxx.xxx form
-    char *     port;   // The target port/service in the form "http" or "25565"
-    bool       server; // Listen for incoming clients?
-    SocketType type;   // The type of socket, TCP/UDP
-    bool       nonblocking;  // non-blocking operation?
-    int        backlog_size; // set a custom backlog size
-    SocketOpt  sockopts[SOCKET_MAX_SOCK_OPTS];
-} SocketConfig;
-
-// Result from calling open with a given config.
+// Result from calling open with a given config
 typedef struct SocketResult {
-    int status;
-    Socket *socket;
+    int status;                 // Socket result state
+    Socket *socket;             // Socket ref
 } SocketResult;
 
+typedef struct SocketSet {
+    int numsockets;             // Socket set count
+    int maxsockets;             // Socket set max
+    struct Socket **sockets;    // Sockets array
+} SocketSet;
+
 // Packet type
 typedef struct Packet {
-    uint32_t size; // The total size of bytes in data
-    uint32_t offs; // The offset to data access
-    uint32_t maxs; // The max size of data
-    uint8_t *data; // Data stored in network byte order
+    uint32_t size;              // The total size of bytes in data
+    uint32_t offs;              // The offset to data access
+    uint32_t maxs;              // The max size of data
+    uint8_t *data;              // Data stored in network byte order
 } Packet;
 
 
 #ifdef __cplusplus
-extern "C" {            // Prevents name mangling of functions
+extern "C" {        // Prevents name mangling of functions
 #endif
 
 //----------------------------------------------------------------------------------
@@ -338,8 +337,8 @@ extern "C" {            // Prevents name mangling of functions
 //----------------------------------------------------------------------------------
 
 // Initialisation and cleanup
-bool InitNetwork(void);
-void CloseNetwork(void);
+bool InitNetworkDevice(void);
+void CloseNetworkDevice(void);
 
 // Address API
 void ResolveIP(const char *ip, const char *service, int flags, char *outhost, char *outserv);
@@ -347,14 +346,13 @@ int ResolveHost(const char *address, const char *service, int addressType, int f
 int GetAddressFamily(AddressInformation address);
 int GetAddressSocketType(AddressInformation address);
 int GetAddressProtocol(AddressInformation address);
-char* GetAddressCanonName(AddressInformation address);
-char* GetAddressHostAndPort(AddressInformation address, char *outhost, int *outport);
-void PrintAddressInfo(AddressInformation address);
+char *GetAddressCanonName(AddressInformation address);
+char *GetAddressHostAndPort(AddressInformation address, char *outhost, int *outport);
 
 // Address Memory API
-AddressInformation AllocAddress();
-void FreeAddress(AddressInformation *addressInfo);
-AddressInformation *AllocAddressList(int size);
+AddressInformation LoadAddress(void);
+void UnloadAddress(AddressInformation *addressInfo);
+AddressInformation *LoadAddressList(int size);
 
 // Socket API
 bool SocketCreate(SocketConfig *config, SocketResult *result);
@@ -363,6 +361,14 @@ bool SocketListen(SocketConfig *config, SocketResult *result);
 bool SocketConnect(SocketConfig *config, SocketResult *result);
 Socket *SocketAccept(Socket *server, SocketConfig *config);
 
+// General Socket API
+int SocketSend(Socket *sock, const void *datap, int len);
+int SocketReceive(Socket *sock, void *data, int maxlen);
+SocketAddressStorage SocketGetPeerAddress(Socket *sock);
+char *GetSocketAddressHost(SocketAddressStorage storage);
+short GetSocketAddressPort(SocketAddressStorage storage);
+void SocketClose(Socket *sock);
+
 // UDP Socket API
 int SocketSetChannel(Socket *socket, int channel, const IPAddress *address);
 void SocketUnsetChannel(Socket *socket, int channel);
@@ -374,21 +380,13 @@ void FreePacket(SocketDataPacket *packet);
 SocketDataPacket **AllocPacketList(int count, int size);
 void FreePacketList(SocketDataPacket **packets);
 
-// General Socket API
-int SocketSend(Socket *sock, const void *datap, int len);
-int SocketReceive(Socket *sock, void *data, int maxlen);
-void SocketClose(Socket *sock);
-SocketAddressStorage SocketGetPeerAddress(Socket *sock);
-char* GetSocketAddressHost(SocketAddressStorage storage);
-short GetSocketAddressPort(SocketAddressStorage storage);
-
 // Socket Memory API
-Socket *AllocSocket();
-void FreeSocket(Socket **sock);
-SocketResult *AllocSocketResult();
-void FreeSocketResult(SocketResult **result);
-SocketSet *AllocSocketSet(int max);
-void FreeSocketSet(SocketSet *sockset);
+Socket *LoadSocket(void);
+void UnloadSocket(Socket **sock);
+SocketResult *LoadSocketResult(void);
+void UnloadSocketResult(SocketResult **result);
+SocketSet *LoadSocketSet(int max);
+void UnloadSocketSet(SocketSet *sockset);
 
 // Socket I/O API
 bool IsSocketReady(Socket *sock);
@@ -413,4 +411,1842 @@ uint64_t PacketRead64(Packet *packet);
 }
 #endif
 
-#endif  // RNET_H
+#endif  // RNET_H
+
+/***********************************************************************************
+*
+*   RNET IMPLEMENTATION
+*
+************************************************************************************/
+
+#if defined(RNET_IMPLEMENTATION)
+
+#include <assert.h>         // Required for: assert()
+#include <stdio.h>          // Required for: FILE, fopen(), fclose(), fread()
+#include <stdlib.h>         // Required for: malloc(), free()
+#include <string.h>         // Required for: strcmp(), strncmp()
+
+#define NET_DEBUG_ENABLED   1
+
+#if defined(SUPPORT_TRACELOG)
+    #define TRACELOG(level, ...) TraceLog(level, __VA_ARGS__)
+
+    #if defined(SUPPORT_TRACELOG_DEBUG)
+        #define TRACELOGD(...) TraceLog(LOG_DEBUG, __VA_ARGS__)
+    #else
+        #define TRACELOGD(...) (void)0
+    #endif
+#else
+    #define TRACELOG(level, ...) (void)0
+    #define TRACELOGD(...) (void)0
+#endif
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+
+typedef struct _SocketAddress
+{
+    struct sockaddr address;
+} _SocketAddress;
+
+typedef struct _SocketAddressIPv4
+{
+    struct sockaddr_in address;
+} _SocketAddressIPv4;
+
+typedef struct _SocketAddressIPv6
+{
+    struct sockaddr_in6 address;
+} _SocketAddressIPv6;
+
+typedef struct _SocketAddressStorage
+{
+    struct sockaddr_storage address;
+} _SocketAddressStorage;
+
+typedef struct _AddressInformation
+{
+    struct addrinfo addr;
+} _AddressInformation;
+
+//----------------------------------------------------------------------------------
+// Local module Functions Declarations
+//----------------------------------------------------------------------------------
+static void PrintSocket(struct sockaddr_storage *addr, const int family, const int socktype, const int protocol);
+static const char *SocketAddressToString(struct sockaddr_storage *sockaddr);
+static bool IsIPv4Address(const char *ip);
+static bool IsIPv6Address(const char *ip);
+static void *GetSocketPortPtr(struct sockaddr_storage *sa);
+static void *GetSocketAddressPtr(struct sockaddr_storage *sa);
+static bool IsSocketValid(Socket *sock);
+static void SocketSetLastError(int err);
+static int SocketGetLastError();
+static char *SocketGetLastErrorString();
+static char *SocketErrorCodeToString(int err);
+static bool SocketSetDefaults(SocketConfig *config);
+static bool InitSocket(Socket *sock, struct addrinfo *addr);
+static bool CreateSocket(SocketConfig *config, SocketResult *outresult);
+static bool SocketSetBlocking(Socket *sock);
+static bool SocketSetNonBlocking(Socket *sock);
+static bool SocketSetOptions(SocketConfig *config, Socket *sock);
+static void SocketSetHints(SocketConfig *config, struct addrinfo *hints);
+
+//----------------------------------------------------------------------------------
+// Local module Functions Definition
+//----------------------------------------------------------------------------------
+// Print socket information
+static void PrintSocket(struct sockaddr_storage *addr, const int family, const int socktype, const int protocol)
+{
+    switch (family)
+    {
+        case AF_UNSPEC: TRACELOG(LOG_DEBUG, "\tFamily: Unspecified"); break;
+        case AF_INET:
+        {
+            TRACELOG(LOG_DEBUG, "\tFamily: AF_INET (IPv4)");
+            TRACELOG(LOG_INFO, "\t- IPv4 address %s", SocketAddressToString(addr));
+        } break;
+        case AF_INET6:
+        {
+            TRACELOG(LOG_DEBUG, "\tFamily: AF_INET6 (IPv6)");
+            TRACELOG(LOG_INFO, "\t- IPv6 address %s", SocketAddressToString(addr));
+        } break;
+        case AF_NETBIOS:
+        {
+            TRACELOG(LOG_DEBUG, "\tFamily: AF_NETBIOS (NetBIOS)");
+        } break;
+        default: TRACELOG(LOG_DEBUG, "\tFamily: Other %ld", family); break;
+    }
+
+    TRACELOG(LOG_DEBUG, "\tSocket type:");
+    switch (socktype)
+    {
+        case 0: TRACELOG(LOG_DEBUG, "\t- Unspecified"); break;
+        case SOCK_STREAM: TRACELOG(LOG_DEBUG, "\t- SOCK_STREAM (stream)"); break;
+        case SOCK_DGRAM: TRACELOG(LOG_DEBUG, "\t- SOCK_DGRAM (datagram)"); break;
+        case SOCK_RAW: TRACELOG(LOG_DEBUG, "\t- SOCK_RAW (raw)"); break;
+        case SOCK_RDM: TRACELOG(LOG_DEBUG, "\t- SOCK_RDM (reliable message datagram)"); break;
+        case SOCK_SEQPACKET: TRACELOG(LOG_DEBUG, "\t- SOCK_SEQPACKET (pseudo-stream packet)"); break;
+        default: TRACELOG(LOG_DEBUG, "\t- Other %ld", socktype); break;
+    }
+
+    TRACELOG(LOG_DEBUG, "\tProtocol:");
+    switch (protocol)
+    {
+        case 0: TRACELOG(LOG_DEBUG, "\t- Unspecified"); break;
+        case IPPROTO_TCP: TRACELOG(LOG_DEBUG, "\t- IPPROTO_TCP (TCP)"); break;
+        case IPPROTO_UDP: TRACELOG(LOG_DEBUG, "\t- IPPROTO_UDP (UDP)"); break;
+        default: TRACELOG(LOG_DEBUG, "\t- Other %ld", protocol); break;
+    }
+}
+
+// Convert network ordered socket address to human readable string (127.0.0.1)
+static const char *SocketAddressToString(struct sockaddr_storage *sockaddr)
+{
+    //static const char* ipv6[INET6_ADDRSTRLEN];
+    assert(sockaddr != NULL);
+    assert(sockaddr->ss_family == AF_INET || sockaddr->ss_family == AF_INET6);
+
+    switch (sockaddr->ss_family)
+    {
+        case AF_INET:
+        {
+            //struct sockaddr_in *s = ((struct sockaddr_in *)sockaddr);
+            //return inet_ntop(AF_INET, &s->sin_addr, ipv6, INET_ADDRSTRLEN);       // TODO.
+        }
+        break;
+        case AF_INET6:
+        {
+            //struct sockaddr_in6 *s = ((struct sockaddr_in6 *)sockaddr);
+            //return inet_ntop(AF_INET6, &s->sin6_addr, ipv6, INET6_ADDRSTRLEN);    // TODO.
+        }
+        break;
+    }
+
+    return NULL;
+}
+
+// Check if the null terminated string ip is a valid IPv4 address
+static bool IsIPv4Address(const char *ip)
+{
+    /*
+    struct sockaddr_in sa;
+    int result = inet_pton(AF_INET, ip, &(sa.sin_addr));    // TODO.
+    return (result != 0);
+    */
+    return false;
+}
+
+// Check if the null terminated string ip is a valid IPv6 address
+static bool IsIPv6Address(const char *ip)
+{
+    /*
+    struct sockaddr_in6 sa;
+    int result = inet_pton(AF_INET6, ip, &(sa.sin6_addr));    // TODO.
+    return result != 0;
+    */
+    return false;
+}
+
+// Return a pointer to the port from the correct address family (IPv4, or IPv6)
+static void *GetSocketPortPtr(struct sockaddr_storage *sa)
+{
+    if (sa->ss_family == AF_INET)
+    {
+        return &(((struct sockaddr_in *)sa)->sin_port);
+    }
+
+    return &(((struct sockaddr_in6 *)sa)->sin6_port);
+}
+
+// Return a pointer to the address from the correct address family (IPv4, or IPv6)
+static void *GetSocketAddressPtr(struct sockaddr_storage *sa)
+{
+    if (sa->ss_family == AF_INET)
+    {
+        return &(((struct sockaddr_in *)sa)->sin_addr);
+    }
+
+    return &(((struct sockaddr_in6 *)sa)->sin6_addr);
+}
+
+// Is the socket in a valid state?
+static bool IsSocketValid(Socket *sock)
+{
+    if (sock != NULL)
+    {
+        return (sock->channel != INVALID_SOCKET);
+    }
+
+    return false;
+}
+
+// Sets the error code that can be retrieved through the WSAGetLastError function.
+static void SocketSetLastError(int err)
+{
+#if defined(_WIN32)
+    WSASetLastError(err);
+#else
+    errno = err;
+#endif
+}
+
+// Returns the error status for the last Sockets operation that failed
+static int SocketGetLastError(void)
+{
+#if defined(_WIN32)
+    return WSAGetLastError();
+#else
+    return errno;
+#endif
+}
+
+// Returns a human-readable string representing the last error message
+static char *SocketGetLastErrorString(void)
+{
+    return SocketErrorCodeToString(SocketGetLastError());
+}
+
+// Returns a human-readable string representing the error message (err)
+static char *SocketErrorCodeToString(int err)
+{
+#if defined(_WIN32)
+    static char gaiStrErrorBuffer[GAI_STRERROR_BUFFER_SIZE];
+    TRACELOG(LOG_INFO, gaiStrErrorBuffer, "%s", gai_strerror(err));
+    return gaiStrErrorBuffer;
+#else
+    return gai_strerror(err);
+#endif
+}
+
+// Set the defaults in the supplied SocketConfig if they're not already set
+static bool SocketSetDefaults(SocketConfig *config)
+{
+    if (config->backlog_size == 0) config->backlog_size = SOCKET_MAX_QUEUE_SIZE;
+
+    return true;
+}
+
+// Create the socket channel
+static bool InitSocket(Socket *sckt, struct addrinfo *address)
+{
+    switch (sckt->type)
+    {
+        case SOCKET_TCP:
+        {
+            if (address->ai_family == AF_INET) sckt->channel = socket(AF_INET, SOCK_STREAM, 0);
+            else sckt->channel = socket(AF_INET6, SOCK_STREAM, 0);
+        } break;
+        case SOCKET_UDP:
+        {
+            if (address->ai_family == AF_INET) sckt->channel = socket(AF_INET, SOCK_DGRAM, 0);
+            else sckt->channel = socket(AF_INET6, SOCK_DGRAM, 0);
+        } break;
+        default: TRACELOG(LOG_WARNING, "Invalid socket type specified."); break;
+    }
+
+    return IsSocketValid(sckt);
+}
+
+//    CreateSocket() - Interally called by CreateSocket()
+//
+//    This here is the bread and butter of the socket API, This function will
+//    attempt to open a socket, bind and listen to it based on the config passed in
+//
+//    SocketConfig* config - Configuration for which socket to open
+//    SocketResult* result - The results of this function (if any, including errors)
+//
+//    e.g.
+//    SocketConfig server_config = {                SocketConfig client_config = {
+//        .host = "127.0.0.1",                .host = "127.0.0.1",
+//        .port = 8080,                    .port = 8080,
+//        .server = true,                };
+//        .nonblocking = true,
+//    };
+//    SocketResult server_res;                SocketResult client_res;
+static bool CreateSocket(SocketConfig *config, SocketResult *outresult)
+{
+    bool success = true;
+    int addrstatus;
+    struct addrinfo hints;      // Address flags (IPV4, IPV6, UDP?)
+    struct addrinfo *res;       // A pointer to the resulting address list
+
+    outresult->socket->channel = INVALID_SOCKET;
+    outresult->status = RESULT_FAILURE;
+
+    // Set the socket type
+    outresult->socket->type = config->type;
+
+    //    Set the hints based on information in the config
+    //
+    //    AI_CANONNAME    Causes the ai_canonname of the result to the filled  out with the host's canonical (real) name.
+    //    AI_PASSIVE:        Causes the result's IP address to be filled out with INADDR_ANY (IPv4)or in6addr_any (IPv6);
+    //    Note:    This causes a subsequent call to bind() to auto-fill the IP address
+    //            of the struct sockaddr with the address of the current host.
+    //
+    SocketSetHints(config, &hints);
+
+    // Populate address information
+    addrstatus = getaddrinfo(config->host, // e.g. "www.example.com" or IP (Can be null if AI_PASSIVE flag is set
+                             config->port, // e.g. "http" or port number
+                             &hints,       // e.g. SOCK_STREAM/SOCK_DGRAM
+                             &res          // The struct to populate
+    );
+
+    // Did we succeed?
+    if (addrstatus != 0)
+    {
+        outresult->socket->status = SocketGetLastError();
+        TRACELOG(LOG_WARNING, "Socket Error: %s", SocketErrorCodeToString(outresult->socket->status));
+        SocketSetLastError(0);
+        TRACELOG(LOG_WARNING, "Failed to get resolve host %s:%s: %s", config->host, config->port, SocketGetLastErrorString());
+
+        return (success = false);
+    }
+    else
+    {
+        char hoststr[NI_MAXHOST];
+        char portstr[NI_MAXSERV];
+        //socklen_t client_len = sizeof(struct sockaddr_storage);
+        //int rc = getnameinfo((struct sockaddr *)res->ai_addr, client_len, hoststr, sizeof(hoststr), portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV);
+        TRACELOG(LOG_INFO, "Successfully resolved host %s:%s", hoststr, portstr);
+    }
+
+    // Walk the address information linked-list
+    struct addrinfo *it;
+    for (it = res; it != NULL; it = it->ai_next)
+    {
+        // Initialise the socket
+        if (!InitSocket(outresult->socket, it))
+        {
+            outresult->socket->status = SocketGetLastError();
+            TRACELOG(LOG_WARNING, "Socket Error: %s", SocketErrorCodeToString(outresult->socket->status));
+            SocketSetLastError(0);
+            continue;
+        }
+
+        // Set socket options
+        if (!SocketSetOptions(config, outresult->socket))
+        {
+            outresult->socket->status = SocketGetLastError();
+            TRACELOG(LOG_WARNING, "Socket Error: %s", SocketErrorCodeToString(outresult->socket->status));
+            SocketSetLastError(0);
+            freeaddrinfo(res);
+
+            return (success = false);
+        }
+    }
+
+    if (!IsSocketValid(outresult->socket))
+    {
+        outresult->socket->status = SocketGetLastError();
+        TRACELOG(LOG_WARNING, "Socket Error: %s", SocketErrorCodeToString(outresult->status));
+        SocketSetLastError(0);
+        freeaddrinfo(res);
+
+        return (success = false);
+    }
+
+    if (success)
+    {
+        outresult->status = RESULT_SUCCESS;
+        outresult->socket->ready = 0;
+        outresult->socket->status = 0;
+
+        if (!(config->type == SOCKET_UDP)) outresult->socket->isServer = config->server;
+
+        switch (res->ai_addr->sa_family)
+        {
+            case AF_INET:
+            {
+                outresult->socket->addripv4 = (struct _SocketAddressIPv4 *)RNET_MALLOC(sizeof(*outresult->socket->addripv4));
+
+                if (outresult->socket->addripv4 != NULL)
+                {
+                    memset(outresult->socket->addripv4, 0, sizeof(*outresult->socket->addripv4));
+
+                    if (outresult->socket->addripv4 != NULL)
+                    {
+                        memcpy(&outresult->socket->addripv4->address, (struct sockaddr_in *)res->ai_addr, sizeof(struct sockaddr_in));
+
+                        outresult->socket->isIPv6 = false;
+                        char hoststr[NI_MAXHOST];
+                        char portstr[NI_MAXSERV];
+
+                        socklen_t client_len = sizeof(struct sockaddr_storage);
+                        getnameinfo((struct sockaddr *)&outresult->socket->addripv4->address, client_len, hoststr, sizeof(hoststr), portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV);
+
+                        TRACELOG(LOG_INFO, "Socket address set to %s:%s", hoststr, portstr);
+                    }
+                }
+            } break;
+            case AF_INET6:
+            {
+                outresult->socket->addripv6 = (struct _SocketAddressIPv6 *)RNET_MALLOC(
+                    sizeof(*outresult->socket->addripv6));
+                if (outresult->socket->addripv6 != NULL)
+                {
+                    memset(outresult->socket->addripv6, 0,
+                           sizeof(*outresult->socket->addripv6));
+                    if (outresult->socket->addripv6 != NULL)
+                    {
+                        memcpy(&outresult->socket->addripv6->address,
+                               (struct sockaddr_in6 *)res->ai_addr, sizeof(struct sockaddr_in6));
+                        outresult->socket->isIPv6 = true;
+                        char      hoststr[NI_MAXHOST];
+                        char      portstr[NI_MAXSERV];
+                        socklen_t client_len = sizeof(struct sockaddr_storage);
+                        getnameinfo(
+                            (struct sockaddr *)&outresult->socket->addripv6->address, client_len, hoststr, sizeof(hoststr), portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV);
+                        TRACELOG(LOG_INFO, "Socket address set to %s:%s", hoststr, portstr);
+                    }
+                }
+            } break;
+            default: break;
+        }
+    }
+
+    freeaddrinfo(res);
+    return success;
+}
+
+// Set the state of the Socket sock to blocking
+static bool SocketSetBlocking(Socket *sock)
+{
+    bool ret = true;
+#if defined(_WIN32)
+    unsigned long mode = 0;
+    ret = ioctlsocket(sock->channel, FIONBIO, &mode);
+#else
+    const int flags = fcntl(sock->channel, F_GETFL, 0);
+    if (!(flags & O_NONBLOCK))
+    {
+        TRACELOG(LOG_DEBUG, "Socket was already in blocking mode");
+        return ret;
+    }
+
+    ret = (0 == fcntl(sock->channel, F_SETFL, (flags ^ O_NONBLOCK)));
+#endif
+    return ret;
+}
+
+// Set the state of the Socket sock to non-blocking
+static bool SocketSetNonBlocking(Socket *sock)
+{
+    bool ret = true;
+#if defined(_WIN32)
+    unsigned long mode = 1;
+    ret = ioctlsocket(sock->channel, FIONBIO, &mode);
+#else
+    const int flags = fcntl(sock->channel, F_GETFL, 0);
+
+    if ((flags & O_NONBLOCK))
+    {
+        TRACELOG(LOG_DEBUG, "Socket was already in non-blocking mode");
+        return ret;
+    }
+
+    ret = (0 == fcntl(sock->channel, F_SETFL, (flags | O_NONBLOCK)));
+#endif
+    return ret;
+}
+
+// Set options specified in SocketConfig to Socket sock
+static bool SocketSetOptions(SocketConfig *config, Socket *sock)
+{
+    for (int i = 0; i < SOCKET_MAX_SOCK_OPTS; i++)
+    {
+        SocketOpt *opt = &config->sockopts[i];
+
+        if (opt->id == 0) break;
+
+        if (setsockopt(sock->channel, SOL_SOCKET, opt->id, opt->value, opt->valueLen) < 0) return false;
+    }
+
+    return true;
+}
+
+// Set "hints" in an addrinfo struct, to be passed to getaddrinfo.
+static void SocketSetHints(SocketConfig *config, struct addrinfo *hints)
+{
+    if (config == NULL || hints == NULL) return;
+
+    memset(hints, 0, sizeof(*hints));
+
+    // Check if the ip supplied in the config is a valid ipv4 ip ipv6 address
+    if (IsIPv4Address(config->host))
+    {
+        hints->ai_family = AF_INET;
+        hints->ai_flags |= AI_NUMERICHOST;
+    }
+    else
+    {
+        if (IsIPv6Address(config->host))
+        {
+            hints->ai_family = AF_INET6;
+            hints->ai_flags |= AI_NUMERICHOST;
+        }
+        else hints->ai_family = AF_UNSPEC;
+    }
+
+    if (config->type == SOCKET_UDP) hints->ai_socktype = SOCK_DGRAM;
+    else hints->ai_socktype = SOCK_STREAM;
+
+
+    // Set passive unless UDP client
+    if (!(config->type == SOCKET_UDP) || config->server) hints->ai_flags = AI_PASSIVE;
+}
+
+//----------------------------------------------------------------------------------
+// Module implementation
+//----------------------------------------------------------------------------------
+
+//    Initialise the network (requires for windows platforms only)
+bool InitNetworkDevice(void)
+{
+#if defined(_WIN32)
+    WORD wVersionRequested;
+    WSADATA wsaData;
+
+    wVersionRequested = MAKEWORD(2, 2);
+    int err = WSAStartup(wVersionRequested, &wsaData);
+
+    if (err != 0)
+    {
+        TRACELOG(LOG_WARNING, "WinSock failed to initialise.");
+        return false;
+    }
+    else TRACELOG(LOG_INFO, "WinSock initialised.");
+
+    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
+    {
+        TRACELOG(LOG_WARNING, "WinSock failed to initialise.");
+        WSACleanup();
+        return false;
+    }
+
+    return true;
+#else
+    return true;
+#endif
+}
+
+//    Cleanup, and close the network
+void CloseNetworkDevice(void)
+{
+#if defined(_WIN32)
+    WSACleanup();
+#endif
+}
+
+//    Protocol-independent name resolution from an address to an ANSI host name
+//    and from a port number to the ANSI service name.
+//
+//    The flags parameter can be used to customize processing of the getnameinfo function
+//
+//    The following flags are available:
+//
+//    NAME_INFO_DEFAULT        0x00    // No flags set
+//    NAME_INFO_NOFQDN         0x01    // Only return nodename portion for local hosts
+//    NAME_INFO_NUMERICHOST    0x02    // Return numeric form of the host's address
+//    NAME_INFO_NAMEREQD       0x04    // Error if the host's name not in DNS
+//    NAME_INFO_NUMERICSERV    0x08    // Return numeric form of the service (port #)
+//    NAME_INFO_DGRAM          0x10    // Service is a datagram service
+void ResolveIP(const char *ip, const char *port, int flags, char *host, char *serv)
+{
+    // Variables
+    int status;             // Status value to return (0) is success
+    struct addrinfo hints;  // Address flags (IPV4, IPV6, UDP?)
+    struct addrinfo *res;   // A pointer to the resulting address list
+
+    // Set the hints
+    memset(&hints, 0, sizeof hints);
+    hints.ai_family = AF_UNSPEC; // Either IPv4 or IPv6 (AF_INET, AF_INET6)
+    hints.ai_protocol = 0; // Automatically select correct protocol (IPPROTO_TCP), (IPPROTO_UDP)
+
+    // Populate address information
+    status = getaddrinfo(ip,     // e.g. "www.example.com" or IP
+                         port,   // e.g. "http" or port number
+                         &hints, // e.g. SOCK_STREAM/SOCK_DGRAM
+                         &res    // The struct to populate
+    );
+
+    // Did we succeed?
+    if (status != 0) TRACELOG(LOG_WARNING, "Failed to get resolve host %s:%s: %s", ip, port, gai_strerror(errno));
+    else TRACELOG(LOG_DEBUG, "Resolving... %s::%s", ip, port);
+
+    // Attempt to resolve network byte order ip to hostname
+    switch (res->ai_family)
+    {
+        case AF_INET:
+        {
+            status = getnameinfo(&*((struct sockaddr *)res->ai_addr),
+                                 sizeof(*((struct sockaddr_in *)res->ai_addr)),
+                                 host, NI_MAXHOST, serv, NI_MAXSERV, flags);
+        } break;
+        case AF_INET6:
+        {
+        /*
+            status = getnameinfo(&*((struct sockaddr_in6 *)res->ai_addr),          // TODO.
+                                 sizeof(*((struct sockaddr_in6 *)res->ai_addr)),
+                                 host, NI_MAXHOST, serv, NI_MAXSERV, flags);
+        */
+        } break;
+        default: break;
+    }
+
+    if (status != 0) TRACELOG(LOG_WARNING, "Failed to resolve ip %s: %s", ip, SocketGetLastErrorString());
+    else TRACELOG(LOG_DEBUG, "Successfully resolved %s::%s to %s", ip, port, host);
+
+    // Free the pointer to the data returned by addrinfo
+    freeaddrinfo(res);
+}
+
+//    Protocol-independent translation from an ANSI host name to an address
+//
+//    e.g.
+//    const char* address = "127.0.0.1" (local address)
+//    const char* port = "80"
+//
+//  Parameters:
+//      const char* address - A pointer to a NULL-terminated ANSI string that contains a host (node) name or a numeric host address string.
+//      const char* service - A pointer to a NULL-terminated ANSI string that contains either a service name or port number represented as a string.
+//
+//    Returns:
+//        The total amount of addresses found, -1 on error
+//
+int ResolveHost(const char *address, const char *service, int addressType, int flags, AddressInformation *outAddr)
+{
+    // Variables
+    int status; // Status value to return (0) is success
+    struct addrinfo hints;  // Address flags (IPV4, IPV6, UDP?)
+    struct addrinfo *res;    // will point to the results
+    struct addrinfo *iterator;
+    assert(((address != NULL || address != 0) || (service != NULL || service != 0)));
+    assert(((addressType == AF_INET) || (addressType == AF_INET6) || (addressType == AF_UNSPEC)));
+
+    // Set the hints
+    memset(&hints, 0, sizeof hints);
+    hints.ai_family = addressType; // Either IPv4 or IPv6 (ADDRESS_TYPE_IPV4, ADDRESS_TYPE_IPV6)
+    hints.ai_protocol = 0; // Automatically select correct protocol (IPPROTO_TCP), (IPPROTO_UDP)
+    hints.ai_flags = flags;
+    assert((hints.ai_addrlen == 0) || (hints.ai_addrlen == 0));
+    assert((hints.ai_canonname == 0) || (hints.ai_canonname == 0));
+    assert((hints.ai_addr == 0) || (hints.ai_addr == 0));
+    assert((hints.ai_next == 0) || (hints.ai_next == 0));
+
+    // When the address is NULL, populate the IP for me
+    if (address == NULL)
+    {
+        if ((hints.ai_flags & AI_PASSIVE) == 0) hints.ai_flags |= AI_PASSIVE;
+    }
+
+    TRACELOG(LOG_INFO, "Resolving host...");
+
+    // Populate address information
+    status = getaddrinfo(address, // e.g. "www.example.com" or IP
+                         service, // e.g. "http" or port number
+                         &hints,  // e.g. SOCK_STREAM/SOCK_DGRAM
+                         &res     // The struct to populate
+    );
+
+    // Did we succeed?
+    if (status != 0)
+    {
+        int error = SocketGetLastError();
+        SocketSetLastError(0);
+        TRACELOG(LOG_WARNING, "Failed to get resolve host: %s", SocketErrorCodeToString(error));
+        return -1;
+    }
+    else TRACELOG(LOG_INFO, "Successfully resolved host %s:%s", address, service);
+
+    // Calculate the size of the address information list
+    int size = 0;
+    for (iterator = res; iterator != NULL; iterator = iterator->ai_next) size++;
+
+    // Validate the size is > 0, otherwise return
+    if (size <= 0)
+    {
+        TRACELOG(LOG_WARNING, "Error, no addresses found.");
+        return -1;
+    }
+
+    // If not address list was allocated, allocate it dynamically with the known address size
+    if (outAddr == NULL) outAddr = (AddressInformation *)RNET_MALLOC(size * sizeof(AddressInformation));
+
+    // Dynamically allocate an array of address information structs
+    if (outAddr != NULL)
+    {
+        int i;
+        for (i = 0; i < size; ++i)
+        {
+            outAddr[i] = LoadAddress();
+            if (outAddr[i] == NULL)
+            {
+                break;
+            }
+        }
+
+        outAddr[i] = NULL;
+        if (i != size) outAddr = NULL;
+    }
+    else
+    {
+        TRACELOG(LOG_WARNING, "Error, failed to dynamically allocate memory for the address list");
+        return -1;
+    }
+
+    // Copy all the address information from res into outAddrList
+    int i = 0;
+    for (iterator = res; iterator != NULL; iterator = iterator->ai_next)
+    {
+        if (i < size)
+        {
+            outAddr[i]->addr.ai_flags = iterator->ai_flags;
+            outAddr[i]->addr.ai_family = iterator->ai_family;
+            outAddr[i]->addr.ai_socktype = iterator->ai_socktype;
+            outAddr[i]->addr.ai_protocol = iterator->ai_protocol;
+            outAddr[i]->addr.ai_addrlen = iterator->ai_addrlen;
+            *outAddr[i]->addr.ai_addr = *iterator->ai_addr;
+#if NET_DEBUG_ENABLED
+            TRACELOG(LOG_DEBUG, "GetAddressInformation");
+            TRACELOG(LOG_DEBUG, "\tFlags: 0x%x", iterator->ai_flags);
+            //PrintSocket(outAddr[i]->addr.ai_addr, outAddr[i]->addr.ai_family, outAddr[i]->addr.ai_socktype, outAddr[i]->addr.ai_protocol);
+            TRACELOG(LOG_DEBUG, "Length of this sockaddr: %d", outAddr[i]->addr.ai_addrlen);
+            TRACELOG(LOG_DEBUG, "Canonical name: %s", iterator->ai_canonname);
+#endif
+            i++;
+        }
+    }
+
+    // Free the pointer to the data returned by addrinfo
+    freeaddrinfo(res);
+
+    // Return the total count of addresses found
+    return size;
+}
+
+//    This here is the bread and butter of the socket API, This function will
+//    attempt to open a socket, bind and listen to it based on the config passed in
+//
+//    SocketConfig* config - Configuration for which socket to open
+//    SocketResult* result - The results of this function (if any, including errors)
+//
+//    e.g.
+//    SocketConfig server_config = {            SocketConfig client_config = {
+//        .host = "127.0.0.1",                .host = "127.0.0.1",
+//        .port = 8080,                    .port = 8080,
+//        .server = true,                };
+//        .nonblocking = true,
+//    };
+//    SocketResult server_res;                SocketResult client_res;
+bool SocketCreate(SocketConfig *config, SocketResult *result)
+{
+    // Socket creation result
+    bool success = true;
+
+    // Make sure we've not received a null config or result pointer
+    if (config == NULL || result == NULL) return (success = false);
+
+    // Set the defaults based on the config
+    if (!SocketSetDefaults(config))
+    {
+        TRACELOG(LOG_WARNING, "Configuration Error.");
+        success = false;
+    }
+    else
+    {
+        // Create the socket
+        if (CreateSocket(config, result))
+        {
+            if (config->nonblocking) SocketSetNonBlocking(result->socket);
+            else SocketSetBlocking(result->socket);
+        }
+        else success = false;
+    }
+
+    return success;
+}
+
+// Bind a socket to a local address
+// Note: The bind function is required on an unconnected socket before subsequent calls to the listen function.
+bool SocketBind(SocketConfig *config, SocketResult *result)
+{
+    bool success = false;
+    result->status = RESULT_FAILURE;
+    struct sockaddr_storage *sock_addr = NULL;
+
+    // Don't bind to a socket that isn't configured as a server
+    if (!IsSocketValid(result->socket) || !config->server)
+    {
+        TRACELOG(LOG_WARNING, Cannot bind to socket marked as \"Client\" in SocketConfig.");
+        success = false;
+    }
+    else
+    {
+        if (result->socket->isIPv6) sock_addr = (struct sockaddr_storage *)&result->socket->addripv6->address;
+        else sock_addr = (struct sockaddr_storage *)&result->socket->addripv4->address;
+
+        if (sock_addr != NULL)
+        {
+            if (bind(result->socket->channel, (struct sockaddr *)sock_addr, sizeof(*sock_addr)) != SOCKET_ERROR)
+            {
+                TRACELOG(LOG_INFO, "Successfully bound socket.");
+                success = true;
+            }
+            else
+            {
+                result->socket->status = SocketGetLastError();
+                TRACELOG(LOG_WARNING, "Socket Error: %s", SocketErrorCodeToString(result->socket->status));
+                SocketSetLastError(0);
+                success = false;
+            }
+        }
+    }
+
+    // Was the bind a success?
+    if (success)
+    {
+        result->status = RESULT_SUCCESS;
+        result->socket->ready = 0;
+        result->socket->status = 0;
+        socklen_t sock_len = sizeof(*sock_addr);
+
+        if (getsockname(result->socket->channel, (struct sockaddr *)sock_addr, &sock_len) < 0)
+        {
+            TRACELOG(LOG_WARNING, "Couldn't get socket address");
+        }
+        else
+        {
+            struct sockaddr_in *s = (struct sockaddr_in *)sock_addr;
+            // result->socket->address.host = s->sin_addr.s_addr;
+            // result->socket->address.port = s->sin_port;
+
+            result->socket->addripv4 = (struct _SocketAddressIPv4 *)RNET_MALLOC(sizeof(*result->socket->addripv4));
+
+            if (result->socket->addripv4 != NULL) memset(result->socket->addripv4, 0, sizeof(*result->socket->addripv4));
+
+            memcpy(&result->socket->addripv4->address, (struct sockaddr_in *)&s->sin_addr, sizeof(struct sockaddr_in));
+        }
+    }
+    return success;
+}
+
+// Listens (and queues) incoming connections requests for a bound port.
+bool SocketListen(SocketConfig *config, SocketResult *result)
+{
+    bool success = false;
+    result->status = RESULT_FAILURE;
+
+    // Don't bind to a socket that isn't configured as a server
+    if (!IsSocketValid(result->socket) || !config->server)
+    {
+        TRACELOG(LOG_WARNING, "Cannot listen on socket marked as \"Client\" in SocketConfig.");
+        success = false;
+    }
+    else
+    {
+        // Don't listen on UDP sockets
+        if (!(config->type == SOCKET_UDP))
+        {
+            if (listen(result->socket->channel, config->backlog_size) != SOCKET_ERROR)
+            {
+                TRACELOG(LOG_INFO, "Started listening on socket...");
+                success = true;
+            }
+            else
+            {
+                success = false;
+                result->socket->status = SocketGetLastError();
+                TRACELOG(LOG_WARNING, "Socket Error: %s", SocketErrorCodeToString(result->socket->status));
+                SocketSetLastError(0);
+            }
+        }
+        else
+        {
+            TRACELOG(LOG_WARNING, "Cannot listen on socket marked as \"UDP\" (datagram) in SocketConfig.");
+            success = false;
+        }
+    }
+
+    // Was the listen a success?
+    if (success)
+    {
+        result->status = RESULT_SUCCESS;
+        result->socket->ready = 0;
+        result->socket->status = 0;
+    }
+
+    return success;
+}
+
+// Connect the socket to the destination specified by "host" and "port" in SocketConfig
+bool SocketConnect(SocketConfig *config, SocketResult *result)
+{
+    bool success = true;
+    result->status = RESULT_FAILURE;
+
+    // Only bind to sockets marked as server
+    if (config->server)
+    {
+        TRACELOG(LOG_WARNING, "Cannot connect to socket marked as \"Server\" in SocketConfig.");
+        success = false;
+    }
+    else
+    {
+        if (IsIPv4Address(config->host))
+        {
+            struct sockaddr_in ip4addr;
+            ip4addr.sin_family = AF_INET;
+            unsigned long hport;
+            hport = strtoul(config->port, NULL, 0);
+            ip4addr.sin_port = htons(hport);
+
+            // TODO: Changed the code to avoid the usage of inet_pton and inet_ntop replacing them with getnameinfo (that should have a better support on windows).
+
+            //inet_pton(AF_INET, config->host, &ip4addr.sin_addr);
+            int connect_result = connect(result->socket->channel, (struct sockaddr *)&ip4addr, sizeof(ip4addr));
+
+            if (connect_result == SOCKET_ERROR)
+            {
+                result->socket->status = SocketGetLastError();
+                SocketSetLastError(0);
+
+                switch (result->socket->status)
+                {
+                    case WSAEWOULDBLOCK: success = true; break;
+                    default:
+                    {
+                        TRACELOG(LOG_WARNING, "Socket Error: %s", SocketErrorCodeToString(result->socket->status));
+                        success = false;
+                    } break;
+                }
+            }
+            else
+            {
+                TRACELOG(LOG_INFO, "Successfully connected to socket.");
+                success = true;
+            }
+        }
+        else
+        {
+            if (IsIPv6Address(config->host))
+            {
+                struct sockaddr_in6 ip6addr;
+                ip6addr.sin6_family = AF_INET6;
+                unsigned long hport;
+                hport = strtoul(config->port, NULL, 0);
+                ip6addr.sin6_port = htons(hport);
+                //inet_pton(AF_INET6, config->host, &ip6addr.sin6_addr);    // TODO.
+                int connect_result = connect(result->socket->channel, (struct sockaddr *)&ip6addr, sizeof(ip6addr));
+
+                if (connect_result == SOCKET_ERROR)
+                {
+                    result->socket->status = SocketGetLastError();
+                    SocketSetLastError(0);
+
+                    switch (result->socket->status)
+                    {
+                        case WSAEWOULDBLOCK: success = true; break;
+                        default:
+                        {
+                            TRACELOG(LOG_WARNING, "Socket Error: %s", SocketErrorCodeToString(result->socket->status));
+                            success = false;
+                        } break;
+                    }
+                }
+                else
+                {
+                    TRACELOG(LOG_INFO, "Successfully connected to socket.");
+                    success = true;
+                }
+            }
+        }
+    }
+
+    if (success)
+    {
+        result->status = RESULT_SUCCESS;
+        result->socket->ready = 0;
+        result->socket->status = 0;
+    }
+
+    return success;
+}
+
+//    Closes an existing socket
+//
+//    SocketChannel socket - The id of the socket to close
+void SocketClose(Socket *sock)
+{
+    if (sock != NULL)
+    {
+        if (sock->channel != INVALID_SOCKET) closesocket(sock->channel);
+    }
+}
+
+// Returns the sockaddress for a specific socket in a generic storage struct
+SocketAddressStorage SocketGetPeerAddress(Socket *sock)
+{
+    // TODO.
+    /*
+    if (sock->isServer) return NULL;
+    if (sock->isIPv6) return sock->addripv6;
+    else return sock->addripv4;
+    */
+
+    return NULL;
+}
+
+// Return the address-type appropriate host portion of a socket address
+char *GetSocketAddressHost(SocketAddressStorage storage)
+{
+    assert(storage->address.ss_family == AF_INET || storage->address.ss_family == AF_INET6);
+    return SocketAddressToString((struct sockaddr_storage *)storage);
+}
+
+// Return the address-type appropriate port(service) portion of a socket address
+short GetSocketAddressPort(SocketAddressStorage storage)
+{
+    //return ntohs(GetSocketPortPtr(storage));      // TODO.
+
+    return 0;
+}
+
+//    The accept function permits an incoming connection attempt on a socket.
+//
+//    SocketChannel    listener    - The socket to listen for incoming connections on (i.e. server)
+//    SocketResult*    out            - The result of this function (if any, including errors)
+//
+//    e.g.
+//
+//    SocketResult connection;
+//    bool         connected = false;
+//    if (!connected)
+//    {
+//        if (SocketAccept(server_res.socket.channel, &connection))
+//        {
+//            connected = true;
+//        }
+//    }
+Socket *SocketAccept(Socket *server, SocketConfig *config)
+{
+    if (!server->isServer || server->type == SOCKET_UDP) return NULL;
+
+    struct sockaddr_storage sock_addr;
+    socklen_t sock_alen;
+    Socket *sock = LoadSocket();
+    server->ready = 0;
+    sock_alen = sizeof(sock_addr);
+    sock->channel = accept(server->channel, (struct sockaddr *)&sock_addr, &sock_alen);
+
+    if (sock->channel == INVALID_SOCKET)
+    {
+        sock->status = SocketGetLastError();
+        TRACELOG(LOG_WARNING, "Socket Error: %s", SocketErrorCodeToString(sock->status));
+        SocketSetLastError(0);
+        SocketClose(sock);
+
+        return NULL;
+    }
+
+    (config->nonblocking) ? SocketSetNonBlocking(sock) : SocketSetBlocking(sock);
+    sock->isServer = false;
+    sock->ready = 0;
+    sock->type = server->type;
+
+    switch (sock_addr.ss_family)
+    {
+        case AF_INET:
+        {
+            struct sockaddr_in *s = ((struct sockaddr_in *)&sock_addr);
+            sock->addripv4 = (struct _SocketAddressIPv4 *)RNET_MALLOC(sizeof(*sock->addripv4));
+
+            if (sock->addripv4 != NULL)
+            {
+                memset(sock->addripv4, 0, sizeof(*sock->addripv4));
+                memcpy(&sock->addripv4->address, (struct sockaddr_in *)&s->sin_addr, sizeof(struct sockaddr_in));
+                TRACELOG(LOG_INFO, "Server: Got connection from %s::%hu", SocketAddressToString((struct sockaddr_storage *)s), ntohs(sock->addripv4->address.sin_port));
+            }
+        } break;
+        case AF_INET6:
+        {
+            struct sockaddr_in6 *s = ((struct sockaddr_in6 *)&sock_addr);
+            sock->addripv6 = (struct _SocketAddressIPv6 *)RNET_MALLOC(sizeof(*sock->addripv6));
+
+            if (sock->addripv6 != NULL)
+            {
+                memset(sock->addripv6, 0, sizeof(*sock->addripv6));
+                memcpy(&sock->addripv6->address, (struct sockaddr_in6 *)&s->sin6_addr, sizeof(struct sockaddr_in6));
+                TRACELOG(LOG_INFO, "Server: Got connection from %s::%hu", SocketAddressToString((struct sockaddr_storage *)s), ntohs(sock->addripv6->address.sin6_port));
+            }
+        } break;
+    }
+
+    return sock;
+}
+
+// Verify that the channel is in the valid range
+static int ValidChannel(int channel)
+{
+    if ((channel < 0) || (channel >= SOCKET_MAX_UDPCHANNELS))
+    {
+        TRACELOG(LOG_WARNING, "Invalid channel");
+        return 0;
+    }
+
+    return 1;
+}
+
+// Set the socket channel
+int SocketSetChannel(Socket *socket, int channel, const IPAddress *address)
+{
+    struct UDPChannel *binding;
+
+    if (socket == NULL)
+    {
+        TRACELOG(LOG_WARNING, "Passed a NULL socket");
+        return (-1);
+    }
+
+    if (channel == -1)
+    {
+        for (channel = 0; channel < SOCKET_MAX_UDPCHANNELS; ++channel)
+        {
+            binding = &socket->binding[channel];
+            if (binding->numbound < SOCKET_MAX_UDPADDRESSES) break;
+        }
+    }
+    else
+    {
+        if (!ValidChannel(channel)) return (-1);
+
+        binding = &socket->binding[channel];
+    }
+
+    if (binding->numbound == SOCKET_MAX_UDPADDRESSES)
+    {
+        TRACELOG(LOG_WARNING, "No room for new addresses");
+        return (-1);
+    }
+
+    binding->address[binding->numbound++] = *address;
+
+    return (channel);
+}
+
+// Remove the socket channel
+void SocketUnsetChannel(Socket *socket, int channel)
+{
+    if ((channel >= 0) && (channel < SOCKET_MAX_UDPCHANNELS)) socket->binding[channel].numbound = 0;
+}
+
+/* Allocate/free a single UDP packet 'size' bytes long.
+   The new packet is returned, or NULL if the function ran out of memory.
+ */
+SocketDataPacket *AllocPacket(int size)
+{
+    SocketDataPacket *packet = (SocketDataPacket *)RNET_MALLOC(sizeof(*packet));
+    int error = 1;
+
+    if (packet != NULL)
+    {
+        packet->maxlen = size;
+        packet->data = (uint8_t *)RNET_MALLOC(size);
+        if (packet->data != NULL)
+        {
+            error = 0;
+        }
+    }
+
+    if (error)
+    {
+        FreePacket(packet);
+        packet = NULL;
+    }
+
+    return (packet);
+}
+
+int ResizePacket(SocketDataPacket *packet, int newsize)
+{
+    uint8_t *newdata = (uint8_t *)RNET_MALLOC(newsize);
+
+    if (newdata != NULL)
+    {
+        RNET_FREE(packet->data);
+        packet->data = newdata;
+        packet->maxlen = newsize;
+    }
+
+    return (packet->maxlen);
+}
+
+void FreePacket(SocketDataPacket *packet)
+{
+    if (packet)
+    {
+        RNET_FREE(packet->data);
+        RNET_FREE(packet);
+    }
+}
+
+// Allocate/Free a UDP packet vector (array of packets) of 'howmany' packets, each 'size' bytes long.
+// A pointer to the packet array is returned, or NULL if the function ran out of memory.
+SocketDataPacket **AllocPacketList(int howmany, int size)
+{
+    SocketDataPacket **packetV = (SocketDataPacket **)RNET_MALLOC((howmany + 1) * sizeof(*packetV));
+
+    if (packetV != NULL)
+    {
+        int i;
+        for (i = 0; i < howmany; ++i)
+        {
+            packetV[i] = AllocPacket(size);
+            if (packetV[i] == NULL)
+            {
+                break;
+            }
+        }
+        packetV[i] = NULL;
+
+        if (i != howmany)
+        {
+            FreePacketList(packetV);
+            packetV = NULL;
+        }
+    }
+
+    return (packetV);
+}
+
+void FreePacketList(SocketDataPacket **packetV)
+{
+    if (packetV)
+    {
+        for (int i = 0; packetV[i]; ++i) FreePacket(packetV[i]);
+        RNET_FREE(packetV);
+    }
+}
+
+// Send 'len' bytes of 'data' over the non-server socket 'sock'
+int SocketSend(Socket *sock, const void *datap, int length)
+{
+    int sent = 0;
+    int left = length;
+    int status = -1;
+    int numsent = 0;
+    const unsigned char *data = (const unsigned char *)datap;
+
+    // Server sockets are for accepting connections only
+    if (sock->isServer)
+    {
+        TRACELOG(LOG_WARNING, "Cannot send information on a server socket");
+        return -1;
+    }
+
+    // Which socket are we trying to send data on
+    switch (sock->type)
+    {
+        case SOCKET_TCP:
+        {
+            SocketSetLastError(0);
+            do
+            {
+                length = send(sock->channel, (const char *)data, left, 0);
+                if (length > 0)
+                {
+                    sent += length;
+                    left -= length;
+                    data += length;
+                }
+            } while ((left > 0) && // While we still have bytes left to send
+                     ((length > 0) || // The amount of bytes we actually sent is > 0
+                      (SocketGetLastError() == WSAEINTR)) // The socket was interupted
+            );
+
+            if (length == SOCKET_ERROR)
+            {
+                sock->status = SocketGetLastError();
+                TRACELOG(LOG_DEBUG, "Socket Error: %s", SocketErrorCodeToString(sock->status));
+                SocketSetLastError(0);
+            }
+            else TRACELOG(LOG_DEBUG, "Successfully sent \"%s\" (%d bytes)", datap, sent);
+
+            return sent;
+        } break;
+        case SOCKET_UDP:
+        {
+            SocketSetLastError(0);
+
+            if (sock->isIPv6) status = sendto(sock->channel, (const char *)data, left, 0, (struct sockaddr *)&sock->addripv6->address, sizeof(sock->addripv6->address));
+            else status = sendto(sock->channel, (const char *)data, left, 0, (struct sockaddr *)&sock->addripv4->address, sizeof(sock->addripv4->address));
+
+            if (sent >= 0)
+            {
+                sock->status = 0;
+                ++numsent;
+                TRACELOG(LOG_DEBUG, "Successfully sent \"%s\" (%d bytes)", datap, status);
+            }
+            else
+            {
+                sock->status = SocketGetLastError();
+                TRACELOG(LOG_DEBUG, "Socket Error: %s", SocketGetLastErrorString(sock->status));
+                SocketSetLastError(0);
+                return 0;
+            }
+
+            return numsent;
+        } break;
+        default: break;
+    }
+
+    return -1;
+}
+
+//    Receive up to 'maxlen' bytes of data over the non-server socket 'sock',
+//    and store them in the buffer pointed to by 'data'.
+//    This function returns the actual amount of data received.  If the return
+//    value is less than or equal to zero, then either the remote connection was
+//    closed, or an unknown socket error occurred.
+int SocketReceive(Socket *sock, void *data, int maxlen)
+{
+    int len = 0;
+    int numrecv = 0;
+    int status = 0;
+    socklen_t sock_len;
+    struct sockaddr_storage sock_addr;
+    //char ip[INET6_ADDRSTRLEN];
+
+    // Server sockets are for accepting connections only
+    if (sock->isServer && (sock->type == SOCKET_TCP))
+    {
+        sock->status = SocketGetLastError();
+        TRACELOG(LOG_DEBUG, "Socket Error: %s", "Server sockets cannot be used to receive data");
+        SocketSetLastError(0);
+        return 0;
+    }
+
+    // Which socket are we trying to send data on
+    switch (sock->type)
+    {
+        case SOCKET_TCP:
+        {
+            SocketSetLastError(0);
+            do
+            {
+                len = recv(sock->channel, (char *)data, maxlen, 0);
+            } while (SocketGetLastError() == WSAEINTR);
+
+            if (len > 0)
+            {
+                // Who sent the packet?
+                if (sock->type == SOCKET_UDP)
+                {
+                    //TRACELOG(LOG_DEBUG, "Received data from: %s", inet_ntop(sock_addr.ss_family, GetSocketAddressPtr((struct sockaddr *)&sock_addr), ip, sizeof(ip)));
+                }
+
+                ((unsigned char *)data)[len] = '\0'; // Add null terminating character to the end of the stream
+                TRACELOG(LOG_DEBUG, "Received \"%s\" (%d bytes)", data, len);
+            }
+
+            sock->ready = 0;
+            return len;
+        } break;
+        case SOCKET_UDP:
+        {
+            SocketSetLastError(0);
+            sock_len = sizeof(sock_addr);
+            status = recvfrom(sock->channel,    // The receving channel
+                              data,             // A pointer to the data buffer to fill
+                              maxlen,           // The max length of the data to fill
+                              0,                // Flags
+                              (struct sockaddr *)&sock_addr, // The address of the recevied data
+                              &sock_len         // The length of the received data address
+            );
+
+            if (status >= 0) ++numrecv;
+            else
+            {
+                sock->status = SocketGetLastError();
+
+                switch (sock->status)
+                {
+                    case WSAEWOULDBLOCK: break;
+                    default: TRACELOG(LOG_WARNING, "Socket Error: %s", SocketErrorCodeToString(sock->status)); break;
+                }
+
+                SocketSetLastError(0);
+                return 0;
+            }
+
+            sock->ready = 0;
+            return numrecv;
+        } break;
+        default: break;
+    }
+
+    return -1;
+}
+
+// Does the socket have it's 'ready' flag set?
+bool IsSocketReady(Socket *sock)
+{
+    return (sock != NULL) && (sock->ready);
+}
+
+// Check if the socket is considered connected
+bool IsSocketConnected(Socket *sock)
+{
+#if defined(_WIN32)
+    FD_SET writefds;
+    FD_ZERO(&writefds);
+    FD_SET(sock->channel, &writefds);
+    struct timeval timeout;
+    timeout.tv_sec = 1;
+    timeout.tv_usec = 1000000000UL;
+    int total = select(0, NULL, &writefds, NULL, &timeout);
+
+    if (total == -1)
+    { // Error
+        sock->status = SocketGetLastError();
+        TRACELOG(LOG_WARNING, "Socket Error: %s", SocketErrorCodeToString(sock->status));
+        SocketSetLastError(0);
+    }
+    else if (total == 0) return false;   // Timeout
+    else if (FD_ISSET(sock->channel, &writefds)) return true;
+
+    return false;
+#else
+    return true;
+#endif
+}
+
+// Allocate and return a SocketResult struct
+SocketResult *LoadSocketResult(void)
+{
+    struct SocketResult *res = (struct SocketResult *)RNET_MALLOC(sizeof(*res));
+
+    if (res != NULL)
+    {
+        memset(res, 0, sizeof(*res));
+        if ((res->socket = LoadSocket()) == NULL)
+        {
+            RNET_FREE(res);
+            res = NULL;
+        }
+    }
+
+    return res;
+}
+
+// Free an allocated SocketResult
+void UnloadSocketResult(SocketResult **result)
+{
+    if (*result != NULL)
+    {
+        if ((*result)->socket != NULL) UnloadSocket(&((*result)->socket));
+
+        RNET_FREE(*result);
+        *result = NULL;
+    }
+}
+
+// Allocate a Socket
+Socket *LoadSocket(void)
+{
+    struct Socket *sock;
+    sock = (Socket *)RNET_MALLOC(sizeof(*sock));
+
+    if (sock != NULL) memset(sock, 0, sizeof(*sock));
+    else
+    {
+        TRACELOG(LOG_WARNING, "Ran out of memory attempting to allocate a socket");
+        SocketClose(sock);
+        RNET_FREE(sock);
+        sock = NULL;
+    }
+
+    return sock;
+}
+
+// Free an allocated Socket
+void UnloadSocket(Socket **sock)
+{
+    if (*sock != NULL)
+    {
+        RNET_FREE(*sock);
+        *sock = NULL;
+    }
+}
+
+// Allocate a SocketSet
+SocketSet *LoadSocketSet(int max)
+{
+    struct SocketSet *set = (struct SocketSet *)RNET_MALLOC(sizeof(*set));
+
+    if (set != NULL)
+    {
+        set->numsockets = 0;
+        set->maxsockets = max;
+        set->sockets = (struct Socket **)RNET_MALLOC(max * sizeof(*set->sockets));
+        if (set->sockets != NULL)
+        {
+            for (int i = 0; i < max; ++i) set->sockets[i] = NULL;
+        }
+        else
+        {
+            RNET_FREE(set);
+            set = NULL;
+        }
+    }
+
+    return (set);
+}
+
+// Free an allocated SocketSet
+void UnloadSocketSet(SocketSet *set)
+{
+    if (set)
+    {
+        RNET_FREE(set->sockets);
+        RNET_FREE(set);
+    }
+}
+
+// Add a Socket "sock" to the SocketSet "set"
+int AddSocket(SocketSet *set, Socket *sock)
+{
+    if (sock != NULL)
+    {
+        if (set->numsockets == set->maxsockets)
+        {
+            TRACELOG(LOG_DEBUG, "Socket Error: %s", "SocketSet is full");
+            SocketSetLastError(0);
+            return (-1);
+        }
+        set->sockets[set->numsockets++] = (struct Socket *)sock;
+    }
+    else
+    {
+        TRACELOG(LOG_DEBUG, "Socket Error: %s", "Socket was null");
+        SocketSetLastError(0);
+        return (-1);
+    }
+
+    return (set->numsockets);
+}
+
+// Remove a Socket "sock" to the SocketSet "set"
+int RemoveSocket(SocketSet *set, Socket *sock)
+{
+    if (sock != NULL)
+    {
+        int i = 0;
+        for (i = 0; i < set->numsockets; ++i)
+        {
+            if (set->sockets[i] == (struct Socket *)sock) break;
+        }
+
+        if (i == set->numsockets)
+        {
+            TRACELOG(LOG_DEBUG, "Socket Error: %s", "Socket not found");
+            SocketSetLastError(0);
+            return (-1);
+        }
+
+        --set->numsockets;
+        for (; i < set->numsockets; ++i) set->sockets[i] = set->sockets[i + 1];
+    }
+
+    return (set->numsockets);
+}
+
+// Check the sockets in the socket set for pending information
+int CheckSockets(SocketSet *set, unsigned int timeout)
+{
+    int i;
+    SOCKET maxfd;
+    int retval;
+    struct timeval tv;
+    fd_set mask;
+
+    /* Find the largest file descriptor */
+    maxfd = 0;
+    for (i = set->numsockets - 1; i >= 0; --i)
+    {
+        if (set->sockets[i]->channel > maxfd)
+        {
+            maxfd = set->sockets[i]->channel;
+        }
+    }
+
+    // Check the file descriptors for available data
+    do
+    {
+        SocketSetLastError(0);
+
+        // Set up the mask of file descriptors
+        FD_ZERO(&mask);
+        for (i = set->numsockets - 1; i >= 0; --i)
+        {
+            FD_SET(set->sockets[i]->channel, &mask);
+        } // Set up the timeout
+
+        tv.tv_sec = timeout / 1000;
+        tv.tv_usec = (timeout % 1000) * 1000;
+
+        /* Look! */
+        retval = select(maxfd + 1, &mask, NULL, NULL, &tv);
+    } while (SocketGetLastError() == WSAEINTR);
+
+    // Mark all file descriptors ready that have data available
+    if (retval > 0)
+    {
+        for (i = set->numsockets - 1; i >= 0; --i)
+        {
+            if (FD_ISSET(set->sockets[i]->channel, &mask)) set->sockets[i]->ready = 1;
+        }
+    }
+
+    return retval;
+}
+
+// Allocate an AddressInformation
+AddressInformation LoadAddress(void)
+{
+    AddressInformation addressInfo = NULL;
+    addressInfo = (AddressInformation)RNET_CALLOC(1, sizeof(*addressInfo));
+
+    if (addressInfo != NULL)
+    {
+        addressInfo->addr.ai_addr = (struct sockaddr *)RNET_CALLOC(1, sizeof(struct sockaddr));
+        if (addressInfo->addr.ai_addr == NULL) TRACELOG(LOG_WARNING, "Failed to allocate memory for \"struct sockaddr\"");
+    }
+    else TRACELOG(LOG_WARNING, "Failed to allocate memory for \"struct AddressInformation\"");
+
+    return addressInfo;
+}
+
+// Free an AddressInformation struct
+void UnloadAddress(AddressInformation *addressInfo)
+{
+    if (*addressInfo != NULL)
+    {
+        if ((*addressInfo)->addr.ai_addr != NULL)
+        {
+            RNET_FREE((*addressInfo)->addr.ai_addr);
+            (*addressInfo)->addr.ai_addr = NULL;
+        }
+
+        RNET_FREE(*addressInfo);
+        *addressInfo = NULL;
+    }
+}
+
+// Allocate a list of AddressInformation
+AddressInformation *LoadAddressList(int size)
+{
+    AddressInformation *addr;
+    addr = (AddressInformation *)RNET_MALLOC(size * sizeof(AddressInformation));
+    return addr;
+}
+
+// Opaque datatype accessor addrinfo->ai_family
+int GetAddressFamily(AddressInformation address)
+{
+    return address->addr.ai_family;
+}
+
+// Opaque datatype accessor addrinfo->ai_socktype
+int GetAddressSocketType(AddressInformation address)
+{
+    return address->addr.ai_socktype;
+}
+
+// Opaque datatype accessor addrinfo->ai_protocol
+int GetAddressProtocol(AddressInformation address)
+{
+    return address->addr.ai_protocol;
+}
+
+// Opaque datatype accessor addrinfo->ai_canonname
+char *GetAddressCanonName(AddressInformation address)
+{
+    return address->addr.ai_canonname;
+}
+
+// Opaque datatype accessor addrinfo->ai_addr
+char *GetAddressHostAndPort(AddressInformation address, char *outhost, int *outport)
+{
+    //char *ip[INET6_ADDRSTRLEN];
+    char *result = NULL;
+    struct sockaddr_storage *storage = (struct sockaddr_storage *)address->addr.ai_addr;
+
+    switch (storage->ss_family)
+    {
+        case AF_INET:
+        {
+            struct sockaddr_in *s = ((struct sockaddr_in *)address->addr.ai_addr);
+            //result = inet_ntop(AF_INET, &s->sin_addr, ip, INET_ADDRSTRLEN);           // TODO.
+            *outport = ntohs(s->sin_port);
+        } break;
+        case AF_INET6:
+        {
+            struct sockaddr_in6 *s = ((struct sockaddr_in6 *)address->addr.ai_addr);
+            //result = inet_ntop(AF_INET6, &s->sin6_addr, ip, INET6_ADDRSTRLEN);          // TODO.
+            *outport = ntohs(s->sin6_port);
+        } break;
+        default: break;
+    }
+
+    if (result == NULL)
+    {
+        TRACELOG(LOG_WARNING, "Socket Error: %s", SocketErrorCodeToString(SocketGetLastError()));
+        SocketSetLastError(0);
+    }
+    else
+    {
+        strcpy(outhost, result);
+    }
+    return result;
+}
+
+//
+void PacketSend(Packet *packet)
+{
+    TRACELOG(LOG_INFO, "Sending packet (%s) with size %d\n", packet->data, packet->size);
+}
+
+//
+void PacketReceive(Packet *packet)
+{
+    TRACELOG(LOG_INFO, "Receiving packet (%s) with size %d\n", packet->data, packet->size);
+}
+
+//
+void PacketWrite16(Packet *packet, uint16_t value)
+{
+    TRACELOG(LOG_INFO, "Original: 0x%04" PRIX16 " - %" PRIu16 "\n", value, value);
+    uint8_t *data = packet->data + packet->offs;
+    *data++ = (uint8_t)(value >> 8);
+    *data++ = (uint8_t)(value);
+    packet->size += sizeof(uint16_t);
+    packet->offs += sizeof(uint16_t);
+    TRACELOG(LOG_INFO, "Network: 0x%04" PRIX16 " - %" PRIu16 "\n", (uint16_t) *data, (uint16_t) *data);
+}
+
+//
+void PacketWrite32(Packet *packet, uint32_t value)
+{
+    TRACELOG(LOG_INFO, "Original: 0x%08" PRIX32 " - %" PRIu32 "\n", value, value);
+    uint8_t *data = packet->data + packet->offs;
+    *data++ = (uint8_t)(value >> 24);
+    *data++ = (uint8_t)(value >> 16);
+    *data++ = (uint8_t)(value >> 8);
+    *data++ = (uint8_t)(value);
+    packet->size += sizeof(uint32_t);
+    packet->offs += sizeof(uint32_t);
+
+    TRACELOG(LOG_INFO, "Network: 0x%08" PRIX32 " - %" PRIu32 "\n",
+           (uint32_t)(((intptr_t) packet->data) - packet->offs),
+           (uint32_t)(((intptr_t) packet->data) - packet->offs));
+}
+
+//
+void PacketWrite64(Packet *packet, uint64_t value)
+{
+    TRACELOG(LOG_INFO, "Original: 0x%016" PRIX64 " - %" PRIu64 "\n", value, value);
+
+    uint8_t *data = packet->data + packet->offs;
+    *data++ = (uint8_t)(value >> 56);
+    *data++ = (uint8_t)(value >> 48);
+    *data++ = (uint8_t)(value >> 40);
+    *data++ = (uint8_t)(value >> 32);
+    *data++ = (uint8_t)(value >> 24);
+    *data++ = (uint8_t)(value >> 16);
+    *data++ = (uint8_t)(value >> 8);
+    *data++ = (uint8_t)(value);
+    packet->size += sizeof(uint64_t);
+    packet->offs += sizeof(uint64_t);
+
+    TRACELOG(LOG_INFO, "Network: 0x%016" PRIX64 " - %" PRIu64 "\n", (uint64_t)(packet->data - packet->offs), (uint64_t)(packet->data - packet->offs));
+}
+
+//
+uint16_t PacketRead16(Packet *packet)
+{
+    uint8_t *data = packet->data + packet->offs;
+    packet->size += sizeof(uint16_t);
+    packet->offs += sizeof(uint16_t);
+    uint16_t value = ((uint16_t) data[0] << 8) | data[1];
+    TRACELOG(LOG_INFO, "Original: 0x%04" PRIX16 " - %" PRIu16 "\n", value, value);
+
+    return value;
+}
+
+//
+uint32_t PacketRead32(Packet *packet)
+{
+    uint8_t *data = packet->data + packet->offs;
+    packet->size += sizeof(uint32_t);
+    packet->offs += sizeof(uint32_t);
+    uint32_t value = ((uint32_t) data[0] << 24) | ((uint32_t) data[1] << 16) | ((uint32_t) data[2] << 8) | data[3];
+    TRACELOG(LOG_INFO, "Original: 0x%08" PRIX32 " - %" PRIu32 "\n", value, value);
+
+    return value;
+}
+
+//
+uint64_t PacketRead64(Packet *packet)
+{
+    uint8_t *data = packet->data + packet->offs;
+    packet->size += sizeof(uint64_t);
+    packet->offs += sizeof(uint64_t);
+    uint64_t value = ((uint64_t) data[0] << 56) | ((uint64_t) data[1] << 48) | ((uint64_t) data[2] << 40) | ((uint64_t) data[3] << 32) | ((uint64_t) data[4] << 24) | ((uint64_t) data[5] << 16) | ((uint64_t) data[6] << 8) | data[7];
+    TRACELOG(LOG_INFO, "Original: 0x%016" PRIX64 " - %" PRIu64 "\n", value, value);
+
+    return value;
+}
+
+#endif  // RNET_IMPLEMENTATION

+ 5 - 6
lib.mod/raylib/src/shapes.c

@@ -42,8 +42,7 @@
 
 #include "rlgl.h"       // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
 
-#include <stdlib.h>     // Required for: fabs()
-#include <math.h>       // Required for: sinf(), asinf(), cosf(), acosf(), sqrtf()
+#include <math.h>       // Required for: sinf(), asinf(), cosf(), acosf(), sqrtf(), fabsf()
 
 //----------------------------------------------------------------------------------
 // Defines and Macros
@@ -1471,8 +1470,8 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
     int recCenterX = (int)(rec.x + rec.width/2.0f);
     int recCenterY = (int)(rec.y + rec.height/2.0f);
 
-    float dx = (float)fabs(center.x - recCenterX);
-    float dy = (float)fabs(center.y - recCenterY);
+    float dx = fabsf(center.x - (float)recCenterX);
+    float dy = fabsf(center.y - (float)recCenterY);
 
     if (dx > (rec.width/2.0f + radius)) { return false; }
     if (dy > (rec.height/2.0f + radius)) { return false; }
@@ -1493,8 +1492,8 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
 
     if (CheckCollisionRecs(rec1, rec2))
     {
-        float dxx = (float)fabs(rec1.x - rec2.x);
-        float dyy = (float)fabs(rec1.y - rec2.y);
+        float dxx = fabsf(rec1.x - rec2.x);
+        float dyy = fabsf(rec1.y - rec2.y);
 
         if (rec1.x <= rec2.x)
         {

+ 7 - 7
lib.mod/raylib/src/shell.html

@@ -173,8 +173,8 @@ jwE50AGjLCVuS8Yt4H7OgZLKK5EKOsLviEWJSL/+0uMi7gLUSBseYwqEbXvSHCec1CJvZPyHCmYQffaB
         <div class="emscripten" id="status">Downloading...</div>
 
         <span id='controls'>
-          <span><input type="button" value="🖵 FULLSCREEN" onclick="Module.requestFullscreen(false, false)"></span>
-          <span><input type="button" id="btn-audio" value="🔇 SUSPEND" onclick="toggleAudio()"></span>
+          <span><input type="button" value="FULLSCREEN" onclick="Module.requestFullscreen(false, false)"></span>
+          <span><input type="button" id="btn-audio" value="AUDIO OFF" onclick="toggleAudio()"></span>
         </span>
 
         <div class="emscripten">
@@ -241,8 +241,8 @@ jwE50AGjLCVuS8Yt4H7OgZLKK5EKOsLviEWJSL/+0uMi7gLUSBseYwqEbXvSHCec1CJvZPyHCmYQffaB
             canvas: (function() {
                 var canvas = document.querySelector('#canvas');
 
-                // As a default initial behavior, pop up an alert when webgl context is lost. To make your
-                // application robust, you may want to override this behavior before shipping!
+                // As a default initial behavior, pop up an alert when webgl context is lost.
+                // To make your application robust, you may want to override this behavior before shipping!
                 // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
                 canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
 
@@ -305,7 +305,7 @@ jwE50AGjLCVuS8Yt4H7OgZLKK5EKOsLviEWJSL/+0uMi7gLUSBseYwqEbXvSHCec1CJvZPyHCmYQffaB
                 construct(target, args) {
                     const result = new target(...args);
                     audioContexList.push(result);
-                    if (result.state == "suspended") audioBtn.value = "🔈 RESUME";
+                    if (result.state == "suspended") audioBtn.value = "AUDIO ON";
                     return result;
                 }
             });
@@ -318,8 +318,8 @@ jwE50AGjLCVuS8Yt4H7OgZLKK5EKOsLviEWJSL/+0uMi7gLUSBseYwqEbXvSHCec1CJvZPyHCmYQffaB
                 else if (ctx.state == "running") ctx.suspend();
             });
             
-            if (resumed) audioBtn.value = "🔇 SUSPEND";
-            else audioBtn.value = "🔈 RESUME";
+            if (resumed) audioBtn.value = "AUDIO OFF";
+            else audioBtn.value = "AUDIO ON";
         }
     </script>
     {{{ SCRIPT }}}

+ 15 - 41
lib.mod/raylib/src/text.c

@@ -333,11 +333,11 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou
 {
     Font font = { 0 };
 
+#if defined(SUPPORT_FILEFORMAT_TTF)
     font.baseSize = fontSize;
     font.charsCount = (charsCount > 0)? charsCount : 95;
     font.chars = LoadFontData(fileName, font.baseSize, fontChars, font.charsCount, FONT_DEFAULT);
 
-#if defined(SUPPORT_FILEFORMAT_TTF)
     if (font.chars != NULL)
     {
         Image atlas = GenImageFontAtlas(font.chars, &font.recs, font.charsCount, font.baseSize, 2, 0);
@@ -354,7 +354,6 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou
     }
     else font = GetFontDefault();
 #else
-    UnloadFont(font);
     font = GetFontDefault();
 #endif
 
@@ -498,24 +497,16 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
 
 #if defined(SUPPORT_FILEFORMAT_TTF)
     // Load font data (including pixel data) from TTF file
-    // NOTE: Loaded information should be enough to generate font image atlas,
-    // using any packaging method
-    FILE *fontFile = fopen(fileName, "rb");     // Load font file
+    // NOTE: Loaded information should be enough to generate
+    // font image atlas, using any packaging method
+    int dataSize = 0;
+    unsigned char *fileData = LoadFileData(fileName, &dataSize);
 
-    if (fontFile != NULL)
+    if (fileData != NULL)
     {
-        fseek(fontFile, 0, SEEK_END);
-        long size = ftell(fontFile);    // Get file size
-        fseek(fontFile, 0, SEEK_SET);   // Reset file pointer
-
-        unsigned char *fontBuffer = (unsigned char *)RL_MALLOC(size);
-
-        fread(fontBuffer, size, 1, fontFile);
-        fclose(fontFile);
-
         // Init font for data reading
         stbtt_fontinfo fontInfo;
-        if (!stbtt_InitFont(&fontInfo, fontBuffer, 0)) TRACELOG(LOG_WARNING, "Failed to init font!");
+        if (!stbtt_InitFont(&fontInfo, fileData, 0)) TRACELOG(LOG_WARNING, "Failed to init font!");
 
         // Calculate font scale factor
         float scaleFactor = stbtt_ScaleForPixelHeight(&fontInfo, (float)fontSize);
@@ -595,12 +586,9 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
             */
         }
 
-        RL_FREE(fontBuffer);
+        RL_FREE(fileData);
         if (genFontChars) RL_FREE(fontChars);
     }
-    else TRACELOG(LOG_WARNING, "[%s] TTF file could not be opened", fileName);
-#else
-    TRACELOG(LOG_WARNING, "[%s] TTF support is disabled", fileName);
 #endif
 
     return chars;
@@ -768,24 +756,7 @@ void UnloadFont(Font font)
 // NOTE: Uses default font
 void DrawFPS(int posX, int posY)
 {
-    // NOTE: We are rendering fps every certain time for better viewing on high framerates
-
-    static int fps = 0;
-    static int counter = 0;
-    static int refreshRate = 20;
-
-    if (counter < refreshRate) counter++;
-    else
-    {
-        fps = GetFPS();
-        refreshRate = fps;
-        counter = 0;
-    }
-
-    // TODO: Find a better way to calculate FPS, maybe calculate the mean of multiple measures?
-
-    // NOTE: We have rounding errors every frame, so it oscillates a lot
-    DrawText(TextFormat("%2i FPS", fps), posX, posY, 20, LIME);
+    DrawText(TextFormat("%2i FPS", GetFPS()), posX, posY, 20, LIME);
 }
 
 // Draw text (using default font)
@@ -1147,7 +1118,10 @@ unsigned int TextLength(const char *text)
 {
     unsigned int length = 0; //strlen(text)
 
-    while (*text++) length++;
+    if (text != NULL)
+    {
+        while (*text++) length++;
+    }
 
     return length;
 }
@@ -1163,6 +1137,7 @@ const char *TextFormat(const char *text, ...)
     static int  index = 0;
 
     char *currentBuffer = buffers[index];
+    memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH);   // Clear buffer before using
 
     va_list args;
     va_start(args, text);
@@ -1459,7 +1434,7 @@ char *TextToUtf8(int *codepoints, int length)
 
     // Resize memory to text length + string NULL terminator
     void *ptr = RL_REALLOC(text, size + 1);
-    
+
     if (ptr != NULL) text = (char *)ptr;
 
     return text;
@@ -1669,7 +1644,6 @@ static Font LoadBMFont(const char *fileName)
     #define MAX_BUFFER_SIZE     256
 
     Font font = { 0 };
-    font.texture.id = 0;
 
     char buffer[MAX_BUFFER_SIZE] = { 0 };
     char *searchPoint = NULL;

+ 61 - 88
lib.mod/raylib/src/textures.c

@@ -64,15 +64,16 @@
     #include "config.h"         // Defines module configuration flags
 #endif
 
-#include <stdlib.h>             // Required for: malloc(), free(), fabs()
+#include <stdlib.h>             // Required for: malloc(), free()
 #include <stdio.h>              // Required for: FILE, fopen(), fclose(), fread()
 #include <string.h>             // Required for: strlen() [Used in ImageTextEx()]
+#include <math.h>               // Required for: fabsf()
 
 #include "utils.h"              // Required for: fopen() Android mapping
 
 #include "rlgl.h"               // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3 or ES2
                                 // Required for: rlLoadTexture() rlDeleteTextures(),
-                                //      rlGenerateMipmaps(), some funcs for DrawTexturePro()
+                                // rlGenerateMipmaps(), some funcs for DrawTexturePro()
 
 // Support only desired texture formats on stb_image
 #if !defined(SUPPORT_FILEFORMAT_BMP)
@@ -195,6 +196,7 @@ Image LoadImage(const char *fileName)
     defined(SUPPORT_FILEFORMAT_TGA) || \
     defined(SUPPORT_FILEFORMAT_GIF) || \
     defined(SUPPORT_FILEFORMAT_PIC) || \
+    defined(SUPPORT_FILEFORMAT_HDR) || \
     defined(SUPPORT_FILEFORMAT_PSD)
 #define STBI_REQUIRED
 #endif
@@ -225,53 +227,53 @@ Image LoadImage(const char *fileName)
        )
     {
 #if defined(STBI_REQUIRED)
-        int imgWidth = 0;
-        int imgHeight = 0;
-        int imgBpp = 0;
+        // NOTE: Using stb_image to load images (Supports multiple image formats)
 
-        FILE *imFile = fopen(fileName, "rb");
+        int dataSize = 0;
+        unsigned char *fileData = LoadFileData(fileName, &dataSize);
 
-        if (imFile != NULL)
+        if (fileData != NULL)
         {
-            // NOTE: Using stb_image to load images (Supports multiple image formats)
-            image.data = stbi_load_from_file(imFile, &imgWidth, &imgHeight, &imgBpp, 0);
+            int comp = 0;
+            image.data = stbi_load_from_memory(fileData, dataSize, &image.width, &image.height, &comp, 0);
 
-            fclose(imFile);
-
-            image.width = imgWidth;
-            image.height = imgHeight;
             image.mipmaps = 1;
 
-            if (imgBpp == 1) image.format = UNCOMPRESSED_GRAYSCALE;
-            else if (imgBpp == 2) image.format = UNCOMPRESSED_GRAY_ALPHA;
-            else if (imgBpp == 3) image.format = UNCOMPRESSED_R8G8B8;
-            else if (imgBpp == 4) image.format = UNCOMPRESSED_R8G8B8A8;
+            if (comp == 1) image.format = UNCOMPRESSED_GRAYSCALE;
+            else if (comp == 2) image.format = UNCOMPRESSED_GRAY_ALPHA;
+            else if (comp == 3) image.format = UNCOMPRESSED_R8G8B8;
+            else if (comp == 4) image.format = UNCOMPRESSED_R8G8B8A8;
+
+            RL_FREE(fileData);
         }
 #endif
     }
 #if defined(SUPPORT_FILEFORMAT_HDR)
     else if (IsFileExtension(fileName, ".hdr"))
     {
-        int imgBpp = 0;
-
-        FILE *imFile = fopen(fileName, "rb");
+#if defined(STBI_REQUIRED)
+        int dataSize = 0;
+        unsigned char *fileData = LoadFileData(fileName, &dataSize);
 
-        // Load 32 bit per channel floats data
-        //stbi_set_flip_vertically_on_load(true);
-        image.data = stbi_loadf_from_file(imFile, &image.width, &image.height, &imgBpp, 0);
+        if (fileData != NULL)
+        {
+            int comp = 0;
+            image.data = stbi_loadf_from_memory(fileData, dataSize, &image.width, &image.height, &comp, 0);
 
-        fclose(imFile);
+            image.mipmaps = 1;
 
-        image.mipmaps = 1;
+            if (comp == 1) image.format = UNCOMPRESSED_R32;
+            else if (comp == 3) image.format = UNCOMPRESSED_R32G32B32;
+            else if (comp == 4) image.format = UNCOMPRESSED_R32G32B32A32;
+            else
+            {
+                TRACELOG(LOG_WARNING, "[%s] HDR Image fileformat not supported", fileName);
+                UnloadImage(image);
+            }
 
-        if (imgBpp == 1) image.format = UNCOMPRESSED_R32;
-        else if (imgBpp == 3) image.format = UNCOMPRESSED_R32G32B32;
-        else if (imgBpp == 4) image.format = UNCOMPRESSED_R32G32B32A32;
-        else
-        {
-            TRACELOG(LOG_WARNING, "[%s] Image fileformat not supported", fileName);
-            UnloadImage(image);
+            RL_FREE(fileData);
         }
+#endif
     }
 #endif
 #if defined(SUPPORT_FILEFORMAT_DDS)
@@ -346,40 +348,24 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int
 {
     Image image = { 0 };
 
-    FILE *rawFile = fopen(fileName, "rb");
+    int dataSize = 0;
+    unsigned char *fileData = LoadFileData(fileName, &dataSize);
 
-    if (rawFile == NULL)
+    if (fileData != NULL)
     {
-        TRACELOG(LOG_WARNING, "[%s] RAW image file could not be opened", fileName);
-    }
-    else
-    {
-        if (headerSize > 0) fseek(rawFile, headerSize, SEEK_SET);
-
+        unsigned char *dataPtr = fileData;
         unsigned int size = GetPixelDataSize(width, height, format);
 
-        image.data = RL_MALLOC(size);      // Allocate required memory in bytes
-
-        // NOTE: fread() returns num read elements instead of bytes,
-        // to get bytes we need to read (1 byte size, elements) instead of (x byte size, 1 element)
-        int bytes = fread(image.data, 1, size, rawFile);
+        if (headerSize > 0) dataPtr += headerSize;
 
-        // Check if data has been read successfully
-        if (bytes < size)
-        {
-            TRACELOG(LOG_WARNING, "[%s] RAW image data can not be read, wrong requested format or size", fileName);
-
-            RL_FREE(image.data);
-        }
-        else
-        {
-            image.width = width;
-            image.height = height;
-            image.mipmaps = 1;
-            image.format = format;
-        }
+        image.data = RL_MALLOC(size);      // Allocate required memory in bytes
+        memcpy(image.data, dataPtr, size); // Copy required data to image
+        image.width = width;
+        image.height = height;
+        image.mipmaps = 1;
+        image.format = format;
 
-        fclose(rawFile);
+        RL_FREE(fileData);
     }
 
     return image;
@@ -844,9 +830,8 @@ void ExportImage(Image image, const char *fileName)
     {
         // Export raw pixel data (without header)
         // NOTE: It's up to the user to track image parameters
-        FILE *rawFile = fopen(fileName, "wb");
-        success = fwrite(image.data, GetPixelDataSize(image.width, image.height, image.format), 1, rawFile);
-        fclose(rawFile);
+        SaveFileData(fileName, image.data, GetPixelDataSize(image.width, image.height, image.format));
+        success = true;
     }
 
     RL_FREE(imgData);
@@ -2704,7 +2689,7 @@ void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float sc
 // Draw a part of a texture (defined by a rectangle)
 void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint)
 {
-    Rectangle destRec = { position.x, position.y, (float)fabs(sourceRec.width), (float)fabs(sourceRec.height) };
+    Rectangle destRec = { position.x, position.y, fabsf(sourceRec.width), fabsf(sourceRec.height) };
     Vector2 origin = { 0.0f, 0.0f };
 
     DrawTexturePro(texture, sourceRec, destRec, origin, 0.0f, tint);
@@ -2983,30 +2968,18 @@ static Image LoadAnimatedGIF(const char *fileName, int *frames, int **delays)
 {
     Image image = { 0 };
 
-    FILE *gifFile = fopen(fileName, "rb");
+    int dataSize = 0;
+    unsigned char *fileData = LoadFileData(fileName, &dataSize);
 
-    if (gifFile == NULL)
-    {
-        TRACELOG(LOG_WARNING, "[%s] Animated GIF file could not be opened", fileName);
-    }
-    else
+    if (fileData != NULL)
     {
-        fseek(gifFile, 0L, SEEK_END);
-        int size = ftell(gifFile);
-        fseek(gifFile, 0L, SEEK_SET);
-
-        unsigned char *buffer = (unsigned char *)RL_CALLOC(size, sizeof(char));
-        fread(buffer, sizeof(char), size, gifFile);
-
-        fclose(gifFile);    // Close file pointer
-
         int comp = 0;
-        image.data = stbi_load_gif_from_memory(buffer, size, delays, &image.width, &image.height, frames, &comp, 4);
+        image.data = stbi_load_gif_from_memory(fileData, dataSize, delays, &image.width, &image.height, frames, &comp, 4);
 
         image.mipmaps = 1;
         image.format = UNCOMPRESSED_R8G8B8A8;
 
-        free(buffer);
+        RL_FREE(fileData);
     }
 
     return image;
@@ -3071,7 +3044,7 @@ static Image LoadDDS(const char *fileName)
     else
     {
         // Verify the type of file
-        char ddsHeaderId[4];
+        char ddsHeaderId[4] = { 0 };
 
         fread(ddsHeaderId, 4, 1, ddsFile);
 
@@ -3081,7 +3054,7 @@ static Image LoadDDS(const char *fileName)
         }
         else
         {
-            DDSHeader ddsHeader;
+            DDSHeader ddsHeader = { 0 };
 
             // Get the image header
             fread(&ddsHeader, sizeof(DDSHeader), 1, ddsFile);
@@ -3250,7 +3223,7 @@ static Image LoadPKM(const char *fileName)
     }
     else
     {
-        PKMHeader pkmHeader;
+        PKMHeader pkmHeader = { 0 };
 
         // Get the image header
         fread(&pkmHeader, sizeof(PKMHeader), 1, pkmFile);
@@ -3343,7 +3316,7 @@ static Image LoadKTX(const char *fileName)
     }
     else
     {
-        KTXHeader ktxHeader;
+        KTXHeader ktxHeader = { 0 };
 
         // Get the image header
         fread(&ktxHeader, sizeof(KTXHeader), 1, ktxFile);
@@ -3424,7 +3397,7 @@ static int SaveKTX(Image image, const char *fileName)
     if (ktxFile == NULL) TRACELOG(LOG_WARNING, "[%s] KTX image file could not be created", fileName);
     else
     {
-        KTXHeader ktxHeader;
+        KTXHeader ktxHeader = { 0 };
 
         // KTX identifier (v1.1)
         //unsigned char id[12] = { '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n' };
@@ -3560,7 +3533,7 @@ static Image LoadPVR(const char *fileName)
         // Load different PVR data formats
         if (pvrVersion == 0x50)
         {
-            PVRHeaderV3 pvrHeader;
+            PVRHeaderV3 pvrHeader = { 0 };
 
             // Get PVR image header
             fread(&pvrHeader, sizeof(PVRHeaderV3), 1, pvrFile);
@@ -3670,7 +3643,7 @@ static Image LoadASTC(const char *fileName)
     }
     else
     {
-        ASTCHeader astcHeader;
+        ASTCHeader astcHeader = { 0 };
 
         // Get ASTC image header
         fread(&astcHeader, sizeof(ASTCHeader), 1, astcFile);

+ 128 - 1
lib.mod/raylib/src/utils.c

@@ -64,7 +64,7 @@ static int logTypeExit = LOG_ERROR;                     // Log type that exits
 static TraceLogCallback logCallback = NULL;             // Log callback function pointer
 
 #if defined(PLATFORM_ANDROID)
-static AAssetManager *assetManager = NULL;              // Android assets manager pointer 
+static AAssetManager *assetManager = NULL;              // Android assets manager pointer
 #endif
 
 #if defined(PLATFORM_UWP)
@@ -163,6 +163,133 @@ void TraceLog(int logType, const char *text, ...)
 #endif  // SUPPORT_TRACELOG
 }
 
+// Load data from file into a buffer
+unsigned char *LoadFileData(const char *fileName, int *bytesRead)
+{
+    unsigned char *data = NULL;
+    *bytesRead = 0;
+
+    if (fileName != NULL)
+    {
+        FILE *file = fopen(fileName, "rb");
+
+        if (file != NULL)
+        {
+            // WARNING: On binary streams SEEK_END could not be found,
+            // using fseek() and ftell() could not work in some (rare) cases
+            fseek(file, 0, SEEK_END);
+            int size = ftell(file);
+            fseek(file, 0, SEEK_SET);
+
+            if (size > 0)
+            {
+                data = (unsigned char *)RL_MALLOC(sizeof(unsigned char)*size);
+
+                // NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements]
+                int count = fread(data, sizeof(unsigned char), size, file);
+                *bytesRead = count;
+
+                if (count != size) TRACELOG(LOG_WARNING, "[%s] File partially loaded", fileName);
+                else TRACELOG(LOG_INFO, "[%s] File loaded successfully", fileName);
+            }
+            else TRACELOG(LOG_WARNING, "[%s] File could not be read", fileName);
+
+            fclose(file);
+        }
+        else TRACELOG(LOG_WARNING, "[%s] File could not be opened", fileName);
+    }
+    else TRACELOG(LOG_WARNING, "File name provided is not valid");
+
+    return data;
+}
+
+// Save data to file from buffer
+void SaveFileData(const char *fileName, void *data, int bytesToWrite)
+{
+    if (fileName != NULL)
+    {
+        FILE *file = fopen(fileName, "wb");
+
+        if (file != NULL)
+        {
+            int count = fwrite(data, sizeof(unsigned char), bytesToWrite, file);
+
+            if (count == 0) TRACELOG(LOG_WARNING, "[%s] File could not be written", fileName);
+            else if (count != bytesToWrite) TRACELOG(LOG_WARNING, "[%s] File partially written", fileName);
+            else TRACELOG(LOG_INFO, "[%s] File successfully saved", fileName);
+
+            fclose(file);
+        }
+        else TRACELOG(LOG_WARNING, "[%s] File could not be opened", fileName);
+    }
+    else TRACELOG(LOG_WARNING, "File name provided is not valid");
+}
+
+// Load text data from file, returns a '\0' terminated string
+// NOTE: text chars array should be freed manually
+char *LoadFileText(const char *fileName)
+{
+    char *text = NULL;
+
+    if (fileName != NULL)
+    {
+        FILE *textFile = fopen(fileName, "rt");
+
+        if (textFile != NULL)
+        {
+            // WARNING: When reading a file as 'text' file,
+            // text mode causes carriage return-linefeed translation...
+            // ...but using fseek() should return correct byte-offset
+            fseek(textFile, 0, SEEK_END);
+            int size = ftell(textFile);
+            fseek(textFile, 0, SEEK_SET);
+
+            if (size > 0)
+            {
+                text = (char *)RL_MALLOC(sizeof(char)*(size + 1));
+                int count = fread(text, sizeof(char), size, textFile);
+
+                // WARNING: \r\n is converted to \n on reading, so,
+                // read bytes count gets reduced by the number of lines
+                if (count < size) text = RL_REALLOC(text, count + 1);
+
+                // Zero-terminate the string
+                text[count] = '\0';
+                
+                TRACELOG(LOG_INFO, "[%s] Text file loaded successfully", fileName);
+            }
+            else TRACELOG(LOG_WARNING, "[%s] Text file could not be read", fileName);
+
+            fclose(textFile);
+        }
+        else TRACELOG(LOG_WARNING, "[%s] Text file could not be opened", fileName);
+    }
+    else TRACELOG(LOG_WARNING, "File name provided is not valid");
+
+    return text;
+}
+
+// Save text data to file (write), string must be '\0' terminated
+void SaveFileText(const char *fileName, char *text)
+{
+    if (fileName != NULL)
+    {
+        FILE *file = fopen(fileName, "wt");
+
+        if (file != NULL)
+        {
+            int count = fprintf(file, "%s", text);
+
+            if (count == 0) TRACELOG(LOG_WARNING, "[%s] Text file could not be written", fileName);
+            else TRACELOG(LOG_INFO, "[%s] Text file successfully saved", fileName);
+
+            fclose(file);
+        }
+        else TRACELOG(LOG_WARNING, "[%s] Text file could not be opened", fileName);
+    }
+    else TRACELOG(LOG_WARNING, "File name provided is not valid");
+}
+
 #if defined(PLATFORM_ANDROID)
 // Initialize asset manager from android app
 void InitAssetManager(AAssetManager *manager)

+ 1 - 0
math.mod/common.bmx

@@ -44,6 +44,7 @@ Extern
 	Function bmx_raymath_Vector2DivideV:RVector2(v1:RVector2, v2:RVector2)="Vector2DivideV"
 	Function bmx_raymath_Vector2Normalize:RVector2(v:RVector2)="Vector2Normalize"
 	Function bmx_raymath_Vector2Lerp:RVector2(v1:RVector2, v2:RVector2, amount:Float)="Vector2Lerp"
+	Function bmx_raymath_Vector2Rotate:RVector2(v:RVector2, degs:Float)="Vector2Rotate"
 
 	Function bmx_raymath_Vector3Zero:RVector3()="Vector3Zero"
 	Function bmx_raymath_Vector3One:RVector3()="Vector3One"

+ 6 - 0
math.mod/math.bmx

@@ -177,6 +177,12 @@ Function Vector2Lerp:RVector2(v1:RVector2, v2:RVector2, amount:Float)
 	Return bmx_raymath_Vector2Lerp(v1, v2, amount)
 End Function
 
+Rem
+bbdoc: Rotates Vector by float in Degrees.
+End Rem
+Function Vector2Rotate:RVector2(v:RVector2, degs:Float)
+	Return bmx_raymath_Vector2Rotate(v, degs)
+End Function
 
 Rem
 bbdoc: #RVector3 with components value 0.0.