packages feed

h-raylib 4.5.1.1 → 4.5.2.0

raw patch · 29 files changed

+2099/−1255 lines, 29 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Raylib.Audio: addFinalizerToAudioStream :: AudioStream -> IO ()
- Raylib.Audio: addFinalizerToMusicStream :: Music -> IO ()
- Raylib.Audio: unloadAudioStream :: AudioStream -> IO ()
- Raylib.Audio: unloadMusicStream :: Music -> IO ()
- Raylib.Audio: unloadSound :: Sound -> IO ()
- Raylib.Audio: unloadWave :: Wave -> IO ()
- Raylib.Core: setCameraAltControl :: Int -> IO ()
- Raylib.Core: setCameraMode :: Camera3D -> CameraMode -> IO ()
- Raylib.Core: setCameraMoveControls :: Int -> Int -> Int -> Int -> Int -> Int -> IO ()
- Raylib.Core: setCameraPanControl :: Int -> IO ()
- Raylib.Core: setCameraSmoothZoomControl :: Int -> IO ()
- Raylib.Core: unloadDirectoryFiles :: FilePathList -> IO ()
- Raylib.Core: unloadDroppedFiles :: FilePathList -> IO ()
- Raylib.Core: unloadFileText :: String -> IO ()
- Raylib.Core: unloadShader :: Shader -> IO ()
- Raylib.Core: unloadVrStereoConfig :: VrStereoConfig -> IO ()
- Raylib.Models: unloadMaterial :: Material -> IO ()
- Raylib.Models: unloadMesh :: Mesh -> IO ()
- Raylib.Models: unloadModel :: Model -> IO ()
- Raylib.Models: unloadModelAnimation :: ModelAnimation -> IO ()
- Raylib.Models: unloadModelAnimations :: [ModelAnimation] -> IO ()
- Raylib.Models: unloadModelKeepMeshes :: Model -> IO ()
- Raylib.Text: unloadCodepoints :: Ptr CInt -> IO ()
- Raylib.Text: unloadFont :: Font -> IO ()
- Raylib.Text: unloadFontData :: [GlyphInfo] -> IO ()
- Raylib.Text: unloadUTF8 :: CString -> IO ()
- Raylib.Textures: unloadImage :: Image -> IO ()
- Raylib.Textures: unloadImageColors :: Ptr Color -> IO ()
- Raylib.Textures: unloadImagePalette :: Ptr Color -> IO ()
- Raylib.Textures: unloadRenderTexture :: RenderTexture -> IO ()
- Raylib.Textures: unloadTexture :: Texture -> IO ()
- Raylib.Types: [camera2d'rotation] :: Camera2D -> Float
- Raylib.Types: [camera2d'zoom] :: Camera2D -> Float
- Raylib.Types: [glyphinfo'image] :: GlyphInfo -> Image
- Raylib.Types: [glyphinfo'value] :: GlyphInfo -> Int
- Raylib.Types: [materialmap'color] :: MaterialMap -> Color
- Raylib.Types: [materialmap'texture] :: MaterialMap -> Texture
- Raylib.Types: [materialmap'value] :: MaterialMap -> Float
- Raylib.Types: [nPatchinfo'bottom] :: NPatchInfo -> Int
- Raylib.Types: [nPatchinfo'layout] :: NPatchInfo -> NPatchLayout
- Raylib.Types: [nPatchinfo'left] :: NPatchInfo -> Int
- Raylib.Types: [nPatchinfo'right] :: NPatchInfo -> Int
- Raylib.Types: [nPatchinfo'source] :: NPatchInfo -> Rectangle
- Raylib.Types: [nPatchinfo'top] :: NPatchInfo -> Int
- Raylib.Types: [rendertexture'depth] :: RenderTexture -> Texture
- Raylib.Types: [rendertexture'id] :: RenderTexture -> Integer
- Raylib.Types: [rendertexture'texture] :: RenderTexture -> Texture
- Raylib.Types: c'getPixelDataSize :: CInt -> CInt -> CInt -> IO CInt
- Raylib.Types: getPixelDataSize :: Int -> Int -> PixelFormat -> Int
- Raylib.Types: p'getPixelDataSize :: FunPtr (CInt -> CInt -> CInt -> IO CInt)
+ Raylib.Core: setWindowIcons :: [Image] -> IO ()
+ Raylib.Models: storeMaterialData :: [Material] -> IO ()
+ Raylib.Models: storeMeshData :: Mesh -> IO Mesh
+ Raylib.Types: (|*|) :: Vector a => a -> Float -> a
+ Raylib.Types: (|+|) :: Vector a => a -> a -> a
+ Raylib.Types: (|-|) :: Vector a => a -> a -> a
+ Raylib.Types: (|.|) :: Vector a => a -> a -> Float
+ Raylib.Types: (|/|) :: Vector a => a -> Float -> a
+ Raylib.Types: [camera2D'rotation] :: Camera2D -> Float
+ Raylib.Types: [camera2D'zoom] :: Camera2D -> Float
+ Raylib.Types: [glyphInfo'image] :: GlyphInfo -> Image
+ Raylib.Types: [glyphInfo'value] :: GlyphInfo -> Int
+ Raylib.Types: [materialMap'color] :: MaterialMap -> Color
+ Raylib.Types: [materialMap'texture] :: MaterialMap -> Texture
+ Raylib.Types: [materialMap'value] :: MaterialMap -> Float
+ Raylib.Types: [nPatchInfo'bottom] :: NPatchInfo -> Int
+ Raylib.Types: [nPatchInfo'layout] :: NPatchInfo -> NPatchLayout
+ Raylib.Types: [nPatchInfo'left] :: NPatchInfo -> Int
+ Raylib.Types: [nPatchInfo'right] :: NPatchInfo -> Int
+ Raylib.Types: [nPatchInfo'source] :: NPatchInfo -> Rectangle
+ Raylib.Types: [nPatchInfo'top] :: NPatchInfo -> Int
+ Raylib.Types: [renderTexture'depth] :: RenderTexture -> Texture
+ Raylib.Types: [renderTexture'id] :: RenderTexture -> Integer
+ Raylib.Types: [renderTexture'texture] :: RenderTexture -> Texture
+ Raylib.Types: class Vector a
+ Raylib.Types: cross :: Vector3 -> Vector3 -> Vector3
+ Raylib.Types: instance Raylib.Types.Vector Raylib.Types.Vector2
+ Raylib.Types: instance Raylib.Types.Vector Raylib.Types.Vector3
+ Raylib.Types: instance Raylib.Types.Vector Raylib.Types.Vector4
+ Raylib.Types: inverse :: Vector a => a -> a
+ Raylib.Types: magnitude :: Vector a => a -> Float
+ Raylib.Types: normalize :: Vector a => a -> a
+ Raylib.Types: zero :: Vector a => a
- Raylib.Core: updateCamera :: Camera3D -> IO Camera3D
+ Raylib.Core: updateCamera :: Camera3D -> CameraMode -> IO Camera3D
- Raylib.Types: Material :: Shader -> [MaterialMap] -> [Float] -> Material
+ Raylib.Types: Material :: Shader -> Maybe [MaterialMap] -> [Float] -> Material
- Raylib.Types: Mesh :: Int -> Int -> [Vector3] -> [Vector2] -> Maybe [Vector2] -> [Vector3] -> Maybe [Vector4] -> Maybe [Color] -> Maybe [Word16] -> Maybe [Vector3] -> Maybe [Vector3] -> Maybe [Word8] -> Maybe [Float] -> Integer -> [Integer] -> Mesh
+ Raylib.Types: Mesh :: Int -> Int -> [Vector3] -> [Vector2] -> Maybe [Vector2] -> [Vector3] -> Maybe [Vector4] -> Maybe [Color] -> Maybe [Word16] -> Maybe [Vector3] -> Maybe [Vector3] -> Maybe [Word8] -> Maybe [Float] -> Integer -> Maybe [Integer] -> Mesh
- Raylib.Types: [material'maps] :: Material -> [MaterialMap]
+ Raylib.Types: [material'maps] :: Material -> Maybe [MaterialMap]
- Raylib.Types: [mesh'vboId] :: Mesh -> [Integer]
+ Raylib.Types: [mesh'vboId] :: Mesh -> Maybe [Integer]

Files

CHANGELOG.md view
@@ -1,8 +1,18 @@ # h-raylib changelog
 
+## Version 4.5.2.0
+_21 February, 2023_
+
+- **BREAKING CHANGE**: Removed asset unloading functions
+- **BREAKING CHANGE**: Changed `Camera3D` API to match C code
+- Added code to automatically unload assets
+- Added mathematical operators for vector types
+- Updated raylib to the master branch
+
 ## Version 4.5.1.1
 _14 February, 2023_
 
+- Added finalizers to auto-unload audio data
 - Fixed C include errors
 
 ## Version 4.5.1.0
+ CONTRIBUTING.md view
@@ -0,0 +1,71 @@+# h-raylib contributor guide
+
+Anybody willing to contribute to the project is welcome to do so. Please use the GitHub issue tracker to report any bugs you find.
+
+You can run the examples by using `cabal run {example name}` in the project directory.
+
+You can use `run-all-examples.sh` to run all of the examples in one go.
+
+[ROADMAP.md](https://github.com/Anut-py/h-raylib/blob/master/ROADMAP.md) is a list of features that may be added to this project. Contributors are welcome to help implement these.
+
+## Project structure
+
+_This section only contains h-raylib specific information. For information about raylib in general, view the [raylib wiki](https://github.com/raysan5/raylib/wiki)._
+
+This project is split into 8 public modules. `Raylib.Types` contains all of raylib's types and low-level code to convert them to and from raw bytes. `Raylib.Colors` contains some colors defined by raylib. The other 6 public modules, `Core`, `Shapes`, `Textures`, `Text`, `Models`, and `Audio`, correspond to their respective raylib modules.
+
+The functions in h-raylib are an almost one-to-one mapping to their corresponding raylib functions. The types are, in some cases, slightly modified if it is possible to utilize Haskell features.
+
+Below are some descriptions of these public modules and their purposes.
+
+### Raylib.Types
+
+`Raylib.Types` has 4 sections: one for enumerations, one for typeclasses, one for structures, and one for callbacks.
+
+The enumerations section contains Haskell sum types that are instances of `Enum`. Each of these types corresponds to a raylib `enum`. The `fromEnum` and `toEnum` functions for these types use the numbers associated with these values in the C `enum`s. Most of these types are instances of `Storable` so they can be converted to raw bytes and passed to a C function. _NOTE: Some of these Haskell types correspond to C `enum`s that are in C source files, rather than `raylib.h`._
+
+The typeclasses section contains Haskell typeclasses that are derived by some of the types in the structures section.
+
+The structures section contains Haskell types that correspond to each of raylib's `structs`. Each field in these types is named `typeName'fieldName` (e.g. the C struct `Vector2`'s `x` field is called `vector2'x` in Haskell). These structs also all derive the typeclass `Freeable` (declared in the internal `Raylib.Util` module). This typeclass allows types to describe how to properly free all the data associated with a pointer to that type. For example, `Image`'s implementation of `Freeable` also frees the pointer stored in the `Image.data` field in C. Finally, all of these types derive `Storable`, obviously, to convert them to and from pointers.
+
+The callbacks section contains `FunPtr` types that are passed to some functions. _NOTE: These callbacks are very unlikely to be used, so they may be removed in the future._
+
+### Raylib.Colors
+
+`Raylib.Colors` is very simple: it declares 26 colors defined in `raylib.h`, namely `lightGray`, `gray`, `darkGray`, `yellow`, `gold`, `orange`, `pink`, `red`, `maroon`, `green`, `lime`, `darkGreen`, `skyBlue`, `blue`, `darkBlue`, `purple`, `violet`, `darkPurple`, `beige`, `brown`, `darkBrown`, `white`, `black`, `blank`, `magenta`, and `rayWhite`.
+
+### The other 6 modules
+
+These modules contain only functions. Each of these functions corresponds to a C function. The `unload*` functions were removed to make memory management automatic (this may be revised in the future, see `ROADMAP.md`). Functions that took a pointer as an argument in C were changed to take a regular type as an argument and return an updated version of the argument.
+
+### Private modules
+
+h-raylib has 3 modules that are not exposed for external use: `Raylib.Native`, `Raylib.Internal`, and `Raylib.Util`.
+
+#### Raylib.Native
+
+`Raylib.Native` consists solely of `foreign import` functions. These are used in the 6 public modules mentioned above.
+
+#### Raylib.Internal
+
+`Raylib.Internal` contains some functions used for automatic memory management. The automatic memory management flow is summarized in the "Memory management" section.
+
+#### Raylib.Util
+
+`Raylib.Util` contains miscellaneous utility functions for marshalling values to/from C. The most notable thing in this module is the `Freeable` typeclass.
+
+The `Freeable` typeclass contains two methods, `rlFreeDependents` and `rlFree`. `rlFree` receives a pointer and frees all of the data associated with it, including the pointer itself. `rlFreeDependents` only frees the data "dependent" on the pointer, which usually means dynamic C arrays, i.e. pointers.
+
+## Memory management
+
+The automatic memory management flow is as follows:
+
+1. A `load*` function is called (e.g. `loadModel`).
+2. The data is loaded.
+3. Any data that requires extra functions be called to unload it is stored in `Raylib.Internal` (e.g. shaders need to be freed from the GPU).
+4. The window is closed and `closeWindow` is called.
+5. All the data stored in `Raylib.Internal` is now unloaded (e.g. `rlUnloadShaderProgram` is called on all loaded shaders).
+
+Keep in mind that this is all automatic; no extra action in the code is necessary for this to happen. Take a look at `Raylib.Internal` to see the functions used for this.
+
+Unfortunately, this could lead to performance problems in larger projects, as large assets such as models must stay in memory for the duration of the program. This is why manual unloading is in the roadmap.
README.md view
@@ -41,13 +41,7 @@ 
 h-raylib should automatically work if you do not disable the `detect-platform` flag. In that case, you may skip this step.
 
-**If you do disable the `detect-platform` flag when building:**
-
-Add the following in your cabal file, or use the `platform-windows` flag when building.
-
-```cabal
-extra-libraries: gdi32 opengl32 winmm kernel32
-```
+**If you do disable the `detect-platform` flag when building,** use the `platform-windows` flag when building.
 
 ### Ubuntu/Debian based systems
 
@@ -59,13 +53,7 @@ 
 Now, h-raylib should automatically work if you do not disable the `detect-platform` flag. In that case, you may skip the following.
 
-**If you do disable the `detect-platform` flag when building:**
-
-Include the following in your cabal file, or use the `platform-linux` flag when building
-
-```cabal
-extra-libraries: GL c m pthread dl rt X11 Xinerama Xcursor Xrandr Xi
-```
+**If you do disable the `detect-platform` flag when building,** use the `platform-linux` flag when building
 
 ### Other platforms
 
@@ -76,13 +64,7 @@ 
 ## Contributing
 
-Anybody willing to contribute to the project is welcome to do so. This
-library is very new, so please report any bugs in the GitHub issue tracker.
-
-You can run the examples by using `cabal run {example name}` in the project directory.
-
-You can use `run-all-examples.sh` to run all of the examples in one go. In the future I will add an example that uses
-all the major functions for testing if everything is working correctly.
+See [CONTRIBUTING.md](https://github.com/Anut-py/h-raylib/blob/master/CONTRIBUTING.md).
 
 ## License
 
+ ROADMAP.md view
@@ -0,0 +1,8 @@+# h-raylib roadmap
+
+## Uncompleted
+- Allow manual unloading of assets for larger projects
+- Bind `raymath` and `raygui`
+
+## Completed
+(none)
examples/basic-images/src/Main.hs view
@@ -25,7 +25,7 @@     loadRenderTexture,
     loadTextureFromImage,
   )
-import Raylib.Types (Rectangle (Rectangle), RenderTexture (rendertexture'texture), Texture, Vector2 (Vector2))
+import Raylib.Types (Rectangle (Rectangle), RenderTexture (renderTexture'texture), Texture, Vector2 (Vector2))
 
 logoPath :: String
 logoPath = "../../../../../../../../../examples/basic-images/assets/raylib-logo.png"
@@ -57,7 +57,7 @@ 
   clearBackground white
   drawTexture texture 0 0 orange
-  drawTexturePro (rendertexture'texture rt) (Rectangle 0 0 200 (-200)) (Rectangle 50 50 300 300) (Vector2 0 0) 0 white
+  drawTexturePro (renderTexture'texture rt) (Rectangle 0 0 200 (-200)) (Rectangle 50 50 300 300) (Vector2 0 0) 0 white
   drawTexturePro logo (Rectangle 0 0 256 256) (Rectangle 375 50 175 175) (Vector2 0 0) 0 white
 
   endDrawing
examples/basic-models/src/Main.hs view
@@ -3,7 +3,7 @@ module Main where
 
 import Control.Monad (unless)
-import Raylib.Core (changeDirectory, closeWindow, getApplicationDirectory, initWindow, setTargetFPS, beginDrawing, endDrawing, windowShouldClose, clearBackground, beginMode3D, endMode3D, updateCamera, setCameraMode)
+import Raylib.Core (changeDirectory, closeWindow, getApplicationDirectory, initWindow, setTargetFPS, beginDrawing, endDrawing, windowShouldClose, clearBackground, beginMode3D, endMode3D, updateCamera, disableCursor)
 import Raylib.Models (genMeshCube, loadModelFromMesh, drawModel, loadModel, drawGrid)
 import Raylib.Types (Model, Camera3D (Camera3D), Vector3 (Vector3), CameraProjection (CameraPerspective), Camera, CameraMode (CameraModeFirstPerson))
 import Raylib.Colors (white, orange)
@@ -15,13 +15,14 @@ main = do
   initWindow 650 400 "raylib [models] example - basic models"
   setTargetFPS 60
+  disableCursor
   _ <- getApplicationDirectory >>= changeDirectory
 
   mesh <- genMeshCube 2 3 4
   cubeModel <- loadModelFromMesh mesh
   customModel <- loadModel modelPath
+
   let camera = Camera3D (Vector3 3 2 3) (Vector3 0 0 0) (Vector3 0 1 0) 70 CameraPerspective
-  setCameraMode camera CameraModeFirstPerson
 
   gameLoop cubeModel customModel camera
 
@@ -42,6 +43,6 @@ 
   endDrawing
 
-  newCamera <- updateCamera camera
+  newCamera <- updateCamera camera CameraModeFirstPerson
   shouldClose <- windowShouldClose
   unless shouldClose $ gameLoop cubeModel customModel newCamera
examples/camera-ray-collision/src/Main.hs view
@@ -11,10 +11,9 @@     endDrawing,
     endMode3D,
     initWindow,
-    setCameraMode,
     setTargetFPS,
     updateCamera,
-    windowShouldClose,
+    windowShouldClose, disableCursor
   )
 import Raylib.Models
   ( drawBoundingBox,
@@ -27,10 +26,13 @@ main :: IO ()
 main = do
   initWindow 600 450 "raylib [core] example - camera ray collision"
-  let camera = Camera3D (Vector3 0 0 0) (Vector3 2 0 1) (Vector3 0 1 0) 70 CameraPerspective
-  setCameraMode camera CameraModeFirstPerson
   setTargetFPS 60
+  disableCursor
+  
+  let camera = Camera3D (Vector3 0 0 0) (Vector3 2 0 1) (Vector3 0 1 0) 70 CameraPerspective
+  
   gameLoop camera
+
   closeWindow
 
 gameLoop :: Camera3D -> IO ()
@@ -52,7 +54,7 @@   endMode3D
 
   endDrawing
-  newCam <- updateCamera camera
+  newCam <- updateCamera camera CameraModeFirstPerson
   shouldClose <- windowShouldClose
   unless shouldClose $ gameLoop newCam
 
examples/custom-font-text/src/Main.hs view
@@ -13,9 +13,9 @@     initWindow,
     isKeyPressed,
     setTargetFPS,
-    windowShouldClose,
+    windowShouldClose, closeWindow
   )
-import Raylib.Text (drawText, drawTextEx, loadFont, unloadFont)
+import Raylib.Text (drawText, drawTextEx, loadFont)
 import Raylib.Types (Font, KeyboardKey (KeyDown, KeyUp), Vector2 (Vector2))
 
 mainFontPath :: String
@@ -29,7 +29,8 @@ 
   mainFont <- loadFont mainFontPath
   gameLoop mainFont 20
-  unloadFont mainFont
+
+  closeWindow
 
 gameLoop :: Font -> Int -> IO ()
 gameLoop mainFont size = do
examples/first-person-camera/src/Main.hs view
@@ -11,10 +11,9 @@     endDrawing,
     endMode3D,
     initWindow,
-    setCameraMode,
     setTargetFPS,
     updateCamera,
-    windowShouldClose,
+    windowShouldClose, disableCursor
   )
 import Raylib.Models (drawCircle3D, drawCubeWiresV, drawLine3D)
 import Raylib.Text (drawFPS)
@@ -23,10 +22,13 @@ main :: IO ()
 main = do
   initWindow 600 450 "raylib [core] example - first person camera"
-  let camera = Camera3D (Vector3 0 0 0) (Vector3 2 0 1) (Vector3 0 1 0) 70 CameraPerspective
-  setCameraMode camera CameraModeFirstPerson
   setTargetFPS 60
+  disableCursor
+
+  let camera = Camera3D (Vector3 0 0 0) (Vector3 2 0 1) (Vector3 0 1 0) 70 CameraPerspective
+
   gameLoop camera
+
   closeWindow
 
 gameLoop :: Camera3D -> IO ()
@@ -46,6 +48,6 @@   endMode3D
 
   endDrawing
-  newCam <- updateCamera camera
+  newCam <- updateCamera camera CameraModeFirstPerson
   shouldClose <- windowShouldClose
   unless shouldClose $ gameLoop newCam
h-raylib.cabal view
@@ -1,17 +1,17 @@ cabal-version:      2.4
 name:               h-raylib
-version:            4.5.1.1
+version:            4.5.2.0
 synopsis:           Raylib bindings for Haskell
 category:           graphics
 description:
-  This library includes Haskell bindings to the Raylib library. It supports Windows, Mac, Linux, and BSD.
+  This library contains Haskell bindings to the Raylib library. It supports Windows, Mac, Linux, and BSD.
 
 bug-reports:        https://github.com/Anut-py/h-raylib/issues
 license:            Apache-2.0
 license-file:       LICENSE
 author:             Anut
 maintainer:         Anut
-extra-doc-files:    README.md
+extra-doc-files:    CONTRIBUTING.md README.md ROADMAP.md
 extra-source-files:
   CHANGELOG.md
   lib/*.c
lib/rl_bindings.c view
@@ -249,11 +249,6 @@     return ptr;
 }
 
-void SetCameraMode_(Camera3D *a, int b)
-{
-    SetCameraMode(*a, b);
-}
-
 void SetShapesTexture_(Texture *a, Rectangle *b)
 {
     SetShapesTexture(*a, *b);
@@ -1734,3 +1729,11 @@ {
     DetachAudioStreamProcessor(*a, *b);
 }
+
+void AttachAudioMixedProcessor_(AudioCallback *a) {
+    AttachAudioMixedProcessor(*a);
+}
+
+void DetachAudioMixedProcessor_(AudioCallback *a) {
+    DetachAudioMixedProcessor(*a);
+}
lib/rl_bindings.h view
@@ -90,8 +90,6 @@ 
 Vector2 *GetGesturePinchVector_();
 
-void SetCameraMode_(Camera3D *a, int b);
-
 void SetShapesTexture_(Texture *a, Rectangle *b);
 
 void DrawPixel_(int a, int b, Color *c);
@@ -623,3 +621,7 @@ void AttachAudioStreamProcessor_(AudioStream *a, AudioCallback *b);
 
 void DetachAudioStreamProcessor_(AudioStream *a, AudioCallback *b);
+
+void AttachAudioMixedProcessor_(AudioCallback *a);
+
+void DetachAudioMixedProcessor_(AudioCallback *a);
raylib/src/raudio.c view
@@ -372,6 +372,7 @@         AudioBuffer *last;          // Pointer to last AudioBuffer in the list
         int defaultSize;            // Default audio buffer size for audio streams
     } Buffer;
+    rAudioProcessor *mixedProcessor;
     struct {
         unsigned int poolCounter;                               // AudioBuffer pointers pool counter
         AudioBuffer *pool[MAX_AUDIO_BUFFER_POOL_CHANNELS];      // Multichannel AudioBuffer pointers pool
@@ -388,7 +389,8 @@     // 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 = 0
+    .Buffer.defaultSize = 0,
+    .mixedProcessor = NULL
 };
 
 //----------------------------------------------------------------------------------
@@ -2278,6 +2280,60 @@     ma_mutex_unlock(&AUDIO.System.lock);
 }
 
+// Add processor to audio pipeline. Order of processors is important
+// Works the same way as {Attach,Detach}AudioStreamProcessor functions, except
+// these two work on the already mixed output just before sending it to the
+// sound hardware.
+void AttachAudioMixedProcessor(AudioCallback process)
+{
+    ma_mutex_lock(&AUDIO.System.lock);
+
+    rAudioProcessor *processor = (rAudioProcessor *)RL_CALLOC(1, sizeof(rAudioProcessor));
+    processor->process = process;
+
+    rAudioProcessor *last = AUDIO.mixedProcessor;
+
+    while (last && last->next)
+    {
+        last = last->next;
+    }
+    if (last)
+    {
+        processor->prev = last;
+        last->next = processor;
+    }
+    else AUDIO.mixedProcessor = processor;
+
+    ma_mutex_unlock(&AUDIO.System.lock);
+}
+
+void DetachAudioMixedProcessor(AudioCallback process)
+{
+    ma_mutex_lock(&AUDIO.System.lock);
+
+    rAudioProcessor *processor = AUDIO.mixedProcessor;
+
+    while (processor)
+    {
+        rAudioProcessor *next = processor->next;
+        rAudioProcessor *prev = processor->prev;
+
+        if (processor->process == process)
+        {
+            if (AUDIO.mixedProcessor == processor) AUDIO.mixedProcessor = next;
+            if (prev) prev->next = next;
+            if (next) next->prev = prev;
+
+            RL_FREE(processor);
+        }
+
+        processor = next;
+    }
+
+    ma_mutex_unlock(&AUDIO.System.lock);
+}
+
+
 //----------------------------------------------------------------------------------
 // Module specific Functions Definition
 //----------------------------------------------------------------------------------
@@ -2517,6 +2573,13 @@                 if (framesToRead > 0) break;
             }
         }
+    }
+
+    rAudioProcessor *processor = AUDIO.mixedProcessor;
+    while (processor)
+    {
+        processor->process(pFramesOut, frameCount);
+        processor = processor->next;
     }
 
     ma_mutex_unlock(&AUDIO.System.lock);
raylib/src/raylib.h view
@@ -941,7 +941,8 @@ RLAPI void MaximizeWindow(void);                                  // Set window state: maximized, if resizable (only PLATFORM_DESKTOP)
 RLAPI void MinimizeWindow(void);                                  // Set window state: minimized, if resizable (only PLATFORM_DESKTOP)
 RLAPI void RestoreWindow(void);                                   // Set window state: not minimized/maximized (only PLATFORM_DESKTOP)
-RLAPI void SetWindowIcon(Image image);                            // Set icon for window (only PLATFORM_DESKTOP)
+RLAPI void SetWindowIcon(Image image);                            // Set icon for window (single image, RGBA 32bit, only PLATFORM_DESKTOP)
+RLAPI void SetWindowIcons(Image *images, int count);              // Set icon for window (multiple images, RGBA 32bit, only PLATFORM_DESKTOP)
 RLAPI void SetWindowTitle(const char *title);                     // Set title for window (only PLATFORM_DESKTOP)
 RLAPI void SetWindowPosition(int x, int y);                       // Set window position on screen (only PLATFORM_DESKTOP)
 RLAPI void SetWindowMonitor(int monitor);                         // Set monitor for the current window (fullscreen mode)
@@ -1156,13 +1157,7 @@ //------------------------------------------------------------------------------------
 // Camera System Functions (Module: rcamera)
 //------------------------------------------------------------------------------------
-RLAPI void SetCameraMode(Camera camera, int mode);      // Set camera mode (multiple camera modes available)
-RLAPI void UpdateCamera(Camera *camera);                // Update camera position for selected mode
-
-RLAPI void SetCameraPanControl(int keyPan);             // Set camera pan key to combine with mouse movement (free camera)
-RLAPI void SetCameraAltControl(int keyAlt);             // Set camera alt key to combine with mouse movement (free camera)
-RLAPI void SetCameraSmoothZoomControl(int keySmoothZoom); // Set camera smooth zoom key to combine with mouse (free camera)
-RLAPI void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown); // Set camera move controls (1st person and 3rd person cameras)
+RLAPI void UpdateCamera(Camera *camera, int mode);      // Update camera position for selected mode
 
 //------------------------------------------------------------------------------------
 // Basic Shapes Drawing Functions (Module: shapes)
@@ -1585,6 +1580,9 @@ 
 RLAPI void AttachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Attach audio stream processor to stream
 RLAPI void DetachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Detach audio stream processor from stream
+
+RLAPI void AttachAudioMixedProcessor(AudioCallback processor); // Attach audio stream processor to the entire audio pipeline
+RLAPI void DetachAudioMixedProcessor(AudioCallback processor); // Detach audio stream processor from the entire audio pipeline
 
 #if defined(__cplusplus)
 }
raylib/src/rcamera.h view
@@ -1,8 +1,6 @@ /*******************************************************************************************
 *
-*   rcamera - Basic camera system for multiple camera modes
-*
-*   NOTE: Memory footprint of this library is aproximately 52 bytes (global variables)
+*   rcamera - Basic camera system with support for multiple camera modes
 *
 *   CONFIGURATION:
 *
@@ -17,12 +15,13 @@ *
 *   CONTRIBUTORS:
 *       Ramon Santamaria:   Supervision, review, update and maintenance
+*       Christoph Wagner:   Complete redesign, using raymath (2022)
 *       Marc Palau:         Initial implementation (2014)
 *
 *
 *   LICENSE: zlib/libpng
 *
-*   Copyright (c) 2015-2023 Ramon Santamaria (@raysan5)
+*   Copyright (c) 2022-2023 Christoph Wagner (@Crydsch) & 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.
@@ -48,11 +47,19 @@ // Defines and Macros
 //----------------------------------------------------------------------------------
 //...
+#if defined(CAMERA_STANDALONE)
+#define CAMERA_CULL_DISTANCE_NEAR      0.01
+#define CAMERA_CULL_DISTANCE_FAR    1000.0
+#else
+#define CAMERA_CULL_DISTANCE_NEAR   RL_CULL_DISTANCE_NEAR
+#define CAMERA_CULL_DISTANCE_FAR    RL_CULL_DISTANCE_FAR
+#endif
 
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 // NOTE: Below types are required for CAMERA_STANDALONE usage
 //----------------------------------------------------------------------------------
+// TODO review
 #if defined(CAMERA_STANDALONE)
     // Vector2 type
     typedef struct Vector2 {
@@ -97,8 +104,8 @@ //----------------------------------------------------------------------------------
 // Global Variables Definition
 //----------------------------------------------------------------------------------
-//...
 
+
 //----------------------------------------------------------------------------------
 // Module Functions Declaration
 //----------------------------------------------------------------------------------
@@ -107,18 +114,22 @@ extern "C" {            // Prevents name mangling of functions
 #endif
 
-#if defined(CAMERA_STANDALONE)
-void SetCameraMode(Camera camera, int mode);                // Set camera mode (multiple camera modes available)
-void UpdateCamera(Camera *camera);                          // Update camera position for selected mode
+Vector3 GetCameraForward(Camera *camera);
+Vector3 GetCameraUp(Camera *camera);
+Vector3 GetCameraRight(Camera *camera);
 
-void SetCameraPanControl(int keyPan);                       // Set camera pan key to combine with mouse movement (free camera)
-void SetCameraAltControl(int keyAlt);                       // Set camera alt key to combine with mouse movement (free camera)
-void SetCameraSmoothZoomControl(int szoomKey);              // Set camera smooth zoom key to combine with mouse (free camera)
-void SetCameraMoveControls(int keyFront, int keyBack,
-                           int keyRight, int keyLeft,
-                           int keyUp, int keyDown);         // Set camera move controls (1st person and 3rd person cameras)
-#endif
+void CameraMoveForward(Camera *camera, float distance, bool moveInWorldPlane);
+void CameraMoveUp(Camera *camera, float distance);
+void CameraMoveRight(Camera *camera, float distance, bool moveInWorldPlane);
+void CameraMoveToTarget(Camera *camera, float delta);
 
+void CameraYaw(Camera *camera, float angle, bool rotateAroundTarget);
+void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp);
+void CameraRoll(Camera *camera, float angle);
+
+Matrix GetCameraViewMatrix(Camera *camera);
+Matrix GetCameraProjectionMatrix(Camera* camera, float aspect);
+
 #if defined(__cplusplus)
 }
 #endif
@@ -134,424 +145,325 @@ 
 #if defined(CAMERA_IMPLEMENTATION)
 
-#include <math.h>               // Required for: sinf(), cosf(), sqrtf()
+#include "raymath.h"        // Required for vector maths:
+                            // Vector3Add()
+                            // Vector3Subtract()
+                            // Vector3Scale()
+                            // Vector3Normalize()
+                            // Vector3Distance()
+                            // Vector3CrossProduct()
+                            // Vector3RotateByAxisAngle()
+                            // Vector3Angle()
+                            // Vector3Negate()
+                            // MatrixLookAt()
+                            // MatrixPerspective()
+                            // MatrixOrtho()
+                            // MatrixIdentity()
 
+// raylib required functionality: 
+                            // GetMouseDelta()
+                            // GetMouseWheelMove()
+                            // IsKeyDown()
+                            // IsKeyPressed()
+                            // GetFrameTime()
+
 //----------------------------------------------------------------------------------
 // Defines and Macros
 //----------------------------------------------------------------------------------
-#ifndef PI
-    #define PI 3.14159265358979323846
-#endif
-#ifndef DEG2RAD
-    #define DEG2RAD (PI/180.0f)
-#endif
-#ifndef RAD2DEG
-    #define RAD2DEG (180.0f/PI)
-#endif
+#define CAMERA_MOVE_SPEED                               0.09f
+#define CAMERA_ROTATION_SPEED                           0.03f
 
 // Camera mouse movement sensitivity
-#define CAMERA_MOUSE_MOVE_SENSITIVITY                   0.5f    // TODO: it should be independent of framerate
+#define CAMERA_MOUSE_MOVE_SENSITIVITY                   0.003f    // TODO: it should be independant of framerate
 #define CAMERA_MOUSE_SCROLL_SENSITIVITY                 1.5f
 
-// FREE_CAMERA
-#define CAMERA_FREE_MOUSE_SENSITIVITY                   0.01f
-#define CAMERA_FREE_DISTANCE_MIN_CLAMP                  0.3f
-#define CAMERA_FREE_DISTANCE_MAX_CLAMP                  120.0f
-#define CAMERA_FREE_MIN_CLAMP                           85.0f
-#define CAMERA_FREE_MAX_CLAMP                          -85.0f
-#define CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY             0.05f
-#define CAMERA_FREE_PANNING_DIVIDER                     5.1f
-
-// ORBITAL_CAMERA
 #define CAMERA_ORBITAL_SPEED                            0.5f       // Radians per second
 
-// FIRST_PERSON
-//#define CAMERA_FIRST_PERSON_MOUSE_SENSITIVITY           0.003f
-#define CAMERA_FIRST_PERSON_FOCUS_DISTANCE              25.0f
-#define CAMERA_FIRST_PERSON_MIN_CLAMP                   89.0f
-#define CAMERA_FIRST_PERSON_MAX_CLAMP                  -89.0f
 
-// When walking, y-position of the player moves up-down at step frequency (swinging) but
-// also the body slightly tilts left-right on every step, when all the body weight is left over one foot (tilting)
-#define CAMERA_FIRST_PERSON_STEP_FREQUENCY               1.8f       // Step frequency when walking (steps per second)
-#define CAMERA_FIRST_PERSON_SWINGING_DELTA               0.03f      // Maximum up-down swinging distance when walking
-#define CAMERA_FIRST_PERSON_TILTING_DELTA                0.005f     // Maximum left-right tilting distance when walking
-
-// THIRD_PERSON
-//#define CAMERA_THIRD_PERSON_MOUSE_SENSITIVITY           0.003f
-#define CAMERA_THIRD_PERSON_DISTANCE_CLAMP              1.2f
-#define CAMERA_THIRD_PERSON_MIN_CLAMP                   5.0f
-#define CAMERA_THIRD_PERSON_MAX_CLAMP                  -85.0f
-#define CAMERA_THIRD_PERSON_OFFSET                      (Vector3){ 0.4f, 0.0f, 0.0f }
+#define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER  8.0f
+#define CAMERA_FIRST_PERSON_STEP_DIVIDER                30.0f
+#define CAMERA_FIRST_PERSON_WAVING_DIVIDER              200.0f
 
 // PLAYER (used by camera)
-#define PLAYER_MOVEMENT_SENSITIVITY                     2.0f
+#define PLAYER_MOVEMENT_SENSITIVITY                     20.0f
 
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
-// Camera move modes (first person and third person cameras)
-typedef enum {
-    MOVE_FRONT = 0,
-    MOVE_BACK,
-    MOVE_RIGHT,
-    MOVE_LEFT,
-    MOVE_UP,
-    MOVE_DOWN
-} CameraMove;
-
-// Camera global state context data [56 bytes]
-typedef struct {
-    unsigned int mode;              // Current camera mode
-    float targetDistance;           // Camera distance from position to target
-    float playerEyesPosition;       // Player eyes position from ground (in meters)
-    Vector2 angle;                  // Camera angle in plane XZ
-
-    // Camera movement control keys
-    int moveControl[6];             // Move controls (CAMERA_FIRST_PERSON)
-    int smoothZoomControl;          // Smooth zoom control key
-    int altControl;                 // Alternative control key
-    int panControl;                 // Pan view control key
-} CameraData;
+//...
 
 //----------------------------------------------------------------------------------
 // Global Variables Definition
 //----------------------------------------------------------------------------------
-static CameraData CAMERA = {        // Global CAMERA state context
-    .mode = 0,
-    .targetDistance = 0,
-    .playerEyesPosition = 1.85f,
-    .angle = { 0 },
-    .moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' },
-    .smoothZoomControl = 341,       // raylib: KEY_LEFT_CONTROL
-    .altControl = 342,              // raylib: KEY_LEFT_ALT
-    .panControl = 2                 // raylib: MOUSE_BUTTON_MIDDLE
-};
+//...
 
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
 //----------------------------------------------------------------------------------
-#if defined(CAMERA_STANDALONE)
-// NOTE: Camera controls depend on some raylib input functions
-static void EnableCursor() {}       // Unlock cursor
-static void DisableCursor() {}      // Lock cursor
-
-static int IsKeyDown(int key) { return 0; }
-
-static int IsMouseButtonDown(int button) { return 0;}
-static float GetMouseWheelMove() { return 0.0f; }
-static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; }
-#endif
+//...
 
 //----------------------------------------------------------------------------------
 // Module Functions Definition
 //----------------------------------------------------------------------------------
-
-// Select camera mode (multiple camera modes available)
-void SetCameraMode(Camera camera, int mode)
+// Returns the cameras forward vector (normalized)
+Vector3 GetCameraForward(Camera *camera)
 {
-    Vector3 v1 = camera.position;
-    Vector3 v2 = camera.target;
-
-    float dx = v2.x - v1.x;
-    float dy = v2.y - v1.y;
-    float dz = v2.z - v1.z;
-
-    CAMERA.targetDistance = sqrtf(dx*dx + dy*dy + dz*dz);   // Distance to target
-
-    // Camera angle calculation
-    CAMERA.angle.x = atan2f(dx, dz);                        // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
-    CAMERA.angle.y = atan2f(dy, sqrtf(dx*dx + dz*dz));      // Camera angle in plane XY (0 aligned with X, move positive CW)
-
-    CAMERA.playerEyesPosition = camera.position.y;          // Init player eyes position to camera Y position
-
-    // Lock cursor for first person and third person cameras
-    if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor();
-    else EnableCursor();
-
-    CAMERA.mode = mode;
+    return Vector3Normalize(Vector3Subtract(camera->target, camera->position));
 }
 
-// Update camera depending on selected mode
-// NOTE: Camera controls depend on some raylib functions:
-//       System: EnableCursor(), DisableCursor()
-//       Mouse: IsMouseButtonDown(), GetMousePosition(), GetMouseWheelMove()
-//       Keys:  IsKeyDown()
-void UpdateCamera(Camera *camera)
+// Returns the cameras up vector (normalized)
+// Note: The up vector might not be perpendicular to the forward vector
+Vector3 GetCameraUp(Camera *camera)
 {
-    static float swingCounter = 0.0f;    // Used for 1st person swinging movement
-
-    // TODO: Compute CAMERA.targetDistance and CAMERA.angle here (?)
+    return Vector3Normalize(camera->up);
+}
 
-    // Mouse movement detection
-    Vector2 mousePositionDelta = GetMouseDelta();
-    float mouseWheelMove = GetMouseWheelMove();
+// Returns the cameras right vector (normalized)
+Vector3 GetCameraRight(Camera *camera)
+{
+    Vector3 forward = GetCameraForward(camera);
+    Vector3 up = GetCameraUp(camera);
+    
+    return Vector3CrossProduct(forward, up);
+}
 
-    // Keys input detection
-    // TODO: Input detection is raylib-dependant, it could be moved outside the module
-    bool keyPan = IsMouseButtonDown(CAMERA.panControl);
-    bool keyAlt = IsKeyDown(CAMERA.altControl);
-    bool szoomKey = IsKeyDown(CAMERA.smoothZoomControl);
-    bool direction[6] = { IsKeyDown(CAMERA.moveControl[MOVE_FRONT]),
-                          IsKeyDown(CAMERA.moveControl[MOVE_BACK]),
-                          IsKeyDown(CAMERA.moveControl[MOVE_RIGHT]),
-                          IsKeyDown(CAMERA.moveControl[MOVE_LEFT]),
-                          IsKeyDown(CAMERA.moveControl[MOVE_UP]),
-                          IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) };
+// Moves the camera in its forward direction
+void CameraMoveForward(Camera *camera, float distance, bool moveInWorldPlane)
+{
+    Vector3 forward = GetCameraForward(camera);
 
-    // Support for multiple automatic camera modes
-    // NOTE: In case of CAMERA_CUSTOM nothing happens here, user must update it manually
-    switch (CAMERA.mode)
+    if (moveInWorldPlane)
     {
-        case CAMERA_FREE:           // Camera free controls, using standard 3d-content-creation scheme
-        {
-            // Camera zoom
-            if ((CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
-            {
-                CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
-                if (CAMERA.targetDistance > CAMERA_FREE_DISTANCE_MAX_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MAX_CLAMP;
-            }
-
-            // Camera looking down
-            else if ((camera->position.y > camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
-            {
-                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-            }
-            else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0))
-            {
-                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-
-                // if (camera->target.y < 0) camera->target.y = -0.001;
-            }
-            else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0))
-            {
-                CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
-                if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
-            }
-            // Camera looking up
-            else if ((camera->position.y < camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
-            {
-                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-            }
-            else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0))
-            {
-                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
-
-                // if (camera->target.y > 0) camera->target.y = 0.001;
-            }
-            else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0))
-            {
-                CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
-                if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
-            }
-
-            // Input keys checks
-            if (keyPan)
-            {
-                if (keyAlt)     // Alternative key behaviour
-                {
-                    if (szoomKey)
-                    {
-                        // Camera smooth zoom
-                        CAMERA.targetDistance += (mousePositionDelta.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY);
-                    }
-                    else
-                    {
-                        // Camera rotation
-                        CAMERA.angle.x += mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY;
-                        CAMERA.angle.y += mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY;
+        // Project vector onto world plane
+        forward.y = 0;
+        forward = Vector3Normalize(forward);
+    }
 
-                        // Angle clamp
-                        if (CAMERA.angle.y > CAMERA_FREE_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MIN_CLAMP*DEG2RAD;
-                        else if (CAMERA.angle.y < CAMERA_FREE_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MAX_CLAMP*DEG2RAD;
-                    }
-                }
-                else
-                {
-                    // Camera panning
-                    camera->target.x += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
-                    camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
-                    camera->target.z += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
-                }
-            }
+    // Scale by distance
+    forward = Vector3Scale(forward, distance);
 
-            // Update camera position with changes
-            camera->position.x = -sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
-            camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance + camera->target.y;
-            camera->position.z = -cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
+    // Move position and target
+    camera->position = Vector3Add(camera->position, forward);
+    camera->target = Vector3Add(camera->target, forward);
+}
 
-        } break;
-        case CAMERA_ORBITAL:        // Camera just orbits around target, only zoom allowed
-        {
-            CAMERA.angle.x += CAMERA_ORBITAL_SPEED*GetFrameTime();      // Camera orbit angle
-            CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);   // Camera zoom
+// Moves the camera in its up direction
+void CameraMoveUp(Camera *camera, float distance)
+{
+    Vector3 up = GetCameraUp(camera);
+    
+    // Scale by distance
+    up = Vector3Scale(up, distance);
 
-            // Camera distance clamp
-            if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
+    // Move position and target
+    camera->position = Vector3Add(camera->position, up);
+    camera->target = Vector3Add(camera->target, up);
+}
 
-            // Update camera position with changes
-            camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
-            camera->position.y = ((CAMERA.angle.y <= 0.0f)? 1 : -1)*sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
-            camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
+// Moves the camera target in its current right direction
+void CameraMoveRight(Camera *camera, float distance, bool moveInWorldPlane)
+{
+    Vector3 right = GetCameraRight(camera);
 
-        } break;
-        case CAMERA_FIRST_PERSON:   // Camera moves as in a first-person game, controls are configurable
-        {
-            // NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position'
-            camera->position.y = CAMERA.playerEyesPosition;
+    if (moveInWorldPlane)
+    {
+        // Project vector onto world plane
+        right.y = 0;
+        right = Vector3Normalize(right);
+    }
 
-            camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] -
-                                   sinf(CAMERA.angle.x)*direction[MOVE_FRONT] -
-                                   cosf(CAMERA.angle.x)*direction[MOVE_LEFT] +
-                                   cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
+    // Scale by distance
+    right = Vector3Scale(right, distance);
 
-            camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] -
-                                   sinf(CAMERA.angle.y)*direction[MOVE_BACK] +
-                                   1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
+    // Move position and target
+    camera->position = Vector3Add(camera->position, right);
+    camera->target = Vector3Add(camera->target, right);
+}
 
-            camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] -
-                                   cosf(CAMERA.angle.x)*direction[MOVE_FRONT] +
-                                   sinf(CAMERA.angle.x)*direction[MOVE_LEFT] -
-                                   sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
+// Moves the camera position closer/farther to/from the camera target
+void CameraMoveToTarget(Camera *camera, float delta)
+{
+    float distance = Vector3Distance(camera->position, camera->target);
 
-            // Camera orientation calculation
-            CAMERA.angle.x -= mousePositionDelta.x*CAMERA_MOUSE_MOVE_SENSITIVITY*GetFrameTime();
-            CAMERA.angle.y -= mousePositionDelta.y*CAMERA_MOUSE_MOVE_SENSITIVITY*GetFrameTime();
+    // Apply delta
+    distance += delta;
 
-            // Angle clamp
-            if (CAMERA.angle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD;
-            else if (CAMERA.angle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD;
+    // Distance must be greater than 0
+    if (distance < 0) distance = 0.001f;
 
-            // Calculate translation matrix
-            Matrix matTranslation = { 1.0f, 0.0f, 0.0f, 0.0f,
-                                      0.0f, 1.0f, 0.0f, 0.0f,
-                                      0.0f, 0.0f, 1.0f, (CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER),
-                                      0.0f, 0.0f, 0.0f, 1.0f };
+    // Set new distance by moving the position along the forward vector
+    Vector3 forward = GetCameraForward(camera);
+    camera->position = Vector3Add(camera->target, Vector3Scale(forward, -distance));
+}
 
-            // Calculate rotation matrix
-            Matrix matRotation = { 1.0f, 0.0f, 0.0f, 0.0f,
-                                   0.0f, 1.0f, 0.0f, 0.0f,
-                                   0.0f, 0.0f, 1.0f, 0.0f,
-                                   0.0f, 0.0f, 0.0f, 1.0f };
+// Rotates the camera around its up vector
+// Yaw is "looking left and right"
+// If rotateAroundTarget is false, the camera rotates around its position
+// Note: angle must be provided in radians
+void CameraYaw(Camera *camera, float angle, bool rotateAroundTarget)
+{
+    // Rotation axis
+    Vector3 up = GetCameraUp(camera);
 
-            float cosz = cosf(0.0f);
-            float sinz = sinf(0.0f);
-            float cosy = cosf(-(PI*2 - CAMERA.angle.x));
-            float siny = sinf(-(PI*2 - CAMERA.angle.x));
-            float cosx = cosf(-(PI*2 - CAMERA.angle.y));
-            float sinx = sinf(-(PI*2 - CAMERA.angle.y));
+    // View vector
+    Vector3 target_position = Vector3Subtract(camera->target, camera->position);
 
-            matRotation.m0 = cosz*cosy;
-            matRotation.m4 = (cosz*siny*sinx) - (sinz*cosx);
-            matRotation.m8 = (cosz*siny*cosx) + (sinz*sinx);
-            matRotation.m1 = sinz*cosy;
-            matRotation.m5 = (sinz*siny*sinx) + (cosz*cosx);
-            matRotation.m9 = (sinz*siny*cosx) - (cosz*sinx);
-            matRotation.m2 = -siny;
-            matRotation.m6 = cosy*sinx;
-            matRotation.m10= cosy*cosx;
+    // Rotate view vector around up axis
+    target_position = Vector3RotateByAxisAngle(target_position, up, angle);
 
-            // Multiply translation and rotation matrices
-            Matrix matTransform = { 0 };
-            matTransform.m0 = matTranslation.m0*matRotation.m0 + matTranslation.m1*matRotation.m4 + matTranslation.m2*matRotation.m8 + matTranslation.m3*matRotation.m12;
-            matTransform.m1 = matTranslation.m0*matRotation.m1 + matTranslation.m1*matRotation.m5 + matTranslation.m2*matRotation.m9 + matTranslation.m3*matRotation.m13;
-            matTransform.m2 = matTranslation.m0*matRotation.m2 + matTranslation.m1*matRotation.m6 + matTranslation.m2*matRotation.m10 + matTranslation.m3*matRotation.m14;
-            matTransform.m3 = matTranslation.m0*matRotation.m3 + matTranslation.m1*matRotation.m7 + matTranslation.m2*matRotation.m11 + matTranslation.m3*matRotation.m15;
-            matTransform.m4 = matTranslation.m4*matRotation.m0 + matTranslation.m5*matRotation.m4 + matTranslation.m6*matRotation.m8 + matTranslation.m7*matRotation.m12;
-            matTransform.m5 = matTranslation.m4*matRotation.m1 + matTranslation.m5*matRotation.m5 + matTranslation.m6*matRotation.m9 + matTranslation.m7*matRotation.m13;
-            matTransform.m6 = matTranslation.m4*matRotation.m2 + matTranslation.m5*matRotation.m6 + matTranslation.m6*matRotation.m10 + matTranslation.m7*matRotation.m14;
-            matTransform.m7 = matTranslation.m4*matRotation.m3 + matTranslation.m5*matRotation.m7 + matTranslation.m6*matRotation.m11 + matTranslation.m7*matRotation.m15;
-            matTransform.m8 = matTranslation.m8*matRotation.m0 + matTranslation.m9*matRotation.m4 + matTranslation.m10*matRotation.m8 + matTranslation.m11*matRotation.m12;
-            matTransform.m9 = matTranslation.m8*matRotation.m1 + matTranslation.m9*matRotation.m5 + matTranslation.m10*matRotation.m9 + matTranslation.m11*matRotation.m13;
-            matTransform.m10 = matTranslation.m8*matRotation.m2 + matTranslation.m9*matRotation.m6 + matTranslation.m10*matRotation.m10 + matTranslation.m11*matRotation.m14;
-            matTransform.m11 = matTranslation.m8*matRotation.m3 + matTranslation.m9*matRotation.m7 + matTranslation.m10*matRotation.m11 + matTranslation.m11*matRotation.m15;
-            matTransform.m12 = matTranslation.m12*matRotation.m0 + matTranslation.m13*matRotation.m4 + matTranslation.m14*matRotation.m8 + matTranslation.m15*matRotation.m12;
-            matTransform.m13 = matTranslation.m12*matRotation.m1 + matTranslation.m13*matRotation.m5 + matTranslation.m14*matRotation.m9 + matTranslation.m15*matRotation.m13;
-            matTransform.m14 = matTranslation.m12*matRotation.m2 + matTranslation.m13*matRotation.m6 + matTranslation.m14*matRotation.m10 + matTranslation.m15*matRotation.m14;
-            matTransform.m15 = matTranslation.m12*matRotation.m3 + matTranslation.m13*matRotation.m7 + matTranslation.m14*matRotation.m11 + matTranslation.m15*matRotation.m15;
+    if (rotateAroundTarget)
+    {
+        // Move position relative to target
+        camera->position = Vector3Subtract(camera->target, target_position);
+    }
+    else // rotate around camera.position
+    {
+        // Move target relative to position
+        camera->target = Vector3Add(camera->position, target_position);
+    }
+}
 
-            camera->target.x = camera->position.x - matTransform.m12;
-            camera->target.y = camera->position.y - matTransform.m13;
-            camera->target.z = camera->position.z - matTransform.m14;
+// Rotates the camera around its right vector
+// Pitch is "looking up and down"
+// lockView prevents camera overrotation (aka "somersaults")
+// If rotateAroundTarget is false, the camera rotates around its position
+// rotateUp rotates the up direction as well (typically only usefull in CAMERA_FREE)
+// Note: angle must be provided in radians
+void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp)
+{
+    // Up direction
+    Vector3 up = GetCameraUp(camera);
 
-            // Camera swinging (y-movement), only when walking (some key pressed)
-            for (int i = 0; i < 6; i++) if (direction[i]) { swingCounter += GetFrameTime(); break; }
-            camera->position.y -= sinf(2*PI*CAMERA_FIRST_PERSON_STEP_FREQUENCY*swingCounter)*CAMERA_FIRST_PERSON_SWINGING_DELTA;
+    // View vector
+    Vector3 target_position = Vector3Subtract(camera->target, camera->position);
 
-            // Camera waiving (xz-movement), only when walking (some key pressed)
-            camera->up.x = sinf(2*PI*CAMERA_FIRST_PERSON_STEP_FREQUENCY*swingCounter)*CAMERA_FIRST_PERSON_TILTING_DELTA;
-            camera->up.z = -sinf(2*PI*CAMERA_FIRST_PERSON_STEP_FREQUENCY*swingCounter)*CAMERA_FIRST_PERSON_TILTING_DELTA;
+    if (lockView)
+    {
+        // In these camera modes we clamp the Pitch angle
+        // to allow only viewing straight up or down.
 
-        } break;
-        case CAMERA_THIRD_PERSON:   // Camera moves as in a third-person game, following target at a distance, controls are configurable
-        {
-            camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] -
-                                   sinf(CAMERA.angle.x)*direction[MOVE_FRONT] -
-                                   cosf(CAMERA.angle.x)*direction[MOVE_LEFT] +
-                                   cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
+        // Clamp view up
+        float max_angle_up = Vector3Angle(up, target_position);
+        max_angle_up -= 0.001f; // avoid numerical errors
+        if (angle > max_angle_up) angle = max_angle_up;
 
-            camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] -
-                                   sinf(CAMERA.angle.y)*direction[MOVE_BACK] +
-                                   1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
+        // Clamp view down
+        float max_angle_down = Vector3Angle(Vector3Negate(up), target_position);
+        max_angle_down *= -1.0f; // downwards angle is negative
+        max_angle_down += 0.001f; // avoid numerical errors
+        if (angle < max_angle_down) angle = max_angle_down;
+    }
 
-            camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] -
-                                   cosf(CAMERA.angle.x)*direction[MOVE_FRONT] +
-                                   sinf(CAMERA.angle.x)*direction[MOVE_LEFT] -
-                                   sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
+    // Rotation axis
+    Vector3 right = GetCameraRight(camera);
 
-            // Camera orientation calculation
-            CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
-            CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY);
+    // Rotate view vector around right axis
+    target_position = Vector3RotateByAxisAngle(target_position, right, angle);
 
-            // Angle clamp
-            if (CAMERA.angle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD;
-            else if (CAMERA.angle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD;
+    if (rotateAroundTarget)
+    {
+        // Move position relative to target
+        camera->position = Vector3Subtract(camera->target, target_position);
+    }
+    else // rotate around camera.position
+    {
+        // Move target relative to position
+        camera->target = Vector3Add(camera->position, target_position);
+    }
 
-            // Camera zoom
-            CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
+    if (rotateUp)
+    {
+        // Rotate up direction around right axis
+        camera->up = Vector3RotateByAxisAngle(camera->up, right, angle);
+    }
+}
 
-            // Camera distance clamp
-            if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
+// Rotates the camera around its forward vector
+// Roll is "turning your head sideways to the left or right"
+// Note: angle must be provided in radians
+void CameraRoll(Camera *camera, float angle)
+{
+    // Rotation axis
+    Vector3 forward = GetCameraForward(camera);
 
-            camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
+    // Rotate up direction around forward axis
+    camera->up = Vector3RotateByAxisAngle(camera->up, forward, angle);
+}
 
-            if (CAMERA.angle.y <= 0.0f) camera->position.y = sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
-            else camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
+// Returns the camera view matrix
+Matrix GetCameraViewMatrix(Camera *camera)
+{
+    return MatrixLookAt(camera->position, camera->target, camera->up);
+}
 
-            camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
+// Returns the camera projection matrix
+Matrix GetCameraProjectionMatrix(Camera *camera, float aspect)
+{
+    if (camera->projection == CAMERA_PERSPECTIVE)
+    {
+        return MatrixPerspective(camera->fovy*DEG2RAD, aspect, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR);
+    }
+    else if (camera->projection == CAMERA_ORTHOGRAPHIC)
+    {
+        double top = camera->fovy/2.0;
+        double right = top*aspect;
 
-        } break;
-        case CAMERA_CUSTOM: break;
-        default: break;
+        return MatrixOrtho(-right, right, -top, top, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR);
     }
+    
+    return MatrixIdentity();
 }
 
-// Set camera pan key to combine with mouse movement (free camera)
-void SetCameraPanControl(int keyPan) { CAMERA.panControl = keyPan; }
+#ifndef CAMERA_STANDALONE
+// Update camera position for selected mode
+// Camera mode: CAMERA_FREE, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON, CAMERA_ORBITAL or CUSTOM
+void UpdateCamera(Camera *camera, int mode)
+{
+    Vector2 mousePositionDelta = GetMouseDelta();
 
-// Set camera alt key to combine with mouse movement (free camera)
-void SetCameraAltControl(int keyAlt) { CAMERA.altControl = keyAlt; }
+    bool moveInWorldPlane = ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON));
+    bool rotateAroundTarget = ((mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL));
+    bool lockView = ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL));
+    bool rotateUp = (mode == CAMERA_FREE);
+    
+    if (mode == CAMERA_ORBITAL)
+    {
+        // Orbital can just orbit
+        Matrix rotation = MatrixRotate(GetCameraUp(camera), CAMERA_ORBITAL_SPEED*GetFrameTime());
+        Vector3 view = Vector3Subtract(camera->position, camera->target);
+        view = Vector3Transform(view, rotation);
+        camera->position = Vector3Add(camera->target, view);
+    }
+    else
+    {
+        // Camera rotation
+        if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp);
+        if (IsKeyDown(KEY_UP)) CameraPitch(camera, CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp);
+        if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -CAMERA_ROTATION_SPEED, rotateAroundTarget);
+        if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, CAMERA_ROTATION_SPEED, rotateAroundTarget);
+        if (IsKeyDown(KEY_Q)) CameraRoll(camera, -CAMERA_ROTATION_SPEED);
+        if (IsKeyDown(KEY_E)) CameraRoll(camera, CAMERA_ROTATION_SPEED);
 
-// Set camera smooth zoom key to combine with mouse (free camera)
-void SetCameraSmoothZoomControl(int szoomKey) { CAMERA.smoothZoomControl = szoomKey; }
+        CameraYaw(camera, -mousePositionDelta.x*CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget);
+        CameraPitch(camera, -mousePositionDelta.y*CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp);
+  
+        // Camera movement
+        if (IsKeyDown(KEY_W)) CameraMoveForward(camera, CAMERA_MOVE_SPEED, moveInWorldPlane);
+        if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane);
+        if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane);
+        if (IsKeyDown(KEY_D)) CameraMoveRight(camera, CAMERA_MOVE_SPEED, moveInWorldPlane);
+        //if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, CAMERA_MOVE_SPEED);
+        //if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -CAMERA_MOVE_SPEED);
+    }
 
-// Set camera move controls (1st person and 3rd person cameras)
-void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown)
-{
-    CAMERA.moveControl[MOVE_FRONT] = keyFront;
-    CAMERA.moveControl[MOVE_BACK] = keyBack;
-    CAMERA.moveControl[MOVE_RIGHT] = keyRight;
-    CAMERA.moveControl[MOVE_LEFT] = keyLeft;
-    CAMERA.moveControl[MOVE_UP] = keyUp;
-    CAMERA.moveControl[MOVE_DOWN] = keyDown;
+    if ((mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL))
+    {
+        // Zoom target distance
+        CameraMoveToTarget(camera, -GetMouseWheelMove());
+        if (IsKeyPressed(KEY_KP_SUBTRACT)) CameraMoveToTarget(camera, 2.0f);
+        if (IsKeyPressed(KEY_KP_ADD)) CameraMoveToTarget(camera, -2.0f);
+    }
 }
+#endif // !CAMERA_STANDALONE
 
 #endif // CAMERA_IMPLEMENTATION
+ raylib/src/rcamera.old.h view
@@ -0,0 +1,567 @@+/*******************************************************************************************
+*
+*   rcamera - Basic camera system for multiple camera modes
+*
+*   NOTE: Memory footprint of this library is aproximately 52 bytes (global variables)
+*
+*   CONFIGURATION:
+*
+*   #define CAMERA_IMPLEMENTATION
+*       Generates the implementation of the library into the included file.
+*       If not defined, the library is in header only mode and can be included in other headers
+*       or source files without problems. But only ONE file should hold the implementation.
+*
+*   #define CAMERA_STANDALONE
+*       If defined, the library can be used as standalone as a camera system but some
+*       functions must be redefined to manage inputs accordingly.
+*
+*   CONTRIBUTORS:
+*       Ramon Santamaria:   Supervision, review, update and maintenance
+*       Marc Palau:         Initial implementation (2014)
+*
+*
+*   LICENSE: zlib/libpng
+*
+*   Copyright (c) 2015-2022 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.
+*
+**********************************************************************************************/
+
+#ifndef RCAMERA_H
+#define RCAMERA_H
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+//...
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+// NOTE: Below types are required for CAMERA_STANDALONE usage
+//----------------------------------------------------------------------------------
+#if defined(CAMERA_STANDALONE)
+    // Vector2 type
+    typedef struct Vector2 {
+        float x;
+        float y;
+    } Vector2;
+
+    // Vector3 type
+    typedef struct Vector3 {
+        float x;
+        float y;
+        float z;
+    } Vector3;
+
+    // Camera type, defines a camera position/orientation in 3d space
+    typedef struct Camera3D {
+        Vector3 position;       // Camera position
+        Vector3 target;         // Camera target it looks-at
+        Vector3 up;             // Camera up vector (rotation over its axis)
+        float fovy;             // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic
+        int type;               // Camera type, defines projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC
+    } Camera3D;
+
+    typedef Camera3D Camera;    // Camera type fallback, defaults to Camera3D
+
+    // Camera system modes
+    typedef enum {
+        CAMERA_CUSTOM = 0,
+        CAMERA_FREE,
+        CAMERA_ORBITAL,
+        CAMERA_FIRST_PERSON,
+        CAMERA_THIRD_PERSON
+    } CameraMode;
+
+    // Camera projection modes
+    typedef enum {
+        CAMERA_PERSPECTIVE = 0,
+        CAMERA_ORTHOGRAPHIC
+    } CameraProjection;
+#endif
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+//...
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+//----------------------------------------------------------------------------------
+
+#ifdef __cplusplus
+extern "C" {            // Prevents name mangling of functions
+#endif
+
+#if defined(CAMERA_STANDALONE)
+void SetCameraMode(Camera camera, int mode);                // Set camera mode (multiple camera modes available)
+void UpdateCamera(Camera *camera);                          // Update camera position for selected mode
+
+void SetCameraPanControl(int keyPan);                       // Set camera pan key to combine with mouse movement (free camera)
+void SetCameraAltControl(int keyAlt);                       // Set camera alt key to combine with mouse movement (free camera)
+void SetCameraSmoothZoomControl(int szoomKey);              // Set camera smooth zoom key to combine with mouse (free camera)
+void SetCameraMoveControls(int keyFront, int keyBack,
+                           int keyRight, int keyLeft,
+                           int keyUp, int keyDown);         // Set camera move controls (1st person and 3rd person cameras)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CAMERA_H
+
+
+/***********************************************************************************
+*
+*   CAMERA IMPLEMENTATION
+*
+************************************************************************************/
+
+#if defined(CAMERA_IMPLEMENTATION)
+
+#include <math.h>               // Required for: sinf(), cosf(), sqrtf()
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+#ifndef PI
+    #define PI 3.14159265358979323846
+#endif
+#ifndef DEG2RAD
+    #define DEG2RAD (PI/180.0f)
+#endif
+#ifndef RAD2DEG
+    #define RAD2DEG (180.0f/PI)
+#endif
+
+// Camera mouse movement sensitivity
+#define CAMERA_MOUSE_MOVE_SENSITIVITY                   0.003f
+#define CAMERA_MOUSE_SCROLL_SENSITIVITY                 1.5f
+
+// FREE_CAMERA
+#define CAMERA_FREE_MOUSE_SENSITIVITY                   0.01f
+#define CAMERA_FREE_DISTANCE_MIN_CLAMP                  0.3f
+#define CAMERA_FREE_DISTANCE_MAX_CLAMP                  120.0f
+#define CAMERA_FREE_MIN_CLAMP                           85.0f
+#define CAMERA_FREE_MAX_CLAMP                          -85.0f
+#define CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY             0.05f
+#define CAMERA_FREE_PANNING_DIVIDER                     5.1f
+
+// ORBITAL_CAMERA
+#define CAMERA_ORBITAL_SPEED                            0.01f       // Radians per frame
+
+// FIRST_PERSON
+//#define CAMERA_FIRST_PERSON_MOUSE_SENSITIVITY           0.003f
+#define CAMERA_FIRST_PERSON_FOCUS_DISTANCE              25.0f
+#define CAMERA_FIRST_PERSON_MIN_CLAMP                   89.0f
+#define CAMERA_FIRST_PERSON_MAX_CLAMP                  -89.0f
+
+#define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER  8.0f
+#define CAMERA_FIRST_PERSON_STEP_DIVIDER                30.0f
+#define CAMERA_FIRST_PERSON_WAVING_DIVIDER              200.0f
+
+// THIRD_PERSON
+//#define CAMERA_THIRD_PERSON_MOUSE_SENSITIVITY           0.003f
+#define CAMERA_THIRD_PERSON_DISTANCE_CLAMP              1.2f
+#define CAMERA_THIRD_PERSON_MIN_CLAMP                   5.0f
+#define CAMERA_THIRD_PERSON_MAX_CLAMP                  -85.0f
+#define CAMERA_THIRD_PERSON_OFFSET                      (Vector3){ 0.4f, 0.0f, 0.0f }
+
+// PLAYER (used by camera)
+#define PLAYER_MOVEMENT_SENSITIVITY                     20.0f
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+// Camera move modes (first person and third person cameras)
+typedef enum {
+    MOVE_FRONT = 0,
+    MOVE_BACK,
+    MOVE_RIGHT,
+    MOVE_LEFT,
+    MOVE_UP,
+    MOVE_DOWN
+} CameraMove;
+
+// Camera global state context data [56 bytes]
+typedef struct {
+    unsigned int mode;              // Current camera mode
+    float targetDistance;           // Camera distance from position to target
+    float playerEyesPosition;       // Player eyes position from ground (in meters)
+    Vector2 angle;                  // Camera angle in plane XZ
+    Vector2 previousMousePosition;  // Previous mouse position
+
+    // Camera movement control keys
+    int moveControl[6];             // Move controls (CAMERA_FIRST_PERSON)
+    int smoothZoomControl;          // Smooth zoom control key
+    int altControl;                 // Alternative control key
+    int panControl;                 // Pan view control key
+} CameraData;
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+static CameraData CAMERA = {        // Global CAMERA state context
+    .mode = 0,
+    .targetDistance = 0,
+    .playerEyesPosition = 1.85f,
+    .angle = { 0 },
+    .previousMousePosition = { 0 },
+    .moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' },
+    .smoothZoomControl = 341,       // raylib: KEY_LEFT_CONTROL
+    .altControl = 342,              // raylib: KEY_LEFT_ALT
+    .panControl = 2                 // raylib: MOUSE_BUTTON_MIDDLE
+};
+
+//----------------------------------------------------------------------------------
+// Module specific Functions Declaration
+//----------------------------------------------------------------------------------
+#if defined(CAMERA_STANDALONE)
+// NOTE: Camera controls depend on some raylib input functions
+static void EnableCursor() {}       // Unlock cursor
+static void DisableCursor() {}      // Lock cursor
+
+static int IsKeyDown(int key) { return 0; }
+
+static int IsMouseButtonDown(int button) { return 0;}
+static float GetMouseWheelMove() { return 0.0f; }
+static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; }
+#endif
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+
+// Select camera mode (multiple camera modes available)
+void SetCameraMode(Camera camera, int mode)
+{
+    Vector3 v1 = camera.position;
+    Vector3 v2 = camera.target;
+
+    float dx = v2.x - v1.x;
+    float dy = v2.y - v1.y;
+    float dz = v2.z - v1.z;
+
+    CAMERA.targetDistance = sqrtf(dx*dx + dy*dy + dz*dz);   // Distance to target
+
+    // Camera angle calculation
+    CAMERA.angle.x = atan2f(dx, dz);                        // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
+    CAMERA.angle.y = atan2f(dy, sqrtf(dx*dx + dz*dz));      // Camera angle in plane XY (0 aligned with X, move positive CW)
+
+    CAMERA.playerEyesPosition = camera.position.y;          // Init player eyes position to camera Y position
+
+    CAMERA.previousMousePosition = GetMousePosition();      // Init mouse position
+
+    // Lock cursor for first person and third person cameras
+    if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor();
+    else EnableCursor();
+
+    CAMERA.mode = mode;
+}
+
+// Update camera depending on selected mode
+// NOTE: Camera controls depend on some raylib functions:
+//       System: EnableCursor(), DisableCursor()
+//       Mouse: IsMouseButtonDown(), GetMousePosition(), GetMouseWheelMove()
+//       Keys:  IsKeyDown()
+void UpdateCamera(Camera *camera)
+{
+    static int swingCounter = 0;    // Used for 1st person swinging movement
+
+    // TODO: Compute CAMERA.targetDistance and CAMERA.angle here (?)
+
+    // Mouse movement detection
+    Vector2 mousePositionDelta = { 0.0f, 0.0f };
+    Vector2 mousePosition = GetMousePosition();
+    float mouseWheelMove = GetMouseWheelMove();
+
+    // Keys input detection
+    // TODO: Input detection is raylib-dependant, it could be moved outside the module
+    bool keyPan = IsMouseButtonDown(CAMERA.panControl);
+    bool keyAlt = IsKeyDown(CAMERA.altControl);
+    bool szoomKey = IsKeyDown(CAMERA.smoothZoomControl);
+    bool direction[6] = { IsKeyDown(CAMERA.moveControl[MOVE_FRONT]),
+                          IsKeyDown(CAMERA.moveControl[MOVE_BACK]),
+                          IsKeyDown(CAMERA.moveControl[MOVE_RIGHT]),
+                          IsKeyDown(CAMERA.moveControl[MOVE_LEFT]),
+                          IsKeyDown(CAMERA.moveControl[MOVE_UP]),
+                          IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) };
+
+    if (CAMERA.mode != CAMERA_CUSTOM)
+    {
+        mousePositionDelta.x = mousePosition.x - CAMERA.previousMousePosition.x;
+        mousePositionDelta.y = mousePosition.y - CAMERA.previousMousePosition.y;
+
+        CAMERA.previousMousePosition = mousePosition;
+    }
+
+    // Support for multiple automatic camera modes
+    // NOTE: In case of CAMERA_CUSTOM nothing happens here, user must update it manually
+    switch (CAMERA.mode)
+    {
+        case CAMERA_FREE:           // Camera free controls, using standard 3d-content-creation scheme
+        {
+            // Camera zoom
+            if ((CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
+            {
+                CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
+                if (CAMERA.targetDistance > CAMERA_FREE_DISTANCE_MAX_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MAX_CLAMP;
+            }
+
+            // Camera looking down
+            else if ((camera->position.y > camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
+            {
+                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+            }
+            else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0))
+            {
+                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+
+                // if (camera->target.y < 0) camera->target.y = -0.001;
+            }
+            else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0))
+            {
+                CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
+                if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
+            }
+            // Camera looking up
+            else if ((camera->position.y < camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
+            {
+                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+            }
+            else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0))
+            {
+                camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+                camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+                camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
+
+                // if (camera->target.y > 0) camera->target.y = 0.001;
+            }
+            else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0))
+            {
+                CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
+                if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
+            }
+
+            // Input keys checks
+            if (keyPan)
+            {
+                if (keyAlt)     // Alternative key behaviour
+                {
+                    if (szoomKey)
+                    {
+                        // Camera smooth zoom
+                        CAMERA.targetDistance += (mousePositionDelta.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY);
+                    }
+                    else
+                    {
+                        // Camera rotation
+                        CAMERA.angle.x += mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY;
+                        CAMERA.angle.y += mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY;
+
+                        // Angle clamp
+                        if (CAMERA.angle.y > CAMERA_FREE_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MIN_CLAMP*DEG2RAD;
+                        else if (CAMERA.angle.y < CAMERA_FREE_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MAX_CLAMP*DEG2RAD;
+                    }
+                }
+                else
+                {
+                    // Camera panning
+                    camera->target.x += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
+                    camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
+                    camera->target.z += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
+                }
+            }
+
+            // Update camera position with changes
+            camera->position.x = -sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
+            camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance + camera->target.y;
+            camera->position.z = -cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
+
+        } break;
+        case CAMERA_ORBITAL:        // Camera just orbits around target, only zoom allowed
+        {
+            CAMERA.angle.x += CAMERA_ORBITAL_SPEED;      // Camera orbit angle
+            CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);   // Camera zoom
+
+            // Camera distance clamp
+            if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
+
+            // Update camera position with changes
+            camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
+            camera->position.y = ((CAMERA.angle.y <= 0.0f)? 1 : -1)*sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
+            camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
+
+        } break;
+        case CAMERA_FIRST_PERSON:   // Camera moves as in a first-person game, controls are configurable
+        {
+            camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] -
+                                   sinf(CAMERA.angle.x)*direction[MOVE_FRONT] -
+                                   cosf(CAMERA.angle.x)*direction[MOVE_LEFT] +
+                                   cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
+
+            camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] -
+                                   sinf(CAMERA.angle.y)*direction[MOVE_BACK] +
+                                   1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY;
+
+            camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] -
+                                   cosf(CAMERA.angle.x)*direction[MOVE_FRONT] +
+                                   sinf(CAMERA.angle.x)*direction[MOVE_LEFT] -
+                                   sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
+
+            // Camera orientation calculation
+            CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
+            CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY);
+
+            // Angle clamp
+            if (CAMERA.angle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD;
+            else if (CAMERA.angle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD;
+
+            // Calculate translation matrix
+            Matrix matTranslation = { 1.0f, 0.0f, 0.0f, 0.0f,
+                                      0.0f, 1.0f, 0.0f, 0.0f,
+                                      0.0f, 0.0f, 1.0f, (CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER),
+                                      0.0f, 0.0f, 0.0f, 1.0f };
+
+            // Calculate rotation matrix
+            Matrix matRotation = { 1.0f, 0.0f, 0.0f, 0.0f,
+                                   0.0f, 1.0f, 0.0f, 0.0f,
+                                   0.0f, 0.0f, 1.0f, 0.0f,
+                                   0.0f, 0.0f, 0.0f, 1.0f };
+
+            float cosz = cosf(0.0f);
+            float sinz = sinf(0.0f);
+            float cosy = cosf(-(PI*2 - CAMERA.angle.x));
+            float siny = sinf(-(PI*2 - CAMERA.angle.x));
+            float cosx = cosf(-(PI*2 - CAMERA.angle.y));
+            float sinx = sinf(-(PI*2 - CAMERA.angle.y));
+
+            matRotation.m0 = cosz*cosy;
+            matRotation.m4 = (cosz*siny*sinx) - (sinz*cosx);
+            matRotation.m8 = (cosz*siny*cosx) + (sinz*sinx);
+            matRotation.m1 = sinz*cosy;
+            matRotation.m5 = (sinz*siny*sinx) + (cosz*cosx);
+            matRotation.m9 = (sinz*siny*cosx) - (cosz*sinx);
+            matRotation.m2 = -siny;
+            matRotation.m6 = cosy*sinx;
+            matRotation.m10= cosy*cosx;
+
+            // Multiply translation and rotation matrices
+            Matrix matTransform = { 0 };
+            matTransform.m0 = matTranslation.m0*matRotation.m0 + matTranslation.m1*matRotation.m4 + matTranslation.m2*matRotation.m8 + matTranslation.m3*matRotation.m12;
+            matTransform.m1 = matTranslation.m0*matRotation.m1 + matTranslation.m1*matRotation.m5 + matTranslation.m2*matRotation.m9 + matTranslation.m3*matRotation.m13;
+            matTransform.m2 = matTranslation.m0*matRotation.m2 + matTranslation.m1*matRotation.m6 + matTranslation.m2*matRotation.m10 + matTranslation.m3*matRotation.m14;
+            matTransform.m3 = matTranslation.m0*matRotation.m3 + matTranslation.m1*matRotation.m7 + matTranslation.m2*matRotation.m11 + matTranslation.m3*matRotation.m15;
+            matTransform.m4 = matTranslation.m4*matRotation.m0 + matTranslation.m5*matRotation.m4 + matTranslation.m6*matRotation.m8 + matTranslation.m7*matRotation.m12;
+            matTransform.m5 = matTranslation.m4*matRotation.m1 + matTranslation.m5*matRotation.m5 + matTranslation.m6*matRotation.m9 + matTranslation.m7*matRotation.m13;
+            matTransform.m6 = matTranslation.m4*matRotation.m2 + matTranslation.m5*matRotation.m6 + matTranslation.m6*matRotation.m10 + matTranslation.m7*matRotation.m14;
+            matTransform.m7 = matTranslation.m4*matRotation.m3 + matTranslation.m5*matRotation.m7 + matTranslation.m6*matRotation.m11 + matTranslation.m7*matRotation.m15;
+            matTransform.m8 = matTranslation.m8*matRotation.m0 + matTranslation.m9*matRotation.m4 + matTranslation.m10*matRotation.m8 + matTranslation.m11*matRotation.m12;
+            matTransform.m9 = matTranslation.m8*matRotation.m1 + matTranslation.m9*matRotation.m5 + matTranslation.m10*matRotation.m9 + matTranslation.m11*matRotation.m13;
+            matTransform.m10 = matTranslation.m8*matRotation.m2 + matTranslation.m9*matRotation.m6 + matTranslation.m10*matRotation.m10 + matTranslation.m11*matRotation.m14;
+            matTransform.m11 = matTranslation.m8*matRotation.m3 + matTranslation.m9*matRotation.m7 + matTranslation.m10*matRotation.m11 + matTranslation.m11*matRotation.m15;
+            matTransform.m12 = matTranslation.m12*matRotation.m0 + matTranslation.m13*matRotation.m4 + matTranslation.m14*matRotation.m8 + matTranslation.m15*matRotation.m12;
+            matTransform.m13 = matTranslation.m12*matRotation.m1 + matTranslation.m13*matRotation.m5 + matTranslation.m14*matRotation.m9 + matTranslation.m15*matRotation.m13;
+            matTransform.m14 = matTranslation.m12*matRotation.m2 + matTranslation.m13*matRotation.m6 + matTranslation.m14*matRotation.m10 + matTranslation.m15*matRotation.m14;
+            matTransform.m15 = matTranslation.m12*matRotation.m3 + matTranslation.m13*matRotation.m7 + matTranslation.m14*matRotation.m11 + matTranslation.m15*matRotation.m15;
+
+            camera->target.x = camera->position.x - matTransform.m12;
+            camera->target.y = camera->position.y - matTransform.m13;
+            camera->target.z = camera->position.z - matTransform.m14;
+
+            // If movement detected (some key pressed), increase swinging
+            for (int i = 0; i < 6; i++) if (direction[i]) { swingCounter++; break; }
+
+            // Camera position update
+            // NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position'
+            camera->position.y = CAMERA.playerEyesPosition - sinf(swingCounter/CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/CAMERA_FIRST_PERSON_STEP_DIVIDER;
+
+            camera->up.x = sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER;
+            camera->up.z = -sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER;
+
+        } break;
+        case CAMERA_THIRD_PERSON:   // Camera moves as in a third-person game, following target at a distance, controls are configurable
+        {
+            camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] -
+                                   sinf(CAMERA.angle.x)*direction[MOVE_FRONT] -
+                                   cosf(CAMERA.angle.x)*direction[MOVE_LEFT] +
+                                   cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
+
+            camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] -
+                                   sinf(CAMERA.angle.y)*direction[MOVE_BACK] +
+                                   1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY;
+
+            camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] -
+                                   cosf(CAMERA.angle.x)*direction[MOVE_FRONT] +
+                                   sinf(CAMERA.angle.x)*direction[MOVE_LEFT] -
+                                   sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
+
+            // Camera orientation calculation
+            CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
+            CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY);
+
+            // Angle clamp
+            if (CAMERA.angle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD;
+            else if (CAMERA.angle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD;
+
+            // Camera zoom
+            CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
+
+            // Camera distance clamp
+            if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
+
+            camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
+
+            if (CAMERA.angle.y <= 0.0f) camera->position.y = sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
+            else camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
+
+            camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
+
+        } break;
+        case CAMERA_CUSTOM: break;
+        default: break;
+    }
+}
+
+// Set camera pan key to combine with mouse movement (free camera)
+void SetCameraPanControl(int keyPan) { CAMERA.panControl = keyPan; }
+
+// Set camera alt key to combine with mouse movement (free camera)
+void SetCameraAltControl(int keyAlt) { CAMERA.altControl = keyAlt; }
+
+// Set camera smooth zoom key to combine with mouse (free camera)
+void SetCameraSmoothZoomControl(int szoomKey) { CAMERA.smoothZoomControl = szoomKey; }
+
+// Set camera move controls (1st person and 3rd person cameras)
+void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown)
+{
+    CAMERA.moveControl[MOVE_FRONT] = keyFront;
+    CAMERA.moveControl[MOVE_BACK] = keyBack;
+    CAMERA.moveControl[MOVE_RIGHT] = keyRight;
+    CAMERA.moveControl[MOVE_LEFT] = keyLeft;
+    CAMERA.moveControl[MOVE_UP] = keyUp;
+    CAMERA.moveControl[MOVE_DOWN] = keyDown;
+}
+
+#endif // CAMERA_IMPLEMENTATION
raylib/src/rcore.c view
@@ -849,6 +849,7 @@         TRACELOG(LOG_FATAL, "Failed to initialize Graphic Device");
         return;
     }
+    else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor())/2 - CORE.Window.screen.width/2, GetMonitorHeight(GetCurrentMonitor())/2 - CORE.Window.screen.height/2);
 
     // Initialize hi-res timer
     InitTimer();
@@ -923,9 +924,6 @@     emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback);
 #endif
 
-    CORE.Input.Mouse.currentPosition.x = (float)CORE.Window.screen.width/2.0f;
-    CORE.Input.Mouse.currentPosition.y = (float)CORE.Window.screen.height/2.0f;
-
 #if defined(SUPPORT_EVENTS_AUTOMATION)
     events = (AutomationEvent *)malloc(MAX_CODE_AUTOMATION_EVENTS*sizeof(AutomationEvent));
     CORE.Time.frameCounter = 0;
@@ -1143,9 +1141,8 @@ {
 #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
     return ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0);
-#else
-    return false;
 #endif
+    return false;
 }
 
 // Check if window has been maximized (only PLATFORM_DESKTOP)
@@ -1153,9 +1150,8 @@ {
 #if defined(PLATFORM_DESKTOP)
     return ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0);
-#else
-    return false;
 #endif
+    return false;
 }
 
 // Check if window has the focus
@@ -1163,9 +1159,11 @@ {
 #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
     return ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) == 0);
-#else
-    return true;
 #endif
+#if defined(PLATFORM_ANDROID)
+    return CORE.Android.appEnabled;
+#endif
+    return true;
 }
 
 // Check if window has been resizedLastFrame
@@ -1556,26 +1554,72 @@ }
 
 // Set icon for window (only PLATFORM_DESKTOP)
-// NOTE: Image must be in RGBA format, 8bit per channel
+// NOTE 1: Image must be in RGBA format, 8bit per channel
+// NOTE 2: Image is scaled by the OS for all required sizes 
 void SetWindowIcon(Image image)
 {
 #if defined(PLATFORM_DESKTOP)
-    if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
+    if (image.data == NULL)
     {
-        GLFWimage icon[1] = { 0 };
+        // Revert to the default window icon, pass in an empty image array
+        glfwSetWindowIcon(CORE.Window.handle, 0, NULL);
+    }
+    else
+    {
+        if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
+        {
+            GLFWimage icon[1] = { 0 };
 
-        icon[0].width = image.width;
-        icon[0].height = image.height;
-        icon[0].pixels = (unsigned char *)image.data;
+            icon[0].width = image.width;
+            icon[0].height = image.height;
+            icon[0].pixels = (unsigned char *)image.data;
 
-        // NOTE 1: We only support one image icon
-        // NOTE 2: The specified image data is copied before this function returns
-        glfwSetWindowIcon(CORE.Window.handle, 1, icon);
+            // NOTE 1: We only support one image icon
+            // NOTE 2: The specified image data is copied before this function returns
+            glfwSetWindowIcon(CORE.Window.handle, 1, icon);
+        }
+        else TRACELOG(LOG_WARNING, "GLFW: Window icon image must be in R8G8B8A8 pixel format");
     }
-    else TRACELOG(LOG_WARNING, "GLFW: Window icon image must be in R8G8B8A8 pixel format");
 #endif
 }
 
+// Set icon for window (multiple images, only PLATFORM_DESKTOP)
+// NOTE 1: Images must be in RGBA format, 8bit per channel
+// NOTE 2: The multiple images are used depending on provided sizes
+// Standard Windows icon sizes: 256, 128, 96, 64, 48, 32, 24, 16 
+void SetWindowIcons(Image *images, int count)
+{
+#if defined(PLATFORM_DESKTOP)
+    if ((images == NULL) || (count <= 0))
+    {
+        // Revert to the default window icon, pass in an empty image array
+        glfwSetWindowIcon(CORE.Window.handle, 0, NULL);
+    }
+    else
+    {
+        int valid = 0;
+        GLFWimage *icons = RL_CALLOC(count, sizeof(GLFWimage));
+
+        for (int i = 0; i < count; i++)
+        {
+            if (images[i].format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
+            {
+                icons[valid].width = images[i].width;
+                icons[valid].height = images[i].height;
+                icons[valid].pixels = (unsigned char *)images[i].data;
+
+                valid++;
+            }
+            else TRACELOG(LOG_WARNING, "GLFW: Window icon image must be in R8G8B8A8 pixel format");
+        }
+        // NOTE: Images data is copied internally before this function returns
+        glfwSetWindowIcon(CORE.Window.handle, valid, icons);
+
+        RL_FREE(icons);
+    }
+#endif
+}
+
 // Set title for window (only PLATFORM_DESKTOP)
 void SetWindowTitle(const char *title)
 {
@@ -1788,6 +1832,12 @@     }
     else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
 #endif
+#if defined(PLATFORM_ANDROID)
+    if (CORE.Android.app->window != NULL)
+    {
+        return ANativeWindow_getWidth(CORE.Android.app->window);
+    }
+#endif
     return 0;
 }
 
@@ -1807,6 +1857,12 @@     }
     else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
 #endif
+#if defined(PLATFORM_ANDROID)
+    if (CORE.Android.app->window != NULL)
+    {
+        return ANativeWindow_getHeight(CORE.Android.app->window);
+    }
+#endif
     return 0;
 }
 
@@ -2015,6 +2071,8 @@ #if defined(PLATFORM_WEB)
     emscripten_exit_pointerlock();
 #endif
+    // Set cursor position in the middle
+    SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
 
     CORE.Input.Mouse.cursorHidden = false;
 }
@@ -2028,6 +2086,8 @@ #if defined(PLATFORM_WEB)
     emscripten_request_pointerlock("#canvas", 1);
 #endif
+    // Set cursor position in the middle
+    SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
 
     CORE.Input.Mouse.cursorHidden = true;
 }
@@ -2189,7 +2249,7 @@ }
 
 // Initializes 3D mode with custom camera (3D)
-void BeginMode3D(Camera3D camera)
+void BeginMode3D(Camera camera)
 {
     rlDrawRenderBatchActive();      // Update and draw internal render batch
 
@@ -2513,7 +2573,33 @@ // Check if a shader is ready
 bool IsShaderReady(Shader shader)
 {
-    return shader.locs != NULL;
+    return ((shader.id > 0) &&          // Validate shader id (loaded successfully)
+            (shader.locs != NULL));     // Validate memory has been allocated for default shader locations
+
+    // The following locations are tried to be set automatically (locs[i] >= 0),
+    // any of them can be checked for validation but the only mandatory one is, afaik, SHADER_LOC_VERTEX_POSITION
+    // NOTE: Users can also setup manually their own attributes/uniforms and do not used the default raylib ones
+    
+    // Vertex shader attribute locations (default)
+    // shader.locs[SHADER_LOC_VERTEX_POSITION]      // Set by default internal shader
+    // shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]    // Set by default internal shader
+    // shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]
+    // shader.locs[SHADER_LOC_VERTEX_NORMAL]
+    // shader.locs[SHADER_LOC_VERTEX_TANGENT]
+    // shader.locs[SHADER_LOC_VERTEX_COLOR]         // Set by default internal shader
+
+    // Vertex shader uniform locations (default)
+    // shader.locs[SHADER_LOC_MATRIX_MVP]           // Set by default internal shader
+    // shader.locs[SHADER_LOC_MATRIX_VIEW]
+    // shader.locs[SHADER_LOC_MATRIX_PROJECTION]
+    // shader.locs[SHADER_LOC_MATRIX_MODEL]
+    // shader.locs[SHADER_LOC_MATRIX_NORMAL]
+
+    // Fragment shader uniform locations (default)
+    // shader.locs[SHADER_LOC_COLOR_DIFFUSE]        // Set by default internal shader
+    // shader.locs[SHADER_LOC_MAP_DIFFUSE]          // Set by default internal shader
+    // shader.locs[SHADER_LOC_MAP_SPECULAR]
+    // shader.locs[SHADER_LOC_MAP_NORMAL]
 }
 
 // Unload shader from GPU memory (VRAM)
@@ -3788,7 +3874,7 @@ // Get mouse delta between frames
 Vector2 GetMouseDelta(void)
 {
-    Vector2 delta = {0};
+    Vector2 delta = { 0 };
 
     delta.x = CORE.Input.Mouse.currentPosition.x - CORE.Input.Mouse.previousPosition.x;
     delta.y = CORE.Input.Mouse.currentPosition.y - CORE.Input.Mouse.previousPosition.y;
@@ -3800,6 +3886,8 @@ void SetMousePosition(int x, int y)
 {
     CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
+    CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
+
 #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
     // NOTE: emscripten not implemented
     glfwSetCursorPos(CORE.Window.handle, CORE.Input.Mouse.currentPosition.x, CORE.Input.Mouse.currentPosition.y);
raylib/src/rmodels.c view
@@ -3326,9 +3326,15 @@ 
 // Compute mesh tangents
 // NOTE: To calculate mesh tangents and binormals we need mesh vertex positions and texture coordinates
-// Implementation base don: https://answers.unity.com/questions/7789/calculating-tangents-vector4.html
+// Implementation based on: https://answers.unity.com/questions/7789/calculating-tangents-vector4.html
 void GenMeshTangents(Mesh *mesh)
 {
+    if ((mesh->vertices == NULL) || (mesh->texcoords == NULL))
+    {
+        TRACELOG(LOG_WARNING, "MESH: Tangents generation requires texcoord vertex attribute data");
+        return;
+    }
+
     if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
     else
     {
raylib/src/rtext.c view
@@ -1568,17 +1568,20 @@     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
     memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
 
-    for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
+    if (text != NULL)
     {
-        if (text[i] != '\0')
+        for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
         {
-            buffer[i] = (char)toupper(text[i]);
-            //if ((text[i] >= 'a') && (text[i] <= 'z')) buffer[i] = text[i] - 32;
+            if (text[i] != '\0')
+            {
+                buffer[i] = (char)toupper(text[i]);
+                //if ((text[i] >= 'a') && (text[i] <= 'z')) buffer[i] = text[i] - 32;
 
-            // TODO: Support UTF-8 diacritics to upper-case
-            //if ((text[i] >= 'à') && (text[i] <= 'ý')) buffer[i] = text[i] - 32;
+                // TODO: Support UTF-8 diacritics to upper-case
+                //if ((text[i] >= 'à') && (text[i] <= 'ý')) buffer[i] = text[i] - 32;
+            }
+            else { buffer[i] = '\0'; break; }
         }
-        else { buffer[i] = '\0'; break; }
     }
 
     return buffer;
@@ -1591,14 +1594,17 @@     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
     memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
 
-    for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
+    if (text != NULL)
     {
-        if (text[i] != '\0')
+        for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
         {
-            buffer[i] = (char)tolower(text[i]);
-            //if ((text[i] >= 'A') && (text[i] <= 'Z')) buffer[i] = text[i] + 32;
+            if (text[i] != '\0')
+            {
+                buffer[i] = (char)tolower(text[i]);
+                //if ((text[i] >= 'A') && (text[i] <= 'Z')) buffer[i] = text[i] + 32;
+            }
+            else { buffer[i] = '\0'; break; }
         }
-        else { buffer[i] = '\0'; break; }
     }
 
     return buffer;
@@ -1611,20 +1617,23 @@     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
     memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
 
-    buffer[0] = (char)toupper(text[0]);
-
-    for (int i = 1, j = 1; i < MAX_TEXT_BUFFER_LENGTH; i++, j++)
+    if (text != NULL)
     {
-        if (text[j] != '\0')
+        buffer[0] = (char)toupper(text[0]);
+
+        for (int i = 1, j = 1; i < MAX_TEXT_BUFFER_LENGTH; i++, j++)
         {
-            if (text[j] != '_') buffer[i] = text[j];
-            else
+            if (text[j] != '\0')
             {
-                j++;
-                buffer[i] = (char)toupper(text[j]);
+                if (text[j] != '_') buffer[i] = text[j];
+                else
+                {
+                    j++;
+                    buffer[i] = (char)toupper(text[j]);
+                }
             }
+            else { buffer[i] = '\0'; break; }
         }
-        else { buffer[i] = '\0'; break; }
     }
 
     return buffer;
raylib/src/rtextures.c view
@@ -30,7 +30,7 @@ *
 *   #define SUPPORT_IMAGE_MANIPULATION
 *       Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop...
-*       If not defined only three image editing functions supported: ImageFormat(), ImageAlphaMask(), ImageToPOT()
+*       If not defined only some image editing functions supported: ImageFormat(), ImageAlphaMask(), ImageResize*()
 *
 *   #define SUPPORT_IMAGE_GENERATION
 *       Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)
@@ -190,13 +190,10 @@     #include "external/stb_perlin.h"        // Required for: stb_perlin_fbm_noise3
 #endif
 
-#if defined(SUPPORT_IMAGE_MANIPULATION)
-    #define STBIR_MALLOC(size,c) ((void)(c), RL_MALLOC(size))
-    #define STBIR_FREE(ptr,c) ((void)(c), RL_FREE(ptr))
-
-    #define STB_IMAGE_RESIZE_IMPLEMENTATION
-    #include "external/stb_image_resize.h"  // Required for: stbir_resize_uint8() [ImageResize()]
-#endif
+#define STBIR_MALLOC(size,c) ((void)(c), RL_MALLOC(size))
+#define STBIR_FREE(ptr,c) ((void)(c), RL_FREE(ptr))
+#define STB_IMAGE_RESIZE_IMPLEMENTATION
+#include "external/stb_image_resize.h"  // Required for: stbir_resize_uint8() [ImageResize()]
 
 //----------------------------------------------------------------------------------
 // Defines and Macros
@@ -505,7 +502,11 @@ // Check if an image is ready
 bool IsImageReady(Image image)
 {
-    return image.data != NULL && image.width > 0 && image.height > 0 && image.format > 0;
+    return ((image.data != NULL) &&     // Validate pixel data available
+            (image.width > 0) && 
+            (image.height > 0) &&       // Validate image size
+            (image.format > 0) &&       // Validate image format
+            (image.mipmaps > 0));       // Validate image mipmaps (at least 1 for basic mipmap level)
 }
 
 // Unload image from CPU memory (RAM)
@@ -1228,23 +1229,6 @@     }
 }
 
-// Convert image to POT (power-of-two)
-// NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5)
-void ImageToPOT(Image *image, Color fill)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    // Calculate next power-of-two values
-    // NOTE: Just add the required amount of pixels at the right and bottom sides of image...
-    int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2)));
-    int potHeight = (int)powf(2, ceilf(logf((float)image->height)/logf(2)));
-
-    // Check if POT texture generation is required (if texture is not already POT)
-    if ((potWidth != image->width) || (potHeight != image->height)) ImageResizeCanvas(image, potWidth, potHeight, 0, 0, fill);
-}
-
-#if defined(SUPPORT_IMAGE_MANIPULATION)
 // Create an image from text (default font)
 Image ImageText(const char *text, int fontSize, Color color)
 {
@@ -1330,6 +1314,172 @@     return imText;
 }
 
+// Resize and image to new size using Nearest-Neighbor scaling algorithm
+void ImageResizeNN(Image *image,int newWidth,int newHeight)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    Color *pixels = LoadImageColors(*image);
+    Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color));
+
+    // EDIT: added +1 to account for an early rounding problem
+    int xRatio = (int)((image->width << 16)/newWidth) + 1;
+    int yRatio = (int)((image->height << 16)/newHeight) + 1;
+
+    int x2, y2;
+    for (int y = 0; y < newHeight; y++)
+    {
+        for (int x = 0; x < newWidth; x++)
+        {
+            x2 = ((x*xRatio) >> 16);
+            y2 = ((y*yRatio) >> 16);
+
+            output[(y*newWidth) + x] = pixels[(y2*image->width) + x2] ;
+        }
+    }
+
+    int format = image->format;
+
+    RL_FREE(image->data);
+
+    image->data = output;
+    image->width = newWidth;
+    image->height = newHeight;
+    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+
+    ImageFormat(image, format);  // Reformat 32bit RGBA image to original format
+
+    UnloadImageColors(pixels);
+}
+
+
+// Resize and image to new size
+// NOTE: Uses stb default scaling filters (both bicubic):
+// STBIR_DEFAULT_FILTER_UPSAMPLE    STBIR_FILTER_CATMULLROM
+// STBIR_DEFAULT_FILTER_DOWNSAMPLE  STBIR_FILTER_MITCHELL   (high-quality Catmull-Rom)
+void ImageResize(Image *image, int newWidth, int newHeight)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    // Check if we can use a fast path on image scaling
+    // It can be for 8 bit per channel images with 1 to 4 channels per pixel
+    if ((image->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) ||
+        (image->format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) ||
+        (image->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) ||
+        (image->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8))
+    {
+        int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
+        unsigned char *output = (unsigned char *)RL_MALLOC(newWidth*newHeight*bytesPerPixel);
+
+        switch (image->format)
+        {
+            case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 1); break;
+            case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 2); break;
+            case PIXELFORMAT_UNCOMPRESSED_R8G8B8: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 3); break;
+            case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 4); break;
+            default: break;
+        }
+
+        RL_FREE(image->data);
+        image->data = output;
+        image->width = newWidth;
+        image->height = newHeight;
+    }
+    else
+    {
+        // Get data as Color pixels array to work with it
+        Color *pixels = LoadImageColors(*image);
+        Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color));
+
+        // NOTE: Color data is cast to (unsigned char *), there shouldn't been any problem...
+        stbir_resize_uint8((unsigned char *)pixels, image->width, image->height, 0, (unsigned char *)output, newWidth, newHeight, 0, 4);
+
+        int format = image->format;
+
+        UnloadImageColors(pixels);
+        RL_FREE(image->data);
+
+        image->data = output;
+        image->width = newWidth;
+        image->height = newHeight;
+        image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+
+        ImageFormat(image, format);  // Reformat 32bit RGBA image to original format
+    }
+}
+
+// Resize canvas and fill with color
+// NOTE: Resize offset is relative to the top-left corner of the original image
+void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
+    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
+    else if ((newWidth != image->width) || (newHeight != image->height))
+    {
+        Rectangle srcRec = { 0, 0, (float)image->width, (float)image->height };
+        Vector2 dstPos = { (float)offsetX, (float)offsetY };
+
+        if (offsetX < 0)
+        {
+            srcRec.x = (float)-offsetX;
+            srcRec.width += (float)offsetX;
+            dstPos.x = 0;
+        }
+        else if ((offsetX + image->width) > newWidth) srcRec.width = (float)(newWidth - offsetX);
+
+        if (offsetY < 0)
+        {
+            srcRec.y = (float)-offsetY;
+            srcRec.height += (float)offsetY;
+            dstPos.y = 0;
+        }
+        else if ((offsetY + image->height) > newHeight) srcRec.height = (float)(newHeight - offsetY);
+
+        if (newWidth < srcRec.width) srcRec.width = (float)newWidth;
+        if (newHeight < srcRec.height) srcRec.height = (float)newHeight;
+
+        int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
+        unsigned char *resizedData = (unsigned char *)RL_CALLOC(newWidth*newHeight*bytesPerPixel, 1);
+
+        // TODO: Fill resized canvas with fill color (must be formatted to image->format)
+
+        int dstOffsetSize = ((int)dstPos.y*newWidth + (int)dstPos.x)*bytesPerPixel;
+
+        for (int y = 0; y < (int)srcRec.height; y++)
+        {
+            memcpy(resizedData + dstOffsetSize, ((unsigned char *)image->data) + ((y + (int)srcRec.y)*image->width + (int)srcRec.x)*bytesPerPixel, (int)srcRec.width*bytesPerPixel);
+            dstOffsetSize += (newWidth*bytesPerPixel);
+        }
+
+        RL_FREE(image->data);
+        image->data = resizedData;
+        image->width = newWidth;
+        image->height = newHeight;
+    }
+}
+
+#if defined(SUPPORT_IMAGE_MANIPULATION)
+// Convert image to POT (power-of-two)
+// NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5)
+void ImageToPOT(Image *image, Color fill)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    // Calculate next power-of-two values
+    // NOTE: Just add the required amount of pixels at the right and bottom sides of image...
+    int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2)));
+    int potHeight = (int)powf(2, ceilf(logf((float)image->height)/logf(2)));
+
+    // Check if POT texture generation is required (if texture is not already POT)
+    if ((potWidth != image->width) || (potHeight != image->height)) ImageResizeCanvas(image, potWidth, potHeight, 0, 0, fill);
+}
+
 // Crop image depending on alpha value
 // NOTE: Threshold is defined as a percentage: 0.0f -> 1.0f
 void ImageAlphaCrop(Image *image, float threshold)
@@ -1672,154 +1822,6 @@     ImageFormat(image, format);
 }
 
-// Resize and image to new size
-// NOTE: Uses stb default scaling filters (both bicubic):
-// STBIR_DEFAULT_FILTER_UPSAMPLE    STBIR_FILTER_CATMULLROM
-// STBIR_DEFAULT_FILTER_DOWNSAMPLE  STBIR_FILTER_MITCHELL   (high-quality Catmull-Rom)
-void ImageResize(Image *image, int newWidth, int newHeight)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    // Check if we can use a fast path on image scaling
-    // It can be for 8 bit per channel images with 1 to 4 channels per pixel
-    if ((image->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) ||
-        (image->format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) ||
-        (image->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) ||
-        (image->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8))
-    {
-        int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
-        unsigned char *output = (unsigned char *)RL_MALLOC(newWidth*newHeight*bytesPerPixel);
-
-        switch (image->format)
-        {
-            case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 1); break;
-            case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 2); break;
-            case PIXELFORMAT_UNCOMPRESSED_R8G8B8: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 3); break;
-            case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 4); break;
-            default: break;
-        }
-
-        RL_FREE(image->data);
-        image->data = output;
-        image->width = newWidth;
-        image->height = newHeight;
-    }
-    else
-    {
-        // Get data as Color pixels array to work with it
-        Color *pixels = LoadImageColors(*image);
-        Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color));
-
-        // NOTE: Color data is cast to (unsigned char *), there shouldn't been any problem...
-        stbir_resize_uint8((unsigned char *)pixels, image->width, image->height, 0, (unsigned char *)output, newWidth, newHeight, 0, 4);
-
-        int format = image->format;
-
-        UnloadImageColors(pixels);
-        RL_FREE(image->data);
-
-        image->data = output;
-        image->width = newWidth;
-        image->height = newHeight;
-        image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-
-        ImageFormat(image, format);  // Reformat 32bit RGBA image to original format
-    }
-}
-
-// Resize and image to new size using Nearest-Neighbor scaling algorithm
-void ImageResizeNN(Image *image,int newWidth,int newHeight)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    Color *pixels = LoadImageColors(*image);
-    Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color));
-
-    // EDIT: added +1 to account for an early rounding problem
-    int xRatio = (int)((image->width << 16)/newWidth) + 1;
-    int yRatio = (int)((image->height << 16)/newHeight) + 1;
-
-    int x2, y2;
-    for (int y = 0; y < newHeight; y++)
-    {
-        for (int x = 0; x < newWidth; x++)
-        {
-            x2 = ((x*xRatio) >> 16);
-            y2 = ((y*yRatio) >> 16);
-
-            output[(y*newWidth) + x] = pixels[(y2*image->width) + x2] ;
-        }
-    }
-
-    int format = image->format;
-
-    RL_FREE(image->data);
-
-    image->data = output;
-    image->width = newWidth;
-    image->height = newHeight;
-    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-
-    ImageFormat(image, format);  // Reformat 32bit RGBA image to original format
-
-    UnloadImageColors(pixels);
-}
-
-// Resize canvas and fill with color
-// NOTE: Resize offset is relative to the top-left corner of the original image
-void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
-    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
-    else if ((newWidth != image->width) || (newHeight != image->height))
-    {
-        Rectangle srcRec = { 0, 0, (float)image->width, (float)image->height };
-        Vector2 dstPos = { (float)offsetX, (float)offsetY };
-
-        if (offsetX < 0)
-        {
-            srcRec.x = (float)-offsetX;
-            srcRec.width += (float)offsetX;
-            dstPos.x = 0;
-        }
-        else if ((offsetX + image->width) > newWidth) srcRec.width = (float)(newWidth - offsetX);
-
-        if (offsetY < 0)
-        {
-            srcRec.y = (float)-offsetY;
-            srcRec.height += (float)offsetY;
-            dstPos.y = 0;
-        }
-        else if ((offsetY + image->height) > newHeight) srcRec.height = (float)(newHeight - offsetY);
-
-        if (newWidth < srcRec.width) srcRec.width = (float)newWidth;
-        if (newHeight < srcRec.height) srcRec.height = (float)newHeight;
-
-        int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
-        unsigned char *resizedData = (unsigned char *)RL_CALLOC(newWidth*newHeight*bytesPerPixel, 1);
-
-        // TODO: Fill resized canvas with fill color (must be formatted to image->format)
-
-        int dstOffsetSize = ((int)dstPos.y*newWidth + (int)dstPos.x)*bytesPerPixel;
-
-        for (int y = 0; y < (int)srcRec.height; y++)
-        {
-            memcpy(resizedData + dstOffsetSize, ((unsigned char *)image->data) + ((y + (int)srcRec.y)*image->width + (int)srcRec.x)*bytesPerPixel, (int)srcRec.width*bytesPerPixel);
-            dstOffsetSize += (newWidth*bytesPerPixel);
-        }
-
-        RL_FREE(image->data);
-        image->data = resizedData;
-        image->width = newWidth;
-        image->height = newHeight;
-    }
-}
-
 // Generate all mipmap levels for a provided image
 // NOTE 1: Supports POT and NPOT images
 // NOTE 2: image.data is scaled to include mipmap levels
@@ -3333,7 +3335,13 @@ // Check if a texture is ready
 bool IsTextureReady(Texture2D texture)
 {
-    return texture.id > 0 && texture.width > 0 && texture.height > 0 && texture.format > 0;
+    // TODO: Validate maximum texture size supported by GPU?
+    
+    return ((texture.id > 0) &&         // Validate OpenGL id
+            (texture.width > 0) && 
+            (texture.height > 0) &&     // Validate texture size 
+            (texture.format > 0) &&     // Validate texture pixel format
+            (texture.mipmaps > 0));     // Validate texture mipmaps (at least 1 for basic mipmap level)
 }
 
 // Unload texture from GPU memory (VRAM)
src/Raylib/Audio.hs view
@@ -3,20 +3,19 @@ 
 module Raylib.Audio where
 
-import Control.Monad (void)
 import Foreign
   ( FunPtr,
     Ptr,
     Storable (peek, sizeOf),
-    newForeignPtr,
-    peekArray,
+    castPtr,
     toBool,
     withArrayLen,
   )
 import Foreign.C (CUChar, CUInt, withCString)
-import qualified Foreign.Concurrent as C
+import Raylib.Internal (addAudioBuffer, addCtxData, unloadAudioBuffers, unloadCtxData)
 import Raylib.Native
-  ( c'exportWave,
+  ( c'closeAudioDevice,
+    c'exportWave,
     c'exportWaveAsCode,
     c'getMusicTimeLength,
     c'getMusicTimePlayed,
@@ -62,19 +61,12 @@     c'stopAudioStream,
     c'stopMusicStream,
     c'stopSound,
-    c'unloadAudioStream,
-    c'unloadMusicStream,
-    c'unloadMusicStreamData,
-    c'unloadSound,
-    c'unloadWave,
-    c'unloadWaveSamples,
     c'updateAudioStream,
     c'updateMusicStream,
     c'updateSound,
     c'waveCopy,
     c'waveCrop,
     c'waveFormat,
-    p'unloadAudioBuffer,
   )
 import Raylib.Types
   ( AudioStream (audioStream'buffer),
@@ -84,6 +76,7 @@   )
 import Raylib.Util
   ( pop,
+    popCArray,
     withFreeable,
   )
 
@@ -91,13 +84,11 @@   initAudioDevice ::
     IO ()
 
-foreign import ccall safe "raylib.h CloseAudioDevice"
-  closeAudioDevice ::
-    IO ()
+closeAudioDevice :: IO ()
+closeAudioDevice = unloadCtxData >> unloadAudioBuffers >> c'closeAudioDevice
 
 type AudioCallback = FunPtr (Ptr () -> CUInt -> IO ())
 
--- TODO: redesign this
 isAudioDeviceReady :: IO Bool
 isAudioDeviceReady = toBool <$> c'isAudioDeviceReady
 
@@ -122,15 +113,9 @@ isWaveReady :: Wave -> IO Bool
 isWaveReady wave = toBool <$> withFreeable wave c'isWaveReady
 
-unloadWave :: Wave -> IO ()
-unloadWave wave = withFreeable wave c'unloadWave
-
 isSoundReady :: Sound -> IO Bool
 isSoundReady sound = toBool <$> withFreeable sound c'isSoundReady
 
-unloadSound :: Sound -> IO ()
-unloadSound sound = withFreeable sound c'unloadSound
-
 exportWave :: Wave -> String -> IO Bool
 exportWave wave fileName = toBool <$> withFreeable wave (withCString fileName . c'exportWave)
 
@@ -188,33 +173,25 @@ loadWaveSamples wave =
   withFreeable
     wave
-    ( \w -> do
-        ptr <- c'loadWaveSamples w
-        arr <- peekArray (fromIntegral $ wave'frameCount wave * wave'channels wave) ptr
-        c'unloadWaveSamples ptr
-        return $ map realToFrac arr
-    )
+    (\w -> map realToFrac <$> (popCArray (fromIntegral $ wave'frameCount wave * wave'channels wave) =<< c'loadWaveSamples w))
 
 loadMusicStream :: String -> IO Music
 loadMusicStream fileName = do
   music <- withCString fileName c'loadMusicStream >>= pop
-  addFinalizerToAudioStream $ music'stream music
-  addFinalizerToMusicStream music
+  addAudioBuffer $ castPtr (audioStream'buffer $ music'stream music)
+  addCtxData (fromEnum $ music'ctxType music) (music'ctxData music)
   return music
 
 loadMusicStreamFromMemory :: String -> [Integer] -> IO Music
 loadMusicStreamFromMemory fileType streamData = do
   music <- withCString fileType (\t -> withArrayLen (map fromIntegral streamData) (\size d -> c'loadMusicStreamFromMemory t d (fromIntegral $ size * sizeOf (0 :: CUChar)))) >>= pop
-  addFinalizerToAudioStream $ music'stream music
-  addFinalizerToMusicStream music
+  addAudioBuffer $ castPtr (audioStream'buffer $ music'stream music)
+  addCtxData (fromEnum $ music'ctxType music) (music'ctxData music)
   return music
 
 isMusicReady :: Music -> IO Bool
 isMusicReady music = toBool <$> withFreeable music c'isMusicReady
 
-unloadMusicStream :: Music -> IO ()
-unloadMusicStream music = withFreeable music c'unloadMusicStream
-
 playMusicStream :: Music -> IO ()
 playMusicStream music = withFreeable music c'playMusicStream
 
@@ -254,15 +231,12 @@ loadAudioStream :: Integer -> Integer -> Integer -> IO AudioStream
 loadAudioStream sampleRate sampleSize channels = do
   stream <- c'loadAudioStream (fromIntegral sampleRate) (fromIntegral sampleSize) (fromIntegral channels) >>= pop
-  addFinalizerToAudioStream stream
+  addAudioBuffer $ castPtr (audioStream'buffer stream)
   return stream
 
 isAudioStreamReady :: AudioStream -> IO Bool
 isAudioStreamReady stream = toBool <$> withFreeable stream c'isAudioStreamReady
 
-unloadAudioStream :: AudioStream -> IO ()
-unloadAudioStream stream = withFreeable stream c'unloadAudioStream
-
 updateAudioStream :: AudioStream -> Ptr () -> Int -> IO ()
 updateAudioStream stream value frameCount = withFreeable stream (\s -> c'updateAudioStream s value (fromIntegral frameCount))
 
@@ -295,16 +269,3 @@ 
 setAudioStreamBufferSizeDefault :: Int -> IO ()
 setAudioStreamBufferSizeDefault = setAudioStreamBufferSizeDefault . fromIntegral
-
-addFinalizerToAudioStream :: AudioStream -> IO ()
-addFinalizerToAudioStream stream = void (newForeignPtr p'unloadAudioBuffer (audioStream'buffer stream)) -- Automatically unload audio buffer when it is no longer being used
-
--- Foreign.Concurrent might not call the finalizer, so this may need to be revised in the future
-addFinalizerToMusicStream :: Music -> IO ()
-addFinalizerToMusicStream music = do
-  let ctxData = music'ctxData music
-  _ <-
-    C.newForeignPtr
-      ctxData
-      (c'unloadMusicStreamData (fromIntegral $ fromEnum $ music'ctxType music) ctxData) -- Automatically unload music context data when it is no longer being used
-  return ()
src/Raylib/Core.hs view
@@ -20,6 +20,7 @@     peekCString,
     withCString,
   )
+import Raylib.Internal (addShaderId, unloadFrameBuffers, unloadShaders, unloadTextures, unloadVaoIds, unloadVboIds)
 import Raylib.Native
   ( c'beginBlendMode,
     c'beginMode2D,
@@ -31,6 +32,7 @@     c'changeDirectory,
     c'clearBackground,
     c'clearWindowState,
+    c'closeWindow,
     c'compressData,
     c'decodeDataBase64,
     c'decompressData,
@@ -142,11 +144,6 @@     c'openURL,
     c'saveFileData,
     c'saveFileText,
-    c'setCameraAltControl,
-    c'setCameraMode,
-    c'setCameraMoveControls,
-    c'setCameraPanControl,
-    c'setCameraSmoothZoomControl,
     c'setClipboardText,
     c'setConfigFlags,
     c'setExitKey,
@@ -164,6 +161,7 @@     c'setTargetFPS,
     c'setTraceLogLevel,
     c'setWindowIcon,
+    c'setWindowIcons,
     c'setWindowMinSize,
     c'setWindowMonitor,
     c'setWindowOpacity,
@@ -173,12 +171,6 @@     c'setWindowTitle,
     c'takeScreenshot,
     c'traceLog,
-    c'unloadDirectoryFiles,
-    c'unloadDroppedFiles,
-    c'unloadFileData,
-    c'unloadFileText,
-    c'unloadShader,
-    c'unloadVrStereoConfig,
     c'updateCamera,
     c'waitTime,
     c'windowShouldClose,
@@ -205,7 +197,7 @@     RenderTexture,
     SaveFileDataCallback,
     SaveFileTextCallback,
-    Shader,
+    Shader (shader'id),
     ShaderUniformDataType,
     Texture,
     TraceLogLevel,
@@ -214,7 +206,7 @@     VrDeviceInfo,
     VrStereoConfig,
   )
-import Raylib.Util (configsToBitflag, pop, withFreeable, withMaybeCString)
+import Raylib.Util (configsToBitflag, pop, popCArray, popCString, withFreeable, withMaybeCString)
 
 initWindow :: Int -> Int -> String -> IO ()
 initWindow width height title = withCString title $ c'initWindow (fromIntegral width) (fromIntegral height)
@@ -222,9 +214,14 @@ windowShouldClose :: IO Bool
 windowShouldClose = toBool <$> c'windowShouldClose
 
-foreign import ccall safe "raylib.h CloseWindow"
-  closeWindow ::
-    IO ()
+closeWindow :: IO ()
+closeWindow = do
+  unloadShaders
+  unloadTextures
+  unloadFrameBuffers
+  unloadVaoIds
+  unloadVboIds
+  c'closeWindow
 
 isWindowReady :: IO Bool
 isWindowReady = toBool <$> c'isWindowReady
@@ -275,6 +272,9 @@ setWindowIcon :: Raylib.Types.Image -> IO ()
 setWindowIcon image = withFreeable image c'setWindowIcon
 
+setWindowIcons :: [Raylib.Types.Image] -> IO ()
+setWindowIcons images = withArrayLen images (\l ptr -> c'setWindowIcons ptr (fromIntegral l))
+
 setWindowTitle :: String -> IO ()
 setWindowTitle title = withCString title c'setWindowTitle
 
@@ -452,15 +452,17 @@ loadVrStereoConfig :: Raylib.Types.VrDeviceInfo -> IO Raylib.Types.VrStereoConfig
 loadVrStereoConfig deviceInfo = withFreeable deviceInfo c'loadVrStereoConfig >>= pop
 
-unloadVrStereoConfig :: Raylib.Types.VrStereoConfig -> IO ()
-unloadVrStereoConfig config = withFreeable config c'unloadVrStereoConfig
-
 loadShader :: Maybe String -> Maybe String -> IO Raylib.Types.Shader
-loadShader vsFileName fsFileName =
-  withMaybeCString vsFileName (withMaybeCString fsFileName . c'loadShader) >>= pop
+loadShader vsFileName fsFileName = do
+  shader <- withMaybeCString vsFileName (withMaybeCString fsFileName . c'loadShader) >>= pop
+  addShaderId $ shader'id shader
+  return shader
 
 loadShaderFromMemory :: Maybe String -> Maybe String -> IO Raylib.Types.Shader
-loadShaderFromMemory vsCode fsCode = withMaybeCString vsCode (withMaybeCString fsCode . c'loadShaderFromMemory) >>= pop
+loadShaderFromMemory vsCode fsCode = do
+  shader <- withMaybeCString vsCode (withMaybeCString fsCode . c'loadShaderFromMemory) >>= pop
+  addShaderId $ shader'id shader
+  return shader
 
 isShaderReady :: Shader -> IO Bool
 isShaderReady shader = toBool <$> withFreeable shader c'isShaderReady
@@ -483,9 +485,6 @@ setShaderValueTexture :: Raylib.Types.Shader -> Int -> Raylib.Types.Texture -> IO ()
 setShaderValueTexture shader locIndex tex = withFreeable shader (\s -> withFreeable tex (c'setShaderValueTexture s (fromIntegral locIndex)))
 
-unloadShader :: Raylib.Types.Shader -> IO ()
-unloadShader shader = withFreeable shader c'unloadShader
-
 getMouseRay :: Raylib.Types.Vector2 -> Raylib.Types.Camera3D -> IO Raylib.Types.Ray
 getMouseRay mousePosition camera = withFreeable mousePosition (withFreeable camera . c'getMouseRay) >>= pop
 
@@ -583,9 +582,7 @@           ( \path -> do
               ptr <- c'loadFileData path size
               arrSize <- fromIntegral <$> peek size
-              arr <- peekArray arrSize ptr
-              c'unloadFileData ptr
-              return $ map fromIntegral arr
+              map fromIntegral <$> popCArray arrSize ptr
           )
     )
 
@@ -598,10 +595,7 @@   toBool <$> withArray (map fromInteger contents) (\c -> withCString fileName (c'exportDataAsCode c (fromIntegral size)))
 
 loadFileText :: String -> IO String
-loadFileText fileName = withCString fileName c'loadFileText >>= peekCString
-
-unloadFileText :: String -> IO ()
-unloadFileText text = withCString text c'unloadFileText
+loadFileText fileName = withCString fileName c'loadFileText >>= popCString
 
 saveFileText :: String -> String -> IO Bool
 saveFileText fileName text = toBool <$> withCString fileName (withCString text . c'saveFileText)
@@ -652,18 +646,12 @@ loadDirectoryFilesEx basePath filterStr scanSubdirs =
   withCString basePath (\b -> withCString filterStr (\f -> c'loadDirectoryFilesEx b f (fromBool scanSubdirs))) >>= pop
 
-unloadDirectoryFiles :: Raylib.Types.FilePathList -> IO ()
-unloadDirectoryFiles files = withFreeable files c'unloadDirectoryFiles
-
 isFileDropped :: IO Bool
 isFileDropped = toBool <$> c'isFileDropped
 
 loadDroppedFiles :: IO Raylib.Types.FilePathList
 loadDroppedFiles = c'loadDroppedFiles >>= pop
 
-unloadDroppedFiles :: Raylib.Types.FilePathList -> IO ()
-unloadDroppedFiles files = withFreeable files c'unloadDroppedFiles
-
 getFileModTime :: String -> IO Integer
 getFileModTime fileName = fromIntegral <$> withCString fileName c'getFileModTime
 
@@ -859,33 +847,11 @@ getGesturePinchAngle :: IO Float
 getGesturePinchAngle = realToFrac <$> c'getGesturePinchAngle
 
-setCameraMode :: Raylib.Types.Camera3D -> CameraMode -> IO ()
-setCameraMode camera mode = withFreeable camera (\c -> c'setCameraMode c (fromIntegral $ fromEnum mode))
-
-updateCamera :: Raylib.Types.Camera3D -> IO Raylib.Types.Camera3D
-updateCamera camera =
+updateCamera :: Raylib.Types.Camera3D -> CameraMode -> IO Raylib.Types.Camera3D
+updateCamera camera mode =
   withFreeable
     camera
     ( \c -> do
-        c'updateCamera c
+        c'updateCamera c (fromIntegral $ fromEnum mode)
         peek c
     )
-
-setCameraPanControl :: Int -> IO ()
-setCameraPanControl keyPan = c'setCameraPanControl $ fromIntegral keyPan
-
-setCameraAltControl :: Int -> IO ()
-setCameraAltControl keyAlt = c'setCameraAltControl $ fromIntegral keyAlt
-
-setCameraSmoothZoomControl :: Int -> IO ()
-setCameraSmoothZoomControl keySmoothZoom = c'setCameraSmoothZoomControl $ fromIntegral keySmoothZoom
-
-setCameraMoveControls :: Int -> Int -> Int -> Int -> Int -> Int -> IO ()
-setCameraMoveControls keyFront keyBack keyRight keyLeft keyUp keyDown =
-  c'setCameraMoveControls
-    (fromIntegral keyFront)
-    (fromIntegral keyBack)
-    (fromIntegral keyRight)
-    (fromIntegral keyLeft)
-    (fromIntegral keyUp)
-    (fromIntegral keyDown)
src/Raylib/Internal.hs view
@@ -1,8 +1,152 @@ {-# OPTIONS -Wall #-}
 {-# LANGUAGE ForeignFunctionInterface #-}
 
-module Raylib.Internal (c'rlGetShaderIdDefault) where
+module Raylib.Internal (unloadShaders, unloadTextures, unloadFrameBuffers, unloadVaoIds, unloadVboIds, unloadCtxData, unloadAudioBuffers, addShaderId, addTextureId, addFrameBuffer, addVaoId, addVboIds, addCtxData, addAudioBuffer, c'rlGetShaderIdDefault, getPixelDataSize) where
 
-import Foreign.C (CInt (..))
+import Control.Monad (forM_, unless, when)
+import Data.IORef (IORef, modifyIORef, newIORef, readIORef)
+import Foreign (Ptr)
+import Foreign.C (CInt (..), CUInt (..))
+import GHC.IO (unsafePerformIO)
 
-foreign import ccall safe "rlgl.h rlGetShaderIdDefault" c'rlGetShaderIdDefault :: IO CInt
+shaderIds :: IO (IORef [CUInt])
+shaderIds = newIORef []
+
+textureIds :: IO (IORef [CUInt])
+textureIds = newIORef []
+
+frameBuffers :: IO (IORef [CUInt])
+frameBuffers = newIORef []
+
+vaoIds :: IO (IORef [CUInt])
+vaoIds = newIORef []
+
+vboIds :: IO (IORef [CUInt])
+vboIds = newIORef []
+
+ctxDataPtrs :: IO (IORef [(CInt, Ptr ())])
+ctxDataPtrs = newIORef []
+
+audioBuffers :: IO (IORef [Ptr ()])
+audioBuffers = newIORef []
+
+unloadShaders :: IO ()
+unloadShaders = do
+  shaderIdDefault <- c'rlGetShaderIdDefault
+  shaderIds' <- shaderIds
+  vals <- readIORef shaderIds'
+  forM_ vals (\sId -> unless (sId == shaderIdDefault) (c'rlUnloadShaderProgram sId))
+  putStrLn "INFO: SHADER: h-raylib successfully auto-unloaded shaders"
+
+unloadTextures :: IO ()
+unloadTextures = do
+  textureIds' <- textureIds
+  vals <- readIORef textureIds'
+  forM_ vals (\tId -> when (tId > 0) (c'rlUnloadTexture tId))
+  putStrLn "INFO: TEXTURE: h-raylib successfully auto-unloaded textures"
+
+unloadFrameBuffers :: IO ()
+unloadFrameBuffers = do
+  frameBuffers' <- frameBuffers
+  vals <- readIORef frameBuffers'
+  forM_ vals (\fbId -> when (fbId > 0) (c'rlUnloadFramebuffer fbId))
+  putStrLn "INFO: FBO: h-raylib successfully auto-unloaded frame buffers"
+
+unloadVaoIds :: IO ()
+unloadVaoIds = do
+  vaoIds' <- vaoIds
+  vals <- readIORef vaoIds'
+  forM_ vals c'rlUnloadVertexArray
+  putStrLn "INFO: VAO: h-raylib successfully auto-unloaded vertex arrays"
+
+unloadVboIds :: IO ()
+unloadVboIds = do
+  vboIds' <- vboIds
+  vals <- readIORef vboIds'
+  forM_ vals c'rlUnloadVertexBuffer
+  putStrLn "INFO: VBO: h-raylib successfully auto-unloaded vertex buffers"
+
+unloadCtxData :: IO ()
+unloadCtxData = do
+  ctxDataPtrs' <- ctxDataPtrs
+  vals <- readIORef ctxDataPtrs'
+  forM_ vals $ uncurry c'unloadMusicStreamData
+  putStrLn "INFO: AUDIO: h-raylib successfully auto-unloaded music data"
+
+unloadAudioBuffers :: IO ()
+unloadAudioBuffers = do
+  audioBuffers' <- audioBuffers
+  vals <- readIORef audioBuffers'
+  forM_ vals c'unloadAudioBuffer
+  putStrLn "INFO: AUDIO: h-raylib successfully auto-unloaded audio buffers"
+
+addShaderId :: (Integral a) => a -> IO ()
+addShaderId sId' = do
+  shaderIds' <- shaderIds
+  modifyIORef shaderIds' (\xs -> if sId `elem` xs then xs else sId : xs)
+  where
+    sId = fromIntegral sId'
+
+addTextureId :: (Integral a) => a -> IO ()
+addTextureId tId' = do
+  textureIds' <- textureIds
+  modifyIORef textureIds' (\xs -> if tId `elem` xs then xs else tId : xs)
+  where
+    tId = fromIntegral tId'
+
+addFrameBuffer :: (Integral a) => a -> IO ()
+addFrameBuffer fbId' = do
+  frameBuffers' <- frameBuffers
+  modifyIORef frameBuffers' (\xs -> if fbId `elem` xs then xs else fbId : xs)
+  where
+    fbId = fromIntegral fbId'
+
+addVaoId :: (Integral a) => a -> IO ()
+addVaoId vaoId' = do
+  vaoIds' <- vaoIds
+  modifyIORef vaoIds' (\xs -> if vaoId `elem` xs then xs else vaoId : xs)
+  where
+    vaoId = fromIntegral vaoId'
+
+addVboIds :: (Integral a) => Maybe [a] -> IO ()
+addVboIds Nothing = return ()
+addVboIds (Just bIds') = do
+  vboIds' <- vboIds
+  forM_ bIds (\x -> modifyIORef vboIds' (\xs -> if x `elem` xs then xs else x : xs))
+  where
+    bIds = map fromIntegral bIds'
+
+addCtxData :: (Integral a) => a -> Ptr () -> IO ()
+addCtxData ctxType' ctxData = do
+  ctxDataPtrs' <- ctxDataPtrs
+  modifyIORef ctxDataPtrs' (\xs -> if (ctxType, ctxData) `elem` xs then xs else (ctxType, ctxData) : xs)
+  where
+    ctxType = fromIntegral ctxType'
+
+addAudioBuffer :: Ptr () -> IO ()
+addAudioBuffer buffer = do
+  audioBuffers' <- audioBuffers
+  modifyIORef audioBuffers' (\xs -> if buffer `elem` xs then xs else buffer : xs)
+
+foreign import ccall safe "rlgl.h rlGetShaderIdDefault" c'rlGetShaderIdDefault :: IO CUInt
+
+foreign import ccall safe "rlgl.h rlUnloadShaderProgram" c'rlUnloadShaderProgram :: CUInt -> IO ()
+
+foreign import ccall safe "rlgl.h rlUnloadTexture" c'rlUnloadTexture :: CUInt -> IO ()
+
+foreign import ccall safe "rlgl.h rlUnloadFramebuffer" c'rlUnloadFramebuffer :: CUInt -> IO ()
+
+foreign import ccall safe "rlgl.h rlUnloadVertexArray" c'rlUnloadVertexArray :: CUInt -> IO ()
+
+foreign import ccall safe "rlgl.h rlUnloadVertexBuffer" c'rlUnloadVertexBuffer :: CUInt -> IO ()
+
+foreign import ccall safe "rl_internal.h UnloadMusicStreamData" c'unloadMusicStreamData :: CInt -> Ptr () -> IO ()
+
+foreign import ccall safe "rl_internal.h UnloadAudioBuffer_" c'unloadAudioBuffer :: Ptr () -> IO ()
+
+foreign import ccall safe "raylib.h GetPixelDataSize"
+  c'getPixelDataSize ::
+    CInt -> CInt -> CInt -> IO CInt
+
+getPixelDataSize :: Int -> Int -> Int -> Int
+getPixelDataSize width height format = unsafePerformIO (fromIntegral <$> c'getPixelDataSize (fromIntegral width) (fromIntegral height) (fromIntegral format))
src/Raylib/Models.hs view
@@ -2,11 +2,11 @@ 
 module Raylib.Models where
 
+import Control.Monad (forM_)
 import Foreign
   ( Ptr,
-    Storable (peek, poke),
+    Storable (peek),
     fromBool,
-    malloc,
     peekArray,
     toBool,
     withArray,
@@ -14,6 +14,7 @@   )
 import Foreign.C (CFloat, withCString)
 import GHC.IO (unsafePerformIO)
+import Raylib.Internal (addShaderId, addTextureId, addVaoId, addVboIds)
 import Raylib.Native
   ( c'checkCollisionBoxSphere,
     c'checkCollisionBoxes,
@@ -79,12 +80,6 @@     c'loadModelFromMesh,
     c'setMaterialTexture,
     c'setModelMeshMaterial,
-    c'unloadMaterial,
-    c'unloadMesh,
-    c'unloadModel,
-    c'unloadModelAnimation,
-    c'unloadModelAnimations,
-    c'unloadModelKeepMeshes,
     c'updateMeshBuffer,
     c'updateModelAnimation,
     c'uploadMesh,
@@ -94,20 +89,23 @@     Camera3D,
     Color,
     Image,
-    Material,
+    Material (material'maps, material'shader),
+    MaterialMap (materialMap'texture),
     Matrix,
-    Mesh,
-    Model,
+    Mesh (mesh'vaoId, mesh'vboId),
+    Model (model'materials, model'meshes),
     ModelAnimation,
     Ray,
     RayCollision,
     Rectangle,
-    Texture,
+    Shader (shader'id),
+    Texture (texture'id),
     Vector2,
     Vector3,
   )
 import Raylib.Util
   ( pop,
+    popCArray,
     withFreeable,
   )
 import Prelude hiding (length)
@@ -176,24 +174,21 @@ drawGrid slices spacing = c'drawGrid (fromIntegral slices) (realToFrac spacing)
 
 loadModel :: String -> IO Raylib.Types.Model
-loadModel fileName = withCString fileName c'loadModel >>= pop
+loadModel fileName = do
+  model <- withCString fileName c'loadModel >>= pop
+  forM_ (model'meshes model) storeMeshData
+  storeMaterialData $ model'materials model
+  return model
 
 loadModelFromMesh :: Raylib.Types.Mesh -> IO Raylib.Types.Model
 loadModelFromMesh mesh = do
-  ptr <- malloc
-  poke ptr mesh
-  model <- c'loadModelFromMesh ptr
-  pop model
+  model <- withFreeable mesh c'loadModelFromMesh >>= pop
+  storeMaterialData $ model'materials model
+  return model
 
 isModelReady :: Raylib.Types.Model -> IO Bool
 isModelReady model = toBool <$> withFreeable model c'isModelReady
 
-unloadModel :: Raylib.Types.Model -> IO ()
-unloadModel model = withFreeable model c'unloadModel
-
-unloadModelKeepMeshes :: Raylib.Types.Model -> IO ()
-unloadModelKeepMeshes model = withFreeable model c'unloadModelKeepMeshes
-
 getModelBoundingBox :: Raylib.Types.Model -> IO Raylib.Types.BoundingBox
 getModelBoundingBox model = withFreeable model c'getModelBoundingBox >>= pop
 
@@ -222,14 +217,11 @@ drawBillboardPro camera texture source position up size origin rotation tint = withFreeable camera (\c -> withFreeable texture (\t -> withFreeable source (\s -> withFreeable position (\p -> withFreeable up (\u -> withFreeable size (\sz -> withFreeable origin (\o -> withFreeable tint (c'drawBillboardPro c t s p u sz o (realToFrac rotation)))))))))
 
 uploadMesh :: Raylib.Types.Mesh -> Bool -> IO Raylib.Types.Mesh
-uploadMesh mesh dynamic = withFreeable mesh (\m -> c'uploadMesh m (fromBool dynamic) >> peek m)
+uploadMesh mesh dynamic = withFreeable mesh (\m -> c'uploadMesh m (fromBool dynamic) >> peek m >>= storeMeshData)
 
 updateMeshBuffer :: Raylib.Types.Mesh -> Int -> Ptr () -> Int -> Int -> IO ()
 updateMeshBuffer mesh index dataValue dataSize offset = withFreeable mesh (\m -> c'updateMeshBuffer m (fromIntegral index) dataValue (fromIntegral dataSize) (fromIntegral offset))
 
-unloadMesh :: Raylib.Types.Mesh -> IO ()
-unloadMesh mesh = withFreeable mesh c'unloadMesh
-
 drawMesh :: Raylib.Types.Mesh -> Raylib.Types.Material -> Raylib.Types.Matrix -> IO ()
 drawMesh mesh material transform = withFreeable mesh (\m -> withFreeable material (withFreeable transform . c'drawMesh m))
 
@@ -246,38 +238,45 @@ genMeshTangents mesh = withFreeable mesh (\m -> c'genMeshTangents m >> peek m)
 
 genMeshPoly :: Int -> Float -> IO Raylib.Types.Mesh
-genMeshPoly sides radius = c'genMeshPoly (fromIntegral sides) (realToFrac radius) >>= pop
+genMeshPoly sides radius = c'genMeshPoly (fromIntegral sides) (realToFrac radius) >>= pop >>= storeMeshData
 
 genMeshPlane :: Float -> Float -> Int -> Int -> IO Raylib.Types.Mesh
-genMeshPlane width length resX resZ = c'genMeshPlane (realToFrac width) (realToFrac length) (fromIntegral resX) (fromIntegral resZ) >>= pop
+genMeshPlane width length resX resZ = c'genMeshPlane (realToFrac width) (realToFrac length) (fromIntegral resX) (fromIntegral resZ) >>= pop >>= storeMeshData
 
 genMeshCube :: Float -> Float -> Float -> IO Raylib.Types.Mesh
-genMeshCube width height length = c'genMeshCube (realToFrac width) (realToFrac height) (realToFrac length) >>= pop
+genMeshCube width height length = c'genMeshCube (realToFrac width) (realToFrac height) (realToFrac length) >>= pop >>= storeMeshData
 
 genMeshSphere :: Float -> Int -> Int -> IO Raylib.Types.Mesh
-genMeshSphere radius rings slices = c'genMeshSphere (realToFrac radius) (fromIntegral rings) (fromIntegral slices) >>= pop
+genMeshSphere radius rings slices = c'genMeshSphere (realToFrac radius) (fromIntegral rings) (fromIntegral slices) >>= pop >>= storeMeshData
 
 genMeshHemiSphere :: Float -> Int -> Int -> IO Raylib.Types.Mesh
-genMeshHemiSphere radius rings slices = c'genMeshHemiSphere (realToFrac radius) (fromIntegral rings) (fromIntegral slices) >>= pop
+genMeshHemiSphere radius rings slices = c'genMeshHemiSphere (realToFrac radius) (fromIntegral rings) (fromIntegral slices) >>= pop >>= storeMeshData
 
 genMeshCylinder :: Float -> Float -> Int -> IO Raylib.Types.Mesh
-genMeshCylinder radius height slices = c'genMeshCylinder (realToFrac radius) (realToFrac height) (fromIntegral slices) >>= pop
+genMeshCylinder radius height slices = c'genMeshCylinder (realToFrac radius) (realToFrac height) (fromIntegral slices) >>= pop >>= storeMeshData
 
 genMeshCone :: Float -> Float -> Int -> IO Raylib.Types.Mesh
-genMeshCone radius height slices = c'genMeshCone (realToFrac radius) (realToFrac height) (fromIntegral slices) >>= pop
+genMeshCone radius height slices = c'genMeshCone (realToFrac radius) (realToFrac height) (fromIntegral slices) >>= pop >>= storeMeshData
 
 genMeshTorus :: Float -> Float -> Int -> Int -> IO Raylib.Types.Mesh
-genMeshTorus radius size radSeg sides = c'genMeshTorus (realToFrac radius) (realToFrac size) (fromIntegral radSeg) (fromIntegral sides) >>= pop
+genMeshTorus radius size radSeg sides = c'genMeshTorus (realToFrac radius) (realToFrac size) (fromIntegral radSeg) (fromIntegral sides) >>= pop >>= storeMeshData
 
 genMeshKnot :: Float -> Float -> Int -> Int -> IO Raylib.Types.Mesh
-genMeshKnot radius size radSeg sides = c'genMeshKnot (realToFrac radius) (realToFrac size) (fromIntegral radSeg) (fromIntegral sides) >>= pop
+genMeshKnot radius size radSeg sides = c'genMeshKnot (realToFrac radius) (realToFrac size) (fromIntegral radSeg) (fromIntegral sides) >>= pop >>= storeMeshData
 
 genMeshHeightmap :: Raylib.Types.Image -> Raylib.Types.Vector3 -> IO Raylib.Types.Mesh
-genMeshHeightmap heightmap size = withFreeable heightmap (withFreeable size . c'genMeshHeightmap) >>= pop
+genMeshHeightmap heightmap size = withFreeable heightmap (withFreeable size . c'genMeshHeightmap) >>= pop >>= storeMeshData
 
 genMeshCubicmap :: Raylib.Types.Image -> Raylib.Types.Vector3 -> IO Raylib.Types.Mesh
-genMeshCubicmap cubicmap cubeSize = withFreeable cubicmap (withFreeable cubeSize . c'genMeshCubicmap) >>= pop
+genMeshCubicmap cubicmap cubeSize = withFreeable cubicmap (withFreeable cubeSize . c'genMeshCubicmap) >>= pop >>= storeMeshData
 
+-- Internal
+storeMeshData :: Mesh -> IO Mesh
+storeMeshData mesh = do
+  addVaoId $ mesh'vaoId mesh
+  addVboIds $ mesh'vboId mesh
+  return mesh
+
 loadMaterials :: String -> IO [Raylib.Types.Material]
 loadMaterials fileName =
   withCString
@@ -288,19 +287,29 @@           ( \n -> do
               ptr <- c'loadMaterials f n
               num <- peek n
-              peekArray (fromIntegral num) ptr
+              materials <- popCArray (fromIntegral num) ptr
+              storeMaterialData materials
+              return materials
           )
     )
 
+storeMaterialData :: [Material] -> IO ()
+storeMaterialData materials =
+  forM_
+    materials
+    ( \mat -> do
+        addShaderId $ shader'id $ material'shader mat
+        case material'maps mat of
+          Nothing -> return ()
+          (Just maps) -> forM_ maps (addTextureId . texture'id . materialMap'texture)
+    )
+
 loadMaterialDefault :: IO Raylib.Types.Material
 loadMaterialDefault = c'loadMaterialDefault >>= pop
 
 isMaterialReady :: Raylib.Types.Material -> IO Bool
 isMaterialReady material = toBool <$> withFreeable material c'isMaterialReady
 
-unloadMaterial :: Raylib.Types.Material -> IO ()
-unloadMaterial material = withFreeable material c'unloadMaterial
-
 setMaterialTexture :: Raylib.Types.Material -> Int -> Raylib.Types.Texture -> IO Raylib.Types.Material
 setMaterialTexture material mapType texture = withFreeable material (\m -> withFreeable texture (c'setMaterialTexture m (fromIntegral mapType)) >> peek m)
 
@@ -323,12 +332,6 @@ 
 updateModelAnimation :: Raylib.Types.Model -> Raylib.Types.ModelAnimation -> Int -> IO ()
 updateModelAnimation model animation frame = withFreeable model (\m -> withFreeable animation (\a -> c'updateModelAnimation m a (fromIntegral frame)))
-
-unloadModelAnimation :: ModelAnimation -> IO ()
-unloadModelAnimation animation = withFreeable animation c'unloadModelAnimation
-
-unloadModelAnimations :: [ModelAnimation] -> IO ()
-unloadModelAnimations animations = withArrayLen animations (\num a -> c'unloadModelAnimations a (fromIntegral num))
 
 isModelAnimationValid :: Model -> ModelAnimation -> IO Bool
 isModelAnimationValid model animation = toBool <$> withFreeable model (withFreeable animation . c'isModelAnimationValid)
src/Raylib/Native.hs view
@@ -4,7 +4,7 @@ 
 module Raylib.Native where
 
-import Foreign (FunPtr, Ptr)
+import Foreign (Ptr)
 import Foreign.C
   ( CBool (..),
     CDouble (..),
@@ -35,7 +35,6 @@     ModelAnimation,
     Music,
     NPatchInfo,
-    RAudioBuffer,
     Ray,
     RayCollision,
     Rectangle,
@@ -101,6 +100,10 @@   c'windowShouldClose ::
     IO CBool
 
+foreign import ccall safe "raylib.h CloseWindow"
+  c'closeWindow ::
+    IO ()
+
 foreign import ccall safe "raylib.h IsWindowReady"
   c'isWindowReady ::
     IO CBool
@@ -141,8 +144,10 @@   c'clearWindowState ::
     CUInt -> IO ()
 
-foreign import ccall safe "bindings.h SetWindowIcon_" c'setWindowIcon :: Ptr Raylib.Types.Image -> IO ()
+foreign import ccall safe "rl_bindings.h SetWindowIcon_" c'setWindowIcon :: Ptr Raylib.Types.Image -> IO ()
 
+foreign import ccall safe "raylib.h SetWindowIcons" c'setWindowIcons :: Ptr Raylib.Types.Image -> CInt -> IO ()
+
 foreign import ccall safe "raylib.h SetWindowTitle"
   c'setWindowTitle ::
     CString -> IO ()
@@ -191,7 +196,7 @@   c'getCurrentMonitor ::
     IO CInt
 
-foreign import ccall safe "bindings.h GetMonitorPosition_" c'getMonitorPosition :: CInt -> IO (Ptr Raylib.Types.Vector2)
+foreign import ccall safe "rl_bindings.h GetMonitorPosition_" c'getMonitorPosition :: CInt -> IO (Ptr Raylib.Types.Vector2)
 
 foreign import ccall safe "raylib.h GetMonitorWidth"
   c'getMonitorWidth ::
@@ -213,9 +218,9 @@   c'getMonitorRefreshRate ::
     CInt -> IO CInt
 
-foreign import ccall safe "bindings.h GetWindowPosition_" c'getWindowPosition :: IO (Ptr Raylib.Types.Vector2)
+foreign import ccall safe "rl_bindings.h GetWindowPosition_" c'getWindowPosition :: IO (Ptr Raylib.Types.Vector2)
 
-foreign import ccall safe "bindings.h GetWindowScaleDPI_" c'getWindowScaleDPI :: IO (Ptr Raylib.Types.Vector2)
+foreign import ccall safe "rl_bindings.h GetWindowScaleDPI_" c'getWindowScaleDPI :: IO (Ptr Raylib.Types.Vector2)
 
 foreign import ccall safe "raylib.h GetMonitorName"
   c'getMonitorName ::
@@ -241,15 +246,15 @@   c'isCursorOnScreen ::
     IO CBool
 
-foreign import ccall safe "bindings.h ClearBackground_" c'clearBackground :: Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ClearBackground_" c'clearBackground :: Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h BeginMode2D_" c'beginMode2D :: Ptr Raylib.Types.Camera2D -> IO ()
+foreign import ccall safe "rl_bindings.h BeginMode2D_" c'beginMode2D :: Ptr Raylib.Types.Camera2D -> IO ()
 
-foreign import ccall safe "bindings.h BeginMode3D_" c'beginMode3D :: Ptr Raylib.Types.Camera3D -> IO ()
+foreign import ccall safe "rl_bindings.h BeginMode3D_" c'beginMode3D :: Ptr Raylib.Types.Camera3D -> IO ()
 
-foreign import ccall safe "bindings.h BeginTextureMode_" c'beginTextureMode :: Ptr Raylib.Types.RenderTexture -> IO ()
+foreign import ccall safe "rl_bindings.h BeginTextureMode_" c'beginTextureMode :: Ptr Raylib.Types.RenderTexture -> IO ()
 
-foreign import ccall safe "bindings.h BeginShaderMode_" c'beginShaderMode :: Ptr Raylib.Types.Shader -> IO ()
+foreign import ccall safe "rl_bindings.h BeginShaderMode_" c'beginShaderMode :: Ptr Raylib.Types.Shader -> IO ()
 
 foreign import ccall safe "raylib.h BeginBlendMode"
   c'beginBlendMode ::
@@ -259,45 +264,45 @@   c'beginScissorMode ::
     CInt -> CInt -> CInt -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h BeginVrStereoMode_" c'beginVrStereoMode :: Ptr Raylib.Types.VrStereoConfig -> IO ()
+foreign import ccall safe "rl_bindings.h BeginVrStereoMode_" c'beginVrStereoMode :: Ptr Raylib.Types.VrStereoConfig -> IO ()
 
-foreign import ccall safe "bindings.h LoadVrStereoConfig_" c'loadVrStereoConfig :: Ptr Raylib.Types.VrDeviceInfo -> IO (Ptr Raylib.Types.VrStereoConfig)
+foreign import ccall safe "rl_bindings.h LoadVrStereoConfig_" c'loadVrStereoConfig :: Ptr Raylib.Types.VrDeviceInfo -> IO (Ptr Raylib.Types.VrStereoConfig)
 
-foreign import ccall safe "bindings.h UnloadVrStereoConfig_" c'unloadVrStereoConfig :: Ptr Raylib.Types.VrStereoConfig -> IO ()
+foreign import ccall safe "rl_bindings.h UnloadVrStereoConfig_" c'unloadVrStereoConfig :: Ptr Raylib.Types.VrStereoConfig -> IO ()
 
-foreign import ccall safe "bindings.h LoadShader_" c'loadShader :: CString -> CString -> IO (Ptr Raylib.Types.Shader)
+foreign import ccall safe "rl_bindings.h LoadShader_" c'loadShader :: CString -> CString -> IO (Ptr Raylib.Types.Shader)
 
-foreign import ccall safe "bindings.h LoadShaderFromMemory_" c'loadShaderFromMemory :: CString -> CString -> IO (Ptr Raylib.Types.Shader)
+foreign import ccall safe "rl_bindings.h LoadShaderFromMemory_" c'loadShaderFromMemory :: CString -> CString -> IO (Ptr Raylib.Types.Shader)
 
-foreign import ccall safe "bindings.h IsShaderReady_" c'isShaderReady :: Ptr Shader -> IO CBool
+foreign import ccall safe "rl_bindings.h IsShaderReady_" c'isShaderReady :: Ptr Shader -> IO CBool
 
-foreign import ccall safe "bindings.h GetShaderLocation_" c'getShaderLocation :: Ptr Raylib.Types.Shader -> CString -> IO CInt
+foreign import ccall safe "rl_bindings.h GetShaderLocation_" c'getShaderLocation :: Ptr Raylib.Types.Shader -> CString -> IO CInt
 
-foreign import ccall safe "bindings.h GetShaderLocationAttrib_" c'getShaderLocationAttrib :: Ptr Raylib.Types.Shader -> CString -> IO CInt
+foreign import ccall safe "rl_bindings.h GetShaderLocationAttrib_" c'getShaderLocationAttrib :: Ptr Raylib.Types.Shader -> CString -> IO CInt
 
-foreign import ccall safe "bindings.h SetShaderValue_" c'setShaderValue :: Ptr Raylib.Types.Shader -> CInt -> Ptr () -> CInt -> IO ()
+foreign import ccall safe "rl_bindings.h SetShaderValue_" c'setShaderValue :: Ptr Raylib.Types.Shader -> CInt -> Ptr () -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h SetShaderValueV_" c'setShaderValueV :: Ptr Raylib.Types.Shader -> CInt -> Ptr () -> CInt -> CInt -> IO ()
+foreign import ccall safe "rl_bindings.h SetShaderValueV_" c'setShaderValueV :: Ptr Raylib.Types.Shader -> CInt -> Ptr () -> CInt -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h SetShaderValueMatrix_" c'setShaderValueMatrix :: Ptr Raylib.Types.Shader -> CInt -> Ptr Raylib.Types.Matrix -> IO ()
+foreign import ccall safe "rl_bindings.h SetShaderValueMatrix_" c'setShaderValueMatrix :: Ptr Raylib.Types.Shader -> CInt -> Ptr Raylib.Types.Matrix -> IO ()
 
-foreign import ccall safe "bindings.h SetShaderValueTexture_" c'setShaderValueTexture :: Ptr Raylib.Types.Shader -> CInt -> Ptr Raylib.Types.Texture -> IO ()
+foreign import ccall safe "rl_bindings.h SetShaderValueTexture_" c'setShaderValueTexture :: Ptr Raylib.Types.Shader -> CInt -> Ptr Raylib.Types.Texture -> IO ()
 
-foreign import ccall safe "bindings.h UnloadShader_" c'unloadShader :: Ptr Raylib.Types.Shader -> IO ()
+foreign import ccall safe "rl_bindings.h UnloadShader_" c'unloadShader :: Ptr Raylib.Types.Shader -> IO ()
 
-foreign import ccall safe "bindings.h GetMouseRay_" c'getMouseRay :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Camera3D -> IO (Ptr Raylib.Types.Ray)
+foreign import ccall safe "rl_bindings.h GetMouseRay_" c'getMouseRay :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Camera3D -> IO (Ptr Raylib.Types.Ray)
 
-foreign import ccall safe "bindings.h GetCameraMatrix_" c'getCameraMatrix :: Ptr Raylib.Types.Camera3D -> IO (Ptr Raylib.Types.Matrix)
+foreign import ccall safe "rl_bindings.h GetCameraMatrix_" c'getCameraMatrix :: Ptr Raylib.Types.Camera3D -> IO (Ptr Raylib.Types.Matrix)
 
-foreign import ccall safe "bindings.h GetCameraMatrix2D_" c'getCameraMatrix2D :: Ptr Raylib.Types.Camera2D -> IO (Ptr Raylib.Types.Matrix)
+foreign import ccall safe "rl_bindings.h GetCameraMatrix2D_" c'getCameraMatrix2D :: Ptr Raylib.Types.Camera2D -> IO (Ptr Raylib.Types.Matrix)
 
-foreign import ccall safe "bindings.h GetWorldToScreen_" c'getWorldToScreen :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Camera3D -> IO (Ptr Raylib.Types.Vector2)
+foreign import ccall safe "rl_bindings.h GetWorldToScreen_" c'getWorldToScreen :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Camera3D -> IO (Ptr Raylib.Types.Vector2)
 
-foreign import ccall safe "bindings.h GetScreenToWorld2D_" c'getScreenToWorld2D :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Camera2D -> IO (Ptr Raylib.Types.Vector2)
+foreign import ccall safe "rl_bindings.h GetScreenToWorld2D_" c'getScreenToWorld2D :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Camera2D -> IO (Ptr Raylib.Types.Vector2)
 
-foreign import ccall safe "bindings.h GetWorldToScreenEx_" c'getWorldToScreenEx :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Camera3D -> CInt -> CInt -> IO (Ptr Raylib.Types.Vector2)
+foreign import ccall safe "rl_bindings.h GetWorldToScreenEx_" c'getWorldToScreenEx :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Camera3D -> CInt -> CInt -> IO (Ptr Raylib.Types.Vector2)
 
-foreign import ccall safe "bindings.h GetWorldToScreen2D_" c'getWorldToScreen2D :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Camera2D -> IO (Ptr Raylib.Types.Vector2)
+foreign import ccall safe "rl_bindings.h GetWorldToScreen2D_" c'getWorldToScreen2D :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Camera2D -> IO (Ptr Raylib.Types.Vector2)
 
 foreign import ccall safe "raylib.h SetTargetFPS"
   c'setTargetFPS ::
@@ -435,19 +440,19 @@   c'isPathFile ::
     CString -> IO CBool
 
-foreign import ccall safe "bindings.h LoadDirectoryFiles_" c'loadDirectoryFiles :: CString -> IO (Ptr Raylib.Types.FilePathList)
+foreign import ccall safe "rl_bindings.h LoadDirectoryFiles_" c'loadDirectoryFiles :: CString -> IO (Ptr Raylib.Types.FilePathList)
 
-foreign import ccall safe "bindings.h LoadDirectoryFilesEx_" c'loadDirectoryFilesEx :: CString -> CString -> CInt -> IO (Ptr Raylib.Types.FilePathList)
+foreign import ccall safe "rl_bindings.h LoadDirectoryFilesEx_" c'loadDirectoryFilesEx :: CString -> CString -> CInt -> IO (Ptr Raylib.Types.FilePathList)
 
-foreign import ccall safe "bindings.h UnloadDirectoryFiles_" c'unloadDirectoryFiles :: Ptr Raylib.Types.FilePathList -> IO ()
+foreign import ccall safe "rl_bindings.h UnloadDirectoryFiles_" c'unloadDirectoryFiles :: Ptr Raylib.Types.FilePathList -> IO ()
 
 foreign import ccall safe "raylib.h IsFileDropped"
   c'isFileDropped ::
     IO CBool
 
-foreign import ccall safe "bindings.h LoadDroppedFiles_" c'loadDroppedFiles :: IO (Ptr Raylib.Types.FilePathList)
+foreign import ccall safe "rl_bindings.h LoadDroppedFiles_" c'loadDroppedFiles :: IO (Ptr Raylib.Types.FilePathList)
 
-foreign import ccall safe "bindings.h UnloadDroppedFiles_" c'unloadDroppedFiles :: Ptr Raylib.Types.FilePathList -> IO ()
+foreign import ccall safe "rl_bindings.h UnloadDroppedFiles_" c'unloadDroppedFiles :: Ptr Raylib.Types.FilePathList -> IO ()
 
 foreign import ccall safe "raylib.h GetFileModTime"
   c'getFileModTime ::
@@ -561,9 +566,9 @@   c'getMouseY ::
     IO CInt
 
-foreign import ccall safe "bindings.h GetMousePosition_" c'getMousePosition :: IO (Ptr Raylib.Types.Vector2)
+foreign import ccall safe "rl_bindings.h GetMousePosition_" c'getMousePosition :: IO (Ptr Raylib.Types.Vector2)
 
-foreign import ccall safe "bindings.h GetMouseDelta_" c'getMouseDelta :: IO (Ptr Raylib.Types.Vector2)
+foreign import ccall safe "rl_bindings.h GetMouseDelta_" c'getMouseDelta :: IO (Ptr Raylib.Types.Vector2)
 
 foreign import ccall safe "raylib.h SetMousePosition"
   c'setMousePosition ::
@@ -581,7 +586,7 @@   c'getMouseWheelMove ::
     IO CFloat
 
-foreign import ccall safe "bindings.h GetMouseWheelMoveV_" c'getMouseWheelMoveV :: IO (Ptr Raylib.Types.Vector2)
+foreign import ccall safe "rl_bindings.h GetMouseWheelMoveV_" c'getMouseWheelMoveV :: IO (Ptr Raylib.Types.Vector2)
 
 foreign import ccall safe "raylib.h SetMouseCursor"
   c'setMouseCursor ::
@@ -595,7 +600,7 @@   c'getTouchY ::
     IO CInt
 
-foreign import ccall safe "bindings.h GetTouchPosition_" c'getTouchPosition :: CInt -> IO (Ptr Raylib.Types.Vector2)
+foreign import ccall safe "rl_bindings.h GetTouchPosition_" c'getTouchPosition :: CInt -> IO (Ptr Raylib.Types.Vector2)
 
 foreign import ccall safe "raylib.h GetTouchPointId"
   c'getTouchPointId ::
@@ -621,195 +626,177 @@   c'getGestureHoldDuration ::
     IO CFloat
 
-foreign import ccall safe "bindings.h GetGestureDragVector_" c'getGestureDragVector :: IO (Ptr Raylib.Types.Vector2)
+foreign import ccall safe "rl_bindings.h GetGestureDragVector_" c'getGestureDragVector :: IO (Ptr Raylib.Types.Vector2)
 
 foreign import ccall safe "raylib.h GetGestureDragAngle"
   c'getGestureDragAngle ::
     IO CFloat
 
-foreign import ccall safe "bindings.h GetGesturePinchVector_" c'getGesturePinchVector :: IO (Ptr Raylib.Types.Vector2)
+foreign import ccall safe "rl_bindings.h GetGesturePinchVector_" c'getGesturePinchVector :: IO (Ptr Raylib.Types.Vector2)
 
 foreign import ccall safe "raylib.h GetGesturePinchAngle"
   c'getGesturePinchAngle ::
     IO CFloat
 
-foreign import ccall safe "bindings.h SetCameraMode_" c'setCameraMode :: Ptr Raylib.Types.Camera3D -> CInt -> IO ()
-
 foreign import ccall safe "raylib.h UpdateCamera"
   c'updateCamera ::
-    Ptr Raylib.Types.Camera3D -> IO ()
-
-foreign import ccall safe "raylib.h SetCameraPanControl"
-  c'setCameraPanControl ::
-    CInt -> IO ()
-
-foreign import ccall safe "raylib.h SetCameraAltControl"
-  c'setCameraAltControl ::
-    CInt -> IO ()
-
-foreign import ccall safe "raylib.h SetCameraSmoothZoomControl"
-  c'setCameraSmoothZoomControl ::
-    CInt -> IO ()
-
-foreign import ccall safe "raylib.h SetCameraMoveControls"
-  c'setCameraMoveControls ::
-    CInt -> CInt -> CInt -> CInt -> CInt -> CInt -> IO ()
+    Ptr Raylib.Types.Camera3D -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h SetShapesTexture_" c'setShapesTexture :: Ptr Raylib.Types.Texture -> Ptr Raylib.Types.Rectangle -> IO ()
+foreign import ccall safe "rl_bindings.h SetShapesTexture_" c'setShapesTexture :: Ptr Raylib.Types.Texture -> Ptr Raylib.Types.Rectangle -> IO ()
 
-foreign import ccall safe "bindings.h DrawPixel_" c'drawPixel :: CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawPixel_" c'drawPixel :: CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawPixelV_" c'drawPixelV :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawPixelV_" c'drawPixelV :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawLine_" c'drawLine :: CInt -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawLine_" c'drawLine :: CInt -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawLineV_" c'drawLineV :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawLineV_" c'drawLineV :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawLineEx_" c'drawLineEx :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawLineEx_" c'drawLineEx :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawLineBezier_" c'drawLineBezier :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawLineBezier_" c'drawLineBezier :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawLineBezierQuad_" c'drawLineBezierQuad :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawLineBezierQuad_" c'drawLineBezierQuad :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawLineBezierCubic_" c'drawLineBezierCubic :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawLineBezierCubic_" c'drawLineBezierCubic :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawLineStrip_" c'drawLineStrip :: Ptr Raylib.Types.Vector2 -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawLineStrip_" c'drawLineStrip :: Ptr Raylib.Types.Vector2 -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawCircle_" c'drawCircle :: CInt -> CInt -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawCircle_" c'drawCircle :: CInt -> CInt -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawCircleSector_" c'drawCircleSector :: Ptr Raylib.Types.Vector2 -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawCircleSector_" c'drawCircleSector :: Ptr Raylib.Types.Vector2 -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawCircleSectorLines_" c'drawCircleSectorLines :: Ptr Raylib.Types.Vector2 -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawCircleSectorLines_" c'drawCircleSectorLines :: Ptr Raylib.Types.Vector2 -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawCircleGradient_" c'drawCircleGradient :: CInt -> CInt -> CFloat -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawCircleGradient_" c'drawCircleGradient :: CInt -> CInt -> CFloat -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawCircleV_" c'drawCircleV :: Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawCircleV_" c'drawCircleV :: Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawCircleLines_" c'drawCircleLines :: CInt -> CInt -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawCircleLines_" c'drawCircleLines :: CInt -> CInt -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawEllipse_" c'drawEllipse :: CInt -> CInt -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawEllipse_" c'drawEllipse :: CInt -> CInt -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawEllipseLines_" c'drawEllipseLines :: CInt -> CInt -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawEllipseLines_" c'drawEllipseLines :: CInt -> CInt -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawRing_" c'drawRing :: Ptr Raylib.Types.Vector2 -> CFloat -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawRing_" c'drawRing :: Ptr Raylib.Types.Vector2 -> CFloat -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawRingLines_" c'drawRingLines :: Ptr Raylib.Types.Vector2 -> CFloat -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawRingLines_" c'drawRingLines :: Ptr Raylib.Types.Vector2 -> CFloat -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawRectangle_" c'drawRectangle :: CInt -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawRectangle_" c'drawRectangle :: CInt -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawRectangleV_" c'drawRectangleV :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawRectangleV_" c'drawRectangleV :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawRectangleRec_" c'drawRectangleRec :: Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawRectangleRec_" c'drawRectangleRec :: Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawRectanglePro_" c'drawRectanglePro :: Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawRectanglePro_" c'drawRectanglePro :: Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawRectangleGradientV_" c'drawRectangleGradientV :: CInt -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawRectangleGradientV_" c'drawRectangleGradientV :: CInt -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawRectangleGradientH_" c'drawRectangleGradientH :: CInt -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawRectangleGradientH_" c'drawRectangleGradientH :: CInt -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawRectangleGradientEx_" c'drawRectangleGradientEx :: Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawRectangleGradientEx_" c'drawRectangleGradientEx :: Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawRectangleLines_" c'drawRectangleLines :: CInt -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawRectangleLines_" c'drawRectangleLines :: CInt -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawRectangleLinesEx_" c'drawRectangleLinesEx :: Ptr Raylib.Types.Rectangle -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawRectangleLinesEx_" c'drawRectangleLinesEx :: Ptr Raylib.Types.Rectangle -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawRectangleRounded_" c'drawRectangleRounded :: Ptr Raylib.Types.Rectangle -> CFloat -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawRectangleRounded_" c'drawRectangleRounded :: Ptr Raylib.Types.Rectangle -> CFloat -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawRectangleRoundedLines_" c'drawRectangleRoundedLines :: Ptr Raylib.Types.Rectangle -> CFloat -> CInt -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawRectangleRoundedLines_" c'drawRectangleRoundedLines :: Ptr Raylib.Types.Rectangle -> CFloat -> CInt -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawTriangle_" c'drawTriangle :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawTriangle_" c'drawTriangle :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawTriangleLines_" c'drawTriangleLines :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawTriangleLines_" c'drawTriangleLines :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawTriangleFan_" c'drawTriangleFan :: Ptr Raylib.Types.Vector2 -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawTriangleFan_" c'drawTriangleFan :: Ptr Raylib.Types.Vector2 -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawTriangleStrip_" c'drawTriangleStrip :: Ptr Raylib.Types.Vector2 -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawTriangleStrip_" c'drawTriangleStrip :: Ptr Raylib.Types.Vector2 -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawPoly_" c'drawPoly :: Ptr Raylib.Types.Vector2 -> CInt -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawPoly_" c'drawPoly :: Ptr Raylib.Types.Vector2 -> CInt -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawPolyLines_" c'drawPolyLines :: Ptr Raylib.Types.Vector2 -> CInt -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawPolyLines_" c'drawPolyLines :: Ptr Raylib.Types.Vector2 -> CInt -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawPolyLinesEx_" c'drawPolyLinesEx :: Ptr Raylib.Types.Vector2 -> CInt -> CFloat -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawPolyLinesEx_" c'drawPolyLinesEx :: Ptr Raylib.Types.Vector2 -> CInt -> CFloat -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h CheckCollisionRecs_" c'checkCollisionRecs :: Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Rectangle -> IO CBool
+foreign import ccall safe "rl_bindings.h CheckCollisionRecs_" c'checkCollisionRecs :: Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Rectangle -> IO CBool
 
-foreign import ccall safe "bindings.h CheckCollisionCircles_" c'checkCollisionCircles :: Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Vector2 -> CFloat -> IO CBool
+foreign import ccall safe "rl_bindings.h CheckCollisionCircles_" c'checkCollisionCircles :: Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Vector2 -> CFloat -> IO CBool
 
-foreign import ccall safe "bindings.h CheckCollisionCircleRec_" c'checkCollisionCircleRec :: Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Rectangle -> IO CBool
+foreign import ccall safe "rl_bindings.h CheckCollisionCircleRec_" c'checkCollisionCircleRec :: Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Rectangle -> IO CBool
 
-foreign import ccall safe "bindings.h CheckCollisionPointRec_" c'checkCollisionPointRec :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Rectangle -> IO CBool
+foreign import ccall safe "rl_bindings.h CheckCollisionPointRec_" c'checkCollisionPointRec :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Rectangle -> IO CBool
 
-foreign import ccall safe "bindings.h CheckCollisionPointCircle_" c'checkCollisionPointCircle :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> CFloat -> IO CBool
+foreign import ccall safe "rl_bindings.h CheckCollisionPointCircle_" c'checkCollisionPointCircle :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> CFloat -> IO CBool
 
-foreign import ccall safe "bindings.h CheckCollisionPointTriangle_" c'checkCollisionPointTriangle :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> IO CBool
+foreign import ccall safe "rl_bindings.h CheckCollisionPointTriangle_" c'checkCollisionPointTriangle :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> IO CBool
 
-foreign import ccall safe "bindings.h CheckCollisionLines_" c'checkCollisionLines :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> IO CBool
+foreign import ccall safe "rl_bindings.h CheckCollisionLines_" c'checkCollisionLines :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> IO CBool
 
-foreign import ccall safe "bindings.h CheckCollisionPointLine_" c'checkCollisionPointLine :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> CInt -> IO CBool
+foreign import ccall safe "rl_bindings.h CheckCollisionPointLine_" c'checkCollisionPointLine :: Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> CInt -> IO CBool
 
-foreign import ccall safe "bindings.h GetCollisionRec_" c'getCollisionRec :: Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Rectangle -> IO (Ptr Raylib.Types.Rectangle)
+foreign import ccall safe "rl_bindings.h GetCollisionRec_" c'getCollisionRec :: Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Rectangle -> IO (Ptr Raylib.Types.Rectangle)
 
-foreign import ccall safe "bindings.h LoadImage_" c'loadImage :: CString -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h LoadImage_" c'loadImage :: CString -> IO (Ptr Raylib.Types.Image)
 
-foreign import ccall safe "bindings.h LoadImageRaw_" c'loadImageRaw :: CString -> CInt -> CInt -> CInt -> CInt -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h LoadImageRaw_" c'loadImageRaw :: CString -> CInt -> CInt -> CInt -> CInt -> IO (Ptr Raylib.Types.Image)
 
-foreign import ccall safe "bindings.h LoadImageAnim_" c'loadImageAnim :: CString -> Ptr CInt -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h LoadImageAnim_" c'loadImageAnim :: CString -> Ptr CInt -> IO (Ptr Raylib.Types.Image)
 
-foreign import ccall safe "bindings.h LoadImageFromMemory_" c'loadImageFromMemory :: CString -> Ptr CUChar -> CInt -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h LoadImageFromMemory_" c'loadImageFromMemory :: CString -> Ptr CUChar -> CInt -> IO (Ptr Raylib.Types.Image)
 
-foreign import ccall safe "bindings.h LoadImageFromTexture_" c'loadImageFromTexture :: Ptr Raylib.Types.Texture -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h LoadImageFromTexture_" c'loadImageFromTexture :: Ptr Raylib.Types.Texture -> IO (Ptr Raylib.Types.Image)
 
-foreign import ccall safe "bindings.h LoadImageFromScreen_" c'loadImageFromScreen :: IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h LoadImageFromScreen_" c'loadImageFromScreen :: IO (Ptr Raylib.Types.Image)
 
-foreign import ccall safe "bindings.h IsImageReady_" c'isImageReady :: Ptr Image -> IO CBool
+foreign import ccall safe "rl_bindings.h IsImageReady_" c'isImageReady :: Ptr Image -> IO CBool
 
-foreign import ccall safe "bindings.h UnloadImage_" c'unloadImage :: Ptr Raylib.Types.Image -> IO ()
+foreign import ccall safe "rl_bindings.h UnloadImage_" c'unloadImage :: Ptr Raylib.Types.Image -> IO ()
 
-foreign import ccall safe "bindings.h ExportImage_" c'exportImage :: Ptr Raylib.Types.Image -> CString -> IO CBool
+foreign import ccall safe "rl_bindings.h ExportImage_" c'exportImage :: Ptr Raylib.Types.Image -> CString -> IO CBool
 
-foreign import ccall safe "bindings.h ExportImageAsCode_" c'exportImageAsCode :: Ptr Raylib.Types.Image -> CString -> IO CBool
+foreign import ccall safe "rl_bindings.h ExportImageAsCode_" c'exportImageAsCode :: Ptr Raylib.Types.Image -> CString -> IO CBool
 
-foreign import ccall safe "bindings.h GenImageColor_" c'genImageColor :: CInt -> CInt -> Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h GenImageColor_" c'genImageColor :: CInt -> CInt -> Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Image)
 
-foreign import ccall safe "bindings.h GenImageGradientV_" c'genImageGradientV :: CInt -> CInt -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h GenImageGradientV_" c'genImageGradientV :: CInt -> CInt -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Image)
 
-foreign import ccall safe "bindings.h GenImageGradientH_" c'genImageGradientH :: CInt -> CInt -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h GenImageGradientH_" c'genImageGradientH :: CInt -> CInt -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Image)
 
-foreign import ccall safe "bindings.h GenImageGradientRadial_" c'genImageGradientRadial :: CInt -> CInt -> CFloat -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h GenImageGradientRadial_" c'genImageGradientRadial :: CInt -> CInt -> CFloat -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Image)
 
-foreign import ccall safe "bindings.h GenImageChecked_" c'genImageChecked :: CInt -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h GenImageChecked_" c'genImageChecked :: CInt -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Image)
 
-foreign import ccall safe "bindings.h GenImageWhiteNoise_" c'genImageWhiteNoise :: CInt -> CInt -> CFloat -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h GenImageWhiteNoise_" c'genImageWhiteNoise :: CInt -> CInt -> CFloat -> IO (Ptr Raylib.Types.Image)
 
-foreign import ccall safe "bindings.h GenImagePerlinNoise_" c'genImagePerlinNoise :: CInt -> CInt -> CInt -> CInt -> CFloat -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h GenImagePerlinNoise_" c'genImagePerlinNoise :: CInt -> CInt -> CInt -> CInt -> CFloat -> IO (Ptr Raylib.Types.Image)
 
-foreign import ccall safe "bindings.h GenImageCellular_" c'genImageCellular :: CInt -> CInt -> CInt -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h GenImageCellular_" c'genImageCellular :: CInt -> CInt -> CInt -> IO (Ptr Raylib.Types.Image)
 
-foreign import ccall safe "bindings.h GenImageText_" c'genImageText :: CInt -> CInt -> CString -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h GenImageText_" c'genImageText :: CInt -> CInt -> CString -> IO (Ptr Raylib.Types.Image)
 
-foreign import ccall safe "bindings.h ImageCopy_" c'imageCopy :: Ptr Raylib.Types.Image -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h ImageCopy_" c'imageCopy :: Ptr Raylib.Types.Image -> IO (Ptr Raylib.Types.Image)
 
-foreign import ccall safe "bindings.h ImageFromImage_" c'imageFromImage :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Rectangle -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h ImageFromImage_" c'imageFromImage :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Rectangle -> IO (Ptr Raylib.Types.Image)
 
-foreign import ccall safe "bindings.h ImageText_" c'imageText :: CString -> CInt -> Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h ImageText_" c'imageText :: CString -> CInt -> Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Image)
 
-foreign import ccall safe "bindings.h ImageTextEx_" c'imageTextEx :: Ptr Raylib.Types.Font -> CString -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h ImageTextEx_" c'imageTextEx :: Ptr Raylib.Types.Font -> CString -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Image)
 
 foreign import ccall safe "raylib.h ImageFormat"
   c'imageFormat ::
     Ptr Raylib.Types.Image -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h ImageToPOT_" c'imageToPOT :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageToPOT_" c'imageToPOT :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h ImageCrop_" c'imageCrop :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Rectangle -> IO ()
+foreign import ccall safe "rl_bindings.h ImageCrop_" c'imageCrop :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Rectangle -> IO ()
 
 foreign import ccall safe "raylib.h ImageAlphaCrop"
   c'imageAlphaCrop ::
     Ptr Raylib.Types.Image -> CFloat -> IO ()
 
-foreign import ccall safe "bindings.h ImageAlphaClear_" c'imageAlphaClear :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Color -> CFloat -> IO ()
+foreign import ccall safe "rl_bindings.h ImageAlphaClear_" c'imageAlphaClear :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Color -> CFloat -> IO ()
 
-foreign import ccall safe "bindings.h ImageAlphaMask_" c'imageAlphaMask :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Image -> IO ()
+foreign import ccall safe "rl_bindings.h ImageAlphaMask_" c'imageAlphaMask :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Image -> IO ()
 
 foreign import ccall safe "raylib.h ImageAlphaPremultiply"
   c'imageAlphaPremultiply ::
@@ -827,7 +814,7 @@   c'imageResizeNN ::
     Ptr Raylib.Types.Image -> CInt -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h ImageResizeCanvas_" c'imageResizeCanvas :: Ptr Raylib.Types.Image -> CInt -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageResizeCanvas_" c'imageResizeCanvas :: Ptr Raylib.Types.Image -> CInt -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
 foreign import ccall safe "raylib.h ImageMipmaps"
   c'imageMipmaps ::
@@ -853,7 +840,7 @@   c'imageRotateCCW ::
     Ptr Raylib.Types.Image -> IO ()
 
-foreign import ccall safe "bindings.h ImageColorTint_" c'imageColorTint :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageColorTint_" c'imageColorTint :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Color -> IO ()
 
 foreign import ccall safe "raylib.h ImageColorInvert"
   c'imageColorInvert ::
@@ -871,167 +858,167 @@   c'imageColorBrightness ::
     Ptr Raylib.Types.Image -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h ImageColorReplace_" c'imageColorReplace :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageColorReplace_" c'imageColorReplace :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h LoadImageColors_" c'loadImageColors :: Ptr Raylib.Types.Image -> IO (Ptr Raylib.Types.Color)
+foreign import ccall safe "rl_bindings.h LoadImageColors_" c'loadImageColors :: Ptr Raylib.Types.Image -> IO (Ptr Raylib.Types.Color)
 
-foreign import ccall safe "bindings.h LoadImagePalette_" c'loadImagePalette :: Ptr Raylib.Types.Image -> CInt -> Ptr CInt -> IO (Ptr Raylib.Types.Color)
+foreign import ccall safe "rl_bindings.h LoadImagePalette_" c'loadImagePalette :: Ptr Raylib.Types.Image -> CInt -> Ptr CInt -> IO (Ptr Raylib.Types.Color)
 
-foreign import ccall safe "bindings.h GetImageAlphaBorder_" c'getImageAlphaBorder :: Ptr Raylib.Types.Image -> CFloat -> IO (Ptr Raylib.Types.Rectangle)
+foreign import ccall safe "rl_bindings.h GetImageAlphaBorder_" c'getImageAlphaBorder :: Ptr Raylib.Types.Image -> CFloat -> IO (Ptr Raylib.Types.Rectangle)
 
-foreign import ccall safe "bindings.h GetImageColor_" c'getImageColor :: Ptr Raylib.Types.Image -> CInt -> CInt -> IO (Ptr Raylib.Types.Color)
+foreign import ccall safe "rl_bindings.h GetImageColor_" c'getImageColor :: Ptr Raylib.Types.Image -> CInt -> CInt -> IO (Ptr Raylib.Types.Color)
 
-foreign import ccall safe "bindings.h ImageClearBackground_" c'imageClearBackground :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageClearBackground_" c'imageClearBackground :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h ImageDrawPixel_" c'imageDrawPixel :: Ptr Raylib.Types.Image -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageDrawPixel_" c'imageDrawPixel :: Ptr Raylib.Types.Image -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h ImageDrawPixelV_" c'imageDrawPixelV :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageDrawPixelV_" c'imageDrawPixelV :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h ImageDrawLine_" c'imageDrawLine :: Ptr Raylib.Types.Image -> CInt -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageDrawLine_" c'imageDrawLine :: Ptr Raylib.Types.Image -> CInt -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h ImageDrawLineV_" c'imageDrawLineV :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageDrawLineV_" c'imageDrawLineV :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h ImageDrawCircle_" c'imageDrawCircle :: Ptr Raylib.Types.Image -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageDrawCircle_" c'imageDrawCircle :: Ptr Raylib.Types.Image -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h ImageDrawCircleV_" c'imageDrawCircleV :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Vector2 -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageDrawCircleV_" c'imageDrawCircleV :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Vector2 -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h ImageDrawCircleLines_" c'imageDrawCircleLines :: Ptr Raylib.Types.Image -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageDrawCircleLines_" c'imageDrawCircleLines :: Ptr Raylib.Types.Image -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h ImageDrawCircleLinesV_" c'imageDrawCircleLinesV :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Vector2 -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageDrawCircleLinesV_" c'imageDrawCircleLinesV :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Vector2 -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h ImageDrawRectangle_" c'imageDrawRectangle :: Ptr Raylib.Types.Image -> CInt -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageDrawRectangle_" c'imageDrawRectangle :: Ptr Raylib.Types.Image -> CInt -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h ImageDrawRectangleV_" c'imageDrawRectangleV :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageDrawRectangleV_" c'imageDrawRectangleV :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h ImageDrawRectangleRec_" c'imageDrawRectangleRec :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageDrawRectangleRec_" c'imageDrawRectangleRec :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h ImageDrawRectangleLines_" c'imageDrawRectangleLines :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Rectangle -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageDrawRectangleLines_" c'imageDrawRectangleLines :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Rectangle -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h ImageDraw_" c'imageDraw :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Image -> Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageDraw_" c'imageDraw :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Image -> Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h ImageDrawText_" c'imageDrawText :: Ptr Raylib.Types.Image -> CString -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageDrawText_" c'imageDrawText :: Ptr Raylib.Types.Image -> CString -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h ImageDrawTextEx_" c'imageDrawTextEx :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Font -> CString -> Ptr Raylib.Types.Vector2 -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h ImageDrawTextEx_" c'imageDrawTextEx :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Font -> CString -> Ptr Raylib.Types.Vector2 -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h LoadTexture_" c'loadTexture :: CString -> IO (Ptr Raylib.Types.Texture)
+foreign import ccall safe "rl_bindings.h LoadTexture_" c'loadTexture :: CString -> IO (Ptr Raylib.Types.Texture)
 
-foreign import ccall safe "bindings.h LoadTextureFromImage_" c'loadTextureFromImage :: Ptr Raylib.Types.Image -> IO (Ptr Raylib.Types.Texture)
+foreign import ccall safe "rl_bindings.h LoadTextureFromImage_" c'loadTextureFromImage :: Ptr Raylib.Types.Image -> IO (Ptr Raylib.Types.Texture)
 
-foreign import ccall safe "bindings.h LoadTextureCubemap_" c'loadTextureCubemap :: Ptr Raylib.Types.Image -> CInt -> IO (Ptr Raylib.Types.Texture)
+foreign import ccall safe "rl_bindings.h LoadTextureCubemap_" c'loadTextureCubemap :: Ptr Raylib.Types.Image -> CInt -> IO (Ptr Raylib.Types.Texture)
 
-foreign import ccall safe "bindings.h LoadRenderTexture_" c'loadRenderTexture :: CInt -> CInt -> IO (Ptr Raylib.Types.RenderTexture)
+foreign import ccall safe "rl_bindings.h LoadRenderTexture_" c'loadRenderTexture :: CInt -> CInt -> IO (Ptr Raylib.Types.RenderTexture)
 
-foreign import ccall safe "bindings.h IsTextureReady_" c'isTextureReady :: Ptr Texture -> IO CBool
+foreign import ccall safe "rl_bindings.h IsTextureReady_" c'isTextureReady :: Ptr Texture -> IO CBool
 
-foreign import ccall safe "bindings.h UnloadTexture_" c'unloadTexture :: Ptr Raylib.Types.Texture -> IO ()
+foreign import ccall safe "rl_bindings.h UnloadTexture_" c'unloadTexture :: Ptr Raylib.Types.Texture -> IO ()
 
-foreign import ccall safe "bindings.h IsRenderTextureReady_" c'isRenderTextureReady :: Ptr RenderTexture -> IO CBool
+foreign import ccall safe "rl_bindings.h IsRenderTextureReady_" c'isRenderTextureReady :: Ptr RenderTexture -> IO CBool
 
-foreign import ccall safe "bindings.h UnloadRenderTexture_" c'unloadRenderTexture :: Ptr Raylib.Types.RenderTexture -> IO ()
+foreign import ccall safe "rl_bindings.h UnloadRenderTexture_" c'unloadRenderTexture :: Ptr Raylib.Types.RenderTexture -> IO ()
 
-foreign import ccall safe "bindings.h UpdateTexture_" c'updateTexture :: Ptr Raylib.Types.Texture -> Ptr () -> IO ()
+foreign import ccall safe "rl_bindings.h UpdateTexture_" c'updateTexture :: Ptr Raylib.Types.Texture -> Ptr () -> IO ()
 
-foreign import ccall safe "bindings.h UpdateTextureRec_" c'updateTextureRec :: Ptr Raylib.Types.Texture -> Ptr Raylib.Types.Rectangle -> Ptr () -> IO ()
+foreign import ccall safe "rl_bindings.h UpdateTextureRec_" c'updateTextureRec :: Ptr Raylib.Types.Texture -> Ptr Raylib.Types.Rectangle -> Ptr () -> IO ()
 
 foreign import ccall safe "raylib.h GenTextureMipmaps"
   c'genTextureMipmaps ::
     Ptr Raylib.Types.Texture -> IO ()
 
-foreign import ccall safe "bindings.h SetTextureFilter_" c'setTextureFilter :: Ptr Raylib.Types.Texture -> CInt -> IO ()
+foreign import ccall safe "rl_bindings.h SetTextureFilter_" c'setTextureFilter :: Ptr Raylib.Types.Texture -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h SetTextureWrap_" c'setTextureWrap :: Ptr Raylib.Types.Texture -> CInt -> IO ()
+foreign import ccall safe "rl_bindings.h SetTextureWrap_" c'setTextureWrap :: Ptr Raylib.Types.Texture -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h DrawTexture_" c'drawTexture :: Ptr Raylib.Types.Texture -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawTexture_" c'drawTexture :: Ptr Raylib.Types.Texture -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawTextureV_" c'drawTextureV :: Ptr Raylib.Types.Texture -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawTextureV_" c'drawTextureV :: Ptr Raylib.Types.Texture -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawTextureEx_" c'drawTextureEx :: Ptr Raylib.Types.Texture -> Ptr Raylib.Types.Vector2 -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawTextureEx_" c'drawTextureEx :: Ptr Raylib.Types.Texture -> Ptr Raylib.Types.Vector2 -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawTextureRec_" c'drawTextureRec :: Ptr Raylib.Types.Texture -> Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawTextureRec_" c'drawTextureRec :: Ptr Raylib.Types.Texture -> Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawTexturePro_" c'drawTexturePro :: Ptr Raylib.Types.Texture -> Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawTexturePro_" c'drawTexturePro :: Ptr Raylib.Types.Texture -> Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawTextureNPatch_" c'drawTextureNPatch :: Ptr Raylib.Types.Texture -> Ptr Raylib.Types.NPatchInfo -> Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawTextureNPatch_" c'drawTextureNPatch :: Ptr Raylib.Types.Texture -> Ptr Raylib.Types.NPatchInfo -> Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h Fade_" c'fade :: Ptr Raylib.Types.Color -> CFloat -> IO (Ptr Raylib.Types.Color)
+foreign import ccall safe "rl_bindings.h Fade_" c'fade :: Ptr Raylib.Types.Color -> CFloat -> IO (Ptr Raylib.Types.Color)
 
-foreign import ccall safe "bindings.h ColorToInt_" c'colorToInt :: Ptr Raylib.Types.Color -> IO CInt
+foreign import ccall safe "rl_bindings.h ColorToInt_" c'colorToInt :: Ptr Raylib.Types.Color -> IO CInt
 
-foreign import ccall safe "bindings.h ColorNormalize_" c'colorNormalize :: Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Vector4)
+foreign import ccall safe "rl_bindings.h ColorNormalize_" c'colorNormalize :: Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Vector4)
 
-foreign import ccall safe "bindings.h ColorFromNormalized_" c'colorFromNormalized :: Ptr Raylib.Types.Vector4 -> IO (Ptr Raylib.Types.Color)
+foreign import ccall safe "rl_bindings.h ColorFromNormalized_" c'colorFromNormalized :: Ptr Raylib.Types.Vector4 -> IO (Ptr Raylib.Types.Color)
 
-foreign import ccall safe "bindings.h ColorToHSV_" c'colorToHSV :: Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Vector3)
+foreign import ccall safe "rl_bindings.h ColorToHSV_" c'colorToHSV :: Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Vector3)
 
-foreign import ccall safe "bindings.h ColorFromHSV_" c'colorFromHSV :: CFloat -> CFloat -> CFloat -> IO (Ptr Raylib.Types.Color)
+foreign import ccall safe "rl_bindings.h ColorFromHSV_" c'colorFromHSV :: CFloat -> CFloat -> CFloat -> IO (Ptr Raylib.Types.Color)
 
-foreign import ccall safe "bindings.h ColorTint_" c'colorTint :: Ptr Color -> Ptr Color -> IO (Ptr Raylib.Types.Color)
+foreign import ccall safe "rl_bindings.h ColorTint_" c'colorTint :: Ptr Color -> Ptr Color -> IO (Ptr Raylib.Types.Color)
 
-foreign import ccall safe "bindings.h ColorBrightness_" c'colorBrightness :: Ptr Color -> CFloat -> IO (Ptr Raylib.Types.Color)
+foreign import ccall safe "rl_bindings.h ColorBrightness_" c'colorBrightness :: Ptr Color -> CFloat -> IO (Ptr Raylib.Types.Color)
 
-foreign import ccall safe "bindings.h ColorContrast_" c'colorContrast :: Ptr Color -> CFloat -> IO (Ptr Raylib.Types.Color)
+foreign import ccall safe "rl_bindings.h ColorContrast_" c'colorContrast :: Ptr Color -> CFloat -> IO (Ptr Raylib.Types.Color)
 
-foreign import ccall safe "bindings.h ColorAlpha_" c'colorAlpha :: Ptr Raylib.Types.Color -> CFloat -> IO (Ptr Raylib.Types.Color)
+foreign import ccall safe "rl_bindings.h ColorAlpha_" c'colorAlpha :: Ptr Raylib.Types.Color -> CFloat -> IO (Ptr Raylib.Types.Color)
 
-foreign import ccall safe "bindings.h ColorAlphaBlend_" c'colorAlphaBlend :: Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Color)
+foreign import ccall safe "rl_bindings.h ColorAlphaBlend_" c'colorAlphaBlend :: Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> Ptr Raylib.Types.Color -> IO (Ptr Raylib.Types.Color)
 
-foreign import ccall safe "bindings.h GetColor_" c'getColor :: CUInt -> IO (Ptr Raylib.Types.Color)
+foreign import ccall safe "rl_bindings.h GetColor_" c'getColor :: CUInt -> IO (Ptr Raylib.Types.Color)
 
-foreign import ccall safe "bindings.h GetPixelColor_" c'getPixelColor :: Ptr () -> CInt -> IO (Ptr Raylib.Types.Color)
+foreign import ccall safe "rl_bindings.h GetPixelColor_" c'getPixelColor :: Ptr () -> CInt -> IO (Ptr Raylib.Types.Color)
 
-foreign import ccall safe "bindings.h SetPixelColor_" c'setPixelColor :: Ptr () -> Ptr Raylib.Types.Color -> CInt -> IO ()
+foreign import ccall safe "rl_bindings.h SetPixelColor_" c'setPixelColor :: Ptr () -> Ptr Raylib.Types.Color -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h GetFontDefault_" c'getFontDefault :: IO (Ptr Raylib.Types.Font)
+foreign import ccall safe "rl_bindings.h GetFontDefault_" c'getFontDefault :: IO (Ptr Raylib.Types.Font)
 
-foreign import ccall safe "bindings.h LoadFont_" c'loadFont :: CString -> IO (Ptr Raylib.Types.Font)
+foreign import ccall safe "rl_bindings.h LoadFont_" c'loadFont :: CString -> IO (Ptr Raylib.Types.Font)
 
-foreign import ccall safe "bindings.h LoadFontEx_" c'loadFontEx :: CString -> CInt -> Ptr CInt -> CInt -> IO (Ptr Raylib.Types.Font)
+foreign import ccall safe "rl_bindings.h LoadFontEx_" c'loadFontEx :: CString -> CInt -> Ptr CInt -> CInt -> IO (Ptr Raylib.Types.Font)
 
-foreign import ccall safe "bindings.h LoadFontFromImage_" c'loadFontFromImage :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Color -> CInt -> IO (Ptr Raylib.Types.Font)
+foreign import ccall safe "rl_bindings.h LoadFontFromImage_" c'loadFontFromImage :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Color -> CInt -> IO (Ptr Raylib.Types.Font)
 
-foreign import ccall safe "bindings.h LoadFontFromMemory_" c'loadFontFromMemory :: CString -> Ptr CUChar -> CInt -> CInt -> Ptr CInt -> CInt -> IO (Ptr Raylib.Types.Font)
+foreign import ccall safe "rl_bindings.h LoadFontFromMemory_" c'loadFontFromMemory :: CString -> Ptr CUChar -> CInt -> CInt -> Ptr CInt -> CInt -> IO (Ptr Raylib.Types.Font)
 
 foreign import ccall safe "raylib.h LoadFontData"
   c'loadFontData ::
     Ptr CUChar -> CInt -> CInt -> Ptr CInt -> CInt -> CInt -> IO (Ptr Raylib.Types.GlyphInfo)
 
-foreign import ccall safe "bindings.h GenImageFontAtlas_" c'genImageFontAtlas :: Ptr Raylib.Types.GlyphInfo -> Ptr (Ptr Raylib.Types.Rectangle) -> CInt -> CInt -> CInt -> CInt -> IO (Ptr Raylib.Types.Image)
+foreign import ccall safe "rl_bindings.h GenImageFontAtlas_" c'genImageFontAtlas :: Ptr Raylib.Types.GlyphInfo -> Ptr (Ptr Raylib.Types.Rectangle) -> CInt -> CInt -> CInt -> CInt -> IO (Ptr Raylib.Types.Image)
 
 foreign import ccall safe "raylib.h UnloadFontData"
   c'unloadFontData ::
     Ptr Raylib.Types.GlyphInfo -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h IsFontReady_" c'isFontReady :: Ptr Raylib.Types.Font -> IO CBool
+foreign import ccall safe "rl_bindings.h IsFontReady_" c'isFontReady :: Ptr Raylib.Types.Font -> IO CBool
 
-foreign import ccall safe "bindings.h UnloadFont_" c'unloadFont :: Ptr Raylib.Types.Font -> IO ()
+foreign import ccall safe "rl_bindings.h UnloadFont_" c'unloadFont :: Ptr Raylib.Types.Font -> IO ()
 
-foreign import ccall safe "bindings.h ExportFontAsCode_" c'exportFontAsCode :: Ptr Raylib.Types.Font -> CString -> IO CBool
+foreign import ccall safe "rl_bindings.h ExportFontAsCode_" c'exportFontAsCode :: Ptr Raylib.Types.Font -> CString -> IO CBool
 
 foreign import ccall safe "raylib.h DrawFPS"
   c'drawFPS ::
     CInt -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h DrawText_" c'drawText :: CString -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawText_" c'drawText :: CString -> CInt -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawTextEx_" c'drawTextEx :: Ptr Raylib.Types.Font -> CString -> Ptr Raylib.Types.Vector2 -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawTextEx_" c'drawTextEx :: Ptr Raylib.Types.Font -> CString -> Ptr Raylib.Types.Vector2 -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawTextPro_" c'drawTextPro :: Ptr Raylib.Types.Font -> CString -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> CFloat -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawTextPro_" c'drawTextPro :: Ptr Raylib.Types.Font -> CString -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> CFloat -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawTextCodepoint_" c'drawTextCodepoint :: Ptr Raylib.Types.Font -> CInt -> Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawTextCodepoint_" c'drawTextCodepoint :: Ptr Raylib.Types.Font -> CInt -> Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawTextCodepoints_" c'drawTextCodepoints :: Ptr Raylib.Types.Font -> Ptr CInt -> CInt -> Ptr Raylib.Types.Vector2 -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawTextCodepoints_" c'drawTextCodepoints :: Ptr Raylib.Types.Font -> Ptr CInt -> CInt -> Ptr Raylib.Types.Vector2 -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
 foreign import ccall safe "raylib.h MeasureText"
   c'measureText ::
     CString -> CInt -> IO CInt
 
-foreign import ccall safe "bindings.h MeasureTextEx_" c'measureTextEx :: Ptr Raylib.Types.Font -> CString -> CFloat -> CFloat -> IO (Ptr Raylib.Types.Vector2)
+foreign import ccall safe "rl_bindings.h MeasureTextEx_" c'measureTextEx :: Ptr Raylib.Types.Font -> CString -> CFloat -> CFloat -> IO (Ptr Raylib.Types.Vector2)
 
-foreign import ccall safe "bindings.h GetGlyphIndex_" c'getGlyphIndex :: Ptr Raylib.Types.Font -> CInt -> IO CInt
+foreign import ccall safe "rl_bindings.h GetGlyphIndex_" c'getGlyphIndex :: Ptr Raylib.Types.Font -> CInt -> IO CInt
 
-foreign import ccall safe "bindings.h GetGlyphInfo_" c'getGlyphInfo :: Ptr Raylib.Types.Font -> CInt -> IO (Ptr Raylib.Types.GlyphInfo)
+foreign import ccall safe "rl_bindings.h GetGlyphInfo_" c'getGlyphInfo :: Ptr Raylib.Types.Font -> CInt -> IO (Ptr Raylib.Types.GlyphInfo)
 
-foreign import ccall safe "bindings.h GetGlyphAtlasRec_" c'getGlyphAtlasRec :: Ptr Raylib.Types.Font -> CInt -> IO (Ptr Raylib.Types.Rectangle)
+foreign import ccall safe "rl_bindings.h GetGlyphAtlasRec_" c'getGlyphAtlasRec :: Ptr Raylib.Types.Font -> CInt -> IO (Ptr Raylib.Types.Rectangle)
 
 foreign import ccall safe "raylib.h LoadUTF8"
   c'loadUTF8 ::
@@ -1135,131 +1122,131 @@ -- foreign import ccall safe "raylib.h TextToInteger"
 --   textToInteger ::
 --     CString -> IO CInt
-foreign import ccall safe "bindings.h DrawLine3D_" c'drawLine3D :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawLine3D_" c'drawLine3D :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawPoint3D_" c'drawPoint3D :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawPoint3D_" c'drawPoint3D :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawCircle3D_" c'drawCircle3D :: Ptr Raylib.Types.Vector3 -> CFloat -> Ptr Raylib.Types.Vector3 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawCircle3D_" c'drawCircle3D :: Ptr Raylib.Types.Vector3 -> CFloat -> Ptr Raylib.Types.Vector3 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawTriangle3D_" c'drawTriangle3D :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawTriangle3D_" c'drawTriangle3D :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawTriangleStrip3D_" c'drawTriangleStrip3D :: Ptr Raylib.Types.Vector3 -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawTriangleStrip3D_" c'drawTriangleStrip3D :: Ptr Raylib.Types.Vector3 -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawCube_" c'drawCube :: Ptr Raylib.Types.Vector3 -> CFloat -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawCube_" c'drawCube :: Ptr Raylib.Types.Vector3 -> CFloat -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawCubeV_" c'drawCubeV :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawCubeV_" c'drawCubeV :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawCubeWires_" c'drawCubeWires :: Ptr Raylib.Types.Vector3 -> CFloat -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawCubeWires_" c'drawCubeWires :: Ptr Raylib.Types.Vector3 -> CFloat -> CFloat -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawCubeWiresV_" c'drawCubeWiresV :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawCubeWiresV_" c'drawCubeWiresV :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawSphere_" c'drawSphere :: Ptr Raylib.Types.Vector3 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawSphere_" c'drawSphere :: Ptr Raylib.Types.Vector3 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawSphereEx_" c'drawSphereEx :: Ptr Raylib.Types.Vector3 -> CFloat -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawSphereEx_" c'drawSphereEx :: Ptr Raylib.Types.Vector3 -> CFloat -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawSphereWires_" c'drawSphereWires :: Ptr Raylib.Types.Vector3 -> CFloat -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawSphereWires_" c'drawSphereWires :: Ptr Raylib.Types.Vector3 -> CFloat -> CInt -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawCylinder_" c'drawCylinder :: Ptr Raylib.Types.Vector3 -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawCylinder_" c'drawCylinder :: Ptr Raylib.Types.Vector3 -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawCylinderEx_" c'drawCylinderEx :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> CFloat -> CFloat -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawCylinderEx_" c'drawCylinderEx :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> CFloat -> CFloat -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawCylinderWires_" c'drawCylinderWires :: Ptr Raylib.Types.Vector3 -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawCylinderWires_" c'drawCylinderWires :: Ptr Raylib.Types.Vector3 -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawCylinderWiresEx_" c'drawCylinderWiresEx :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> CFloat -> CFloat -> CInt -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawCylinderWiresEx_" c'drawCylinderWiresEx :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> CFloat -> CFloat -> CInt -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawCapsule_" c'drawCapsule :: Ptr Vector3 -> Ptr Vector3 -> CFloat -> CInt -> CInt -> Ptr Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawCapsule_" c'drawCapsule :: Ptr Vector3 -> Ptr Vector3 -> CFloat -> CInt -> CInt -> Ptr Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawCapsuleWires_" c'drawCapsuleWires :: Ptr Vector3 -> Ptr Vector3 -> CFloat -> CInt -> CInt -> Ptr Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawCapsuleWires_" c'drawCapsuleWires :: Ptr Vector3 -> Ptr Vector3 -> CFloat -> CInt -> CInt -> Ptr Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawPlane_" c'drawPlane :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawPlane_" c'drawPlane :: Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawRay_" c'drawRay :: Ptr Raylib.Types.Ray -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawRay_" c'drawRay :: Ptr Raylib.Types.Ray -> Ptr Raylib.Types.Color -> IO ()
 
 foreign import ccall safe "raylib.h DrawGrid"
   c'drawGrid ::
     CInt -> CFloat -> IO ()
 
-foreign import ccall safe "bindings.h LoadModel_" c'loadModel :: CString -> IO (Ptr Raylib.Types.Model)
+foreign import ccall safe "rl_bindings.h LoadModel_" c'loadModel :: CString -> IO (Ptr Raylib.Types.Model)
 
-foreign import ccall safe "bindings.h LoadModelFromMesh_" c'loadModelFromMesh :: Ptr Raylib.Types.Mesh -> IO (Ptr Raylib.Types.Model)
+foreign import ccall safe "rl_bindings.h LoadModelFromMesh_" c'loadModelFromMesh :: Ptr Raylib.Types.Mesh -> IO (Ptr Raylib.Types.Model)
 
-foreign import ccall safe "bindings.h IsModelReady_" c'isModelReady :: Ptr Raylib.Types.Model -> IO CBool
+foreign import ccall safe "rl_bindings.h IsModelReady_" c'isModelReady :: Ptr Raylib.Types.Model -> IO CBool
 
-foreign import ccall safe "bindings.h UnloadModel_" c'unloadModel :: Ptr Raylib.Types.Model -> IO ()
+foreign import ccall safe "rl_bindings.h UnloadModel_" c'unloadModel :: Ptr Raylib.Types.Model -> IO ()
 
-foreign import ccall safe "bindings.h UnloadModelKeepMeshes_" c'unloadModelKeepMeshes :: Ptr Raylib.Types.Model -> IO ()
+foreign import ccall safe "rl_bindings.h UnloadModelKeepMeshes_" c'unloadModelKeepMeshes :: Ptr Raylib.Types.Model -> IO ()
 
-foreign import ccall safe "bindings.h GetModelBoundingBox_" c'getModelBoundingBox :: Ptr Raylib.Types.Model -> IO (Ptr Raylib.Types.BoundingBox)
+foreign import ccall safe "rl_bindings.h GetModelBoundingBox_" c'getModelBoundingBox :: Ptr Raylib.Types.Model -> IO (Ptr Raylib.Types.BoundingBox)
 
-foreign import ccall safe "bindings.h DrawModel_" c'drawModel :: Ptr Raylib.Types.Model -> Ptr Raylib.Types.Vector3 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawModel_" c'drawModel :: Ptr Raylib.Types.Model -> Ptr Raylib.Types.Vector3 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawModelEx_" c'drawModelEx :: Ptr Raylib.Types.Model -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> CFloat -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawModelEx_" c'drawModelEx :: Ptr Raylib.Types.Model -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> CFloat -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawModelWires_" c'drawModelWires :: Ptr Raylib.Types.Model -> Ptr Raylib.Types.Vector3 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawModelWires_" c'drawModelWires :: Ptr Raylib.Types.Model -> Ptr Raylib.Types.Vector3 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawModelWiresEx_" c'drawModelWiresEx :: Ptr Raylib.Types.Model -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> CFloat -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawModelWiresEx_" c'drawModelWiresEx :: Ptr Raylib.Types.Model -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> CFloat -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawBoundingBox_" c'drawBoundingBox :: Ptr Raylib.Types.BoundingBox -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawBoundingBox_" c'drawBoundingBox :: Ptr Raylib.Types.BoundingBox -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawBillboard_" c'drawBillboard :: Ptr Raylib.Types.Camera3D -> Ptr Raylib.Types.Texture -> Ptr Raylib.Types.Vector3 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawBillboard_" c'drawBillboard :: Ptr Raylib.Types.Camera3D -> Ptr Raylib.Types.Texture -> Ptr Raylib.Types.Vector3 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawBillboardRec_" c'drawBillboardRec :: Ptr Raylib.Types.Camera3D -> Ptr Raylib.Types.Texture -> Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawBillboardRec_" c'drawBillboardRec :: Ptr Raylib.Types.Camera3D -> Ptr Raylib.Types.Texture -> Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Color -> IO ()
 
-foreign import ccall safe "bindings.h DrawBillboardPro_" c'drawBillboardPro :: Ptr Raylib.Types.Camera3D -> Ptr Raylib.Types.Texture -> Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
+foreign import ccall safe "rl_bindings.h DrawBillboardPro_" c'drawBillboardPro :: Ptr Raylib.Types.Camera3D -> Ptr Raylib.Types.Texture -> Ptr Raylib.Types.Rectangle -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector2 -> Ptr Raylib.Types.Vector2 -> CFloat -> Ptr Raylib.Types.Color -> IO ()
 
 foreign import ccall safe "raylib.h UploadMesh"
   c'uploadMesh ::
     Ptr Raylib.Types.Mesh -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h UpdateMeshBuffer_" c'updateMeshBuffer :: Ptr Raylib.Types.Mesh -> CInt -> Ptr () -> CInt -> CInt -> IO ()
+foreign import ccall safe "rl_bindings.h UpdateMeshBuffer_" c'updateMeshBuffer :: Ptr Raylib.Types.Mesh -> CInt -> Ptr () -> CInt -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h UnloadMesh_" c'unloadMesh :: Ptr Raylib.Types.Mesh -> IO ()
+foreign import ccall safe "rl_bindings.h UnloadMesh_" c'unloadMesh :: Ptr Raylib.Types.Mesh -> IO ()
 
-foreign import ccall safe "bindings.h DrawMesh_" c'drawMesh :: Ptr Raylib.Types.Mesh -> Ptr Raylib.Types.Material -> Ptr Raylib.Types.Matrix -> IO ()
+foreign import ccall safe "rl_bindings.h DrawMesh_" c'drawMesh :: Ptr Raylib.Types.Mesh -> Ptr Raylib.Types.Material -> Ptr Raylib.Types.Matrix -> IO ()
 
-foreign import ccall safe "bindings.h DrawMeshInstanced_" c'drawMeshInstanced :: Ptr Raylib.Types.Mesh -> Ptr Raylib.Types.Material -> Ptr Raylib.Types.Matrix -> CInt -> IO ()
+foreign import ccall safe "rl_bindings.h DrawMeshInstanced_" c'drawMeshInstanced :: Ptr Raylib.Types.Mesh -> Ptr Raylib.Types.Material -> Ptr Raylib.Types.Matrix -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h ExportMesh_" c'exportMesh :: Ptr Raylib.Types.Mesh -> CString -> IO CBool
+foreign import ccall safe "rl_bindings.h ExportMesh_" c'exportMesh :: Ptr Raylib.Types.Mesh -> CString -> IO CBool
 
-foreign import ccall safe "bindings.h GetMeshBoundingBox_" c'getMeshBoundingBox :: Ptr Raylib.Types.Mesh -> IO (Ptr Raylib.Types.BoundingBox)
+foreign import ccall safe "rl_bindings.h GetMeshBoundingBox_" c'getMeshBoundingBox :: Ptr Raylib.Types.Mesh -> IO (Ptr Raylib.Types.BoundingBox)
 
 foreign import ccall safe "raylib.h GenMeshTangents"
   c'genMeshTangents ::
     Ptr Raylib.Types.Mesh -> IO ()
 
-foreign import ccall safe "bindings.h GenMeshPoly_" c'genMeshPoly :: CInt -> CFloat -> IO (Ptr Raylib.Types.Mesh)
+foreign import ccall safe "rl_bindings.h GenMeshPoly_" c'genMeshPoly :: CInt -> CFloat -> IO (Ptr Raylib.Types.Mesh)
 
-foreign import ccall safe "bindings.h GenMeshPlane_" c'genMeshPlane :: CFloat -> CFloat -> CInt -> CInt -> IO (Ptr Raylib.Types.Mesh)
+foreign import ccall safe "rl_bindings.h GenMeshPlane_" c'genMeshPlane :: CFloat -> CFloat -> CInt -> CInt -> IO (Ptr Raylib.Types.Mesh)
 
-foreign import ccall safe "bindings.h GenMeshCube_" c'genMeshCube :: CFloat -> CFloat -> CFloat -> IO (Ptr Raylib.Types.Mesh)
+foreign import ccall safe "rl_bindings.h GenMeshCube_" c'genMeshCube :: CFloat -> CFloat -> CFloat -> IO (Ptr Raylib.Types.Mesh)
 
-foreign import ccall safe "bindings.h GenMeshSphere_" c'genMeshSphere :: CFloat -> CInt -> CInt -> IO (Ptr Raylib.Types.Mesh)
+foreign import ccall safe "rl_bindings.h GenMeshSphere_" c'genMeshSphere :: CFloat -> CInt -> CInt -> IO (Ptr Raylib.Types.Mesh)
 
-foreign import ccall safe "bindings.h GenMeshHemiSphere_" c'genMeshHemiSphere :: CFloat -> CInt -> CInt -> IO (Ptr Raylib.Types.Mesh)
+foreign import ccall safe "rl_bindings.h GenMeshHemiSphere_" c'genMeshHemiSphere :: CFloat -> CInt -> CInt -> IO (Ptr Raylib.Types.Mesh)
 
-foreign import ccall safe "bindings.h GenMeshCylinder_" c'genMeshCylinder :: CFloat -> CFloat -> CInt -> IO (Ptr Raylib.Types.Mesh)
+foreign import ccall safe "rl_bindings.h GenMeshCylinder_" c'genMeshCylinder :: CFloat -> CFloat -> CInt -> IO (Ptr Raylib.Types.Mesh)
 
-foreign import ccall safe "bindings.h GenMeshCone_" c'genMeshCone :: CFloat -> CFloat -> CInt -> IO (Ptr Raylib.Types.Mesh)
+foreign import ccall safe "rl_bindings.h GenMeshCone_" c'genMeshCone :: CFloat -> CFloat -> CInt -> IO (Ptr Raylib.Types.Mesh)
 
-foreign import ccall safe "bindings.h GenMeshTorus_" c'genMeshTorus :: CFloat -> CFloat -> CInt -> CInt -> IO (Ptr Raylib.Types.Mesh)
+foreign import ccall safe "rl_bindings.h GenMeshTorus_" c'genMeshTorus :: CFloat -> CFloat -> CInt -> CInt -> IO (Ptr Raylib.Types.Mesh)
 
-foreign import ccall safe "bindings.h GenMeshKnot_" c'genMeshKnot :: CFloat -> CFloat -> CInt -> CInt -> IO (Ptr Raylib.Types.Mesh)
+foreign import ccall safe "rl_bindings.h GenMeshKnot_" c'genMeshKnot :: CFloat -> CFloat -> CInt -> CInt -> IO (Ptr Raylib.Types.Mesh)
 
-foreign import ccall safe "bindings.h GenMeshHeightmap_" c'genMeshHeightmap :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Vector3 -> IO (Ptr Raylib.Types.Mesh)
+foreign import ccall safe "rl_bindings.h GenMeshHeightmap_" c'genMeshHeightmap :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Vector3 -> IO (Ptr Raylib.Types.Mesh)
 
-foreign import ccall safe "bindings.h GenMeshCubicmap_" c'genMeshCubicmap :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Vector3 -> IO (Ptr Raylib.Types.Mesh)
+foreign import ccall safe "rl_bindings.h GenMeshCubicmap_" c'genMeshCubicmap :: Ptr Raylib.Types.Image -> Ptr Raylib.Types.Vector3 -> IO (Ptr Raylib.Types.Mesh)
 
 foreign import ccall safe "raylib.h LoadMaterials"
   c'loadMaterials ::
     CString -> Ptr CInt -> IO (Ptr Raylib.Types.Material)
 
-foreign import ccall safe "bindings.h LoadMaterialDefault_" c'loadMaterialDefault :: IO (Ptr Raylib.Types.Material)
+foreign import ccall safe "rl_bindings.h LoadMaterialDefault_" c'loadMaterialDefault :: IO (Ptr Raylib.Types.Material)
 
-foreign import ccall safe "bindings.h IsMaterialReady_" c'isMaterialReady :: Ptr Raylib.Types.Material -> IO CBool
+foreign import ccall safe "rl_bindings.h IsMaterialReady_" c'isMaterialReady :: Ptr Raylib.Types.Material -> IO CBool
 
-foreign import ccall safe "bindings.h UnloadMaterial_" c'unloadMaterial :: Ptr Raylib.Types.Material -> IO ()
+foreign import ccall safe "rl_bindings.h UnloadMaterial_" c'unloadMaterial :: Ptr Raylib.Types.Material -> IO ()
 
-foreign import ccall safe "bindings.h SetMaterialTexture_" c'setMaterialTexture :: Ptr Raylib.Types.Material -> CInt -> Ptr Raylib.Types.Texture -> IO ()
+foreign import ccall safe "rl_bindings.h SetMaterialTexture_" c'setMaterialTexture :: Ptr Raylib.Types.Material -> CInt -> Ptr Raylib.Types.Texture -> IO ()
 
 foreign import ccall safe "raylib.h SetModelMeshMaterial"
   c'setModelMeshMaterial ::
@@ -1269,31 +1256,31 @@   c'loadModelAnimations ::
     CString -> Ptr CUInt -> IO (Ptr Raylib.Types.ModelAnimation)
 
-foreign import ccall safe "bindings.h UpdateModelAnimation_" c'updateModelAnimation :: Ptr Raylib.Types.Model -> Ptr Raylib.Types.ModelAnimation -> CInt -> IO ()
+foreign import ccall safe "rl_bindings.h UpdateModelAnimation_" c'updateModelAnimation :: Ptr Raylib.Types.Model -> Ptr Raylib.Types.ModelAnimation -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h UnloadModelAnimation_" c'unloadModelAnimation :: Ptr Raylib.Types.ModelAnimation -> IO ()
+foreign import ccall safe "rl_bindings.h UnloadModelAnimation_" c'unloadModelAnimation :: Ptr Raylib.Types.ModelAnimation -> IO ()
 
 foreign import ccall safe "raylib.h UnloadModelAnimations"
   c'unloadModelAnimations ::
     Ptr Raylib.Types.ModelAnimation -> CUInt -> IO ()
 
-foreign import ccall safe "bindings.h IsModelAnimationValid_" c'isModelAnimationValid :: Ptr Raylib.Types.Model -> Ptr Raylib.Types.ModelAnimation -> IO CBool
+foreign import ccall safe "rl_bindings.h IsModelAnimationValid_" c'isModelAnimationValid :: Ptr Raylib.Types.Model -> Ptr Raylib.Types.ModelAnimation -> IO CBool
 
-foreign import ccall safe "bindings.h CheckCollisionSpheres_" c'checkCollisionSpheres :: Ptr Raylib.Types.Vector3 -> CFloat -> Ptr Raylib.Types.Vector3 -> CFloat -> IO CBool
+foreign import ccall safe "rl_bindings.h CheckCollisionSpheres_" c'checkCollisionSpheres :: Ptr Raylib.Types.Vector3 -> CFloat -> Ptr Raylib.Types.Vector3 -> CFloat -> IO CBool
 
-foreign import ccall safe "bindings.h CheckCollisionBoxes_" c'checkCollisionBoxes :: Ptr Raylib.Types.BoundingBox -> Ptr Raylib.Types.BoundingBox -> IO CBool
+foreign import ccall safe "rl_bindings.h CheckCollisionBoxes_" c'checkCollisionBoxes :: Ptr Raylib.Types.BoundingBox -> Ptr Raylib.Types.BoundingBox -> IO CBool
 
-foreign import ccall safe "bindings.h CheckCollisionBoxSphere_" c'checkCollisionBoxSphere :: Ptr Raylib.Types.BoundingBox -> Ptr Raylib.Types.Vector3 -> CFloat -> IO CBool
+foreign import ccall safe "rl_bindings.h CheckCollisionBoxSphere_" c'checkCollisionBoxSphere :: Ptr Raylib.Types.BoundingBox -> Ptr Raylib.Types.Vector3 -> CFloat -> IO CBool
 
-foreign import ccall safe "bindings.h GetRayCollisionSphere_" c'getRayCollisionSphere :: Ptr Raylib.Types.Ray -> Ptr Raylib.Types.Vector3 -> CFloat -> IO (Ptr Raylib.Types.RayCollision)
+foreign import ccall safe "rl_bindings.h GetRayCollisionSphere_" c'getRayCollisionSphere :: Ptr Raylib.Types.Ray -> Ptr Raylib.Types.Vector3 -> CFloat -> IO (Ptr Raylib.Types.RayCollision)
 
-foreign import ccall safe "bindings.h GetRayCollisionBox_" c'getRayCollisionBox :: Ptr Raylib.Types.Ray -> Ptr Raylib.Types.BoundingBox -> IO (Ptr Raylib.Types.RayCollision)
+foreign import ccall safe "rl_bindings.h GetRayCollisionBox_" c'getRayCollisionBox :: Ptr Raylib.Types.Ray -> Ptr Raylib.Types.BoundingBox -> IO (Ptr Raylib.Types.RayCollision)
 
-foreign import ccall safe "bindings.h GetRayCollisionMesh_" c'getRayCollisionMesh :: Ptr Raylib.Types.Ray -> Ptr Raylib.Types.Mesh -> Ptr Raylib.Types.Matrix -> IO (Ptr Raylib.Types.RayCollision)
+foreign import ccall safe "rl_bindings.h GetRayCollisionMesh_" c'getRayCollisionMesh :: Ptr Raylib.Types.Ray -> Ptr Raylib.Types.Mesh -> Ptr Raylib.Types.Matrix -> IO (Ptr Raylib.Types.RayCollision)
 
-foreign import ccall safe "bindings.h GetRayCollisionTriangle_" c'getRayCollisionTriangle :: Ptr Raylib.Types.Ray -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> IO (Ptr Raylib.Types.RayCollision)
+foreign import ccall safe "rl_bindings.h GetRayCollisionTriangle_" c'getRayCollisionTriangle :: Ptr Raylib.Types.Ray -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> IO (Ptr Raylib.Types.RayCollision)
 
-foreign import ccall safe "bindings.h GetRayCollisionQuad_" c'getRayCollisionQuad :: Ptr Raylib.Types.Ray -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> IO (Ptr Raylib.Types.RayCollision)
+foreign import ccall safe "rl_bindings.h GetRayCollisionQuad_" c'getRayCollisionQuad :: Ptr Raylib.Types.Ray -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> Ptr Raylib.Types.Vector3 -> IO (Ptr Raylib.Types.RayCollision)
 
 -- TODO: redesign this
 foreign import ccall safe "wrapper"
@@ -1304,6 +1291,10 @@   mK'audioCallback ::
     AudioCallback -> (Ptr () -> CUInt -> IO ())
 
+foreign import ccall safe "raylib.h CloseAudioDevice"
+  c'closeAudioDevice ::
+    IO ()
+
 foreign import ccall safe "raylib.h IsAudioDeviceReady"
   c'isAudioDeviceReady ::
     IO CBool
@@ -1312,51 +1303,51 @@   c'setMasterVolume ::
     CFloat -> IO ()
 
-foreign import ccall safe "bindings.h LoadWave_" c'loadWave :: CString -> IO (Ptr Raylib.Types.Wave)
+foreign import ccall safe "rl_bindings.h LoadWave_" c'loadWave :: CString -> IO (Ptr Raylib.Types.Wave)
 
-foreign import ccall safe "bindings.h LoadWaveFromMemory_" c'loadWaveFromMemory :: CString -> Ptr CUChar -> CInt -> IO (Ptr Raylib.Types.Wave)
+foreign import ccall safe "rl_bindings.h LoadWaveFromMemory_" c'loadWaveFromMemory :: CString -> Ptr CUChar -> CInt -> IO (Ptr Raylib.Types.Wave)
 
-foreign import ccall safe "bindings.h LoadSound_" c'loadSound :: CString -> IO (Ptr Raylib.Types.Sound)
+foreign import ccall safe "rl_bindings.h LoadSound_" c'loadSound :: CString -> IO (Ptr Raylib.Types.Sound)
 
-foreign import ccall safe "bindings.h LoadSoundFromWave_" c'loadSoundFromWave :: Ptr Raylib.Types.Wave -> IO (Ptr Raylib.Types.Sound)
+foreign import ccall safe "rl_bindings.h LoadSoundFromWave_" c'loadSoundFromWave :: Ptr Raylib.Types.Wave -> IO (Ptr Raylib.Types.Sound)
 
-foreign import ccall safe "bindings.h UpdateSound_" c'updateSound :: Ptr Raylib.Types.Sound -> Ptr () -> CInt -> IO ()
+foreign import ccall safe "rl_bindings.h UpdateSound_" c'updateSound :: Ptr Raylib.Types.Sound -> Ptr () -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h IsWaveReady_" c'isWaveReady :: Ptr Raylib.Types.Wave -> IO CBool
+foreign import ccall safe "rl_bindings.h IsWaveReady_" c'isWaveReady :: Ptr Raylib.Types.Wave -> IO CBool
 
-foreign import ccall safe "bindings.h UnloadWave_" c'unloadWave :: Ptr Raylib.Types.Wave -> IO ()
+foreign import ccall safe "rl_bindings.h UnloadWave_" c'unloadWave :: Ptr Raylib.Types.Wave -> IO ()
 
-foreign import ccall safe "bindings.h IsSoundReady_" c'isSoundReady :: Ptr Raylib.Types.Sound -> IO CBool
+foreign import ccall safe "rl_bindings.h IsSoundReady_" c'isSoundReady :: Ptr Raylib.Types.Sound -> IO CBool
 
-foreign import ccall safe "bindings.h UnloadSound_" c'unloadSound :: Ptr Raylib.Types.Sound -> IO ()
+foreign import ccall safe "rl_bindings.h UnloadSound_" c'unloadSound :: Ptr Raylib.Types.Sound -> IO ()
 
-foreign import ccall safe "bindings.h ExportWave_" c'exportWave :: Ptr Raylib.Types.Wave -> CString -> IO CBool
+foreign import ccall safe "rl_bindings.h ExportWave_" c'exportWave :: Ptr Raylib.Types.Wave -> CString -> IO CBool
 
-foreign import ccall safe "bindings.h ExportWaveAsCode_" c'exportWaveAsCode :: Ptr Raylib.Types.Wave -> CString -> IO CBool
+foreign import ccall safe "rl_bindings.h ExportWaveAsCode_" c'exportWaveAsCode :: Ptr Raylib.Types.Wave -> CString -> IO CBool
 
-foreign import ccall safe "bindings.h PlaySound_" c'playSound :: Ptr Raylib.Types.Sound -> IO ()
+foreign import ccall safe "rl_bindings.h PlaySound_" c'playSound :: Ptr Raylib.Types.Sound -> IO ()
 
-foreign import ccall safe "bindings.h StopSound_" c'stopSound :: Ptr Raylib.Types.Sound -> IO ()
+foreign import ccall safe "rl_bindings.h StopSound_" c'stopSound :: Ptr Raylib.Types.Sound -> IO ()
 
-foreign import ccall safe "bindings.h PauseSound_" c'pauseSound :: Ptr Raylib.Types.Sound -> IO ()
+foreign import ccall safe "rl_bindings.h PauseSound_" c'pauseSound :: Ptr Raylib.Types.Sound -> IO ()
 
-foreign import ccall safe "bindings.h ResumeSound_" c'resumeSound :: Ptr Raylib.Types.Sound -> IO ()
+foreign import ccall safe "rl_bindings.h ResumeSound_" c'resumeSound :: Ptr Raylib.Types.Sound -> IO ()
 
-foreign import ccall safe "bindings.h PlaySoundMulti_" c'playSoundMulti :: Ptr Raylib.Types.Sound -> IO ()
+foreign import ccall safe "rl_bindings.h PlaySoundMulti_" c'playSoundMulti :: Ptr Raylib.Types.Sound -> IO ()
 
 foreign import ccall safe "raylib.h GetSoundsPlaying"
   c'getSoundsPlaying ::
     IO CInt
 
-foreign import ccall safe "bindings.h IsSoundPlaying_" c'isSoundPlaying :: Ptr Raylib.Types.Sound -> IO CBool
+foreign import ccall safe "rl_bindings.h IsSoundPlaying_" c'isSoundPlaying :: Ptr Raylib.Types.Sound -> IO CBool
 
-foreign import ccall safe "bindings.h SetSoundVolume_" c'setSoundVolume :: Ptr Raylib.Types.Sound -> CFloat -> IO ()
+foreign import ccall safe "rl_bindings.h SetSoundVolume_" c'setSoundVolume :: Ptr Raylib.Types.Sound -> CFloat -> IO ()
 
-foreign import ccall safe "bindings.h SetSoundPitch_" c'setSoundPitch :: Ptr Raylib.Types.Sound -> CFloat -> IO ()
+foreign import ccall safe "rl_bindings.h SetSoundPitch_" c'setSoundPitch :: Ptr Raylib.Types.Sound -> CFloat -> IO ()
 
-foreign import ccall safe "bindings.h SetSoundPan_" c'setSoundPan :: Ptr Raylib.Types.Sound -> CFloat -> IO ()
+foreign import ccall safe "rl_bindings.h SetSoundPan_" c'setSoundPan :: Ptr Raylib.Types.Sound -> CFloat -> IO ()
 
-foreign import ccall safe "bindings.h WaveCopy_" c'waveCopy :: Ptr Raylib.Types.Wave -> IO (Ptr Raylib.Types.Wave)
+foreign import ccall safe "rl_bindings.h WaveCopy_" c'waveCopy :: Ptr Raylib.Types.Wave -> IO (Ptr Raylib.Types.Wave)
 
 foreign import ccall safe "raylib.h WaveCrop"
   c'waveCrop ::
@@ -1366,80 +1357,80 @@   c'waveFormat ::
     Ptr Raylib.Types.Wave -> CInt -> CInt -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h LoadWaveSamples_" c'loadWaveSamples :: Ptr Raylib.Types.Wave -> IO (Ptr CFloat)
+foreign import ccall safe "rl_bindings.h LoadWaveSamples_" c'loadWaveSamples :: Ptr Raylib.Types.Wave -> IO (Ptr CFloat)
 
 foreign import ccall safe "raylib.h UnloadWaveSamples"
   c'unloadWaveSamples ::
     Ptr CFloat -> IO ()
 
-foreign import ccall safe "bindings.h LoadMusicStream_" c'loadMusicStream :: CString -> IO (Ptr Raylib.Types.Music)
+foreign import ccall safe "rl_bindings.h LoadMusicStream_" c'loadMusicStream :: CString -> IO (Ptr Raylib.Types.Music)
 
-foreign import ccall safe "bindings.h LoadMusicStreamFromMemory_" c'loadMusicStreamFromMemory :: CString -> Ptr CUChar -> CInt -> IO (Ptr Raylib.Types.Music)
+foreign import ccall safe "rl_bindings.h LoadMusicStreamFromMemory_" c'loadMusicStreamFromMemory :: CString -> Ptr CUChar -> CInt -> IO (Ptr Raylib.Types.Music)
 
-foreign import ccall safe "bindings.h IsMusicReady_" c'isMusicReady :: Ptr Raylib.Types.Music -> IO CBool
+foreign import ccall safe "rl_bindings.h IsMusicReady_" c'isMusicReady :: Ptr Raylib.Types.Music -> IO CBool
 
-foreign import ccall safe "bindings.h UnloadMusicStream_" c'unloadMusicStream :: Ptr Raylib.Types.Music -> IO ()
+foreign import ccall safe "rl_bindings.h UnloadMusicStream_" c'unloadMusicStream :: Ptr Raylib.Types.Music -> IO ()
 
-foreign import ccall safe "bindings.h PlayMusicStream_" c'playMusicStream :: Ptr Raylib.Types.Music -> IO ()
+foreign import ccall safe "rl_bindings.h PlayMusicStream_" c'playMusicStream :: Ptr Raylib.Types.Music -> IO ()
 
-foreign import ccall safe "bindings.h IsMusicStreamPlaying_" c'isMusicStreamPlaying :: Ptr Raylib.Types.Music -> IO CBool
+foreign import ccall safe "rl_bindings.h IsMusicStreamPlaying_" c'isMusicStreamPlaying :: Ptr Raylib.Types.Music -> IO CBool
 
-foreign import ccall safe "bindings.h UpdateMusicStream_" c'updateMusicStream :: Ptr Raylib.Types.Music -> IO ()
+foreign import ccall safe "rl_bindings.h UpdateMusicStream_" c'updateMusicStream :: Ptr Raylib.Types.Music -> IO ()
 
-foreign import ccall safe "bindings.h StopMusicStream_" c'stopMusicStream :: Ptr Raylib.Types.Music -> IO ()
+foreign import ccall safe "rl_bindings.h StopMusicStream_" c'stopMusicStream :: Ptr Raylib.Types.Music -> IO ()
 
-foreign import ccall safe "bindings.h PauseMusicStream_" c'pauseMusicStream :: Ptr Raylib.Types.Music -> IO ()
+foreign import ccall safe "rl_bindings.h PauseMusicStream_" c'pauseMusicStream :: Ptr Raylib.Types.Music -> IO ()
 
-foreign import ccall safe "bindings.h ResumeMusicStream_" c'resumeMusicStream :: Ptr Raylib.Types.Music -> IO ()
+foreign import ccall safe "rl_bindings.h ResumeMusicStream_" c'resumeMusicStream :: Ptr Raylib.Types.Music -> IO ()
 
-foreign import ccall safe "bindings.h SeekMusicStream_" c'seekMusicStream :: Ptr Raylib.Types.Music -> CFloat -> IO ()
+foreign import ccall safe "rl_bindings.h SeekMusicStream_" c'seekMusicStream :: Ptr Raylib.Types.Music -> CFloat -> IO ()
 
-foreign import ccall safe "bindings.h SetMusicVolume_" c'setMusicVolume :: Ptr Raylib.Types.Music -> CFloat -> IO ()
+foreign import ccall safe "rl_bindings.h SetMusicVolume_" c'setMusicVolume :: Ptr Raylib.Types.Music -> CFloat -> IO ()
 
-foreign import ccall safe "bindings.h SetMusicPitch_" c'setMusicPitch :: Ptr Raylib.Types.Music -> CFloat -> IO ()
+foreign import ccall safe "rl_bindings.h SetMusicPitch_" c'setMusicPitch :: Ptr Raylib.Types.Music -> CFloat -> IO ()
 
-foreign import ccall safe "bindings.h SetMusicPan_" c'setMusicPan :: Ptr Raylib.Types.Music -> CFloat -> IO ()
+foreign import ccall safe "rl_bindings.h SetMusicPan_" c'setMusicPan :: Ptr Raylib.Types.Music -> CFloat -> IO ()
 
-foreign import ccall safe "bindings.h GetMusicTimeLength_" c'getMusicTimeLength :: Ptr Raylib.Types.Music -> IO CFloat
+foreign import ccall safe "rl_bindings.h GetMusicTimeLength_" c'getMusicTimeLength :: Ptr Raylib.Types.Music -> IO CFloat
 
-foreign import ccall safe "bindings.h GetMusicTimePlayed_" c'getMusicTimePlayed :: Ptr Raylib.Types.Music -> IO CFloat
+foreign import ccall safe "rl_bindings.h GetMusicTimePlayed_" c'getMusicTimePlayed :: Ptr Raylib.Types.Music -> IO CFloat
 
-foreign import ccall safe "bindings.h LoadAudioStream_" c'loadAudioStream :: CUInt -> CUInt -> CUInt -> IO (Ptr Raylib.Types.AudioStream)
+foreign import ccall safe "rl_bindings.h LoadAudioStream_" c'loadAudioStream :: CUInt -> CUInt -> CUInt -> IO (Ptr Raylib.Types.AudioStream)
 
-foreign import ccall safe "bindings.h IsAudioStreamReady_" c'isAudioStreamReady :: Ptr Raylib.Types.AudioStream -> IO CBool
+foreign import ccall safe "rl_bindings.h IsAudioStreamReady_" c'isAudioStreamReady :: Ptr Raylib.Types.AudioStream -> IO CBool
 
-foreign import ccall safe "bindings.h UnloadAudioStream_" c'unloadAudioStream :: Ptr Raylib.Types.AudioStream -> IO ()
+foreign import ccall safe "rl_bindings.h UnloadAudioStream_" c'unloadAudioStream :: Ptr Raylib.Types.AudioStream -> IO ()
 
-foreign import ccall safe "bindings.h UpdateAudioStream_" c'updateAudioStream :: Ptr Raylib.Types.AudioStream -> Ptr () -> CInt -> IO ()
+foreign import ccall safe "rl_bindings.h UpdateAudioStream_" c'updateAudioStream :: Ptr Raylib.Types.AudioStream -> Ptr () -> CInt -> IO ()
 
-foreign import ccall safe "bindings.h IsAudioStreamProcessed_" c'isAudioStreamProcessed :: Ptr Raylib.Types.AudioStream -> IO CBool
+foreign import ccall safe "rl_bindings.h IsAudioStreamProcessed_" c'isAudioStreamProcessed :: Ptr Raylib.Types.AudioStream -> IO CBool
 
-foreign import ccall safe "bindings.h PlayAudioStream_" c'playAudioStream :: Ptr Raylib.Types.AudioStream -> IO ()
+foreign import ccall safe "rl_bindings.h PlayAudioStream_" c'playAudioStream :: Ptr Raylib.Types.AudioStream -> IO ()
 
-foreign import ccall safe "bindings.h PauseAudioStream_" c'pauseAudioStream :: Ptr Raylib.Types.AudioStream -> IO ()
+foreign import ccall safe "rl_bindings.h PauseAudioStream_" c'pauseAudioStream :: Ptr Raylib.Types.AudioStream -> IO ()
 
-foreign import ccall safe "bindings.h ResumeAudioStream_" c'resumeAudioStream :: Ptr Raylib.Types.AudioStream -> IO ()
+foreign import ccall safe "rl_bindings.h ResumeAudioStream_" c'resumeAudioStream :: Ptr Raylib.Types.AudioStream -> IO ()
 
-foreign import ccall safe "bindings.h IsAudioStreamPlaying_" c'isAudioStreamPlaying :: Ptr Raylib.Types.AudioStream -> IO CBool
+foreign import ccall safe "rl_bindings.h IsAudioStreamPlaying_" c'isAudioStreamPlaying :: Ptr Raylib.Types.AudioStream -> IO CBool
 
-foreign import ccall safe "bindings.h StopAudioStream_" c'stopAudioStream :: Ptr Raylib.Types.AudioStream -> IO ()
+foreign import ccall safe "rl_bindings.h StopAudioStream_" c'stopAudioStream :: Ptr Raylib.Types.AudioStream -> IO ()
 
-foreign import ccall safe "bindings.h SetAudioStreamVolume_" c'setAudioStreamVolume :: Ptr Raylib.Types.AudioStream -> CFloat -> IO ()
+foreign import ccall safe "rl_bindings.h SetAudioStreamVolume_" c'setAudioStreamVolume :: Ptr Raylib.Types.AudioStream -> CFloat -> IO ()
 
-foreign import ccall safe "bindings.h SetAudioStreamPitch_" c'setAudioStreamPitch :: Ptr Raylib.Types.AudioStream -> CFloat -> IO ()
+foreign import ccall safe "rl_bindings.h SetAudioStreamPitch_" c'setAudioStreamPitch :: Ptr Raylib.Types.AudioStream -> CFloat -> IO ()
 
-foreign import ccall safe "bindings.h SetAudioStreamPan_" c'setAudioStreamPan :: Ptr Raylib.Types.AudioStream -> CFloat -> IO ()
+foreign import ccall safe "rl_bindings.h SetAudioStreamPan_" c'setAudioStreamPan :: Ptr Raylib.Types.AudioStream -> CFloat -> IO ()
 
 foreign import ccall safe "raylib.h SetAudioStreamBufferSizeDefault"
   c'setAudioStreamBufferSizeDefault ::
     CInt -> IO ()
 
-foreign import ccall safe "bindings.h SetAudioStreamCallback_" c'setAudioStreamCallback :: Ptr Raylib.Types.AudioStream -> Ptr AudioCallback -> IO ()
+foreign import ccall safe "rl_bindings.h SetAudioStreamCallback_" c'setAudioStreamCallback :: Ptr Raylib.Types.AudioStream -> Ptr AudioCallback -> IO ()
 
-foreign import ccall safe "bindings.h AttachAudioStreamProcessor_" c'attachAudioStreamProcessor :: Ptr Raylib.Types.AudioStream -> Ptr AudioCallback -> IO ()
+foreign import ccall safe "rl_bindings.h AttachAudioStreamProcessor_" c'attachAudioStreamProcessor :: Ptr Raylib.Types.AudioStream -> Ptr AudioCallback -> IO ()
 
-foreign import ccall safe "bindings.h DetachAudioStreamProcessor_" c'detachAudioStreamProcessor :: Ptr Raylib.Types.AudioStream -> Ptr AudioCallback -> IO ()
+foreign import ccall safe "rl_bindings.h DetachAudioStreamProcessor_" c'detachAudioStreamProcessor :: Ptr Raylib.Types.AudioStream -> Ptr AudioCallback -> IO ()
 
-foreign import ccall safe "rl_internal.h &UnloadAudioBuffer_" p'unloadAudioBuffer :: FunPtr (Ptr Raylib.Types.RAudioBuffer -> IO ())
+foreign import ccall safe "rl_bindings.h AttachAudioMixedProcessor_" c'attachAudioMixedProcessor :: Ptr AudioCallback -> IO ()
 
-foreign import ccall safe "rl_internal.h UnloadMusicStreamData" c'unloadMusicStreamData :: CInt -> Ptr () -> IO ()
+foreign import ccall safe "rl_bindings.h DetachAudioMixedProcessor_" c'detachAudioMixedProcessor :: Ptr AudioCallback -> IO ()
src/Raylib/Text.hs view
@@ -5,20 +5,17 @@ module Raylib.Text where
 
 import Foreign
-  ( Ptr,
-    Storable (peek, sizeOf),
-    peekArray,
+  ( Storable (peek, sizeOf),
     toBool,
     withArray,
     withArrayLen,
   )
 import Foreign.C
-  ( CInt,
-    CString,
-    CUChar,
+  ( CUChar,
     peekCString,
     withCString,
   )
+import Raylib.Internal (addTextureId)
 import Raylib.Native
   ( c'codepointToUTF8,
     c'drawFPS,
@@ -46,20 +43,21 @@     c'loadUTF8,
     c'measureText,
     c'measureTextEx,
-    c'unloadFont,
-    c'unloadFontData,
   )
 import Raylib.Types
   ( Color,
-    Font,
+    Font (font'texture),
     FontType,
     GlyphInfo,
     Image,
     Rectangle,
+    Texture (texture'id),
     Vector2,
   )
 import Raylib.Util
   ( pop,
+    popCArray,
+    popCString,
     withArray2D,
     withFreeable,
   )
@@ -68,16 +66,28 @@ getFontDefault = c'getFontDefault >>= pop
 
 loadFont :: String -> IO Raylib.Types.Font
-loadFont fileName = withCString fileName c'loadFont >>= pop
+loadFont fileName = do
+  font <- withCString fileName c'loadFont >>= pop
+  addTextureId $ texture'id $ font'texture font
+  return font
 
 loadFontEx :: String -> Int -> [Int] -> Int -> IO Raylib.Types.Font
-loadFontEx fileName fontSize fontChars glyphCount = withCString fileName (\f -> withArray (map fromIntegral fontChars) (\c -> c'loadFontEx f (fromIntegral fontSize) c (fromIntegral glyphCount))) >>= pop
+loadFontEx fileName fontSize fontChars glyphCount = do
+  font <- withCString fileName (\f -> withArray (map fromIntegral fontChars) (\c -> c'loadFontEx f (fromIntegral fontSize) c (fromIntegral glyphCount))) >>= pop
+  addTextureId $ texture'id $ font'texture font
+  return font
 
 loadFontFromImage :: Raylib.Types.Image -> Raylib.Types.Color -> Int -> IO Raylib.Types.Font
-loadFontFromImage image key firstChar = withFreeable image (\i -> withFreeable key (\k -> c'loadFontFromImage i k (fromIntegral firstChar))) >>= pop
+loadFontFromImage image key firstChar = do
+  font <- withFreeable image (\i -> withFreeable key (\k -> c'loadFontFromImage i k (fromIntegral firstChar))) >>= pop
+  addTextureId $ texture'id $ font'texture font
+  return font
 
 loadFontFromMemory :: String -> [Integer] -> Int -> [Int] -> Int -> IO Raylib.Types.Font
-loadFontFromMemory fileType fileData fontSize fontChars glyphCount = withCString fileType (\t -> withArrayLen (map fromIntegral fileData) (\size d -> withArray (map fromIntegral fontChars) (\c -> c'loadFontFromMemory t d (fromIntegral $ size * sizeOf (0 :: CUChar)) (fromIntegral fontSize) c (fromIntegral glyphCount)))) >>= pop
+loadFontFromMemory fileType fileData fontSize fontChars glyphCount = do
+  font <- withCString fileType (\t -> withArrayLen (map fromIntegral fileData) (\size d -> withArray (map fromIntegral fontChars) (\c -> c'loadFontFromMemory t d (fromIntegral $ size * sizeOf (0 :: CUChar)) (fromIntegral fontSize) c (fromIntegral glyphCount)))) >>= pop
+  addTextureId $ texture'id $ font'texture font
+  return font
 
 loadFontData :: [Integer] -> Int -> [Int] -> Int -> FontType -> IO Raylib.Types.GlyphInfo
 loadFontData fileData fontSize fontChars glyphCount fontType = withArrayLen (map fromIntegral fileData) (\size d -> withArray (map fromIntegral fontChars) (\c -> c'loadFontData d (fromIntegral $ size * sizeOf (0 :: CUChar)) (fromIntegral fontSize) c (fromIntegral glyphCount) (fromIntegral $ fromEnum fontType))) >>= pop
@@ -85,15 +95,9 @@ genImageFontAtlas :: [Raylib.Types.GlyphInfo] -> [[Raylib.Types.Rectangle]] -> Int -> Int -> Int -> Int -> IO Raylib.Types.Image
 genImageFontAtlas chars recs glyphCount fontSize padding packMethod = withArray chars (\c -> withArray2D recs (\r -> c'genImageFontAtlas c r (fromIntegral glyphCount) (fromIntegral fontSize) (fromIntegral padding) (fromIntegral packMethod))) >>= pop
 
-unloadFontData :: [Raylib.Types.GlyphInfo] -> IO ()
-unloadFontData glyphs = withArrayLen glyphs (\size g -> c'unloadFontData g (fromIntegral size))
-
 isFontReady :: Raylib.Types.Font -> IO Bool
 isFontReady font = toBool <$> withFreeable font c'isFontReady
 
-unloadFont :: Raylib.Types.Font -> IO ()
-unloadFont font = withFreeable font c'unloadFont
-
 exportFontAsCode :: Raylib.Types.Font -> String -> IO Bool
 exportFontAsCode font fileName = toBool <$> withFreeable font (withCString fileName . c'exportFontAsCode)
 
@@ -137,15 +141,7 @@     ( \size c ->
         c'loadUTF8 c (fromIntegral size)
     )
-    >>= ( \s -> do
-            val <- peekCString s
-            unloadUTF8 s
-            return val
-        )
-
-foreign import ccall safe "raylib.h UnloadUTF8"
-  unloadUTF8 ::
-    CString -> IO ()
+    >>= popCString
 
 loadCodepoints :: String -> IO [Int]
 loadCodepoints text =
@@ -157,15 +153,9 @@           ( \n -> do
               res <- c'loadCodepoints t n
               num <- peek n
-              arr <- peekArray (fromIntegral num) res
-              unloadCodepoints res
-              return $ fromIntegral <$> arr
+              map fromIntegral <$> popCArray (fromIntegral num) res
           )
     )
-
-foreign import ccall safe "raylib.h UnloadCodepoints"
-  unloadCodepoints ::
-    Ptr CInt -> IO ()
 
 getCodepointCount :: String -> IO Int
 getCodepointCount text = fromIntegral <$> withCString text c'getCodepointCount
src/Raylib/Textures.hs view
@@ -4,15 +4,16 @@ 
 module Raylib.Textures where
 
+import Control.Monad ((<=<))
 import Foreign
   ( Ptr,
     Storable (peek, sizeOf),
-    peekArray,
     toBool,
     withArrayLen,
   )
 import Foreign.C (CUChar, withCString)
 import GHC.IO (unsafePerformIO)
+import Raylib.Internal (addFrameBuffer, addTextureId)
 import Raylib.Native
   ( c'colorAlpha,
     c'colorAlphaBlend,
@@ -108,9 +109,6 @@     c'setPixelColor,
     c'setTextureFilter,
     c'setTextureWrap,
-    c'unloadImage,
-    c'unloadRenderTexture,
-    c'unloadTexture,
     c'updateTexture,
     c'updateTextureRec,
   )
@@ -122,8 +120,8 @@     NPatchInfo,
     PixelFormat,
     Rectangle,
-    RenderTexture,
-    Texture,
+    RenderTexture (renderTexture'id, renderTexture'texture),
+    Texture (texture'id),
     TextureFilter,
     TextureWrap,
     Vector2,
@@ -132,6 +130,7 @@   )
 import Raylib.Util
   ( pop,
+    popCArray,
     withFreeable,
   )
 
@@ -142,7 +141,7 @@ loadImageRaw fileName width height format headerSize =
   withCString fileName (\str -> c'loadImageRaw str (fromIntegral width) (fromIntegral height) (fromIntegral $ fromEnum format) (fromIntegral headerSize)) >>= pop
 
--- | Returns the final image and the framees in a tuple, e.g. @(img, 18)@
+-- | Returns the animation and the frames in a tuple
 loadImageAnim :: String -> IO (Raylib.Types.Image, Int)
 loadImageAnim fileName =
   withFreeable
@@ -170,9 +169,6 @@ isImageReady :: Image -> IO Bool
 isImageReady image = toBool <$> withFreeable image c'isImageReady
 
-unloadImage :: Raylib.Types.Image -> IO ()
-unloadImage image = withFreeable image c'unloadImage
-
 exportImage :: Raylib.Types.Image -> String -> IO Bool
 exportImage image fileName = toBool <$> withFreeable image (withCString fileName . c'exportImage)
 
@@ -303,12 +299,7 @@ loadImageColors image =
   withFreeable
     image
-    ( \i -> do
-        colors <- c'loadImageColors i
-        colArray <- peekArray (fromIntegral $ Raylib.Types.image'width image * Raylib.Types.image'height image) colors
-        unloadImageColors colors
-        return colArray
-    )
+    (popCArray (fromIntegral $ Raylib.Types.image'width image * Raylib.Types.image'height image) <=< c'loadImageColors)
 
 loadImagePalette :: Raylib.Types.Image -> Int -> IO [Raylib.Types.Color]
 loadImagePalette image maxPaletteSize =
@@ -323,19 +314,9 @@                 s <- peek size
                 return (cols, s)
             )
-        colArray <- peekArray (fromIntegral num) palette
-        unloadImagePalette palette
-        return colArray
+        popCArray (fromIntegral num) palette
     )
 
-foreign import ccall safe "raylib.h UnloadImageColors"
-  unloadImageColors ::
-    Ptr Raylib.Types.Color -> IO ()
-
-foreign import ccall safe "raylib.h UnloadImagePalette"
-  unloadImagePalette ::
-    Ptr Raylib.Types.Color -> IO ()
-
 getImageAlphaBorder :: Raylib.Types.Image -> Float -> IO Raylib.Types.Rectangle
 getImageAlphaBorder image threshold = withFreeable image (\i -> c'getImageAlphaBorder i (realToFrac threshold)) >>= pop
 
@@ -391,28 +372,35 @@ imageDrawTextEx image font text position fontSize spacing tint = withFreeable image (\i -> withFreeable font (\f -> withCString text (\t -> withFreeable position (\p -> withFreeable tint (c'imageDrawTextEx i f t p (realToFrac fontSize) (realToFrac spacing))))) >> peek i)
 
 loadTexture :: String -> IO Raylib.Types.Texture
-loadTexture fileName = withCString fileName c'loadTexture >>= pop
+loadTexture fileName = do
+  texture <- withCString fileName c'loadTexture >>= pop
+  addTextureId $ texture'id texture
+  return texture
 
 loadTextureFromImage :: Raylib.Types.Image -> IO Raylib.Types.Texture
-loadTextureFromImage image = withFreeable image c'loadTextureFromImage >>= pop
+loadTextureFromImage image = do
+  texture <- withFreeable image c'loadTextureFromImage >>= pop
+  addTextureId $ texture'id texture
+  return texture
 
 loadTextureCubemap :: Raylib.Types.Image -> CubemapLayout -> IO Raylib.Types.Texture
-loadTextureCubemap image layout = withFreeable image (\i -> c'loadTextureCubemap i (fromIntegral $ fromEnum layout)) >>= pop
+loadTextureCubemap image layout = do
+  texture <- withFreeable image (\i -> c'loadTextureCubemap i (fromIntegral $ fromEnum layout)) >>= pop
+  addTextureId $ texture'id texture
+  return texture
 
 loadRenderTexture :: Int -> Int -> IO Raylib.Types.RenderTexture
-loadRenderTexture width height = c'loadRenderTexture (fromIntegral width) (fromIntegral height) >>= pop
+loadRenderTexture width height = do
+  renderTexture <- c'loadRenderTexture (fromIntegral width) (fromIntegral height) >>= pop
+  addFrameBuffer $ renderTexture'id renderTexture
+  addTextureId $ texture'id $ renderTexture'texture renderTexture
+  return renderTexture
 
 isTextureReady :: Texture -> IO Bool
 isTextureReady texture = toBool <$> withFreeable texture c'isTextureReady
 
-unloadTexture :: Raylib.Types.Texture -> IO ()
-unloadTexture texture = withFreeable texture c'unloadTexture
-
 isRenderTextureReady :: RenderTexture -> IO Bool
 isRenderTextureReady renderTexture = toBool <$> withFreeable renderTexture c'isRenderTextureReady
-
-unloadRenderTexture :: Raylib.Types.RenderTexture -> IO ()
-unloadRenderTexture target = withFreeable target c'unloadRenderTexture
 
 updateTexture :: Raylib.Types.Texture -> Ptr () -> IO Raylib.Types.Texture
 updateTexture texture pixels = withFreeable texture (\t -> c'updateTexture t pixels >> peek t)
src/Raylib/Types.hs view
@@ -3,10 +3,6 @@ 
 module Raylib.Types where
 
--- This file includes Haskell counterparts to the structs defined in raylib
-
--- This file includes Haskell counterparts to the structs defined in raylib
-
 import Control.Monad (forM_, unless)
 import Foreign
   ( FunPtr,
@@ -40,21 +36,8 @@     peekCString,
   )
 import Foreign.C.String (castCCharToChar)
-import GHC.IO (unsafePerformIO)
-import Raylib.Internal (c'rlGetShaderIdDefault)
-import Raylib.Util (Freeable (rlFreeDependents), c'free, freeMaybePtr, newMaybeArray, p'free, peekMaybeArray, peekStaticArray, peekStaticArrayOff, pokeMaybeOff, pokeStaticArray, pokeStaticArrayOff, rightPad, rlFreeArray)
-
--- Necessary functions
-foreign import ccall safe "raylib.h GetPixelDataSize"
-  c'getPixelDataSize ::
-    CInt -> CInt -> CInt -> IO CInt
-
-getPixelDataSize :: Int -> Int -> PixelFormat -> Int
-getPixelDataSize width height format = unsafePerformIO (fromIntegral <$> c'getPixelDataSize (fromIntegral width) (fromIntegral height) (fromIntegral $ fromEnum format))
-
-foreign import ccall safe "raylib.h &GetPixelDataSize"
-  p'getPixelDataSize ::
-    FunPtr (CInt -> CInt -> CInt -> IO CInt)
+import Raylib.Internal (c'rlGetShaderIdDefault, getPixelDataSize)
+import Raylib.Util (Freeable (rlFreeDependents), c'free, freeMaybePtr, newMaybeArray, p'free, peekMaybeArray, peekStaticArray, peekStaticArrayOff, pokeMaybeOff, pokeStaticArray, pokeStaticArrayOff, rightPad, rlFreeArray, rlFreeMaybeArray)
 
 ------------------------------------------------
 -- Raylib enumerations -------------------------
@@ -786,6 +769,42 @@   poke ptr v = poke (castPtr ptr) (fromIntegral (fromEnum v) :: CInt)
 
 ------------------------------------------------
+-- Raylib typeclasses --------------------------
+------------------------------------------------
+
+class Vector a where
+  -- Vector-vector addition
+  (|+|) :: a -> a -> a
+
+  -- Vector-vector subtraction
+  (|-|) :: a -> a -> a
+  v1 |-| v2 = v1 |+| inverse v2
+
+  -- Vector-scalar multiplication
+  (|*|) :: a -> Float -> a
+
+  -- Vector-scalar division
+  (|/|) :: a -> Float -> a
+  v |/| num = v |*| (1 / num)
+
+  -- Vector-vector dot product
+  (|.|) :: a -> a -> Float
+
+  -- Zero vector
+  zero :: a
+
+  -- Vector additive inverse
+  inverse :: a -> a
+
+  -- Normalize vector (same direction, magnitude 1)
+  normalize :: a -> a
+  normalize v = v |/| magnitude v
+
+  -- Vector magnitude
+  magnitude :: a -> Float
+  magnitude x = sqrt $ x |.| x
+
+------------------------------------------------
 -- Raylib structures ---------------------------
 ------------------------------------------------
 
@@ -807,6 +826,15 @@     pokeByteOff _p 4 (realToFrac y :: CFloat)
     return ()
 
+instance Vector Vector2 where
+  (Vector2 x1 y1) |+| (Vector2 x2 y2) = Vector2 (x1 + x2) (y1 + y2)
+  (Vector2 x y) |*| num = Vector2 (x * num) (y * num)
+
+  (Vector2 x1 y1) |.| (Vector2 x2 y2) = (x1 * x2) + (y1 * y2)
+
+  zero = Vector2 0 0
+  inverse (Vector2 x y) = Vector2 (- x) (- y)
+
 data Vector3 = Vector3
   { vector3'x :: Float,
     vector3'y :: Float,
@@ -828,6 +856,19 @@     pokeByteOff _p 8 (realToFrac z :: CFloat)
     return ()
 
+-- Vector cross-product
+cross :: Vector3 -> Vector3 -> Vector3
+(Vector3 x1 y1 z1) `cross` (Vector3 x2 y2 z2) = Vector3 (y1 * z2 - z1 * y2) (z1 * x2 - x1 * z2) (x1 * y2 - y1 * x2)
+
+instance Vector Vector3 where
+  (Vector3 x1 y1 z1) |+| (Vector3 x2 y2 z2) = Vector3 (x1 + x2) (y1 + y2) (z1 + z2)
+  (Vector3 x y z) |*| num = Vector3 (x * num) (y * num) (z * num)
+
+  (Vector3 x1 y1 z1) |.| (Vector3 x2 y2 z2) = (x1 * x2) + (y1 * y2) + (z1 * z2)
+
+  zero = Vector3 0 0 0
+  inverse (Vector3 x y z) = Vector3 (- x) (- y) (- z)
+
 data Vector4 = Vector4
   { vector4'x :: Float,
     vector4'y :: Float,
@@ -852,6 +893,15 @@     pokeByteOff _p 12 (realToFrac w :: CFloat)
     return ()
 
+instance Vector Vector4 where
+  (Vector4 x1 y1 z1 w1) |+| (Vector4 x2 y2 z2 w2) = Vector4 (x1 + x2) (y1 + y2) (z1 + z2) (w1 + w2)
+  (Vector4 x y z w) |*| num = Vector4 (x * num) (y * num) (z * num) (w * num)
+
+  (Vector4 x1 y1 z1 w1) |.| (Vector4 x2 y2 z2 w2) = (x1 * x2) + (y1 * y2) + (z1 * z2) + (w1 * w2)
+
+  zero = Vector4 0 0 0 0
+  inverse (Vector4 x y z w) = Vector4 (- x) (- y) (- z) (- w)
+
 type Quaternion = Vector4
 
 data Matrix = Matrix
@@ -980,7 +1030,7 @@     mipmaps <- fromIntegral <$> (peekByteOff _p 16 :: IO CInt)
     format <- peekByteOff _p 20
     ptr <- (peekByteOff _p 0 :: IO (Ptr CUChar))
-    arr <- peekArray (getPixelDataSize width height format) ptr
+    arr <- peekArray (getPixelDataSize width height (fromEnum format)) ptr
     return $ Image (map fromIntegral arr) width height mipmaps format
   poke _p (Image arr width height mipmaps format) = do
     pokeByteOff _p 0 =<< newArray (map fromIntegral arr :: [CUChar])
@@ -1027,9 +1077,9 @@ type TextureCubemap = Texture
 
 data RenderTexture = RenderTexture
-  { rendertexture'id :: Integer,
-    rendertexture'texture :: Texture,
-    rendertexture'depth :: Texture
+  { renderTexture'id :: Integer,
+    renderTexture'texture :: Texture,
+    renderTexture'depth :: Texture
   }
   deriving (Eq, Show, Freeable)
 
@@ -1050,12 +1100,12 @@ type RenderTexture2D = RenderTexture
 
 data NPatchInfo = NPatchInfo
-  { nPatchinfo'source :: Rectangle,
-    nPatchinfo'left :: Int,
-    nPatchinfo'top :: Int,
-    nPatchinfo'right :: Int,
-    nPatchinfo'bottom :: Int,
-    nPatchinfo'layout :: NPatchLayout
+  { nPatchInfo'source :: Rectangle,
+    nPatchInfo'left :: Int,
+    nPatchInfo'top :: Int,
+    nPatchInfo'right :: Int,
+    nPatchInfo'bottom :: Int,
+    nPatchInfo'layout :: NPatchLayout
   }
   deriving (Eq, Show, Freeable)
 
@@ -1080,11 +1130,11 @@     return ()
 
 data GlyphInfo = GlyphInfo
-  { glyphinfo'value :: Int,
+  { glyphInfo'value :: Int,
     glyphInfo'offsetX :: Int,
     glyphInfo'offsetY :: Int,
     glyphInfo'advanceX :: Int,
-    glyphinfo'image :: Image
+    glyphInfo'image :: Image
   }
   deriving (Eq, Show)
 
@@ -1182,8 +1232,8 @@ data Camera2D = Camera2D
   { camera2D'offset :: Vector2,
     camera2D'target :: Vector2,
-    camera2d'rotation :: Float,
-    camera2d'zoom :: Float
+    camera2D'rotation :: Float,
+    camera2D'zoom :: Float
   }
   deriving (Eq, Show, Freeable)
 
@@ -1218,7 +1268,7 @@     mesh'boneIds :: Maybe [Word8],
     mesh'boneWeights :: Maybe [Float],
     mesh'vaoId :: Integer,
-    mesh'vboId :: [Integer]
+    mesh'vboId :: Maybe [Integer]
   }
   deriving (Eq, Show)
 
@@ -1252,7 +1302,7 @@     boneWeights <- peekMaybeArray (vertexCount * 4) boneWeightsPtr
     vaoId <- fromIntegral <$> (peekByteOff _p 96 :: IO CUInt)
     vboIdPtr <- (peekByteOff _p 104 :: IO (Ptr CUInt))
-    vboId <- map fromIntegral <$> peekArray 7 vboIdPtr
+    vboId <- (\m -> map fromIntegral <$> m) <$> peekMaybeArray 7 vboIdPtr
     return $ Mesh vertexCount triangleCount vertices texcoords texcoords2 normals tangents colors indices animVertices animNormals boneIds boneWeights vaoId vboId
   poke _p (Mesh vertexCount triangleCount vertices texcoords texcoords2 normals tangents colors indices animVertices animNormals boneIds boneWeights vaoId vboId) = do
     pokeByteOff _p 0 (fromIntegral vertexCount :: CInt)
@@ -1263,13 +1313,13 @@     pokeByteOff _p 32 =<< newArray normals
     newMaybeArray tangents >>= pokeByteOff _p 40
     newMaybeArray colors >>= pokeByteOff _p 48
-    newMaybeArray ((\m -> map fromIntegral m :: [CUShort]) <$> indices) >>= pokeByteOff _p 56
+    newMaybeArray (map fromIntegral <$> indices :: Maybe [CUShort]) >>= pokeByteOff _p 56
     newMaybeArray animVertices >>= pokeByteOff _p 64
     newMaybeArray animNormals >>= pokeByteOff _p 72
-    newMaybeArray ((\m -> map fromIntegral m :: [CUChar]) <$> boneIds) >>= pokeByteOff _p 80
+    newMaybeArray (map fromIntegral <$> boneIds :: Maybe [CUChar]) >>= pokeByteOff _p 80
     newMaybeArray boneWeights >>= pokeByteOff _p 88
     pokeByteOff _p 96 (fromIntegral vaoId :: CUInt)
-    pokeByteOff _p 104 =<< newArray (map fromIntegral vboId :: [CUInt])
+    newMaybeArray (map fromIntegral <$> vboId :: Maybe [CUInt]) >>= pokeByteOff _p 104
     return ()
 
 instance Freeable Mesh where
@@ -1335,9 +1385,9 @@       )
 
 data MaterialMap = MaterialMap
-  { materialmap'texture :: Texture,
-    materialmap'color :: Color,
-    materialmap'value :: Float
+  { materialMap'texture :: Texture,
+    materialMap'color :: Color,
+    materialMap'value :: Float
   }
   deriving (Eq, Show, Freeable)
 
@@ -1357,7 +1407,7 @@ 
 data Material = Material
   { material'shader :: Shader,
-    material'maps :: [MaterialMap],
+    material'maps :: Maybe [MaterialMap],
     material'params :: [Float]
   }
   deriving (Eq, Show)
@@ -1368,12 +1418,12 @@   peek _p = do
     shader <- peekByteOff _p 0
     mapsPtr <- (peekByteOff _p 16 :: IO (Ptr MaterialMap))
-    maps <- peekArray 12 mapsPtr
+    maps <- peekMaybeArray 12 mapsPtr
     params <- map realToFrac <$> peekStaticArrayOff 4 (castPtr _p :: Ptr CFloat) 24
     return $ Material shader maps params
   poke _p (Material shader maps params) = do
     pokeByteOff _p 0 shader
-    pokeByteOff _p 16 =<< newArray maps
+    pokeByteOff _p 16 =<< newMaybeArray maps
     pokeStaticArrayOff (castPtr _p :: Ptr CFloat) 24 (map realToFrac params :: [CFloat])
     return ()
 
@@ -1381,7 +1431,7 @@   rlFreeDependents val ptr = do
     rlFreeDependents (material'shader val) (castPtr ptr :: Ptr Shader)
     mapsPtr <- (peekByteOff ptr 16 :: IO (Ptr MaterialMap))
-    rlFreeArray (material'maps val) mapsPtr
+    rlFreeMaybeArray (material'maps val) mapsPtr
 
 data Transform = Transform
   { transform'translation :: Vector3,
@@ -1608,10 +1658,10 @@     dataPtr <- peekByteOff ptr 16 :: IO (Ptr CShort)
     c'free $ castPtr dataPtr
 
--- These types don't work perfectly right now, I need to fix them later on.
+-- RAudioBuffer/Processor don't work perfectly right now, I need to fix them later on.
 -- They are currently used as `Ptr`s because peeking/poking them every time
 -- an audio function is called doesn't work properly (they are stored in a
--- linked list in C, which makes it very difficult to properly peek/poke them)
+-- linked list in C, which makes it very difficult to properly marshal them)
 data RAudioBuffer = RAudioBuffer
   { rAudioBuffer'converter :: [Int], -- Implemented as an array of 39 integers because binding the entire `ma_data_converter` type is too painful
     rAudioBuffer'callback :: AudioCallback,
@@ -1983,6 +2033,10 @@     pathsCStrings <- peekArray (length $ filePathList'paths val) pathsPtr
     mapM_ (c'free . castPtr) pathsCStrings
     c'free $ castPtr pathsPtr
+
+------------------------------------------------
+-- Raylib callbacks ----------------------------
+------------------------------------------------
 
 type LoadFileDataCallback = FunPtr (CString -> Ptr CUInt -> IO (Ptr CUChar))
 
src/Raylib/Util.hs view
@@ -1,11 +1,11 @@ {-# OPTIONS -Wall #-}
 
-module Raylib.Util (c'free, p'free, freeMaybePtr, Freeable (..), rlFreeArray, pop, popCArray, withFreeable, withArray2D, configsToBitflag, withMaybe, withMaybeCString, peekMaybe, peekMaybeOff, pokeMaybe, pokeMaybeOff, peekMaybeArray, newMaybeArray, peekStaticArray, peekStaticArrayOff, pokeStaticArray, pokeStaticArrayOff, rightPad) where
+module Raylib.Util (c'free, p'free, freeMaybePtr, Freeable (..), rlFreeArray, rlFreeMaybeArray, pop, popCArray, popCString, withFreeable, withArray2D, configsToBitflag, withMaybe, withMaybeCString, peekMaybe, peekMaybeOff, pokeMaybe, pokeMaybeOff, peekMaybeArray, newMaybeArray, peekStaticArray, peekStaticArrayOff, pokeStaticArray, pokeStaticArrayOff, rightPad) where
 
 import Control.Monad (forM_, unless)
 import Data.Bits ((.|.))
 import Foreign (FunPtr, Ptr, Storable (peek, peekByteOff, poke, sizeOf), castPtr, free, malloc, newArray, nullPtr, peekArray, plusPtr, with)
-import Foreign.C (CInt, CString, CUInt, withCString)
+import Foreign.C (CFloat, CInt, CString, CUChar, CUInt, peekCString, withCString)
 
 -- Internal utility functions
 
@@ -27,7 +27,11 @@ 
 instance Freeable CUInt
 
-rlFreeArray :: (Freeable a, Show a, Storable a) => [a] -> Ptr a -> IO ()
+instance Freeable CUChar
+
+instance Freeable CFloat
+
+rlFreeArray :: (Freeable a, Storable a) => [a] -> Ptr a -> IO ()
 rlFreeArray arr ptr = do
   forM_
     [0 .. length arr - 1]
@@ -36,6 +40,10 @@     )
   c'free $ castPtr ptr
 
+rlFreeMaybeArray :: (Freeable a, Storable a) => Maybe [a] -> Ptr a -> IO ()
+rlFreeMaybeArray Nothing _ = return ()
+rlFreeMaybeArray (Just arr) ptr = rlFreeArray arr ptr
+
 pop :: (Freeable a, Storable a) => Ptr a -> IO a
 pop ptr = do
   val <- peek ptr
@@ -45,6 +53,12 @@ popCArray :: (Freeable a, Storable a) => Int -> Ptr a -> IO [a]
 popCArray count ptr = do
   str <- peekArray count ptr
+  c'free $ castPtr ptr
+  return str
+
+popCString :: CString -> IO String
+popCString ptr = do
+  str <- peekCString ptr
   c'free $ castPtr ptr
   return str