瀏覽代碼

Updated to raylib 5.5.377248b (#9)

* Updated to raylib 5.5.377248b

* Win32 build fix.

* Fixed some math Functions.

* Updated examples.

* Updated models examples.

* Added audio callback support. Updated audio examples.

* Removed old audio example.

* Updated samples. Fixed some issues.

* Updated shader examples.

* Updated text examples.

* Updated core examples.

Added math functions.
Brucey 9 月之前
父節點
當前提交
e0bdd9df7c
共有 100 個文件被更改,包括 4590 次插入1927 次删除
  1. 2 0
      .gitignore
  2. 1 1
      LICENSE.md
  3. 124 49
      audio.mod/audio.bmx
  4. 35 18
      audio.mod/common.bmx
  5. 1 1
      audio.mod/glue.c
  6. 1 1
      audio.mod/source.bmx
  7. 19 0
      examples/audio/audio_module_playing.bmx
  8. 0 61
      examples/audio/audio_multichannel_sound.bmx
  9. 7 7
      examples/audio/audio_music_stream.bmx
  10. 49 48
      examples/audio/audio_raw_stream.bmx
  11. 1 1
      examples/audio/audio_sound_loading.bmx
  12. 2 2
      examples/core/core_2d_camera.bmx
  13. 126 0
      examples/core/core_2d_camera_mouse_zoom.bmx
  14. 110 12
      examples/core/core_3d_camera_first_person.bmx
  15. 6 8
      examples/core/core_3d_camera_free.bmx
  16. 1 1
      examples/core/core_3d_camera_mode.bmx
  17. 23 13
      examples/core/core_3d_picking.bmx
  18. 2 2
      examples/core/core_random_values.bmx
  19. 15 37
      examples/core/core_window_letterbox.bmx
  20. 6 4
      examples/core/core_world_screen.bmx
  21. 10 17
      examples/models/models_animation.bmx
  22. 35 5
      examples/models/models_billboard.bmx
  23. 10 4
      examples/models/models_cubicmap.bmx
  24. 6 10
      examples/models/models_first_person_maze.bmx
  25. 4 1
      examples/models/models_geometric_shapes.bmx
  26. 3 5
      examples/models/models_heightmap.bmx
  27. 51 6
      examples/models/models_mesh_generation.bmx
  28. 4 6
      examples/models/models_waving_cubes.bmx
  29. 38 124
      examples/models/models_yaw_pitch_roll.bmx
  30. 16 26
      examples/shaders/shaders_custom_uniform.bmx
  31. 10 10
      examples/shaders/shaders_eratosthenes.bmx
  32. 69 60
      examples/shaders/shaders_julia_set.bmx
  33. 4 5
      examples/shaders/shaders_model_shader.bmx
  34. 1 1
      examples/shaders/shaders_palette_switch.bmx
  35. 17 22
      examples/shaders/shaders_postprocessing.bmx
  36. 17 17
      examples/shaders/shaders_raymarching.bmx
  37. 21 20
      examples/shaders/shaders_simple_mask.bmx
  38. 2 2
      examples/shaders/shaders_texture_drawing.bmx
  39. 9 9
      examples/shaders/shaders_texture_waves.bmx
  40. 12 10
      examples/shapes/shapes_draw_circle_sector.bmx
  41. 15 15
      examples/shapes/shapes_draw_rectangle_rounded.bmx
  42. 14 14
      examples/shapes/shapes_draw_ring.bmx
  43. 7 7
      examples/text/text_font_filters.bmx
  44. 2 0
      examples/text/text_font_loading.bmx
  45. 17 9
      examples/text/text_font_sdf.bmx
  46. 14 10
      examples/text/text_input_box.bmx
  47. 156 1
      examples/text/text_rectangle_bounds.bmx
  48. 83 0
      examples/textures/textures_blend_modes.bmx
  49. 22 12
      examples/textures/textures_image_generation.bmx
  50. 2 1
      examples/textures/textures_image_loading.bmx
  51. 26 18
      examples/textures/textures_image_processing.bmx
  52. 1 1
      examples/textures/textures_image_text.bmx
  53. 10 3
      examples/textures/textures_mouse_painting.bmx
  54. 4 4
      examples/textures/textures_npatch_drawing.bmx
  55. 4 4
      examples/textures/textures_particles_blending.bmx
  56. 3 3
      examples/textures/textures_raw_data.bmx
  57. 0 96
      examples/textures/textures_rectangle.bmx
  58. 6 6
      examples/textures/textures_sprite_explosion.bmx
  59. 3 1
      examples/textures/textures_to_image.bmx
  60. 68 56
      gui.mod/common.bmx
  61. 24 1
      gui.mod/glue.c
  62. 164 86
      gui.mod/gui.bmx
  63. 0 1
      gui.mod/raygui/.gitattributes
  64. 0 12
      gui.mod/raygui/.github/FUNDING.yml
  65. 0 62
      gui.mod/raygui/.gitignore
  66. 1 1
      gui.mod/raygui/LICENSE
  67. 122 32
      gui.mod/raygui/README.md
  68. 12 7
      gui.mod/raygui/examples/Makefile
  69. 477 0
      gui.mod/raygui/examples/animation_curve/animation_curve.c
  70. 543 0
      gui.mod/raygui/examples/animation_curve/gui_curve_editor.h
  71. 165 94
      gui.mod/raygui/examples/controls_test_suite/controls_test_suite.c
  72. 二進制
      gui.mod/raygui/examples/controls_test_suite/controls_test_suite.png
  73. 二進制
      gui.mod/raygui/examples/controls_test_suite/fonts/FiveByFive10.ttf
  74. 二進制
      gui.mod/raygui/examples/controls_test_suite/fonts/NorthernLights.ttf
  75. 二進制
      gui.mod/raygui/examples/controls_test_suite/fonts/PIXEARG11.ttf
  76. 二進制
      gui.mod/raygui/examples/controls_test_suite/fonts/PixelOperator8.ttf
  77. 二進制
      gui.mod/raygui/examples/controls_test_suite/fonts/pixelpoiiz10.ttf
  78. 二進制
      gui.mod/raygui/examples/controls_test_suite/fonts/prstartk8.ttf
  79. 二進制
      gui.mod/raygui/examples/controls_test_suite/fonts/rainyhearts16.ttf
  80. 71 0
      gui.mod/raygui/examples/controls_test_suite/gui_value_box_float.c
  81. 19 21
      gui.mod/raygui/examples/custom_file_dialog/custom_file_dialog.c
  82. 0 558
      gui.mod/raygui/examples/custom_file_dialog/gui_file_dialog.h
  83. 625 0
      gui.mod/raygui/examples/custom_file_dialog/gui_window_file_dialog.h
  84. 223 0
      gui.mod/raygui/examples/custom_input_box/custom_input_box.c
  85. 470 0
      gui.mod/raygui/examples/custom_sliders/custom_sliders.c
  86. 148 0
      gui.mod/raygui/examples/floating_window/floating_window.c
  87. 21 24
      gui.mod/raygui/examples/image_exporter/image_exporter.c
  88. 0 0
      gui.mod/raygui/examples/image_importer_raw/design/raw_importer_REF.png
  89. 0 0
      gui.mod/raygui/examples/image_importer_raw/design/raw_importer_REV0.png
  90. 0 0
      gui.mod/raygui/examples/image_importer_raw/design/raw_importer_REV1.png
  91. 0 0
      gui.mod/raygui/examples/image_importer_raw/design/raw_importer_REV2.png
  92. 0 0
      gui.mod/raygui/examples/image_importer_raw/design/raw_importer_REV3.png
  93. 0 0
      gui.mod/raygui/examples/image_importer_raw/design/raw_importer_REV4.png
  94. 0 0
      gui.mod/raygui/examples/image_importer_raw/design/raw_importer_REV5.png
  95. 0 0
      gui.mod/raygui/examples/image_importer_raw/image_2x2_RGBA.raw
  96. 21 23
      gui.mod/raygui/examples/image_importer_raw/image_importer_raw.c
  97. 11 10
      gui.mod/raygui/examples/portable_window/portable_window.c
  98. 87 87
      gui.mod/raygui/examples/property_list/dm_property_list.h
  99. 32 21
      gui.mod/raygui/examples/property_list/property_list.c
  100. 27 0
      gui.mod/raygui/examples/property_list/test.props

+ 2 - 0
.gitignore

@@ -10,3 +10,5 @@
 
 *.i2
 *.app
+
+.DS_Store

+ 1 - 1
LICENSE.md

@@ -1,6 +1,6 @@
 zlib License
 	
-Copyright (c) 2020 Bruce A Henderson
+Copyright (c) 2020-2024 Bruce A Henderson
 
 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.

+ 124 - 49
audio.mod/audio.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2020 Bruce A Henderson
+' Copyright (c) 2024 Bruce A Henderson
 '
 ' This software is provided 'as-is', without any express or implied
 ' warranty. In no event will the authors be held liable for any damages
@@ -28,8 +28,8 @@ Module Ray.Audio
 
 ModuleInfo "Version: 1.00"
 ModuleInfo "License: zlib"
-ModuleInfo "Copyright: Wrapper - 2020 Bruce A Henderson"
-ModuleInfo "Copyright: raylib - 2013-2020 Ramon Santamaria"
+ModuleInfo "Copyright: Wrapper - 2024 Bruce A Henderson"
+ModuleInfo "Copyright: raylib - 2013-2024 Ramon Santamaria"
 
 ModuleInfo "History: 1.00"
 ModuleInfo "History: Initial Release."
@@ -85,6 +85,13 @@ Function SetMasterVolume(volume:Float)
 	bmx_raylib_SetMasterVolume(volume)
 End Function
 
+Rem
+bbdoc: Gets master volume (listener).
+End Rem
+Function GetMasterVolume:Float()
+	Return bmx_raylib_GetMasterVolume()
+End Function
+
 
 ' Wave/Sound loading/unloading functions
 Rem
@@ -97,6 +104,17 @@ Function LoadWave:RWave(filename:String)
 	Return wave
 End Function
 
+Function LoadWaveFromMemory:RWave(fileType:String, data:Byte Ptr, dataSize:Int)
+	Local f:Byte Ptr = fileType.ToUTF8String()
+	Local wave:RWave = bmx_raylib_LoadWaveFromMemory(f, data, dataSize)
+	MemFree(f)
+	Return wave
+End Function
+
+Function IsWaveValid:Int(wave:RWave)
+	Return bmx_raylib_IsWaveValid(wave)
+End Function
+
 Rem
 bbdoc: Loads sound from file.
 End Rem
@@ -114,6 +132,14 @@ Function LoadSoundFromWave:RSound(wave:RWave)
 	Return bmx_raylib_LoadSoundFromWave(wave)
 End Function
 
+Function LoadSoundAlias:RSound(source:RSound)
+	Return bmx_raylib_LoadSoundAlias(source)
+End Function
+
+Function IsSoundValid:Int(sound:RSound)
+	Return bmx_raylib_IsSoundValid(sound)
+End Function
+
 Rem
 bbdoc: Updates sound buffer with new data.
 End Rem
@@ -135,6 +161,10 @@ Function UnloadSound(sound:RSound)
 	bmx_raylib_UnloadSound(sound)
 End Function
 
+Function UnloadSoundAlias(sound:RSound)
+	bmx_raylib_UnloadSoundAlias(sound)
+End Function
+
 Rem
 bbdoc: Exports wave data to file.
 End Rem
@@ -183,27 +213,6 @@ Function ResumeSound(sound:RSound)
 	bmx_raylib_ResumeSound(sound)
 End Function
 
-Rem
-bbdoc: Plays a sound (using multichannel buffer pool).
-End Rem
-Function PlaySoundMulti(sound:RSound)
-	bmx_raylib_PlaySoundMulti(sound)
-End Function
-
-Rem
-bbdoc: Stops any sound playing (using multichannel buffer pool).
-End Rem
-Function StopSoundMulti()
-	bmx_raylib_StopSoundMulti()
-End Function
-
-Rem
-bbdoc: Gets number of sounds playing in the multichannel.
-End Rem
-Function GetSoundsPlaying:Int()
-	Return bmx_raylib_GetSoundsPlaying()
-End Function
-
 Rem
 bbdoc: Checks if a sound is currently playing.
 End Rem
@@ -225,11 +234,8 @@ Function SetSoundPitch(sound:RSound, pitch:Float)
 	bmx_raylib_SetSoundPitch(sound, pitch)
 End Function
 
-Rem
-bbdoc: Converts wave data to desired format.
-End Rem
-Function WaveFormat(wave:RWave Var, sampleRate:Int, sampleSize:Int, channels:Int)
-	bmx_raylib_WaveFormat(wave, sampleRate, sampleSize, channels)
+Function SetSoundPan(sound:RSound, pan:Float)
+	bmx_raylib_SetSoundPan(sound, pan)
 End Function
 
 Rem
@@ -246,11 +252,22 @@ Function WaveCrop(wave:RWave Var, initSample:Int, finalSample:Int)
 	bmx_raylib_WaveCrop(wave, initSample, finalSample)
 End Function
 
+Rem
+bbdoc: Converts wave data to desired format.
+End Rem
+Function WaveFormat(wave:RWave Var, sampleRate:Int, sampleSize:Int, channels:Int)
+	bmx_raylib_WaveFormat(wave, sampleRate, sampleSize, channels)
+End Function
+
 Rem
 bbdoc: Gets samples data from wave as a floats array.
 End Rem
-Function GetWaveData:Float Ptr(wave:RWave)
-	Return bmx_raylib_GetWaveData(wave)
+Function LoadWaveSamples:Float Ptr(wave:RWave)
+	Return bmx_raylib_LoadWaveSamples(wave)
+End Function
+
+Function UnloadWaveSamples(data:Float Ptr)
+	bmx_raylib_UnloadWaveSamples(data)
 End Function
 
 ' Music management functions
@@ -264,6 +281,17 @@ Function LoadMusicStream:RMusic(filename:String)
 	Return music
 End Function
 
+Function LoadMusicStreamFromMemory:RMusic(fileType:String, data:Byte Ptr, dataSize:Int)
+	Local f:Byte Ptr = fileType.ToUTF8String()
+	Local music:RMusic = bmx_raylib_LoadMusicStreamFromMemory(f, data, dataSize)
+	MemFree(f)
+	Return music
+End Function
+
+Function IsMusicValid:Int(music:RMusic)
+	Return bmx_raylib_IsMusicValid(music)
+End Function
+
 Rem
 bbdoc: Unloads music stream.
 End Rem
@@ -278,6 +306,10 @@ Function PlayMusicStream(music:RMusic)
 	bmx_raylib_PlayMusicStream(music)
 End Function
 
+Function IsMusicStreamPlaying:Int(music:RMusic)
+	Return bmx_raylib_IsMusicStreamPlaying(music)
+End Function
+
 Rem
 bbdoc: Updates buffers for music streaming.
 End Rem
@@ -306,11 +338,8 @@ Function ResumeMusicStream(music:RMusic)
 	bmx_raylib_ResumeMusicStream(music)
 End Function
 
-Rem
-bbdoc: Checks if music is playing.
-End Rem
-Function IsMusicPlaying:Int(music:RMusic)
-	bmx_raylib_IsMusicPlaying(music)
+Function SeekMusicStream(music:RMusic, position:Float)
+	bmx_raylib_SeekMusicStream(music, position)
 End Function
 
 Rem
@@ -327,11 +356,8 @@ Function SetMusicPitch(music:RMusic, pitch:Float)
 	bmx_raylib_SetMusicPitch(music, pitch)
 End Function
 
-Rem
-bbdoc: Sets music loop count (loop repeats).
-End Rem
-Function SetMusicLoopCount(music:RMusic, count:Int)
-	bmx_raylib_SetMusicLoopCount(music, count)
+Function SetMusicPan(music:RMusic, pan:Float)
+	bmx_raylib_SetMusicPan(music, pan)
 End Function
 
 Rem
@@ -353,22 +379,29 @@ End Function
 Rem
 bbdoc: Inits audio stream (to stream raw audio pcm data).
 End Rem
-Function InitAudioStream:RAudioStream(sampleRate:UInt, sampleSize:UInt, channels:UInt)
-	Return bmx_raylib_InitAudioStream(sampleRate, sampleSize, channels)
+Function LoadAudioStream:RAudioStream(sampleRate:UInt, sampleSize:UInt, channels:UInt)
+	Return bmx_raylib_LoadAudioStream(sampleRate, sampleSize, channels)
 End Function
 
 Rem
-bbdoc: Updates audio stream buffers with data.
+bbdoc: Checks if an audio stream is valid (buffers initialized).
 End Rem
-Function UpdateAudioStream(stream:RAudioStream, data:Byte Ptr, samplesCount:Int)
-	bmx_raylib_UpdateAudioStream(stream, data, samplesCount)
+Function IsAudioStreamValid:Int(stream:RAudioStream)
+	Return bmx_raylib_IsAudioStreamValid(stream)
 End Function
 
 Rem
-bbdoc: Closes audio stream and free memory.
+bbdoc: Unloads audio stream and free memory.
 End Rem
-Function CloseAudioStream(stream:RAudioStream)
-	bmx_raylib_CloseAudioStream(stream)
+Function UnloadAudioStream(stream:RAudioStream)
+	bmx_raylib_UnloadAudioStream(stream)
+End Function
+
+Rem
+bbdoc: Updates audio stream buffers with data.
+End Rem
+Function UpdateAudioStream(stream:RAudioStream, data:Byte Ptr, samplesCount:Int)
+	bmx_raylib_UpdateAudioStream(stream, data, samplesCount)
 End Function
 
 Rem
@@ -427,9 +460,51 @@ Function SetAudioStreamPitch(stream:RAudioStream, pitch:Float)
 	bmx_raylib_SetAudioStreamPitch(stream, pitch)
 End Function
 
+Rem
+bbdoc: Sets pan for audio stream (0.5 is centered).
+End Rem
+Function SetAudioStreamPan(stream:RAudioStream, pan:Float)
+	bmx_raylib_SetAudioStreamPan(stream, pan)
+End Function
+
 Rem
 bbdoc: Sets the default buffer size for new audio streams.
 End Rem
 Function SetAudioStreamBufferSizeDefault(size:Int)
 	bmx_raylib_SetAudioStreamBufferSizeDefault(size)
 End Function
+
+Rem
+bbdoc: Sets audio thread callback to request new data.
+End Rem
+Function SetAudioStreamCallback(stream:RAudioStream, processor(data:Byte Ptr, frames:UInt))
+	bmx_raylib_SetAudioStreamCallback(stream, processor)
+End Function
+
+Rem
+bbdoc: Attaches audio stream processor to stream, receives the samples as 'float'.
+End Rem
+Function AttachAudioStreamProcessor(stream:RAudioStream, processor(data:Byte Ptr, frames:UInt))
+	bmx_raylib_AttachAudioStreamProcessor(stream, processor)
+End Function
+
+Rem
+bbdoc: Detaches audio stream processor from stream.
+End Rem
+Function DetachAudioStreamProcessor(stream:RAudioStream, processor(data:Byte Ptr, frames:UInt))
+	bmx_raylib_DetachAudioStreamProcessor(stream, processor)
+End Function
+
+Rem
+bbdoc: Attaches audio stream processor to the entire audio pipeline, receives the samples as 'float'.
+End Rem
+Function AttachAudioMixedProcessor(processor(data:Byte Ptr, frames:UInt))
+	bmx_raylib_AttachAudioMixedProcessor(processor)
+End Function
+
+Rem
+bbdoc: Detaches audio stream processor from the entire audio pipeline.
+End Rem
+Function DetachAudioMixedProcessor(processor(data:Byte Ptr, frames:UInt))
+	bmx_raylib_DetachAudioMixedProcessor(processor)
+End Function

+ 35 - 18
audio.mod/common.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2020 Bruce A Henderson
+' Copyright (c) 2024 Bruce A Henderson
 '
 ' This software is provided 'as-is', without any express or implied
 ' warranty. In no event will the authors be held liable for any damages
@@ -30,13 +30,19 @@ Extern
 	Function bmx_raylib_CloseAudioDevice()="CloseAudioDevice"
 	Function bmx_raylib_IsAudioDeviceReady:Int()="IsAudioDeviceReady"
 	Function bmx_raylib_SetMasterVolume(volume:Float)="SetMasterVolume"
+	Function bmx_raylib_GetMasterVolume:Float()="GetMasterVolume"
 
 	Function bmx_raylib_LoadWave:RWave(fileName:Byte Ptr)="LoadWave"
+	Function bmx_raylib_LoadWaveFromMemory:RWave(fileType:Byte Ptr, data:Byte Ptr, dataSize:Int)="LoadWaveFromMemory"
+	Function bmx_raylib_IsWaveValid:Int(wave:RWave)="IsWaveValid"
 	Function bmx_raylib_LoadSound:RSound(fileName:Byte Ptr)="LoadSound"
 	Function bmx_raylib_LoadSoundFromWave:RSound(wave:RWave)="LoadSoundFromWave"
+	Function bmx_raylib_LoadSoundAlias:RSound(source:RSound)="LoadSoundAlias"
+	Function bmx_raylib_IsSoundValid:Int(sound:RSound)="IsSoundValid"
 	Function bmx_raylib_UpdateSound(sound:RSound, data:Byte Ptr, samplesCount:Int)="UpdateSound"
 	Function bmx_raylib_UnloadWave(wave:RWave)="UnloadWave"
 	Function bmx_raylib_UnloadSound(sound:RSound)="UnloadSound"
+	Function bmx_raylib_UnloadSoundAlias(sound:RSound)="UnloadSoundAlias"
 	Function bmx_raylib_ExportWave(wave:RWave, fileName:Byte Ptr)="ExportWave"
 	Function bmx_raylib_ExportWaveAsCode(wave:RWave, fileName:Byte Ptr)="ExportWaveAsCode"
 
@@ -44,34 +50,37 @@ Extern
 	Function bmx_raylib_StopSound(sound:RSound)="StopSound"
 	Function bmx_raylib_PauseSound(sound:RSound)="PauseSound"
 	Function bmx_raylib_ResumeSound(sound:RSound)="ResumeSound"
-	Function bmx_raylib_PlaySoundMulti(sound:RSound)="PlaySoundMulti"
-	Function bmx_raylib_StopSoundMulti()="StopSoundMulti"
-	Function bmx_raylib_GetSoundsPlaying:Int()="GetSoundsPlaying"
 	Function bmx_raylib_IsSoundPlaying:Int(sound:RSound)="IsSoundPlaying"
 	Function bmx_raylib_SetSoundVolume(sound:RSound, volume:Float)="SetSoundVolume"
 	Function bmx_raylib_SetSoundPitch(sound:RSound, pitch:Float)="SetSoundPitch"
-	Function bmx_raylib_WaveFormat(wave:RWave Var, sampleRate:Int, sampleSize:Int, channels:Int)="WaveFormat"
+	Function bmx_raylib_SetSoundPan(sound:RSound, pan:Float)="SetSoundPan"
 	Function bmx_raylib_WaveCopy:RWave(wave:RWave)="WaveCopy"
 	Function bmx_raylib_WaveCrop(wave:RWave Var, initSample:Int, finalSample:Int)="WaveCrop"
-	Function bmx_raylib_GetWaveData:Float Ptr(wave:RWave)="GetWaveData"
+	Function bmx_raylib_WaveFormat(wave:RWave Var, sampleRate:Int, sampleSize:Int, channels:Int)="WaveFormat"
+	Function bmx_raylib_LoadWaveSamples:Float Ptr(wave:RWave)="LoadWaveSamples"
+	FUnction bmx_raylib_UnloadWaveSamples(samples:Float Ptr)="UnloadWaveSamples"
 
 	Function bmx_raylib_LoadMusicStream:RMusic(fileName:Byte Ptr)="LoadMusicStream"
+	Function bmx_raylib_LoadMusicStreamFromMemory:RMusic(fileType:Byte Ptr, data:Byte Ptr, dataSize:Int)="LoadMusicStreamFromMemory"
+	Function bmx_raylib_IsMusicValid:Int(music:RMusic)="IsMusicValid"
 	Function bmx_raylib_UnloadMusicStream(music:RMusic)="UnloadMusicStream"
 	Function bmx_raylib_PlayMusicStream(music:RMusic)="PlayMusicStream"
+	Function bmx_raylib_IsMusicStreamPlaying:Int(music:RMusic)="IsMusicStreamPlaying"
 	Function bmx_raylib_UpdateMusicStream(music:RMusic)="UpdateMusicStream"
 	Function bmx_raylib_StopMusicStream(music:RMusic)="StopMusicStream"
 	Function bmx_raylib_PauseMusicStream(music:RMusic)="PauseMusicStream"
 	Function bmx_raylib_ResumeMusicStream(music:RMusic)="ResumeMusicStream"
-	Function bmx_raylib_IsMusicPlaying:Int(music:RMusic)="IsMusicPlaying"
+	Function bmx_raylib_SeekMusicStream(music:RMusic, position:Float)="SeekMusicStream"
 	Function bmx_raylib_SetMusicVolume(music:RMusic, volume:Float)="SetMusicVolume"
 	Function bmx_raylib_SetMusicPitch(music:RMusic, pitch:Float)="SetMusicPitch"
-	Function bmx_raylib_SetMusicLoopCount(music:RMusic, count:Int)="SetMusicLoopCount"
+	Function bmx_raylib_SetMusicPan(music:RMusic, pan:Float)="SetMusicPan"
 	Function bmx_raylib_GetMusicTimeLength:Float(music:RMusic)="GetMusicTimeLength"
 	Function bmx_raylib_GetMusicTimePlayed:Float(music:RMusic)="GetMusicTimePlayed"
 
-	Function bmx_raylib_InitAudioStream:RAudioStream(sampleRate:UInt, sampleSize:UInt, channels:UInt)="InitAudioStream"
+	Function bmx_raylib_LoadAudioStream:RAudioStream(sampleRate:UInt, sampleSize:UInt, channels:UInt)="LoadAudioStream"
+	Function bmx_raylib_IsAudioStreamValid:Int(stream:RAudioStream)="IsAudioStreamValid"
+	Function bmx_raylib_UnloadAudioStream(stream:RAudioStream)="UnloadAudioStream"
 	Function bmx_raylib_UpdateAudioStream(stream:RAudioStream, data:Byte Ptr, samplesCount:Int)="UpdateAudioStream"
-	Function bmx_raylib_CloseAudioStream(stream:RAudioStream)="CloseAudioStream"
 	Function bmx_raylib_IsAudioStreamProcessed:Int(stream:RAudioStream)="IsAudioStreamProcessed"
 	Function bmx_raylib_PlayAudioStream(stream:RAudioStream)="PlayAudioStream"
 	Function bmx_raylib_PauseAudioStream(stream:RAudioStream)="PauseAudioStream"
@@ -80,12 +89,19 @@ Extern
 	Function bmx_raylib_StopAudioStream(stream:RAudioStream)="StopAudioStream"
 	Function bmx_raylib_SetAudioStreamVolume(stream:RAudioStream, volume:Float)="SetAudioStreamVolume"
 	Function bmx_raylib_SetAudioStreamPitch(stream:RAudioStream, pitch:Float)="SetAudioStreamPitch"
+	Function bmx_raylib_SetAudioStreamPan(stream:RAudioStream, pan:Float)="SetAudioStreamPan"
 	Function bmx_raylib_SetAudioStreamBufferSizeDefault(size:Int)="SetAudioStreamBufferSizeDefault"
+	Function bmx_raylib_SetAudioStreamCallback(stream:RAudioStream, processor(data:Byte Ptr, frames:UInt))="SetAudioStreamCallback"
+
+	Function bmx_raylib_AttachAudioStreamProcessor(stream:RAudioStream, processor(data:Byte Ptr, frames:UInt))="AttachAudioStreamProcessor"
+	Function bmx_raylib_DetachAudioStreamProcessor(stream:RAudioStream, processor(data:Byte Ptr, frames:UInt))="DetachAudioStreamProcessor"
 
+	Function bmx_raylib_AttachAudioMixedProcessor(processor(data:Byte Ptr, frames:UInt))="AttachAudioMixedProcessor"
+	Function bmx_raylib_DetachAudioMixedProcessor(processor(data:Byte Ptr, frames:UInt))="DetachAudioMixedProcessor"
 End Extern
 
 Struct RWave
-	Field sampleCount:UInt
+	Field frameCount:UInt
 	Field sampleRate:UInt
 	Field sampleSize:UInt
 	Field channels:UInt
@@ -93,23 +109,24 @@ Struct RWave
 End Struct
 
 Struct RAudioStream
+	Field buffer:Byte Ptr
+	Field processor:Byte Ptr
+
 	Field sampleRate:UInt
 	Field sampleSize:UInt
 	Field channels:UInt
-	Field buffer:Byte Ptr
 End Struct
 
 Struct RSound
-	Field sampleCount:UInt
 	Field stream:RAudioStream
+	Field frameCount:UInt
 End Struct
 
 Struct RMusic
+	Field stream:RAudioStream
+	Field frameCount:UInt
+	Field looping:Int
+	
 	Field ctxType:Int
 	Field ctxData:Byte Ptr
-	
-	Field sampleCount:UInt
-	Field loopCount:UInt
-	
-	Field stream:RAudioStream
 End Struct

+ 1 - 1
audio.mod/glue.c

@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2020 Bruce A Henderson
+  Copyright (c) 2024 Bruce A Henderson
 
   This software is provided 'as-is', without any express or implied
   warranty. In no event will the authors be held liable for any damages

+ 1 - 1
audio.mod/source.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2020 Bruce A Henderson
+' Copyright (c) 2024 Bruce A Henderson
 '
 ' This software is provided 'as-is', without any express or implied
 ' warranty. In no event will the authors be held liable for any damages

+ 19 - 0
examples/audio/audio_module_playing.bmx

@@ -35,6 +35,8 @@ While i >= 0
 Wend
 
 Local music:RMusic = LoadMusicStream("../../lib.mod/raylib/examples/audio/resources/mini1111.xm")
+music.looping = False
+Local pitch:Float = 1.0
 
 PlayMusicStream(music)
 
@@ -54,6 +56,7 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 	If IsKeyPressed(KEY_SPACE) Then
 		StopMusicStream(music)
 		PlayMusicStream(music)
+		pause = False
 	End If
 
 	' Pause/Resume music playing
@@ -67,6 +70,14 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 		End If
 	End If
 
+	If IsKeyDown(KEY_DOWN) Then
+		pitch :- 0.01
+	Else If IsKeyDown(KEY_UP) Then
+		pitch :+ 0.01
+	End If
+
+	SetMusicPitch(music, pitch)
+
 	' Get timePlayed scaled to bar dimensions
 	timePlayed = GetMusicTimePlayed(music)/GetMusicTimeLength(music)*(screenWidth - 40)
 
@@ -109,6 +120,14 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 		DrawRectangle(20, screenHeight - 20 - 12, Int(timePlayed), 12, MAROON)
 		DrawRectangleLines(20, screenHeight - 20 - 12, screenWidth - 40, 12, GRAY)
 
+		' Draw help instructions
+		DrawRectangle(20, 20, 425, 145, WHITE)
+		DrawRectangleLines(20, 20, 425, 145, GRAY)
+		DrawText("PRESS SPACE TO RESTART MUSIC", 40, 40, 20, BLACK)
+		DrawText("PRESS P TO PAUSE/RESUME", 40, 70, 20, BLACK)
+		DrawText("PRESS UP/DOWN TO CHANGE SPEED", 40, 100, 20, BLACK)
+		DrawText("SPEED: " + pitch, 40, 130, 20, MAROON)
+
 	EndDrawing()
 	'----------------------------------------------------------------------------------
 Wend

+ 0 - 61
examples/audio/audio_multichannel_sound.bmx

@@ -1,61 +0,0 @@
-SuperStrict
-
-Framework Ray.Lib
-Import Ray.Audio
-
-' Initialization
-'--------------------------------------------------------------------------------------
-Const screenWidth:Int = 800
-Const screenHeight:Int = 450
-
-InitWindow(screenWidth, screenHeight, "raylib [audio] example - Multichannel sound playing")
-
-InitAudioDevice()      ' Initialize audio device
-
-Local fxWav:RSound = LoadSound("../../lib.mod/raylib/examples/audio/resources/sound.wav")         ' Load WAV audio file
-Local fxOgg:RSound = LoadSound("../../lib.mod/raylib/examples/audio/resources/tanatana.ogg")      ' Load OGG audio file
-
-SetSoundVolume(fxWav, 0.2)
-
-SetTargetFPS(60)       ' Set our game to run at 60 frames-per-second
-'--------------------------------------------------------------------------------------
-
-' Main game loop
-While Not WindowShouldClose()    ' Detect window close button or ESC key
-	' Update
-	'----------------------------------------------------------------------------------
-	If IsKeyPressed(KEY_ENTER) Then
-		PlaySoundMulti(fxWav)     ' Play a new wav sound instance
-	End If
-	If IsKeyPressed(KEY_SPACE) Then
-		PlaySoundMulti(fxOgg)     ' Play a new ogg sound instance
-	End If
-	'----------------------------------------------------------------------------------
-
-	' Draw
-	'----------------------------------------------------------------------------------
-	BeginDrawing()
-
-		ClearBackground(RAYWHITE)
-		
-		DrawText("MULTICHANNEL SOUND PLAYING", 20, 20, 20, GRAY)
-		DrawText("Press SPACE to play new ogg instance!", 200, 120, 20, LIGHTGRAY)
-		DrawText("Press ENTER to play new wav instance!", 200, 180, 20, LIGHTGRAY)
-
-		DrawText("CONCURRENT SOUNDS PLAYING: " + GetSoundsPlaying(), 220, 280, 20, RED)
-
-	EndDrawing()
-	'----------------------------------------------------------------------------------
-Wend
-
-' De-Initialization
-'--------------------------------------------------------------------------------------
-StopSoundMulti()       ' We must stop the buffer pool before unloading
-
-UnloadSound(fxWav)     ' Unload sound data
-UnloadSound(fxOgg)     ' Unload sound data
-
-CloseAudioDevice()     ' Close audio device
-
-CloseWindow()          ' Close window and OpenGL context
-'--------------------------------------------------------------------------------------

+ 7 - 7
examples/audio/audio_music_stream.bmx

@@ -12,14 +12,14 @@ InitWindow(screenWidth, screenHeight, "raylib [audio] example - music playing (s
 
 InitAudioDevice()              ' Initialize audio device
 
-Local music:RMusic = LoadMusicStream("../../lib.mod/raylib/examples/audio/resources/guitar_noodling.ogg")
+Local music:RMusic = LoadMusicStream("../../lib.mod/raylib/examples/audio/resources/country.mp3")
 
 PlayMusicStream(music)
 
 Local timePlayed:Float = 0.0
 Local pause:Int = False
 
-SetTargetFPS(60)               ' Set our game to run at 60 frames-per-second
+SetTargetFPS(30)               ' Set our game to run at 30 frames-per-second
 '--------------------------------------------------------------------------------------
 
 ' Main game loop
@@ -45,11 +45,11 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 		End If
 	End If
 
-	' Get timePlayed scaled to bar dimensions (400 pixels)
-	timePlayed = GetMusicTimePlayed(music)/GetMusicTimeLength(music)*400
+	' Get normalized time played for current music stream
+	timePlayed = GetMusicTimePlayed(music)/GetMusicTimeLength(music)
 
-	If timePlayed > 400 Then
-		StopMusicStream(music)
+	If timePlayed > 1.0 Then ' Make sure time played is no longer than music
+		timePlayed = 1.0
 	End If
 	'----------------------------------------------------------------------------------
 
@@ -62,7 +62,7 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 		DrawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, LIGHTGRAY)
 
 		DrawRectangle(200, 200, 400, 12, LIGHTGRAY)
-		DrawRectangle(200, 200, Int(timePlayed), 12, MAROON)
+		DrawRectangle(200, 200, Int(timePlayed * 400), 12, MAROON)
 		DrawRectangleLines(200, 200, 400, 12, GRAY)
 
 		DrawText("PRESS SPACE TO RESTART MUSIC", 215, 250, 20, LIGHTGRAY)

+ 49 - 48
examples/audio/audio_raw_stream.bmx

@@ -7,6 +7,18 @@ Import BRL.Math
 Const MAX_SAMPLES:Int = 512
 Const MAX_SAMPLES_PER_UPDATE:Int = 4096
 
+' Cycles per second (hz)
+Global frequency:Float = 440.0
+
+' Audio frequency, for smoothing
+Global audioFrequency:Float = 440.0
+
+' Previous value, used to test if sine needs to be rewritten, and to smoothly modulate frequency
+Local oldFrequency:Float = 1.0
+
+' Index for audio rendering
+Global sineIdx:Float = 0.0
+
 ' Initialization
 '--------------------------------------------------------------------------------------
 Const screenWidth:Int = 800
@@ -16,29 +28,24 @@ InitWindow(screenWidth, screenHeight, "raylib [audio] example - raw audio stream
 
 InitAudioDevice()              ' Initialize audio device
 
-' Init raw audio stream (sample rate: 22050, sample size: 16bit-short, channels: 1-mono)
-Local stream:RAudioStream = InitAudioStream(22050, 16, 1)
+SetAudioStreamBufferSizeDefault(MAX_SAMPLES_PER_UPDATE)
+
+' Init raw audio stream (sample rate: 44100, sample size: 16bit-short, channels: 1-mono)
+Local stream:RAudioStream = LoadAudioStream(44100, 16, 1)
+
+SetAudioStreamCallback(stream, AudioInputCallback)
 
 ' Buffer for the single cycle waveform we are synthesizing
-Local data:Short Ptr = MemAlloc(2 * MAX_SAMPLES)
+Local data:Short Ptr = RMemAlloc(2 * MAX_SAMPLES)
 
 ' Frame buffer, describing the waveform when repeated over the course of a frame
-Local writeBuf:Short Ptr = MemAlloc(2 * MAX_SAMPLES_PER_UPDATE)
+Local writeBuf:Short Ptr = RMemAlloc(2 * MAX_SAMPLES_PER_UPDATE)
 
 PlayAudioStream(stream)        ' Start processing stream buffer (no data loaded currently)
 
 ' Position read in to determine next frequency
 Local mousePosition:RVector2 = New RVector2(-100.0, -100.0)
 
-' Cycles per second (hz)
-Local frequency:Float = 440.0
-
-' Previous value, used to test if sine needs to be rewritten, and to smoothly modulate frequency
-Local oldFrequency:Float = 1.0
-
-' Cursor to read and copy the samples of the sine wave buffer
-Local readCursor:Int = 0
-
 ' Computed size in samples of the sine wave
 Local waveLength:Int = 1
 
@@ -56,14 +63,18 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 	mousePosition = GetMousePosition()
 
 	If IsMouseButtonDown(MOUSE_LEFT_BUTTON) Then
-		frequency = 40.0 + mousePosition.y
+		Local fp:Float = mousePosition.y
+		frequency = 40.0 + fp
+
+		Local pan:Float = (mousePosition.x / Float(screenWidth))
+		SetAudioStreamPan(stream, pan)
 	End If
 
 	' Rewrite the sine wave.
 	' Compute two cycles to allow the buffer padding, simplifying any modulation, resampling, etc.
 	If frequency <> oldFrequency Then
 		' Compute wavelength. Limit size in both directions.
-		Local oldWavelength:Int = waveLength
+
 		waveLength = Int(22050 / frequency)
 		If waveLength > MAX_SAMPLES/2 Then
 			waveLength = MAX_SAMPLES/2
@@ -77,39 +88,14 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 			data[i] = Sin(((2*Pi*Float(i)/waveLength)) * 57.2958)*32000
 		Next
 
-		' Scale read cursor's position to minimize transition artifacts
-		readCursor = Int(readCursor * (Float(waveLength) / oldWavelength))
+		' Make sure the rest of the line is flat
+		For Local i:Int = waveLength*2 Until MAX_SAMPLES
+			data[i] = 0
+		Next
+		
 		oldFrequency = frequency
 	End If
 
-	' Refill audio stream if required
-	If IsAudioStreamProcessed(stream) Then
-		' Synthesize a buffer that is exactly the requested size
-		Local writeCursor:Int = 0
-
-		While writeCursor < MAX_SAMPLES_PER_UPDATE
-			' Start by trying to write the whole chunk at once
-			Local writeLength:Int = MAX_SAMPLES_PER_UPDATE-writeCursor
-
-			' Limit to the maximum readable size
-			Local readLength:Int = waveLength-readCursor
-
-			If writeLength > readLength Then
-				writeLength = readLength
-			End If
-
-			' Write the slice
-			MemCopy(writeBuf + writeCursor, data + readCursor, writeLength*2)
-
-			' Update cursors and loop audio
-			readCursor = (readCursor + writeLength) Mod waveLength
-
-			writeCursor :+ writeLength
-		Wend
-
-		' Copy finished frame to audio stream
-		UpdateAudioStream(stream, writeBuf, MAX_SAMPLES_PER_UPDATE)
-	End If
 	'----------------------------------------------------------------------------------
 
 	' Draw
@@ -135,11 +121,26 @@ Wend
 
 ' De-Initialization
 '--------------------------------------------------------------------------------------
-MemFree(data)                 ' Unload sine wave data
-MemFree(writeBuf)             ' Unload write buffer
+RMemFree(data)                 ' Unload sine wave data
+RMemFree(writeBuf)             ' Unload write buffer
 
-CloseAudioStream(stream)   ' Close raw audio stream and delete buffers from RAM
+UnloadAudioStream(stream)   ' Close raw audio stream and delete buffers from RAM
 CloseAudioDevice()         ' Close audio device (music streaming is automatically stopped)
 
 CloseWindow()              ' Close window and OpenGL context
 '--------------------------------------------------------------------------------------
+
+Function AudioInputCallback(buffer:Byte Ptr, frames:UInt)
+	audioFrequency = frequency + (audioFrequency - frequency)*0.95
+	
+	Local incr:Float = audioFrequency/44100.0
+	Local d:Short Ptr = buffer
+	
+	For Local i:UInt = 0 Until frames
+		d[i] = Short(32000.0*Sin(2 * Pi * sineIdx))
+		sineIdx :+ incr
+		If sineIdx > 1.0 Then
+			sineIdx :- 1.0
+		End IF
+	Next
+End Function

+ 1 - 1
examples/audio/audio_sound_loading.bmx

@@ -13,7 +13,7 @@ InitWindow(screenWidth, screenHeight, "raylib [audio] example - sound loading an
 InitAudioDevice()      ' Initialize audio device
 
 Local fxWav:RSound = LoadSound("../../lib.mod/raylib/examples/audio/resources/sound.wav")         ' Load WAV audio file
-Local fxOgg:RSound = LoadSound("../../lib.mod/raylib/examples/audio/resources/tanatana.ogg")      ' Load OGG audio file
+Local fxOgg:RSound = LoadSound("../../lib.mod/raylib/examples/audio/resources/target.ogg")      ' Load OGG audio file
 
 SetTargetFPS(60)               ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------

+ 2 - 2
examples/core/core_2d_camera.bmx

@@ -96,8 +96,8 @@ While Not WindowShouldClose()        ' Detect window close button or ESC key
 
 			DrawRectangleRec(player, RED)
 
-			DrawLine(camera.target.x, -screenHeight * 10, camera.target.x, screenHeight * 10, GREEN)
-			DrawLine(-screenWidth * 10, camera.target.y, screenWidth * 10, camera.target.y, GREEN)
+			DrawLine(Int(camera.target.x), -screenHeight * 10, Int(camera.target.x), screenHeight * 10, GREEN)
+			DrawLine(-screenWidth * 10, Int(camera.target.y), screenWidth * 10, Int(camera.target.y), GREEN)
 
 		EndMode2D()
 

+ 126 - 0
examples/core/core_2d_camera_mouse_zoom.bmx

@@ -0,0 +1,126 @@
+SuperStrict
+
+Framework Ray.Lib
+Import Ray.Math
+Import Ray.rlgl
+
+Const MAX_BUILDINGS:Int = 100
+
+Const screenWidth:Int = 800
+Const screenHeight:Int = 450
+
+InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera mouse zoom")
+
+Local camera:RCamera2D = New RCamera2D()
+camera.zoom = 1.0
+
+Local zoomMode:Int = 0 ' 0-Mouse Wheel, 1-Mouse Move
+
+SetTargetFPS(60)                   ' Set our game to run at 60 frames-per-second
+'--------------------------------------------------------------------------------------
+
+' Main game loop
+While Not WindowShouldClose()        ' Detect window close button or ESC key
+
+	' Update
+	'----------------------------------------------------------------------------------
+	If IsKeyPressed(KEY_ONE) Then
+		zoomMode = 0
+	Else If IsKeyPressed(KEY_TWO) Then
+		zoomMode = 1
+	End If
+	
+	' Translate based on mouse right click
+	If IsMouseButtonDown(MOUSE_BUTTON_LEFT) Then
+		Local delta:RVector2 = GetMouseDelta()
+		delta = Vector2Scale(delta, -1.0/camera.zoom)
+		camera.target = Vector2Add(camera.target, delta)
+	End If
+
+	if zoomMode = 0 Then
+		' Zoom based on mouse wheel
+		Local wheel:Float = GetMouseWheelMove()
+		If wheel <> 0 Then
+		
+			' Get the world point that is under the mouse
+			Local mouseWorldPos:RVector2 = GetScreenToWorld2D(GetMousePosition(), camera)
+
+			' Set the offset to where the mouse is
+			camera.offset = GetMousePosition()
+
+			' Set the target to match, so that the camera maps the world space point 
+			' under the cursor to the screen space point under the cursor at any zoom
+			camera.target = mouseWorldPos
+
+			' Zoom increment
+			Local scaleFactor:Float = 1.0 + (0.25 * Abs(wheel))
+			If wheel < 0 Then
+				scaleFactor = 1.0/scaleFactor
+			End If
+			camera.zoom = Clamp(camera.zoom*scaleFactor, 0.125, 64.0)
+		End If
+	Else
+		' Zoom based on mouse right click
+		If IsMouseButtonPressed(MOUSE_BUTTON_RIGHT) Then
+			' Get the world point that is under the mouse
+			Local mouseWorldPos:RVector2 = GetScreenToWorld2D(GetMousePosition(), camera)
+
+			' Set the offset to where the mouse is
+			camera.offset = GetMousePosition()
+
+			' Set the target to match, so that the camera maps the world space point 
+			' under the cursor to the screen space point under the cursor at any zoom
+			camera.target = mouseWorldPos
+		End If
+		If IsMouseButtonDown(MOUSE_BUTTON_RIGHT) Then
+			' Zoom increment
+			Local deltaX:Float = GetMouseDelta().x
+			Local scaleFactor:Float = 1.0 + (0.01 * Abs(deltaX))
+			If deltaX < 0 Then
+				scaleFactor = 1.0/scaleFactor
+			End If
+			camera.zoom = Clamp(camera.zoom*scaleFactor, 0.125, 64.0)
+		End If
+	End If
+	'----------------------------------------------------------------------------------
+
+	' Draw
+	'----------------------------------------------------------------------------------
+	BeginDrawing()
+		ClearBackground(RAYWHITE)
+
+		BeginMode2D(camera)
+
+			' Draw the 3d grid, rotated 90 degrees and centered around 0,0 
+			' just so we have something in the XY plane
+			rlPushMatrix()
+				rlTranslatef(0, 25*50, 0)
+				rlRotatef(90, 1, 0, 0)
+				DrawGrid(100, 50)
+			rlPopMatrix()
+
+			' Draw a reference circle
+			DrawCircle(GetScreenWidth()/2, GetScreenHeight()/2, 50, MAROON)
+			
+		EndMode2D()
+		
+		' Draw mouse reference
+		'Vector2 mousePos = GetWorldToScreen2D(GetMousePosition(), camera)
+		DrawCircleV(GetMousePosition(), 4, DARKGRAY)
+		DrawTextEx(GetFontDefault(), "[" + GetMouseX() +", " + GetMouseY() + "]", ..
+			Vector2Add(GetMousePosition(), New RVector2(-44, -24)), 20, 2, BLACK)
+
+		DrawText("[1][2] Select mouse zoom mode (Wheel or Move)", 20, 20, 20, DARKGRAY)
+		If zoomMode = 0 Then
+			DrawText("Mouse left button drag to move, mouse wheel to zoom", 20, 50, 20, DARKGRAY)
+		Else
+			DrawText("Mouse left button drag to move, mouse press and move to zoom", 20, 50, 20, DARKGRAY)
+		End If
+	
+	EndDrawing()
+	'----------------------------------------------------------------------------------
+Wend
+
+' De-Initialization
+'--------------------------------------------------------------------------------------
+CloseWindow()        ' Close window and OpenGL context

+ 110 - 12
examples/core/core_3d_camera_first_person.bmx

@@ -1,6 +1,7 @@
 SuperStrict
 
 Framework Ray.Lib
+Import BRL.Math
 
 Const MAX_COLUMNS:Int = 20
 
@@ -11,11 +12,13 @@ InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera first p
 
 ' Define the camera to look into our 3d world (position, target, up vector)
 Local camera:RCamera = New RCamera()
-camera.position = New RVector3(4.0, 2.0, 4.0)
-camera.target = New RVector3(0.0, 1.8, 0.0)
-camera.up = New RVector3(0.0, 1.0, 0.0)
-camera.fovy = 60.0
-camera.cameraType = CAMERA_PERSPECTIVE
+camera.position = New RVector3(0.0, 2.0, 4.0)     ' Camera position
+camera.target = New RVector3(0.0, 2.0, 0.0)       ' Camera looking at point
+camera.up = New RVector3(0.0, 1.0, 0.0)           ' Camera up vector (rotation towards target)
+camera.fovy = 60.0                                ' Camera field-of-view Y
+camera.projection = CAMERA_PERSPECTIVE            ' Camera projection type
+
+Local cameraMode:Int = CAMERA_FIRST_PERSON
 
 ' Generates some random columns
 Local heights:Float[MAX_COLUMNS]
@@ -28,7 +31,7 @@ For Local i:Int = 0 Until MAX_COLUMNS
 	colors[i] = New RColor(GetRandomValue(20, 255), GetRandomValue(10, 55), 30, 255)
 Next
 
-SetCameraMode(camera, CAMERA_FIRST_PERSON) ' Set a first person camera mode
+DisableCursor()                            ' Limit cursor to relative movement inside the window
 
 SetTargetFPS(60)                           ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
@@ -37,7 +40,55 @@ SetTargetFPS(60)                           ' Set our game to run at 60 frames-pe
 While Not WindowShouldClose()                ' Detect window close button or ESC key
 	' Update
 	'----------------------------------------------------------------------------------
-	UpdateCamera(camera)                  ' Update camera
+	' Switch camera mode
+	If IsKeyPressed(KEY_ONE) Then
+		cameraMode = CAMERA_FREE
+		camera.up = New RVector3(0.0, 1.0, 0.0) ' Reset roll
+	End If
+
+	If IsKeyPressed(KEY_TWO) Then
+		cameraMode = CAMERA_FIRST_PERSON
+		camera.up = New RVector3(0.0, 1.0, 0.0) ' Reset roll
+	End If
+
+	If IsKeyPressed(KEY_THREE) Then
+		cameraMode = CAMERA_THIRD_PERSON
+		camera.up = New RVector3(0.0, 1.0, 0.0) ' Reset roll
+	End If
+
+	If IsKeyPressed(KEY_FOUR) Then
+		cameraMode = CAMERA_ORBITAL
+		camera.up = New RVector3(0.0, 1.0, 0.0) ' Reset roll
+	End If
+
+	' Switch camera projection
+	If IsKeyPressed(KEY_P) Then
+		if camera.projection = CAMERA_PERSPECTIVE Then
+			' Create isometric view
+			cameraMode = CAMERA_THIRD_PERSON
+			' Note: The target distance is related to the render distance in the orthographic projection
+			camera.position = New RVector3(0.0, 2.0, -100.0)
+			camera.target = New RVector3(0.0, 2.0, 0.0)
+			camera.up = New RVector3(0.0, 1.0, 0.0)
+			camera.projection = CAMERA_ORTHOGRAPHIC
+			camera.fovy = 20.0 ' near plane width in CAMERA_ORTHOGRAPHIC
+			CameraYaw(camera, Deg2RadF(-135), True)
+			CameraPitch(camera, Deg2RadF(-45), True, True, False)
+		Else
+			' Reset to default view
+			cameraMode = CAMERA_THIRD_PERSON
+			camera.position = New RVector3(0.0, 2.0, 10.0)
+			camera.target = New RVector3(0.0, 2.0, 0.0)
+			camera.up = New RVector3(0.0, 1.0, 0.0)
+			camera.projection = CAMERA_PERSPECTIVE
+			camera.fovy = 60.0
+		End If
+	End If
+
+	' Update camera computes movement internally depending on the camera mode
+	' Some default standard keyboard/mouse inputs are hardcoded to simplify use
+	' For advance camera controls, it's reecommended to compute camera movement manually
+	UpdateCamera(camera, cameraMode)                  ' Update camera
 	'----------------------------------------------------------------------------------
 
 	' Draw
@@ -59,14 +110,61 @@ While Not WindowShouldClose()                ' Detect window close button or ESC
 				DrawCubeWires(positions[i], 2.0, heights[i], 2.0, MAROON)
 			Next
 
+			' Draw player cube
+			If cameraMode = CAMERA_THIRD_PERSON Then
+				DrawCube(camera.target, 0.5, 0.5, 0.5, PURPLE)
+				DrawCubeWires(camera.target, 0.5, 0.5, 0.5, DARKPURPLE)
+			End If
+
 		EndMode3D()
 
-		DrawRectangle( 10, 10, 220, 70, Fade(SKYBLUE, 0.5))
-		DrawRectangleLines( 10, 10, 220, 70, BLUE)
+		DrawRectangle( 5, 5, 330, 100, Fade(SKYBLUE, 0.5))
+		DrawRectangleLines( 5, 5, 330, 100, BLUE)
+
+		DrawText("Camera controls:", 15, 15, 10, BLACK)
+		DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, BLACK)
+		DrawText("- Look around: arrow keys or mouse", 15, 45, 10, BLACK)
+		DrawText("- Camera mode keys: 1, 2, 3, 4", 15, 60, 10, BLACK)
+		DrawText("- Zoom keys: num-plus, num-minus or mouse scroll", 15, 75, 10, BLACK)
+		DrawText("- Camera projection key: P", 15, 90, 10, BLACK)
+
+		DrawRectangle(600, 5, 195, 100, Fade(SKYBLUE, 0.5))
+		DrawRectangleLines(600, 5, 195, 100, BLUE)
+
+		DrawText("Camera status:", 610, 15, 10, BLACK)
+
+		Local mode:String
+		Select cameraMode
+			Case CAMERA_FREE
+				mode = "FREE"
+			Case CAMERA_FIRST_PERSON
+				mode = "FIRST_PERSON"
+			Case CAMERA_THIRD_PERSON
+				mode = "THIRD_PERSON"
+			Case CAMERA_ORBITAL
+				mode = "ORBITAL"
+			Default
+				mode = "CUSTOM"
+		End Select
+
+		DrawText("- Mode: " + mode, 610, 30, 10, BLACK)
+
+		Local projection:String
+
+		Select camera.projection
+			Case CAMERA_PERSPECTIVE
+				projection = "PERSPECTIVE"
+			Case CAMERA_ORTHOGRAPHIC
+				projection = "ORTHOGRAPHIC"
+			Default
+				projection = "CUSTOM"
+		End Select
+
+		DrawText("- Projection: " + projection, 610, 45, 10, BLACK)
+		DrawText("- Position: (" + camera.position.x + ", " + camera.position.y + ", " + camera.position.z + ")", 610, 60, 10, BLACK)
+		DrawText("- Target: (" + camera.target.x + ", " + camera.target.y + ", " + camera.target.z + ")", 610, 75, 10, BLACK)
+		DrawText("- Up: (" + camera.up.x + ", " + camera.up.y + ", " + camera.up.z + ")", 610, 90, 10, BLACK)
 
-		DrawText("First person camera default controls:", 20, 20, 10, BLACK)
-		DrawText("- Move with keys: W, A, S, D", 40, 40, 10, DARKGRAY)
-		DrawText("- Mouse move to look around", 40, 60, 10, DARKGRAY)
 
 	EndDrawing()
 	'----------------------------------------------------------------------------------

+ 6 - 8
examples/core/core_3d_camera_free.bmx

@@ -15,11 +15,11 @@ camera.position = New RVector3(10.0, 10.0, 10.0) ' Camera position
 camera.target = New RVector3(0.0, 0.0, 0.0)      ' Camera looking at point
 camera.up = New RVector3(0.0, 1.0, 0.0)          ' Camera up vector (rotation towards target)
 camera.fovy = 45.0                               ' Camera field-of-view Y
-camera.cameraType = CAMERA_PERSPECTIVE           ' Camera mode type
+camera.projection = CAMERA_PERSPECTIVE           ' Camera mode type
 
 Local cubePosition:RVector3 = New RVector3(0.0, 0.0, 0.0)
 
-SetCameraMode(camera, CAMERA_FREE) ' Set a free camera mode
+DisableCursor()                    ' Limit cursor to relative movement inside the window
 
 SetTargetFPS(60)                   ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
@@ -28,7 +28,7 @@ SetTargetFPS(60)                   ' Set our game to run at 60 frames-per-second
 While Not WindowShouldClose()        ' Detect window close button or ESC key
 	' Update
 	'----------------------------------------------------------------------------------
-	UpdateCamera(camera)          ' Update camera
+	UpdateCamera(camera, CAMERA_FREE)          ' Update camera
 
 	If IsKeyDown(Asc("Z")) Then
 		camera.target = New RVector3(0.0, 0.0, 0.0)
@@ -50,15 +50,13 @@ While Not WindowShouldClose()        ' Detect window close button or ESC key
 
 		EndMode3D()
 
-		DrawRectangle( 10, 10, 320, 133, Fade(SKYBLUE, 0.5))
-		DrawRectangleLines( 10, 10, 320, 133, BLUE)
+		DrawRectangle( 10, 10, 320, 93, Fade(SKYBLUE, 0.5))
+		DrawRectangleLines( 10, 10, 320, 93, BLUE)
 
 		DrawText("Free camera default controls:", 20, 20, 10, BLACK)
 		DrawText("- Mouse Wheel to Zoom in-out", 40, 40, 10, DARKGRAY)
 		DrawText("- Mouse Wheel Pressed to Pan", 40, 60, 10, DARKGRAY)
-		DrawText("- Alt + Mouse Wheel Pressed to Rotate", 40, 80, 10, DARKGRAY)
-		DrawText("- Alt + Ctrl + Mouse Wheel Pressed for Smooth Zoom", 40, 100, 10, DARKGRAY)
-		DrawText("- Z to zoom to (0, 0, 0)", 40, 120, 10, DARKGRAY)
+		DrawText("- Z to zoom to (0, 0, 0)", 40, 80, 10, DARKGRAY)
 
 	EndDrawing()
 	'----------------------------------------------------------------------------------

+ 1 - 1
examples/core/core_3d_camera_mode.bmx

@@ -15,7 +15,7 @@ camera.position = New RVector3(0.0, 10.0, 10.0)  ' Camera position
 camera.target = New RVector3(0.0, 0.0, 0.0)      ' Camera looking at point
 camera.up = New RVector3(0.0, 1.0, 0.0)          ' Camera up vector (rotation towards target)
 camera.fovy = 45.0                               ' Camera field-of-view Y
-camera.cameraType = CAMERA_PERSPECTIVE           ' Camera mode type
+camera.projection = CAMERA_PERSPECTIVE           ' Camera mode type
 
 Local cubePosition:RVector3 = New RVector3(0.0, 0.0, 0.0)
 

+ 23 - 13
examples/core/core_3d_picking.bmx

@@ -15,16 +15,13 @@ camera.position = New RVector3(10.0, 10.0, 10.0) ' Camera position
 camera.target = New RVector3(0.0, 0.0, 0.0)      ' Camera looking at point
 camera.up = New RVector3(0.0, 1.0, 0.0)          ' Camera up vector (rotation towards target)
 camera.fovy = 45.0                                ' Camera field-of-view Y
-camera.cameraType = CAMERA_PERSPECTIVE                   ' Camera mode type
+camera.projection = CAMERA_PERSPECTIVE                   ' Camera mode type
 
 Local cubePosition:RVector3 = New RVector3(0.0, 1.0, 0.0)
 Local cubeSize:RVector3 = New RVector3(2.0, 2.0, 2.0)
 
 Local ray:RRay                    ' Picking line ray
-
-Local collision:Int = False
-
-SetCameraMode(camera, CAMERA_FREE) ' Set a free camera mode
+Local collision:RRayCollision ' Ray collision hit info
 
 SetTargetFPS(60)                   ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
@@ -33,18 +30,29 @@ SetTargetFPS(60)                   ' Set our game to run at 60 frames-per-second
 While Not WindowShouldClose()        ' Detect window close button or ESC key
 	' Update
 	'----------------------------------------------------------------------------------
-	UpdateCamera(camera)          ' Update camera
+	If IsCursorHidden() Then
+		UpdateCamera(camera, CAMERA_FIRST_PERSON)
+	End If
+
+	' Toggle camera controls
+	If IsMouseButtonPressed(MOUSE_BUTTON_RIGHT) Then
+		If IsCursorHidden() Then
+			EnableCursor()
+		Else
+			DisableCursor()
+		End If
+	End If
 
 	If IsMouseButtonPressed(MOUSE_LEFT_BUTTON) Then
-		If Not collision Then
-			ray = GetMouseRay(GetMousePosition(), camera)
+		If Not collision.hit Then
+			ray = GetScreenToWorldRay(GetMousePosition(), camera)
 
 			' Check collision between ray and box
-			collision = CheckCollisionRayBox(ray, ..
+			collision = GetRayCollisionBox(ray, ..
 						New RBoundingBox(New RVector3(cubePosition.x - cubeSize.x/2, cubePosition.y - cubeSize.y/2, cubePosition.z - cubeSize.z/2), ..
 									     New RVector3(cubePosition.x + cubeSize.x/2, cubePosition.y + cubeSize.y/2, cubePosition.z + cubeSize.z/2)))
 		Else
-			collision = False
+			collision.hit = False
 		End If
 	End If
 	'----------------------------------------------------------------------------------
@@ -57,7 +65,7 @@ While Not WindowShouldClose()        ' Detect window close button or ESC key
 
 		BeginMode3D(camera)
 
-			If collision Then
+			If collision.hit Then
 				DrawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, RED)
 				DrawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, MAROON)
 
@@ -74,10 +82,12 @@ While Not WindowShouldClose()        ' Detect window close button or ESC key
 
 		DrawText("Try selecting the box with mouse!", 240, 10, 20, DARKGRAY)
 
-		If collision Then
-			DrawText("BOX SELECTED", (screenWidth - MeasureText("BOX SELECTED", 30)) / 2, screenHeight * 0.1, 30, GREEN)
+		If collision.hit Then
+			DrawText("BOX SELECTED", (screenWidth - MeasureText("BOX SELECTED", 30)) / 2, Int(screenHeight * 0.1), 30, GREEN)
 		End If
 
+		DrawText("Right click mouse to toggle camera controls", 10, 430, 10, GRAY)
+
 		DrawFPS(10, 10)
 
 	EndDrawing()

+ 2 - 2
examples/core/core_random_values.bmx

@@ -9,10 +9,10 @@ Const screenHeight:Int = 450
 
 InitWindow(screenWidth, screenHeight, "raylib [core] example - generate random values")
 
-Local framesCounter:Int = 0          ' Variable used to count frames
-
 Local randValue:Int = GetRandomValue(-8, 5)   ' Get a random integer number between -8 and 5 (both included)
 
+Local framesCounter:Int = 0          ' Variable used to count frames
+
 SetTargetFPS(60)               ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
 

+ 15 - 37
examples/core/core_window_letterbox.bmx

@@ -1,6 +1,7 @@
 SuperStrict
 
 Framework Ray.Lib
+Import Ray.Math
 Import Text.Format
 
 Local defFormatter:TFormatter = TFormatter.Create("Default Mouse: [%i , %i]")
@@ -19,7 +20,7 @@ Local gameScreenHeight:Int = 480
 
 ' Render texture initialization, used to hold the rendering result so we can easily resize it
 Local target:RRenderTexture2D = LoadRenderTexture(gameScreenWidth, gameScreenHeight)
-SetTextureFilter(target.texture, FILTER_BILINEAR)  ' Texture scale filter to use
+SetTextureFilter(target.texture, TEXTURE_FILTER_BILINEAR)  ' Texture scale filter to use
 
 Local colors:RColor[10]
 For Local i:Int = 0 Until 10
@@ -49,28 +50,28 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 	Local virtualMouse:RVector2
 	virtualMouse.x = (mouse.x - (GetScreenWidth() - (gameScreenWidth * scale)) * 0.5) / scale
 	virtualMouse.y = (mouse.y - (GetScreenHeight() - (gameScreenHeight * scale)) * 0.5) / scale
-	virtualMouse = ClampValue(virtualMouse, New RVector2(0, 0), New RVector2(gameScreenWidth, gameScreenHeight)) 
+	virtualMouse = Vector2Clamp(virtualMouse, New RVector2(0, 0), New RVector2(gameScreenWidth, gameScreenHeight)) 
 	
 	' Draw
 	'----------------------------------------------------------------------------------
-	BeginDrawing()
-		ClearBackground(BLACK)
+	' Draw everything in the render texture, note this will not be rendered on screen, yet
+	BeginTextureMode(target)
 
-		' Draw everything in the render texture, note this will not be rendered on screen, yet
-		BeginTextureMode(target)
+		ClearBackground(RAYWHITE)         ' Clear render texture background color
 
-			ClearBackground(RAYWHITE)         ' Clear render texture background color
+		For Local i:Int = 0 Until 10
+			DrawRectangle(0, (gameScreenHeight / 10) * i, gameScreenWidth, gameScreenHeight / 10, colors[i])
+		Next
 
-			For Local i:Int = 0 Until 10
-				DrawRectangle(0, (gameScreenHeight / 10) * i, gameScreenWidth, gameScreenHeight / 10, colors[i])
-			Next
+		DrawText("If executed inside a window,~nyou can resize the window,~nand see the screen scaling!", 10, 25, 20, WHITE)
 
-			DrawText("If executed inside a window,~nyou can resize the window,~nand see the screen scaling!", 10, 25, 20, WHITE)
+		DrawText(defFormatter.Clear().Arg(Int(mouse.x)).Arg(Int(mouse.y)).Format(), 350, 25, 20, GREEN)
+		DrawText(virFormatter.Clear().Arg(Int(virtualMouse.x)).Arg(Int(virtualMouse.y)).Format(), 350, 55, 20, YELLOW)
 
-			DrawText(defFormatter.Clear().Arg(Int(mouse.x)).Arg(Int(mouse.y)).Format(), 350, 25, 20, GREEN)
-			DrawText(virFormatter.Clear().Arg(Int(virtualMouse.x)).Arg(Int(virtualMouse.y)).Format(), 350, 55, 20, YELLOW)
+	EndTextureMode()
 
-		EndTextureMode()
+	BeginDrawing()
+		ClearBackground(BLACK)
 
 		' Draw RenderTexture2D to window, properly scaled
 		DrawTexturePro(target.texture, ..
@@ -89,26 +90,3 @@ UnloadRenderTexture(target)    ' Unload render texture
 CloseWindow()                  ' Close window and OpenGL context
 '--------------------------------------------------------------------------------------
 
-' Clamp Vector2 value with min and max and return a new vector2
-' NOTE: Required for virtual mouse, to clamp inside virtual game size
-Function ClampValue:RVector2(value:RVector2, minimum:RVector2, maximum:RVector2)
-	Local result:RVector2 = value
-
-	If result.x > maximum.x Then
-		result.x = maximum.x
-	End If
-	
-	If result.x < minimum.x Then
-		result.x = minimum.x
-	End If
-	
-	If result.y > maximum.y Then
-		result.y = maximum.y
-	End If
-	
-	If result.y < minimum.y Then
-		result.y = minimum.y
-	End If
-
-	Return result
-End Function

+ 6 - 4
examples/core/core_world_screen.bmx

@@ -15,12 +15,12 @@ camera.position = New RVector3(10.0, 10.0, 10.0)
 camera.target = New RVector3(0.0, 0.0, 0.0)
 camera.up = New RVector3(0.0, 1.0, 0.0)
 camera.fovy = 45.0
-camera.cameraType = CAMERA_PERSPECTIVE
+camera.projection = CAMERA_PERSPECTIVE
 
 Local cubePosition:RVector3 = New RVector3(0.0, 0.0, 0.0)
 Local cubeScreenPosition:RVector2 = New RVector2(0.0, 0.0)
 
-SetCameraMode(camera, CAMERA_FREE) ' Set a free camera mode
+DisableCursor()                    ' Limit cursor to relative movement inside the window
 
 SetTargetFPS(60)                   ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
@@ -29,7 +29,7 @@ SetTargetFPS(60)                   ' Set our game to run at 60 frames-per-second
 While Not WindowShouldClose()        ' Detect window close button or ESC key
 	' Update
 	'----------------------------------------------------------------------------------
-	UpdateCamera(camera)          ' Update camera
+	UpdateCamera(camera, CAMERA_THIRD_PERSON)          ' Update camera
 
 	' Calculate cube screen space position (with a little offset to be in top)
 	cubeScreenPosition = GetWorldToScreen(New RVector3(cubePosition.x, cubePosition.y + 2.5, cubePosition.z), camera)
@@ -51,7 +51,9 @@ While Not WindowShouldClose()        ' Detect window close button or ESC key
 		EndMode3D()
 
 		DrawText("Enemy: 100 / 100", Int(cubeScreenPosition.x - MeasureText("Enemy: 100/100", 20)/2), Int(cubeScreenPosition.y), 20, BLACK)
-		DrawText("Text is always on top of the cube", (screenWidth - MeasureText("Text is always on top of the cube", 20))/2, 25, 20, GRAY)
+
+		DrawText("Cube position in screen space coordinates: [ " + Int(cubeScreenPosition.x) + ", " + Int(cubeScreenPosition.y) + "]", 10, 10, 20, LIME);
+		DrawText("Text 2d should be always on top of the cube", 10, 40, 20, GRAY)
 
 	EndDrawing()
 	'----------------------------------------------------------------------------------

+ 10 - 17
examples/models/models_animation.bmx

@@ -15,22 +15,21 @@ camera.position = New RVector3(10.0, 10.0, 10.0) ' Camera position
 camera.target = New RVector3(0.0, 0.0, 0.0)      ' Camera looking at point
 camera.up = New RVector3(0.0, 1.0, 0.0)          ' Camera up vector (rotation towards target)
 camera.fovy = 45.0                                ' Camera field-of-view Y
-camera.cameraType = CAMERA_PERSPECTIVE                   ' Camera mode type
+camera.projection = CAMERA_PERSPECTIVE                   ' Camera mode type
 
 
-Local model:RModel = LoadModel("../../lib.mod/raylib/examples/models/resources/guy/guy.iqm")               ' Load the animated model mesh and basic data
-Local texture:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/models/resources/guy/guytex.png")    ' Load model texture and set material
-SetMaterialTexture(model.materials[0], MAP_DIFFUSE, texture)  ' Set model material map texture
+Local model:RModel = LoadModel("../../lib.mod/raylib/examples/models/resources/models/iqm/guy.iqm")               ' Load the animated model mesh and basic data
+Local texture:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/models/resources/models/iqm/guytex.png")    ' Load model texture and set material
+SetMaterialTexture(model.materials[0], MATERIAL_MAP_DIFFUSE, texture)  ' Set model material map texture
 
 Local position:RVector3            ' Set model position
 
 ' Load animation data
 Local animsCount:Int = 0
-Local anims:RModelAnimation Ptr = LoadModelAnimations("../../lib.mod/raylib/examples/models/resources/guy/guyanim.iqm", animsCount)
+Local anims:RModelAnimation Ptr = LoadModelAnimations("../../lib.mod/raylib/examples/models/resources/models/iqm/guyanim.iqm", animsCount)
 Local animFrameCounter:Int = 0
 
-SetCameraMode(camera, CAMERA_FREE) ' Set free camera mode
-
+DisableCursor()                    ' Catch cursor
 SetTargetFPS(60)                   ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
 
@@ -38,7 +37,7 @@ SetTargetFPS(60)                   ' Set our game to run at 60 frames-per-second
 While Not WindowShouldClose()        ' Detect window close button or ESC key
 	' Update
 	'----------------------------------------------------------------------------------
-	UpdateCamera(camera)
+	UpdateCamera(camera, CAMERA_FIRST_PERSON)
 
 	' Play animation when spacebar is held down
 	If IsKeyDown(KEY_SPACE) Then
@@ -77,15 +76,9 @@ Wend
 
 ' De-Initialization
 '--------------------------------------------------------------------------------------
-UnloadTexture(texture)     ' Unload texture
-
-' Unload model animations data
-For Local i:Int = 0 Until animsCount
-	UnloadModelAnimation(anims[i])
-Next
-RlFree(anims)
-
-UnloadModel(model)         ' Unload model
+UnloadTexture(texture)                     ' Unload texture
+UnloadModelAnimations(anims, animsCount)   ' Unload model animations data
+UnloadModel(model)                         ' Unload model
 
 CloseWindow()              ' Close window and OpenGL context
 '--------------------------------------------------------------------------------------

+ 35 - 5
examples/models/models_billboard.bmx

@@ -1,6 +1,7 @@
 SuperStrict
 
 Framework Ray.Lib
+Import Ray.Math
 
 ' Initialization
 '--------------------------------------------------------------------------------------
@@ -15,12 +16,30 @@ camera.position = New RVector3(5.0, 4.0, 5.0)
 camera.target = New RVector3(0.0, 2.0, 0.0)
 camera.up = New RVector3(0.0, 1.0, 0.0)
 camera.fovy = 45.0
-camera.cameraType = CAMERA_PERSPECTIVE
+camera.projection = CAMERA_PERSPECTIVE
 
 Local bill:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/models/resources/billboard.png")     ' Our texture billboard
-Local billPosition:RVector3 = New RVector3(0.0, 2.0, 0.0)                 ' Position where draw billboard
+Local billPositionStatic:RVector3 = New RVector3(0.0, 2.0, 0.0)                 ' Position of static billboard
+Local billPositionRotating:RVector3 = New RVector3(1.0, 2.0, 1.0)               ' Position of rotating billboard
 
-SetCameraMode(camera, CAMERA_ORBITAL)  ' Set an orbital camera mode
+' Entire billboard texture, source is used to take a segment from a larger texture.
+Local source:RRectangle = New RRectangle(0.0, 0.0, Float(bill.width), Float(bill.height))
+
+' NOTE: Billboard locked on axis-Y
+Local billUp:RVector3 = New RVector3(0.0, 1.0, 0.0)
+
+' Set the height of the rotating billboard to 1.0 with the aspect ratio fixed
+Local size:RVector2 = New RVector2(source.width/source.height, 1.0)
+
+' Rotate around origin
+' Here we choose to rotate around the image center
+Local origin:RVector2 = Vector2Scale(size, 0.5)
+
+' Distance is needed for the correct billboard draw order
+' Larger distance (further away from the camera) should be drawn prior to smaller distance.
+Local distanceStatic:Float
+Local distanceRotating:Float
+Local rotation:Float = 0.0
 
 SetTargetFPS(60)                       ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
@@ -29,7 +48,11 @@ SetTargetFPS(60)                       ' Set our game to run at 60 frames-per-se
 While Not WindowShouldClose()            ' Detect window close button or ESC key
 	' Update
 	'----------------------------------------------------------------------------------
-	UpdateCamera(camera)              ' Update camera
+	UpdateCamera(camera, CAMERA_ORBITAL)              ' Update camera
+
+	rotation :+ 0.4
+	distanceStatic = Vector3Distance(camera.position, billPositionStatic)
+	distanceRotating = Vector3Distance(camera.position, billPositionRotating)
 	'----------------------------------------------------------------------------------
 
 	' Draw
@@ -42,7 +65,14 @@ While Not WindowShouldClose()            ' Detect window close button or ESC key
 
 			DrawGrid(10, 1.0)        ' Draw a grid
 
-			DrawBillboard(camera, bill, billPosition, 2.0, WHITE)
+			' Draw order matters!
+			If distanceStatic > distanceRotating Then
+				DrawBillboard(camera, bill, billPositionStatic, 2.0, WHITE)
+				DrawBillboardPro(camera, bill, source, billPositionRotating, billUp, size, origin, rotation, WHITE)
+			Else
+				DrawBillboardPro(camera, bill, source, billPositionRotating, billUp, size, origin, rotation, WHITE)
+				DrawBillboard(camera, bill, billPositionStatic, 2.0, WHITE)
+			End If
 
 		EndMode3D()
 

+ 10 - 4
examples/models/models_cubicmap.bmx

@@ -10,7 +10,7 @@ Const screenHeight:Int = 450
 InitWindow(screenWidth, screenHeight, "raylib [models] example - cubesmap loading and drawing")
 
 ' Define the camera to look into our 3d world
-Local camera:RCamera = New RCamera(New RVector3(16.0, 14.0, 16.0), New RVector3(0.0, 0.0, 0.0), New RVector3(0.0, 1.0, 0.0), 45.0, 0)
+Local camera:RCamera = New RCamera(New RVector3(16.0, 14.0, 16.0), New RVector3(0.0, 0.0, 0.0), New RVector3(0.0, 1.0, 0.0), 45.0, CAMERA_PERSPECTIVE)
 
 Local image:RImage = LoadImage("../../lib.mod/raylib/examples/models/resources/cubicmap.png")      ' Load cubicmap image (RAM)
 Local cubicmap:RTexture2D = LoadTextureFromImage(image)       ' Convert image to texture to display (VRAM)
@@ -20,13 +20,13 @@ Local model:RModel = LoadModelFromMesh(mesh)
 
 ' NOTE: By default each cube is mapped to one part of texture atlas
 Local texture:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/models/resources/cubicmap_atlas.png")    ' Load map texture
-model.materials[0].maps[MAP_DIFFUSE].texture = texture             ' Set map diffuse texture
+model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture             ' Set map diffuse texture
 
 Local mapPosition:RVector3 = New RVector3(-16.0, 0.0, -8.0)          ' Set model position
 
 UnloadImage(image)     ' Unload cubesmap image from RAM, already uploaded to VRAM
 
-SetCameraMode(camera, CAMERA_ORBITAL)  ' Set an orbital camera mode
+Local pause:Int = false     ' Pause camera orbital rotation (and zoom)
 
 SetTargetFPS(60)                       ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
@@ -35,7 +35,13 @@ SetTargetFPS(60)                       ' Set our game to run at 60 frames-per-se
 While Not WindowShouldClose()            ' Detect window close button or ESC key
 	' Update
 	'----------------------------------------------------------------------------------
-	UpdateCamera(camera)              ' Update camera
+	If IsKeyPressed(KEY_P) Then
+		pause = Not pause
+	End If
+
+	If Not pause Then
+		UpdateCamera(camera, CAMERA_ORBITAL)              ' Update camera
+	End If
 	'----------------------------------------------------------------------------------
 
 	' Draw

+ 6 - 10
examples/models/models_first_person_maze.bmx

@@ -10,7 +10,7 @@ Const screenHeight:Int = 450
 InitWindow(screenWidth, screenHeight, "raylib [models] example - first person maze")
 
 ' Define the camera to look into our 3d world
-Local camera:RCamera = New RCamera( New RVector3(0.2, 0.4, 0.2), New RVector3(0.0, 0.0, 0.0), New RVector3(0.0, 1.0, 0.0), 45.0, 0 )
+Local camera:RCamera = New RCamera( New RVector3(0.2, 0.4, 0.2), New RVector3(0.185, 0.0, 0.0), New RVector3(0.0, 1.0, 0.0), 45.0, CAMERA_PERSPECTIVE )
 
 Local imMap:RImage = LoadImage("../../lib.mod/raylib/examples/models/resources/cubicmap.png")      ' Load cubicmap image (RAM)
 Local cubicmap:RTexture2D = LoadTextureFromImage(imMap)       ' Convert image to texture to display (VRAM)
@@ -19,16 +19,15 @@ Local model:RModel = LoadModelFromMesh(mesh)
 
 ' NOTE: By default each cube is mapped to one part of texture atlas
 Local texture:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/models/resources/cubicmap_atlas.png")    ' Load map texture
-model.materials[0].maps[MAP_DIFFUSE].texture = texture             ' Set map diffuse texture
+model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture             ' Set map diffuse texture
 
 ' Get map image data to be used for collision detection
-Local mapPixels:RColor Ptr = GetImageData(imMap)
+Local mapPixels:RColor Ptr = LoadImageColors(imMap)
 UnloadImage(imMap)             ' Unload image from RAM
 
 Local mapPosition:RVector3 = New RVector3(-16.0, 0.0, -8.0)  ' Set model position
-Local playerPosition:RVector3 = camera.position       ' Set player position
 
-SetCameraMode(camera, CAMERA_FIRST_PERSON)     ' Set camera mode
+DisableCursor()                ' Limit cursor to relative movement inside the window
 
 SetTargetFPS(60)               ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
@@ -39,7 +38,7 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 	'----------------------------------------------------------------------------------
 	Local oldCamPos:RVector3 = camera.position    ' Store old camera position
 
-	UpdateCamera(camera)      ' Update camera
+	UpdateCamera(camera, CAMERA_FIRST_PERSON)      ' Update camera
 
 	' Check player collision (we simplify to 2D collision detection)
 	Local playerPos:RVector2 = New RVector2(camera.position.x, camera.position.z)
@@ -81,10 +80,7 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 		ClearBackground(RAYWHITE)
 
 		BeginMode3D(camera)
-
 			DrawModel(model, mapPosition, 1.0, WHITE)                     ' Draw maze map
-			'DrawCubeV(playerPosition, new RVector3(0.2, 0.4, 0.2), RED)  ' Draw player
-
 		EndMode3D()
 
 		DrawTextureEx(cubicmap, New RVector2(GetScreenWidth() - cubicmap.width*4 - 20, 20), 0.0, 4.0, WHITE)
@@ -101,7 +97,7 @@ Wend
 
 ' De-Initialization
 '--------------------------------------------------------------------------------------
-RLFree(mapPixels)            ' Unload color array
+UnloadImageColors(mapPixels)            ' Unload color array
 
 UnloadTexture(cubicmap)    ' Unload cubicmap texture
 UnloadTexture(texture)     ' Unload map texture

+ 4 - 1
examples/models/models_geometric_shapes.bmx

@@ -15,7 +15,7 @@ camera.position = New RVector3(0.0, 10.0, 10.0)
 camera.target = New RVector3(0.0, 0.0, 0.0)
 camera.up = New RVector3(0.0, 1.0, 0.0)
 camera.fovy = 45.0
-camera.cameraType = CAMERA_PERSPECTIVE
+camera.projection = CAMERA_PERSPECTIVE
 
 SetTargetFPS(60)               ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
@@ -49,6 +49,9 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 			DrawCylinder(New RVector3(1.0, 0.0, -4.0), 0.0, 1.5, 3.0, 8, GOLD)
 			DrawCylinderWires(New RVector3(1.0, 0.0, -4.0), 0.0, 1.5, 3.0, 8, PINK)
 
+			DrawCapsule(New RVector3(-3.0, 1.5, -4.0), New RVector3(-4.0, -1.0, -4.0), 1.2, 8, 8, VIOLET)
+			DrawCapsuleWires(New RVector3(-3.0, 1.5, -4.0), New RVector3(-4.0, -1.0, -4.0), 1.2, 8, 8, PURPLE)
+
 			DrawGrid(10, 1.0)        ' Draw a grid
 
 		EndMode3D()

+ 3 - 5
examples/models/models_heightmap.bmx

@@ -10,7 +10,7 @@ Const screenHeight:Int = 450
 InitWindow(screenWidth, screenHeight, "raylib [models] example - heightmap loading and drawing")
 
 ' Define our custom camera to look into our 3d world
-Local camera:RCamera = New RCamera(New RVector3(18.0, 18.0, 18.0), New RVector3(0.0, 0.0, 0.0), New RVector3(0.0, 1.0, 0.0), 45.0, 0)
+Local camera:RCamera = New RCamera(New RVector3(18.0, 21.0, 18.0), New RVector3(0.0, 0.0, 0.0), New RVector3(0.0, 1.0, 0.0), 45.0, CAMERA_PERSPECTIVE)
 
 Local image:RImage = LoadImage("../../lib.mod/raylib/examples/models/resources/heightmap.png")             ' Load heightmap image (RAM)
 Local texture:RTexture2D = LoadTextureFromImage(image)                ' Convert image to texture (VRAM)
@@ -18,13 +18,11 @@ Local texture:RTexture2D = LoadTextureFromImage(image)                ' Convert
 Local mesh:RMesh = GenMeshHeightmap(image, New RVector3(16, 8, 16))    ' Generate heightmap mesh (RAM and VRAM)
 Local model:RModel = LoadModelFromMesh(mesh)                          ' Load model from generated mesh
 
-model.materials[0].maps[MAP_DIFFUSE].texture = texture         ' Set map diffuse texture
+model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture         ' Set map diffuse texture
 Local mapPosition:RVector3 = New RVector3(-8.0, 0.0, -8.0)                   ' Define model position
 
 UnloadImage(image)                     ' Unload heightmap image from RAM, already uploaded to VRAM
 
-SetCameraMode(camera, CAMERA_ORBITAL)  ' Set an orbital camera mode
-
 SetTargetFPS(60)                       ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
 
@@ -32,7 +30,7 @@ SetTargetFPS(60)                       ' Set our game to run at 60 frames-per-se
 While Not WindowShouldClose()            ' Detect window close button or ESC key
 	' Update
 	'----------------------------------------------------------------------------------
-	UpdateCamera(camera)              ' Update camera
+	UpdateCamera(camera, CAMERA_ORBITAL)              ' Update camera
 	'----------------------------------------------------------------------------------
 
 	' Draw

+ 51 - 6
examples/models/models_mesh_generation.bmx

@@ -2,7 +2,7 @@ SuperStrict
 
 Framework Ray.Lib
 
-Const NUM_MODELS:Int = 8      ' Parametric 3d shapes to generate
+Const NUM_MODELS:Int = 9      ' Parametric 3d shapes to generate
 
 ' Initialization
 '--------------------------------------------------------------------------------------
@@ -18,7 +18,7 @@ UnloadImage(checked)
 
 Local models:RModel[NUM_MODELS]
 
-models[0] = LoadModelFromMesh(GenMeshPlane(2, 2, 5, 5))
+models[0] = LoadModelFromMesh(GenMeshPlane(2, 2, 4, 3))
 models[1] = LoadModelFromMesh(GenMeshCube(2.0, 1.0, 2.0))
 models[2] = LoadModelFromMesh(GenMeshSphere(2, 32, 32))
 models[3] = LoadModelFromMesh(GenMeshHemiSphere(2, 16, 16))
@@ -26,10 +26,11 @@ models[4] = LoadModelFromMesh(GenMeshCylinder(1, 2, 16))
 models[5] = LoadModelFromMesh(GenMeshTorus(0.25, 4.0, 16, 32))
 models[6] = LoadModelFromMesh(GenMeshKnot(1.0, 2.0, 16, 128))
 models[7] = LoadModelFromMesh(GenMeshPoly(5, 2.0))
+models[8] = LoadModelFromMesh(GenMeshCustom())
 
 ' Set checked texture as default diffuse component for all models material
 For Local i:Int = 0 Until NUM_MODELS
-	models[i].materials[0].maps[MAP_DIFFUSE].texture = texture
+	models[i].materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture
 Next
 
 ' Define the camera to look into our 3d world
@@ -40,8 +41,6 @@ Local position:RVector3 = New RVector3(0.0, 0.0, 0.0)
 
 Local currentModel:Int = 0
 
-SetCameraMode(camera, CAMERA_ORBITAL)  ' Set a orbital camera mode
-
 SetTargetFPS(60)               ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
 
@@ -49,7 +48,7 @@ SetTargetFPS(60)               ' Set our game to run at 60 frames-per-second
 While Not WindowShouldClose()    ' Detect window close button or ESC key
 	' Update
 	'----------------------------------------------------------------------------------
-	UpdateCamera(camera)      ' Update internal camera and our camera
+	UpdateCamera(camera, CAMERA_ORBITAL)      ' Update internal camera and our camera
 
 	If IsMouseButtonPressed(MOUSE_LEFT_BUTTON) Then
 		currentModel = (currentModel + 1) Mod NUM_MODELS ' Cycle between the textures
@@ -103,6 +102,8 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 				DrawText("KNOT", 680, 10, 20, DARKBLUE)
 			Case 7
 				DrawText("POLY", 680, 10, 20, DARKBLUE)
+			Case 8
+				DrawText("Custom (triangle)", 580, 10, 20, DARKBLUE)
 		End Select
 
 	EndDrawing()
@@ -120,3 +121,47 @@ Next
 
 CloseWindow()          ' Close window and OpenGL context
 '--------------------------------------------------------------------------------------
+
+' Generate a simple triangle mesh from code
+Function GenMeshCustom:RMesh()
+	Local mesh:RMesh = New RMesh()
+	mesh.triangleCount = 1
+	mesh.vertexCount = mesh.triangleCount*3
+	mesh.vertices = RMemAlloc(UInt(mesh.vertexCount*3*4))    ' 3 vertices, 3 coordinates each (x, y, z)
+	mesh.texcoords = RMemAlloc(UInt(mesh.vertexCount*2*4))   ' 3 vertices, 2 coordinates each (x, y)
+	mesh.normals = RMemAlloc(UInt(mesh.vertexCount*3*4))     ' 3 vertices, 3 coordinates each (x, y, z)
+
+	' Vertex at (0, 0, 0)
+	mesh.vertices[0] = 0
+	mesh.vertices[1] = 0
+	mesh.vertices[2] = 0
+	mesh.normals[0] = 0
+	mesh.normals[1] = 1
+	mesh.normals[2] = 0
+	mesh.texcoords[0] = 0
+	mesh.texcoords[1] = 0
+
+	' Vertex at (1, 0, 2)
+	mesh.vertices[3] = 1
+	mesh.vertices[4] = 0
+	mesh.vertices[5] = 2
+	mesh.normals[3] = 0
+	mesh.normals[4] = 1
+	mesh.normals[5] = 0
+	mesh.texcoords[2] = 0.5
+	mesh.texcoords[3] = 1.0
+
+	' Vertex at (2, 0, 0)
+	mesh.vertices[6] = 2
+	mesh.vertices[7] = 0
+	mesh.vertices[8] = 0
+	mesh.normals[6] = 0
+	mesh.normals[7] = 1
+	mesh.normals[8] = 0
+	mesh.texcoords[4] = 1
+	mesh.texcoords[5] = 0
+
+	UploadMesh(mesh, False)
+
+	Return mesh
+End Function

+ 4 - 6
examples/models/models_waving_cubes.bmx

@@ -3,8 +3,6 @@ SuperStrict
 Framework Ray.Lib
 Import BRL.Math
 
-Const RAD2DEG:Float = 57.2958
-
 ' Initialization
 '--------------------------------------------------------------------------------------
 Const screenWidth:Int = 800
@@ -18,7 +16,7 @@ camera.position = New RVector3(30.0, 20.0, 30.0)
 camera.target = New RVector3(0.0, 0.0, 0.0)
 camera.up = New RVector3(0.0, 1.0, 0.0)
 camera.fovy = 70.0
-camera.cameraType = CAMERA_PERSPECTIVE
+camera.projection = CAMERA_PERSPECTIVE
 
 ' Specify the amount of blocks in each direction
 Const numBlocks:Int = 15
@@ -33,12 +31,12 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 	Local time:Double = GetTime()
 
 	' Calculate time scale for cube position and size
-	Local scale:Float = (2.0 + Float(Sin(time * RAD2DEG)))*0.7
+	Local scale:Float = (2.0 + Float(Sin(Rad2Deg(time))))*0.7
 
 	' Move camera around the scene
 	Local cameraTime:Double = time * 0.3
-	camera.position.x = Float(Cos(cameraTime * RAD2DEG))*40.0
-	camera.position.z = Float(Sin(cameraTime * RAD2DEG))*40.0
+	camera.position.x = Float(Cos(Rad2Deg(cameraTime)))*40.0
+	camera.position.z = Float(Sin(Rad2Deg(cameraTime)))*40.0
 	'----------------------------------------------------------------------------------
 	
 	' Draw

+ 38 - 124
examples/models/models_yaw_pitch_roll.bmx

@@ -13,25 +13,16 @@ Const screenHeight:Int = 450
 
 InitWindow(screenWidth, screenHeight, "raylib [models] example - plane rotations (yaw, pitch, roll)")
 
-Local texAngleGauge:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/models/resources/angle_gauge.png")
-Local texBackground:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/models/resources/background.png")
-Local texPitch:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/models/resources/pitch.png")
-Local texPlane:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/models/resources/plane.png")
-
-Local framebuffer:RRenderTexture2D = LoadRenderTexture(192, 192)
-
-' Model loading
-Local model:RModel = LoadModel("../../lib.mod/raylib/examples/models/resources/plane.obj")     ' Load OBJ model
-model.materials[0].maps[MAP_DIFFUSE].texture = LoadTexture("../../lib.mod/raylib/examples/models/resources/plane_diffuse.png") ' Set map diffuse texture
-
-GenTextureMipmaps(model.materials[0].maps[MAP_DIFFUSE].texture)
-
 Local camera:RCamera
-camera.position = New RVector3(0.0, 60.0, -120.0)  ' Camera position perspective
-camera.target = New RVector3(0.0, 12.0, 0.0)       ' Camera looking at point
+camera.position = New RVector3(0.0, 50.0, -120.0)  ' Camera position perspective
+camera.target = New RVector3(0.0, 0.0, 0.0)        ' Camera looking at point
 camera.up = New RVector3(0.0, 1.0, 0.0)            ' Camera up vector (rotation towards target)
 camera.fovy = 30.0                                 ' Camera field-of-view Y
-camera.cameraType = CAMERA_PERSPECTIVE             ' Camera type
+camera.projection = CAMERA_PERSPECTIVE             ' Camera type
+
+Local model:RModel = LoadModel("../../lib.mod/raylib/examples/models/resources/models/obj/plane.obj")     ' Load OBJ model
+Local texture:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/models/resources/models/obj/plane_diffuse.png") ' Load model texture
+model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture ' Set map diffuse texture
 
 Local pitch:Float = 0.0
 Local roll:Float = 0.0
@@ -45,24 +36,24 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 	' Update
 	'----------------------------------------------------------------------------------
 
-	' Plane roll (x-axis) controls
-	If IsKeyDown(KEY_LEFT) Then
-		roll :+ 1.0
-	Else If IsKeyDown(KEY_RIGHT) Then
-		roll :- 1.0
+	' Plane pitch (x-axis) controls
+	If IsKeyDown(KEY_DOWN) Then
+		pitch :+ 0.6
+	Else If IsKeyDown(KEY_UP) Then
+		pitch :- 0.6
 	Else
-		If roll > 0.0 Then
-			roll :- 0.5
-		Else If roll < 0.0 Then
-			roll :+ 0.5
+		If pitch > 0.3 Then
+			pitch :- 0.3
+		Else If pitch < -0.3 Then
+			pitch :+ 0.3
 		End If
 	End If
 
 	' Plane yaw (y-axis) controls
 	If IsKeyDown(KEY_S) Then
-		yaw :+ 1.0
-	Else If IsKeyDown(KEY_A) Then
 		yaw :- 1.0
+	Else If IsKeyDown(KEY_A) Then
+		yaw :+ 1.0
 	Else
 		If yaw > 0.0 Then
 			yaw :- 0.5
@@ -71,40 +62,20 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 		End If
 	End If
 
-	' Plane pitch (z-axis) controls
-	If IsKeyDown(KEY_DOWN) Then
-		pitch :+ 0.6
-	Else If IsKeyDown(KEY_UP) Then
-		pitch :- 0.6
+	' Plane roll (z-axis) controls
+	If IsKeyDown(KEY_LEFT) Then
+		roll :- 1.0
+	Else If IsKeyDown(KEY_RIGHT) Then
+		roll :+1.0
 	Else
-		If pitch > 0.3 Then
-			pitch :- 0.3
-		Else If pitch < -0.3 Then
-			pitch :+ 0.3
+		If roll > 0.0 Then
+			roll :- 0.5
+		Else If roll < 0.0 Then
+			roll :+ 0.5
 		End If
 	End If
 
-	' Wraps the phase of an angle to fit between -180 and +180 degrees
-	Local pitchOffset:Int = pitch
-	While pitchOffset > 180
-		pitchOffset :- 360
-	Wend
-	While pitchOffset < -180
-		pitchOffset :+ 360
-	Wend
-	pitchOffset :* 10
-
-	Rem
-	' matrix transform done with multiplication To combine rotations
-	Local transform:RMatrix = MatrixIdentity()
-
-	transform = MatrixMultiply(transform, MatrixRotateZ(roll))
-	transform = MatrixMultiply(transform, MatrixRotateX(pitch))
-	transform = MatrixMultiply(transform, MatrixRotateY(yaw))
-
-	model.transform = transform
-	End Rem
-	' matrix created from multiple axes at once
+	' Tranformation matrix for rotations
 	model.transform = MatrixRotateXYZ(New RVector3(pitch, yaw, roll))
 
 	'----------------------------------------------------------------------------------
@@ -114,55 +85,23 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 
 		ClearBackground(RAYWHITE)
 
-		' Draw framebuffer texture (Ahrs Display)
-		Local centerX:Int = framebuffer.texture.width/2
-		Local centerY:Int = framebuffer.texture.height/2
-		Local scaleFactor:Float = 0.5
-
-		BeginTextureMode(framebuffer)
-
-			BeginBlendMode(BLEND_ALPHA)
-
-			DrawTexturePro(texBackground, New RRectangle(0, 0, texBackground.width, texBackground.height), ..
-						   New RRectangle(centerX, centerY, texBackground.width*scaleFactor, texBackground.height*scaleFactor), ..
-						   New RVector2(texBackground.width/2*scaleFactor, texBackground.height/2*scaleFactor + pitchOffset*scaleFactor), roll, WHITE)
-
-			DrawTexturePro(texPitch, New RRectangle(0, 0, texPitch.width, texPitch.height), ..
-						   New RRectangle(centerX, centerY, texPitch.width*scaleFactor, texPitch.height*scaleFactor), ..
-						   New RVector2(texPitch.width/2*scaleFactor, texPitch.height/2*scaleFactor + pitchOffset*scaleFactor), roll, WHITE)
-
-			DrawTexturePro(texPlane, New RRectangle(0, 0, texPlane.width, texPlane.height), ..
-						   New RRectangle(centerX, centerY, texPlane.width*scaleFactor, texPlane.height*scaleFactor), ..
-						   New RVector2(texPlane.width/2*scaleFactor, texPlane.height/2*scaleFactor), 0, WHITE)
-
-			EndBlendMode()
-
-		EndTextureMode()
-
 		' Draw 3D model (recomended to draw 3D always before 2D)
 		BeginMode3D(camera)
 
-			DrawModel(model, New RVector3(0, 6.0, 0), 1.0, WHITE)   ' Draw 3d model with texture
+			DrawModel(model, New RVector3(0.0, -8.0, 0.0), 1.0, WHITE)   ' Draw 3d model with texture
 			DrawGrid(10, 10.0)
 
 		EndMode3D()
 
-		' Draw 2D GUI stuff
-		DrawAngleGauge(texAngleGauge, 80, 70, roll, "roll", RED)
-		DrawAngleGauge(texAngleGauge, 190, 70, pitch, "pitch", GREEN)
-		DrawAngleGauge(texAngleGauge, 300, 70, yaw, "yaw", SKYBLUE)
-
-		DrawRectangle(30, 360, 260, 70, Fade(SKYBLUE, 0.5))
-		DrawRectangleLines(30, 360, 260, 70, Fade(DARKBLUE, 0.5))
-		DrawText("Pitch controlled with: KEY_UP / KEY_DOWN", 40, 370, 10, DARKGRAY)
-		DrawText("Roll controlled with: KEY_LEFT / KEY_RIGHT", 40, 390, 10, DARKGRAY)
-		DrawText("Yaw controlled with: KEY_A / KEY_S", 40, 410, 10, DARKGRAY)
+		' Draw controls info
+		DrawRectangle(30, 370, 260, 70, Fade(GREEN, 0.5))
+		DrawRectangleLines(30, 370, 260, 70, Fade(DARKGREEN, 0.5))
+		DrawText("Pitch controlled with: KEY_UP / KEY_DOWN", 40, 380, 10, DARKGRAY)
+		DrawText("Roll controlled with: KEY_LEFT / KEY_RIGHT", 40, 400, 10, DARKGRAY)
+		DrawText("Yaw controlled with: KEY_A / KEY_S", 40, 420, 10, DARKGRAY)
 
-		' Draw framebuffer texture
-		DrawTextureRec(framebuffer.texture, New RRectangle(0, 0, framebuffer.texture.width, -framebuffer.texture.height), ..
-					   New RVector2(screenWidth - framebuffer.texture.width - 20, 20), Fade(WHITE, 0.8))
+		DrawText("(c) WWI Plane Model created by GiaHanLam", screenWidth - 240, screenHeight - 20, 10, DARKGRAY)
 
-		DrawRectangleLines(screenWidth - framebuffer.texture.width - 20, 20, framebuffer.texture.width, framebuffer.texture.height, DARKGRAY)
 
 	EndDrawing()
 	'----------------------------------------------------------------------------------
@@ -172,33 +111,8 @@ Wend
 '--------------------------------------------------------------------------------------
 
 ' Unload all loaded data
-UnloadTexture(model.materials[0].maps[MAP_DIFFUSE].texture)
-UnloadModel(model)
-
-UnloadRenderTexture(framebuffer)
-
-UnloadTexture(texAngleGauge)
-UnloadTexture(texBackground)
-UnloadTexture(texPitch)
-UnloadTexture(texPlane)
+UnloadModel(model)     ' Unload model data
+UnloadTexture(texture) ' Unload texture data
 
 CloseWindow()        ' Close window and OpenGL context
 '--------------------------------------------------------------------------------------
-
-
-' Draw angle gauge controls
-Function DrawAngleGauge(angleGauge:RTexture2D, x:Int, y:Int, angle:Float, title:String, color:RColor)
-
-	Local srcRec:RRectangle = New RRectangle(0, 0, angleGauge.width, angleGauge.height)
-	Local dstRec:RRectangle = New RRectangle(x, y, angleGauge.width, angleGauge.height)
-	Local origin:RVector2 = New RVector2(angleGauge.width/2, angleGauge.height/2)
-	Local textSize:Int = 20
-
-	DrawTexturePro(angleGauge, srcRec, dstRec, origin, angle, color)
-
-	Local formatted:String = formatter.Arg(angle).Format()
-	formatter.Clear()
-
-	DrawText(formatted, x - MeasureText(formatted, textSize) / 2, y + 10, textSize, DARKGRAY)
-	DrawText(title, x - MeasureText(title, textSize) / 2, y + 60, textSize, DARKGRAY)
-End Function

+ 16 - 26
examples/shaders/shaders_custom_uniform.bmx

@@ -23,11 +23,11 @@ camera.position = New RVector3(8.0, 8.0, 8.0)
 camera.target = New RVector3(0.0, 1.5, 0.0)
 camera.up = New RVector3(0.0, 1.0, 0.0)
 camera.fovy = 45.0
-camera.cameraType = CAMERA_PERSPECTIVE
+camera.projection = CAMERA_PERSPECTIVE
 
 Local model:RModel = LoadModel("../../lib.mod/raylib/examples/shaders/resources/models/barracks.obj")                   ' Load OBJ model
 Local texture:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/shaders/resources/models/barracks_diffuse.png")   ' Load model texture (diffuse map)
-model.materials[0].maps[MAP_DIFFUSE].texture = texture                     ' Set model diffuse texture
+model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture                     ' Set model diffuse texture
 
 Local position:RVector3                                    ' Set model position
 
@@ -44,9 +44,6 @@ Local swirlCenter:Float[] = [Float(screenWidth/2), Float(screenHeight/2)]
 ' Create a RenderTexture2D to be used for render to texture
 Local target:RRenderTexture2D = LoadRenderTexture(screenWidth, screenHeight)
 
-' Setup orbital camera
-SetCameraMode(camera, CAMERA_ORBITAL)  ' Set an orbital camera mode
-
 SetTargetFPS(60)                       ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
 
@@ -54,44 +51,37 @@ SetTargetFPS(60)                       ' Set our game to run at 60 frames-per-se
 While Not WindowShouldClose()            ' Detect window close button or ESC key
 	' Update
 	'----------------------------------------------------------------------------------
+	UpdateCamera(camera, CAMERA_ORBITAL)              ' Update camera
+
 	Local mousePosition:RVector2 = GetMousePosition()
 
 	swirlCenter[0] = mousePosition.x
 	swirlCenter[1] = screenHeight - mousePosition.y
 
 	' Send new value to the shader to be used on drawing
-	SetShaderValue(shader, swirlCenterLoc, swirlCenter, UNIFORM_VEC2)
-
-	UpdateCamera(camera)              ' Update camera
+	SetShaderValue(shader, swirlCenterLoc, swirlCenter, SHADER_UNIFORM_VEC2)
 	'----------------------------------------------------------------------------------
 
 	' Draw
 	'----------------------------------------------------------------------------------
-	BeginDrawing()
-
-		ClearBackground(RAYWHITE)
-
-		BeginTextureMode(target)       ' Enable drawing to texture
+	BeginTextureMode(target)       ' Enable drawing to texture
 
-			ClearBackground(RAYWHITE)  ' Clear texture background
+		ClearBackground(RAYWHITE)  ' Clear texture background
 
-			BeginMode3D(camera)        ' Begin 3d mode drawing
+		BeginMode3D(camera)        ' Begin 3d mode drawing
+			DrawModel(model, position, 0.5, WHITE)   ' Draw 3d model with texture
+			DrawGrid(10, 1.0)     ' Draw a grid
+		EndMode3D()                ' End 3d mode drawing, returns to orthographic 2d mode
 
-				DrawModel(model, position, 0.5, WHITE)   ' Draw 3d model with texture
+		DrawText("TEXT DRAWN IN RENDER TEXTURE", 200, 10, 30, RED)
+	EndTextureMode()               ' End drawing to texture (now we have a texture available for next passes)
 
-				DrawGrid(10, 1.0)     ' Draw a grid
-
-			EndMode3D()                ' End 3d mode drawing, returns to orthographic 2d mode
-
-			DrawText("TEXT DRAWN IN RENDER TEXTURE", 200, 10, 30, RED)
-
-		EndTextureMode()               ' End drawing to texture (now we have a texture available for next passes)
+	BeginDrawing()
+		ClearBackground(RAYWHITE)
 
 		BeginShaderMode(shader)
-
 			' NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom)
-			DrawTextureRec(target.texture, New RRectangle(0, 0, target.texture.width, -target.texture.height), New RVector2( 0, 0 ), WHITE)
-
+		 	DrawTextureRec(target.texture, New RRectangle(0, 0, target.texture.width, -target.texture.height), New RVector2( 0, 0 ), WHITE)
 		EndShaderMode()
 
 		' Draw some 2d text over drawn texture

+ 10 - 10
examples/shaders/shaders_eratosthenes.bmx

@@ -33,19 +33,19 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 
 	' Draw
 	'----------------------------------------------------------------------------------
-	BeginDrawing()
+	BeginTextureMode(target)   ' Enable drawing to texture
+		ClearBackground(BLACK) ' Clear the render texture
 
-		ClearBackground(RAYWHITE)
+		' Draw a rectangle in shader mode to be used as shader canvas
+		' NOTE: Rectangle uses font white character texture coordinates,
+		' so shader can not be applied here directly because input vertexTexCoord
+		' do not represent full screen coordinates (space where want to apply shader)
+		DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), BLACK)
+	EndTextureMode()           ' End drawing to texture (now we have a blank texture available for the shader)
 
-		BeginTextureMode(target)   ' Enable drawing to texture
-			ClearBackground(BLACK) ' Clear the render texture
+	BeginDrawing()
 
-			' Draw a rectangle in shader mode to be used as shader canvas
-			' NOTE: Rectangle uses font white character texture coordinates,
-			' so shader can not be applied here directly because input vertexTexCoord
-			' do not represent full screen coordinates (space where want to apply shader)
-			DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), BLACK)
-		EndTextureMode()           ' End drawing to texture (now we have a blank texture available for the shader)
+		ClearBackground(RAYWHITE)
 
 		BeginShaderMode(shader)
 			' NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom)

+ 69 - 60
examples/shaders/shaders_julia_set.bmx

@@ -21,6 +21,10 @@ Local POINTS_OF_INTEREST:Float[] = [ ..
 '--------------------------------------------------------------------------------------
 Const screenWidth:Int = 800
 Const screenHeight:Int = 450
+Const zoomSpeed:Float = 1.01
+Const offsetSpeedMul:Float = 2.0
+
+Const startingZoom:Float = 0.75
 
 InitWindow(screenWidth, screenHeight, "raylib [shaders] example - julia sets")
 
@@ -28,12 +32,15 @@ InitWindow(screenWidth, screenHeight, "raylib [shaders] example - julia sets")
 ' NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader
 Local shader:RShader = LoadShader(0, "../../lib.mod/raylib/examples/shaders/resources/shaders/glsl" + GLSL_VERSION + "/julia_set.fs")
 
+' Create a RenderTexture2D to be used for render to texture
+Local target:RRenderTexture2D = LoadRenderTexture(GetScreenWidth(), GetScreenHeight())
+
 ' c constant to use in z^2 + c
 Local c:Float[] = [POINTS_OF_INTEREST[0], POINTS_OF_INTEREST[1]]
 
 ' Offset and zoom to draw the julia set at. (centered on screen and default size)
-Local offset:Float[] = [-Float(screenWidth/2), -Float(screenHeight/2)]
-Local zoom:Float = 1.0
+Local offset:Float[] = [0, 0]
+Local zoom:Float = startingZoom
 
 Local offsetSpeed:RVector2
 
@@ -43,20 +50,13 @@ Local cLoc:Int = GetShaderLocation(shader, "c")
 Local zoomLoc:Int = GetShaderLocation(shader, "zoom")
 Local offsetLoc:Int = GetShaderLocation(shader, "offset")
 
-' Tell the shader what the screen dimensions, zoom, offset and c are
-Local screenDims:Float[] = [Float(screenWidth), Float(screenHeight)]
-SetShaderValue(shader, GetShaderLocation(shader, "screenDims"), screenDims, UNIFORM_VEC2)
-
-SetShaderValue(shader, cLoc, c, UNIFORM_VEC2)
-SetShaderValue(shader, zoomLoc, Varptr zoom, UNIFORM_FLOAT)
-SetShaderValue(shader, offsetLoc, Varptr offset, UNIFORM_VEC2)
-
-' Create a RenderTexture2D to be used for render to texture
-Local target:RRenderTexture2D = LoadRenderTexture(screenWidth, screenHeight)
+' Upload the shader uniform values!
+SetShaderValue(shader, cLoc, c, SHADER_UNIFORM_VEC2)
+SetShaderValue(shader, zoomLoc, Varptr zoom, SHADER_UNIFORM_FLOAT)
+SetShaderValue(shader, offsetLoc, offset, SHADER_UNIFORM_VEC2)
 
 Local incrementSpeed:Int = 0         ' Multiplier of speed to change c value
 Local showControls:Int = True       ' Show controls
-Local pause:Int = False             ' Pause animation
 
 SetTargetFPS(60)               ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
@@ -93,79 +93,87 @@ While Not windowShouldClose()    ' Detect window close button or ESC key
 			c[1] = POINTS_OF_INTEREST[11]
 		End If
 
-		SetShaderValue(shader, cLoc, c, UNIFORM_VEC2)
+		SetShaderValue(shader, cLoc, c, SHADER_UNIFORM_VEC2)
+	End If
+
+	' If "R" is pressed, reset zoom and offset.
+	if IsKeyPressed(KEY_R) Then
+		zoom = startingZoom
+		offset[0] = 0.0
+		offset[1] = 0.0
+		SetShaderValue(shader, zoomLoc, VarPtr zoom, SHADER_UNIFORM_FLOAT)
+		SetShaderValue(shader, offsetLoc, offset, SHADER_UNIFORM_VEC2)
 	End If
 
 	If IsKeyPressed(KEY_SPACE) Then
-		pause = Not pause                 ' Pause animation (c change)
+		incrementSpeed = 0
 	End If
 	
 	If IsKeyPressed(KEY_F1) Then
 		showControls = Not showControls  ' Toggle whether or not to show controls
 	End If
 
-	If Not pause Then
-		If IsKeyPressed(KEY_RIGHT) Then
-			incrementSpeed :+ 1
-		Else If IsKeyPressed(KEY_LEFT) Then
-			incrementSpeed :- 1
-		End If
+	If IsKeyPressed(KEY_RIGHT) Then
+		incrementSpeed :+ 1
+	Else If IsKeyPressed(KEY_LEFT) Then
+		incrementSpeed :- 1
+	End If
 
-		' TODO: The idea is to zoom and move around with mouse
-		' Probably offset movement should be proportional to zoom level
-		If IsMouseButtonDown(MOUSE_LEFT_BUTTON) Or IsMouseButtonDown(MOUSE_RIGHT_BUTTON) Then
-			If IsMouseButtonDown(MOUSE_LEFT_BUTTON) Then
-				zoom :+ zoom * 0.003
-			End If
-			If IsMouseButtonDown(MOUSE_RIGHT_BUTTON) Then
-				zoom :- zoom * 0.003
-			End If
+	' If either left or right button is pressed, zoom in/out.
+	If IsMouseButtonDown(MOUSE_LEFT_BUTTON) Or IsMouseButtonDown(MOUSE_RIGHT_BUTTON) Then	
+		' Change zoom. If Mouse left -> zoom in. Mouse right -> zoom out.
+		If IsMouseButtonDown(MOUSE_BUTTON_LEFT) Then
+			zoom :* zoomSpeed
+		Else
+			zoom :* 1.0/zoomSpeed
+		End IF
 
-			Local mousePos:RVector2 = GetMousePosition()
+		Local  mousePos:RVector2 = GetMousePosition()
+		Local offsetVelocity:RVector2
 
-			offsetSpeed.x = mousePos.x -Float(screenWidth/2)
-			offsetSpeed.y = mousePos.y -Float(screenHeight/2)
+		' Find the velocity at which to change the camera. Take the distance of the mouse
+		' from the center of the screen as the direction, and adjust magnitude based on
+		' the current zoom.
+		offsetVelocity.x = (mousePos.x/Float(screenWidth) - 0.5)*offsetSpeedMul/zoom
+		offsetVelocity.y = (mousePos.y/Float(screenHeight) - 0.5)*offsetSpeedMul/zoom
 
-			' Slowly move camera to targetOffset
-			offset[0] :+ GetFrameTime()*offsetSpeed.x*0.8
-			offset[1] :+ GetFrameTime()*offsetSpeed.y*0.8
-		Else
-			offsetSpeed = New RVector2
-		End If
+		' Apply move velocity to camera
+		offset[0] :+ GetFrameTime()*offsetVelocity.x
+		offset[1] :+ GetFrameTime()*offsetVelocity.y
 
-		SetShaderValue(shader, zoomLoc, Varptr zoom, UNIFORM_FLOAT)
-		SetShaderValue(shader, offsetLoc, offset, UNIFORM_VEC2)
+		' Update the shader uniform values!
+		SetShaderValue(shader, zoomLoc, VarPtr zoom, SHADER_UNIFORM_FLOAT)
+		SetShaderValue(shader, offsetLoc, offset, SHADER_UNIFORM_VEC2)
+	End If
 
-		' Increment c value with time
-		Local amount:Float = GetFrameTime() * incrementSpeed * 0.0005
-		c[0] :+ amount
-		c[1] :+ amount
+	' Increment c value with time
+	Local  dc:Float = GetFrameTime() * Float(incrementSpeed) * 0.0005
+	c[0] :+ dc
+	c[1] :+ dc
+	SetShaderValue(shader, cLoc, c, SHADER_UNIFORM_VEC2)
 
-		SetShaderValue(shader, cLoc, c, UNIFORM_VEC2)
-	End If
 	'----------------------------------------------------------------------------------
 
 	' Draw
 	'----------------------------------------------------------------------------------
-	BeginDrawing()
-
-		ClearBackground(BLACK)         ' Clear the screen of the previous frame.
+	' Using a render texture to draw Julia set
+	BeginTextureMode(target)       ' Enable drawing to texture
+		ClearBackground(BLACK)     ' Clear the render texture
 
-		' Using a render texture to draw Julia set
-		BeginTextureMode(target)       ' Enable drawing to texture
-			ClearBackground(BLACK)     ' Clear the render texture
+		' Draw a rectangle in shader mode to be used as shader canvas
+		' NOTE: Rectangle uses font white character texture coordinates,
+		' so shader can not be applied here directly because input vertexTexCoord
+		' do not represent full screen coordinates (space where want to apply shader)
+		DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), BLACK)
+	EndTextureMode()
 
-			' Draw a rectangle in shader mode to be used as shader canvas
-			' NOTE: Rectangle uses font white character texture coordinates,
-			' so shader can not be applied here directly because input vertexTexCoord
-			' do not represent full screen coordinates (space where want to apply shader)
-			DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), BLACK)
-		EndTextureMode()
+	BeginDrawing()
+		ClearBackground(BLACK)         ' Clear the screen of the previous frame.
 
 		' Draw the saved texture and rendered julia set with shader
 		' NOTE: We do not invert texture on Y, already considered inside shader
 		BeginShaderMode(shader)
-			DrawTexture(target.texture, 0, 0, WHITE)
+			DrawTextureEx(target.texture, New RVector2, 0, 1, WHITE)
 		EndShaderMode()
 
 		If showControls Then
@@ -174,6 +182,7 @@ While Not windowShouldClose()    ' Detect window close button or ESC key
 			DrawText("Press KEYS [1 - 6] to change point of interest", 10, 45, 10, RAYWHITE)
 			DrawText("Press KEY_LEFT | KEY_RIGHT to change speed", 10, 60, 10, RAYWHITE)
 			DrawText("Press KEY_SPACE to pause movement animation", 10, 75, 10, RAYWHITE)
+			DrawText("Press KEY_R to recenter the camera", 10, 90, 10, RAYWHITE)
 		End If
 
 	EndDrawing()

+ 4 - 5
examples/shaders/shaders_model_shader.bmx

@@ -23,7 +23,7 @@ camera.position = New RVector3(4.0, 4.0, 4.0)
 camera.target = New RVector3(0.0, 1.0, -1.0)
 camera.up = New RVector3(0.0, 1.0, 0.0)
 camera.fovy = 45.0
-camera.cameraType = CAMERA_PERSPECTIVE
+camera.projection = CAMERA_PERSPECTIVE
 
 Local model:RModel = LoadModel("../../lib.mod/raylib/examples/shaders/resources/models/watermill.obj")                   ' Load OBJ model
 Local texture:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/shaders/resources/models/watermill_diffuse.png")   ' Load model texture
@@ -33,12 +33,11 @@ Local texture:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/shaders/re
 Local shader:RShader = LoadShader(0, "../../lib.mod/raylib/examples/shaders/resources/shaders/glsl"  + GLSL_VERSION + "/grayscale.fs")
 
 model.materials[0].shader = shader                     ' Set shader effect to 3d model
-model.materials[0].maps[MAP_DIFFUSE].texture = texture ' Bind texture to model
+model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture ' Bind texture to model
 
 Local position:RVector3 = New RVector3(0.0, 0.0, 0.0)    ' Set model position
 
-SetCameraMode(camera, CAMERA_FREE)         ' Set an orbital camera mode
-
+DisableCursor()                            ' Limit cursor to relative movement inside the window
 SetTargetFPS(60)                           ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
 
@@ -46,7 +45,7 @@ SetTargetFPS(60)                           ' Set our game to run at 60 frames-pe
 While Not WindowShouldClose()                ' Detect window close button or ESC key
 	' Update
 	'----------------------------------------------------------------------------------
-	UpdateCamera(camera)                  ' Update camera
+	UpdateCamera(camera, CAMERA_FREE)                  ' Update camera
 	'----------------------------------------------------------------------------------
 
 	' Draw

+ 1 - 1
examples/shaders/shaders_palette_switch.bmx

@@ -92,7 +92,7 @@ While Not WindowShouldClose()            ' Detect window close button or ESC key
 
 	' Send new value to the shader to be used on drawing.
 	' NOTE: We are sending RGB triplets w/o the alpha channel
-	SetShaderValueV(shader, paletteLoc, palettes[currentPalette], UNIFORM_IVEC3, COLORS_PER_PALETTE)
+	SetShaderValueV(shader, paletteLoc, palettes[currentPalette], SHADER_UNIFORM_IVEC3, COLORS_PER_PALETTE)
 	'----------------------------------------------------------------------------------
 
 	' Draw

+ 17 - 22
examples/shaders/shaders_postprocessing.bmx

@@ -37,11 +37,16 @@ SetConfigFlags(FLAG_MSAA_4X_HINT)      ' Enable Multi Sampling Anti Aliasing 4x
 InitWindow(screenWidth, screenHeight, "raylib [shaders] example - postprocessing shader")
 
 ' Define the camera to look into our 3d world
-Local camera:RCamera = New RCamera(New RVector3(2.0, 3.0, 2.0), New RVector3(0.0, 1.0, 0.0), New RVector3(0.0, 1.0, 0.0), 45.0, 0)
+Local camera:RCamera
+camera.position = New RVector3(2.0, 3.0, 2.0)    ' Camera position
+camera.target = New RVector3(0.0, 1.0, 0.0)      ' Camera looking at point
+camera.up = New RVector3(0.0, 1.0, 0.0)          ' Camera up vector (rotation towards target)
+camera.fovy = 45.0                                ' Camera field-of-view Y
+camera.projection = CAMERA_PERSPECTIVE             ' Camera projection type
 
 Local model:RModel = LoadModel("../../lib.mod/raylib/examples/shaders/resources/models/church.obj")                 ' Load OBJ model
 Local texture:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/shaders/resources/models/church_diffuse.png") ' Load model texture (diffuse map)
-model.materials[0].maps[MAP_DIFFUSE].texture = texture                     ' Set model diffuse texture
+model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture                     ' Set model diffuse texture
 
 Local position:RVector3 = New RVector3(0.0, 0.0, 0.0)                             ' Set model position
 
@@ -69,9 +74,6 @@ Local currentShader:Int = FX_GRAYSCALE
 ' Create a RenderTexture2D to be used for render to texture
 Local target:RRenderTexture2D = LoadRenderTexture(screenWidth, screenHeight)
 
-' Setup orbital camera
-SetCameraMode(camera, CAMERA_ORBITAL)  ' Set an orbital camera mode
-
 SetTargetFPS(60)                       ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
 
@@ -79,7 +81,7 @@ SetTargetFPS(60)                       ' Set our game to run at 60 frames-per-se
 While Not WindowShouldClose()            ' Detect window close button or ESC key
 	' Update
 	'----------------------------------------------------------------------------------
-	UpdateCamera(camera)              ' Update camera
+	UpdateCamera(camera, CAMERA_ORBITAL)              ' Update camera
 
 	If IsKeyPressed(KEY_RIGHT) Then
 		currentShader :+ 1
@@ -96,23 +98,17 @@ While Not WindowShouldClose()            ' Detect window close button or ESC key
 
 	' Draw
 	'----------------------------------------------------------------------------------
-	BeginDrawing()
-
-		ClearBackground(RAYWHITE)
-
-		BeginTextureMode(target)       ' Enable drawing to texture
-
-			ClearBackground(RAYWHITE)  ' Clear texture background
+	BeginTextureMode(target)       ' Enable drawing to texture
+		ClearBackground(RAYWHITE)  ' Clear texture background
 
-			BeginMode3D(camera)        ' Begin 3d mode drawing
+		BeginMode3D(camera)        ' Begin 3d mode drawing
+			DrawModel(model, position, 0.1, WHITE)   ' Draw 3d model with texture
+			DrawGrid(10, 1.0)     ' Draw a grid
+		EndMode3D()                ' End 3d mode drawing, returns to orthographic 2d mode
+	EndTextureMode()               ' End drawing to texture (now we have a texture available for next passes)
 
-				DrawModel(model, position, 0.1, WHITE)   ' Draw 3d model with texture
-
-				DrawGrid(10, 1.0)     ' Draw a grid
-
-			EndMode3D()                ' End 3d mode drawing, returns to orthographic 2d mode
-
-		EndTextureMode()               ' End drawing to texture (now we have a texture available for next passes)
+	BeginDrawing()
+		ClearBackground(RAYWHITE) ' Clear screen background
 
 		' Render previously generated texture using selected postpro shader
 		BeginShaderMode(shaders[currentShader])
@@ -126,7 +122,6 @@ While Not WindowShouldClose()            ' Detect window close button or ESC key
 		DrawRectangle(0, 9, 580, 30, Fade(LIGHTGRAY, 0.7))
 
 		DrawText("(c) Church 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, GRAY)
-
 		DrawText("CURRENT POSTPRO SHADER:", 10, 15, 20, BLACK)
 		DrawText(postproShaderText[currentShader], 330, 15, 20, RED)
 		DrawText("< >", 540, 10, 30, DARKBLUE)

+ 17 - 17
examples/shaders/shaders_raymarching.bmx

@@ -20,9 +20,8 @@ Local camera:RCamera
 camera.position = New RVector3(2.5, 2.5, 3.0)    ' Camera position
 camera.target = New RVector3(0.0, 0.0, 0.7)      ' Camera looking at point
 camera.up = New RVector3(0.0, 1.0, 0.0 )          ' Camera up vector (rotation towards target)
-camera.fovy = 65.0                               ' Camera field-of-view Y
-
-SetCameraMode(camera, CAMERA_FREE)                 ' Set camera mode
+camera.fovy = 65.0                                ' Camera field-of-view Y
+camera.projection = CAMERA_PERSPECTIVE            ' Camera projection type
 
 ' Load raymarching shader
 ' NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader
@@ -35,27 +34,20 @@ Local runTimeLoc:Int = GetShaderLocation(shader, "runTime")
 Local resolutionLoc:Int = GetShaderLocation(shader, "resolution")
 
 Local resolution:Float[] = [Float(screenWidth), Float(screenHeight)]
-SetShaderValue(shader, resolutionLoc, resolution, UNIFORM_VEC2)
+SetShaderValue(shader, resolutionLoc, resolution, SHADER_UNIFORM_VEC2)
 
 Local runTime:Float = 0.0
 
+DisableCursor()                        ' Limit cursor to relative movement inside the window
 SetTargetFPS(60)                       ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
 
 ' Main game loop
 While Not WindowShouldClose()            ' Detect window close button or ESC key
-	' Check if screen is resized
-	'----------------------------------------------------------------------------------
-	If IsWindowResized() Then
-		screenWidth = GetScreenWidth()
-		screenHeight = GetScreenHeight()
-		Local resolution:Float[] = [Float(screenWidth), Float(screenHeight)]
-		SetShaderValue(shader, resolutionLoc, resolution, UNIFORM_VEC2)
-	End If
 
 	' Update
 	'----------------------------------------------------------------------------------
-	UpdateCamera(camera)              ' Update camera
+	UpdateCamera(camera, CAMERA_FIRST_PERSON)              ' Update camera
 
 	Local cameraPos:Float[] = [ camera.position.x, camera.position.y, camera.position.z ]
 	Local cameraTarget:Float[] = [ camera.target.x, camera.target.y, camera.target.z ]
@@ -64,9 +56,17 @@ While Not WindowShouldClose()            ' Detect window close button or ESC key
 	runTime :+ deltaTime
 
 	' Set shader required uniform values
-	SetShaderValue(shader, viewEyeLoc, cameraPos, UNIFORM_VEC3)
-	SetShaderValue(shader, viewCenterLoc, cameraTarget, UNIFORM_VEC3)
-	SetShaderValue(shader, runTimeLoc, Varptr runTime, UNIFORM_FLOAT)
+	SetShaderValue(shader, viewEyeLoc, cameraPos, SHADER_UNIFORM_VEC3)
+	SetShaderValue(shader, viewCenterLoc, cameraTarget, SHADER_UNIFORM_VEC3)
+	SetShaderValue(shader, runTimeLoc, Varptr runTime, SHADER_UNIFORM_FLOAT)
+
+	' Check if screen is resized
+	If IsWindowResized() Then
+		screenWidth = GetScreenWidth()
+		screenHeight = GetScreenHeight()
+		Local resolution:Float[] = [Float(screenWidth), Float(screenHeight)]
+		SetShaderValue(shader, resolutionLoc, resolution, SHADER_UNIFORM_VEC2)
+	End If
 	'----------------------------------------------------------------------------------
 
 	' Draw
@@ -78,7 +78,7 @@ While Not WindowShouldClose()            ' Detect window close button or ESC key
 		' We only draw a white full-screen rectangle,
 		' frame is generated in shader using raymarching
 		BeginShaderMode(shader)
-			DrawRectangle(0, 0, screenWidth, screenHeight, WHITE)
+			DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), WHITE)
 		EndShaderMode()
 
 		DrawText("(c) Raymarching shader by Iñigo Quilez. MIT License.", screenWidth - 280, screenHeight - 20, 10, BLACK)

+ 21 - 20
examples/shaders/shaders_simple_mask.bmx

@@ -16,13 +16,13 @@ camera.position = New RVector3(0.0, 1.0, 2.0)
 camera.target = New RVector3(0.0, 0.0, 0.0)
 camera.up = New RVector3(0.0, 1.0, 0.0)
 camera.fovy = 45.0
-camera.cameraType = CAMERA_PERSPECTIVE
+camera.projection = CAMERA_PERSPECTIVE
 
 ' Define our three models to show the shader on
-Local torus:RMesh = GenMeshTorus(.3, 1, 16, 32)
+Local torus:RMesh = GenMeshTorus(0.3, 1, 16, 32)
 Local model1:RModel = LoadModelFromMesh(torus)
 
-Local cube:RMesh = GenMeshCube(.8,.8,.8)
+Local cube:RMesh = GenMeshCube(0.8,0.8,0.8)
 Local model2:RModel = LoadModelFromMesh(cube)
 
 ' Generate model to be shaded just to see the gaps in the other two
@@ -30,23 +30,23 @@ Local sphere:RMesh = GenMeshSphere(1, 16, 16)
 Local model3:RModel = LoadModelFromMesh(sphere)
 
 ' Load the shader
-Local shader:RShader = LoadShader("../../lib.mod/raylib/examples/shaders/resources/shaders/glsl330/mask.vs", "../../lib.mod/raylib/examples/shaders/resources/shaders/glsl330/mask.fs")
+Local shader:RShader = LoadShader(0, "../../lib.mod/raylib/examples/shaders/resources/shaders/glsl330/mask.fs")
 
 ' Load and apply the diffuse texture (colour map)
 Local texDiffuse:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/shaders/resources/plasma.png")
-model1.materials[0].maps[MAP_DIFFUSE].texture = texDiffuse
-model2.materials[0].maps[MAP_DIFFUSE].texture = texDiffuse
+model1.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texDiffuse
+model2.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texDiffuse
 
 ' Using MAP_EMISSION as a spare slot to use for 2nd texture
 ' NOTE: Don't use MAP_IRRADIANCE, MAP_PREFILTER or  MAP_CUBEMAP
 ' as they are bound as cube maps
 Local texMask:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/shaders/resources/mask.png")
-model1.materials[0].maps[MAP_EMISSION].texture = texMask
-model2.materials[0].maps[MAP_EMISSION].texture = texMask
-shader.locs[LOC_MAP_EMISSION] = GetShaderLocation(shader, "mask")
+model1.materials[0].maps[MATERIAL_MAP_EMISSION].texture = texMask
+model2.materials[0].maps[MATERIAL_MAP_EMISSION].texture = texMask
+shader.locs[SHADER_LOC_MAP_EMISSION] = GetShaderLocation(shader, "mask")
 
 ' Frame is incremented each frame to animate the shader
-Local shaderFrame:Int = GetShaderLocation(shader, "framesCounter")
+Local shaderFrame:Int = GetShaderLocation(shader, "frame")
 
 ' Apply the shader to the two models
 model1.materials[0].shader = shader
@@ -55,6 +55,7 @@ model2.materials[0].shader = shader
 Local framesCounter:Int = 0
 Local Rotation:RVector3        ' Model rotation angles
 
+DisableCursor()                ' Limit cursor to relative movement inside the window
 SetTargetFPS(60)               ' Set  to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
 
@@ -62,18 +63,18 @@ SetTargetFPS(60)               ' Set  to run at 60 frames-per-second
 While Not WindowShouldClose()    ' Detect window close button or ESC key
 	' Update
 	'----------------------------------------------------------------------------------
+	UpdateCamera(camera, CAMERA_FIRST_PERSON)
+
 	framesCounter :+ 1
-	Rotation.x :+ 0.01
-	Rotation.y :+ 0.005
-	Rotation.z :- 0.0025
+	rotation.x :+ 0.01
+	rotation.y :+ 0.005
+	rotation.z :- 0.0025
 
 	' Send frames counter to shader for animation
-	SetShaderValue(shader, shaderFrame, Varptr framesCounter, UNIFORM_INT)
+	SetShaderValue(shader, shaderFrame, Varptr framesCounter, SHADER_UNIFORM_INT)
 
 	' Rotate one of the models
-	model1.transform = MatrixRotateXYZ(Rotation)
-
-	UpdateCamera(camera)
+	model1.transform = MatrixRotateXYZ(rotation)
 	'----------------------------------------------------------------------------------
 
 	' Draw
@@ -85,14 +86,14 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 		BeginMode3D(camera)
 
 			DrawModel(model1, New RVector3(0.5,0,0), 1, WHITE)
-			DrawModelEx(model2, New RVector3(-.5,0,0), New RVector3(1,1,0), 50, New RVector3(1,1,1), WHITE)
+			DrawModelEx(model2, New RVector3(-0.5,0,0), New RVector3(1,1,0), 50, New RVector3(1,1,1), WHITE)
 			DrawModel(model3, New RVector3(0,0,-1.5), 1, WHITE)
 			DrawGrid(10, 1.0)        ' Draw a grid
 
 		EndMode3D()
 
-		DrawRectangle(16, 698, MeasureText("Frame: " + framesCounter, 20) + 8, 42, BLUE)
-		DrawText("Frame: " + framesCounter, 20, 700, 20, WHITE)
+		DrawRectangle(16, 420, MeasureText("Frame: " + framesCounter, 20) + 8, 22, BLUE)
+		DrawText("Frame: " + framesCounter, 20, 422, 20, WHITE)
 
 		DrawFPS(10, 10)
 

+ 2 - 2
examples/shaders/shaders_texture_drawing.bmx

@@ -24,7 +24,7 @@ Local shader:RShader = LoadShader(0,"../../lib.mod/raylib/examples/shaders/resou
 
 Local time:Float = 0.0
 Local timeLoc:Int = GetShaderLocation(shader, "uTime")
-SetShaderValue(shader, timeLoc, Varptr time, UNIFORM_FLOAT)
+SetShaderValue(shader, timeLoc, Varptr time, SHADER_UNIFORM_FLOAT)
 
 SetTargetFPS(60)               ' Set our game to run at 60 frames-per-second
 ' -------------------------------------------------------------------------------------------------------------
@@ -34,7 +34,7 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 	' Update
 	'----------------------------------------------------------------------------------
 	time = GetTime()
-	SetShaderValue(shader, timeLoc, Varptr time, UNIFORM_FLOAT)
+	SetShaderValue(shader, timeLoc, Varptr time, SHADER_UNIFORM_FLOAT)
 	'----------------------------------------------------------------------------------
 
 	' Draw

+ 9 - 9
examples/shaders/shaders_texture_waves.bmx

@@ -21,7 +21,7 @@ Local texture:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/shaders/re
 ' Load shader and setup location points and values
 Local shader:RShader = LoadShader(0, "../../lib.mod/raylib/examples/shaders/resources/shaders/glsl" + GLSL_VERSION + "/wave.fs")
 
-Local secondsLoc:Int = GetShaderLocation(shader, "secondes")
+Local secondsLoc:Int = GetShaderLocation(shader, "seconds")
 Local freqXLoc:Int = GetShaderLocation(shader, "freqX")
 Local freqYLoc:Int = GetShaderLocation(shader, "freqY")
 Local ampXLoc:Int = GetShaderLocation(shader, "ampX")
@@ -38,13 +38,13 @@ Local speedX:Float = 8.0
 Local speedY:Float = 8.0
 
 Local screenSize:Float[] = [Float(GetScreenWidth()), Float(GetScreenHeight())]
-SetShaderValue(shader, GetShaderLocation(shader, "size"), Varptr screenSize, UNIFORM_VEC2)
-SetShaderValue(shader, freqXLoc, Varptr freqX, UNIFORM_FLOAT)
-SetShaderValue(shader, freqYLoc, Varptr freqY, UNIFORM_FLOAT)
-SetShaderValue(shader, ampXLoc, Varptr ampX, UNIFORM_FLOAT)
-SetShaderValue(shader, ampYLoc, Varptr ampY, UNIFORM_FLOAT)
-SetShaderValue(shader, speedXLoc, Varptr speedX, UNIFORM_FLOAT)
-SetShaderValue(shader, speedYLoc, Varptr speedY, UNIFORM_FLOAT)
+SetShaderValue(shader, GetShaderLocation(shader, "size"), Varptr screenSize, SHADER_UNIFORM_VEC2)
+SetShaderValue(shader, freqXLoc, Varptr freqX, SHADER_UNIFORM_FLOAT)
+SetShaderValue(shader, freqYLoc, Varptr freqY, SHADER_UNIFORM_FLOAT)
+SetShaderValue(shader, ampXLoc, Varptr ampX, SHADER_UNIFORM_FLOAT)
+SetShaderValue(shader, ampYLoc, Varptr ampY, SHADER_UNIFORM_FLOAT)
+SetShaderValue(shader, speedXLoc, Varptr speedX, SHADER_UNIFORM_FLOAT)
+SetShaderValue(shader, speedYLoc, Varptr speedY, SHADER_UNIFORM_FLOAT)
 
 Local seconds:Float = 0.0
 
@@ -57,7 +57,7 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 	'----------------------------------------------------------------------------------
 	seconds :+ GetFrameTime()
 	
-	SetShaderValue(shader, secondsLoc, Varptr seconds, UNIFORM_FLOAT)
+	SetShaderValue(shader, secondsLoc, Varptr seconds, SHADER_UNIFORM_FLOAT)
 	'----------------------------------------------------------------------------------
 
 	' Draw

+ 12 - 10
examples/shapes/shapes_draw_circle_sector.bmx

@@ -12,9 +12,10 @@ InitWindow(screenWidth, screenHeight, "raylib [shapes] example - draw circle sec
 Local center:RVector2 = New RVector2((GetScreenWidth() - 300)/2, GetScreenHeight()/2)
 
 Local outerRadius:Float = 180
-Local startAngle:Int = 0
-Local endAngle:Int = 180
-Local segments:Int = 0
+Local startAngle:Float = 0
+Local endAngle:Float = 180
+Local segments:Float = 10
+Local minSegments:Int = 4
 
 SetTargetFPS(60)               ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
@@ -35,21 +36,22 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 		DrawLine(500, 0, 500, GetScreenHeight(), Fade(LIGHTGRAY, 0.6))
 		DrawRectangle(500, 0, GetScreenWidth() - 500, GetScreenHeight(), Fade(LIGHTGRAY, 0.3))
 
-		DrawCircleSector(center, outerRadius, startAngle, endAngle, segments, Fade(MAROON, 0.3))
-		DrawCircleSectorLines(center, outerRadius, startAngle, endAngle, segments, Fade(MAROON, 0.6))
+		DrawCircleSector(center, outerRadius, startAngle, endAngle, Int(segments), Fade(MAROON, 0.3))
+		DrawCircleSectorLines(center, outerRadius, startAngle, endAngle, Int(segments), Fade(MAROON, 0.6))
 		
 		' Draw GUI controls
 		'------------------------------------------------------------------------------
-		startAngle = GuiSliderBar(New RRectangle(600, 40, 120, 20), "StartAngle", "", startAngle, 0, 720)
-		endAngle = GuiSliderBar(New RRectangle(600, 70, 120, 20), "EndAngle", "", endAngle, 0, 720)
+		GuiSliderBar(New RRectangle(600, 40, 120, 20), "StartAngle", "", startAngle, 0, 720)
+		GuiSliderBar(New RRectangle(600, 70, 120, 20), "EndAngle", "", endAngle, 0, 720)
 		
-		outerRadius = GuiSliderBar(New RRectangle( 600, 140, 120, 20), "Radius", "", outerRadius, 0, 200)
-		segments = GuiSliderBar(New RRectangle(600, 170, 120, 20), "Segments", "", segments, 0, 100)
+		GuiSliderBar(New RRectangle( 600, 140, 120, 20), "Radius", "", outerRadius, 0, 200)
+		GuiSliderBar(New RRectangle(600, 170, 120, 20), "Segments", "", segments, 0, 100)
 		'------------------------------------------------------------------------------
 		
+		minSegments = Int(Int((endAngle - startAngle) / 90))
 		Local col:RColor
 		Local txt:String
-		If segments >= 4 Then
+		If segments >= minSegments Then
 			txt = "MODE: MANUAL"
 			col = MAROON
 		Else

+ 15 - 15
examples/shapes/shapes_draw_rectangle_rounded.bmx

@@ -10,10 +10,10 @@ Const screenHeight:Int = 450
 InitWindow(screenWidth, screenHeight, "raylib [shapes] example - draw rectangle rounded")
 
 Local roundness:Float = 0.2
-Local width:Int = 200
-Local height:Int = 100
-Local segments:Int = 0
-Local lineThick:Int = 1
+Local width:Float = 200
+Local height:Float = 100
+Local segments:Float = 0
+Local lineThick:Float = 1
 
 Local DrawRect:Int = False
 Local drawRoundedRect:Int = True
@@ -42,23 +42,23 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 			DrawRectangleRec(rec, Fade(GOLD, 0.6))
 		End If
 		If drawRoundedRect Then
-			DrawRectangleRounded(rec, roundness, segments, Fade(MAROON, 0.2))
+			DrawRectangleRounded(rec, roundness, Int(segments), Fade(MAROON, 0.2))
 		End If
 		If drawRoundedLines Then
-			DrawRectangleRoundedLines(rec, roundness, segments, lineThick, Fade(MAROON, 0.4))
+			DrawRectangleRoundedLinesEx(rec, roundness, Int(segments), lineThick, Fade(MAROON, 0.4))
 		End If
 
 		' Draw GUI controls
 		'------------------------------------------------------------------------------
-		width = GuiSliderBar(New RRectangle(640, 40, 105, 20), "Width", "", width, 0, GetScreenWidth() - 300 )
-		height = GuiSliderBar(New RRectangle(640, 70, 105, 20), "Height", "", height, 0, GetScreenHeight() - 50)
-		roundness = GuiSliderBar(New RRectangle(640, 140, 105, 20), "Roundness", "", roundness, 0.0, 1.0)
-		lineThick = GuiSliderBar(New RRectangle(640, 170, 105, 20), "Thickness", "", lineThick, 0, 20)
-		segments = GuiSliderBar(New RRectangle(640, 240, 105, 20), "Segments", "", segments, 0, 60)
-
-		drawRoundedRect = GuiCheckBox(New RRectangle(640, 320, 20, 20), "DrawRoundedRect", drawRoundedRect)
-		drawRoundedLines = GuiCheckBox(New RRectangle(640, 350, 20, 20), "DrawRoundedLines", drawRoundedLines)
-		DrawRect = GuiCheckBox(New RRectangle(640, 380, 20, 20), "DrawRect", DrawRect)
+		GuiSliderBar(New RRectangle(640, 40, 105, 20), "Width", "", width, 0, GetScreenWidth() - 300 )
+		GuiSliderBar(New RRectangle(640, 70, 105, 20), "Height", "", height, 0, GetScreenHeight() - 50)
+		GuiSliderBar(New RRectangle(640, 140, 105, 20), "Roundness", "", roundness, 0.0, 1.0)
+		GuiSliderBar(New RRectangle(640, 170, 105, 20), "Thickness", "", lineThick, 0, 20)
+		GuiSliderBar(New RRectangle(640, 240, 105, 20), "Segments", "", segments, 0, 60)
+
+		GuiCheckBox(New RRectangle(640, 320, 20, 20), "DrawRoundedRect", drawRoundedRect)
+		GuiCheckBox(New RRectangle(640, 350, 20, 20), "DrawRoundedLines", drawRoundedLines)
+		GuiCheckBox(New RRectangle(640, 380, 20, 20), "DrawRect", DrawRect)
 		'------------------------------------------------------------------------------
 
 		Local txt:String

+ 14 - 14
examples/shapes/shapes_draw_ring.bmx

@@ -14,9 +14,9 @@ Local center:RVector2 = New RVector2((GetScreenWidth() - 300)/2, GetScreenHeight
 Local innerRadius:Float = 80.0
 Local outerRadius:Float = 190.0
 
-Local startAngle:Int = 0
-Local endAngle:Int = 360
-Local segments:Int = 0
+Local startAngle:Float = 0
+Local endAngle:Float = 360
+Local segments:Float = 0
 
 Local shouldDrawRing:Int = True
 Local shouldDrawRingLines:Int = False
@@ -42,28 +42,28 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 		DrawRectangle(500, 0, GetScreenWidth() - 500, GetScreenHeight(), Fade(LIGHTGRAY, 0.3))
 
 		If shouldDrawRing Then
-			DrawRing(center, innerRadius, outerRadius, startAngle, endAngle, segments, Fade(MAROON, 0.3))
+			DrawRing(center, innerRadius, outerRadius, startAngle, endAngle, Int(segments), Fade(MAROON, 0.3))
 		End If
 		If shouldDrawRingLines Then
-			DrawRingLines(center, innerRadius, outerRadius, startAngle, endAngle, segments, Fade(BLACK, 0.4))
+			DrawRingLines(center, innerRadius, outerRadius, startAngle, endAngle, Int(segments), Fade(BLACK, 0.4))
 		End If
 		If shouldDrawCircleLines Then
-			DrawCircleSectorLines(center, outerRadius, startAngle, endAngle, segments, Fade(BLACK, 0.4))
+			DrawCircleSectorLines(center, outerRadius, startAngle, endAngle, Int(segments), Fade(BLACK, 0.4))
 		End If
 
 		' Draw GUI controls
 		'------------------------------------------------------------------------------
-		startAngle = GuiSliderBar(New RRectangle(600, 40, 120, 20), "StartAngle", "", startAngle, -450, 450)
-		endAngle = GuiSliderBar(New RRectangle(600, 70, 120, 20), "EndAngle", "", endAngle, -450, 450)
+		GuiSliderBar(New RRectangle(600, 40, 120, 20), "StartAngle", "", startAngle, -450, 450)
+		GuiSliderBar(New RRectangle(600, 70, 120, 20), "EndAngle", "", endAngle, -450, 450)
 
-		innerRadius = GuiSliderBar(New RRectangle(600, 140, 120, 20), "InnerRadius", "", innerRadius, 0, 100)
-		outerRadius = GuiSliderBar(New RRectangle(600, 170, 120, 20), "OuterRadius", "", outerRadius, 0, 200)
+		GuiSliderBar(New RRectangle(600, 140, 120, 20), "InnerRadius", "", innerRadius, 0, 100)
+		GuiSliderBar(New RRectangle(600, 170, 120, 20), "OuterRadius", "", outerRadius, 0, 200)
 
-		segments = GuiSliderBar(New RRectangle(600, 240, 120, 20), "Segments", "", segments, 0, 100)
+		GuiSliderBar(New RRectangle(600, 240, 120, 20), "Segments", "", segments, 0, 100)
 
-		shouldDrawRing = GuiCheckBox(New RRectangle(600, 320, 20, 20), "Draw Ring", shouldDrawRing)
-		shouldDrawRingLines = GuiCheckBox(New RRectangle(600, 350, 20, 20), "Draw RingLines", shouldDrawRingLines)
-		shouldDrawCircleLines = GuiCheckBox(New RRectangle(600, 380, 20, 20), "Draw CircleLines", shouldDrawCircleLines)
+		GuiCheckBox(New RRectangle(600, 320, 20, 20), "Draw Ring", shouldDrawRing)
+		GuiCheckBox(New RRectangle(600, 350, 20, 20), "Draw RingLines", shouldDrawRingLines)
+		GuiCheckBox(New RRectangle(600, 380, 20, 20), "Draw CircleLines", shouldDrawCircleLines)
 		'------------------------------------------------------------------------------
 
 		Local col:RColor

+ 7 - 7
examples/text/text_font_filters.bmx

@@ -31,8 +31,8 @@ Local fontPosition:RVector2 = New RVector2(40, screenHeight/2 - 80)
 Local textSize:RVector2 = New RVector2(0.0, 0.0)
 
 ' Setup texture scaling filter
-SetTextureFilter(font.texture, FILTER_POINT)
-Local currentFontFilter:Int = 0      ' FILTER_POINT
+SetTextureFilter(font.texture, TEXTURE_FILTER_POINT)
+Local currentFontFilter:Int = 0      ' TEXTURE_FILTER_POINT
 
 SetTargetFPS(60)               ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
@@ -45,14 +45,14 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 
 	' Choose font texture filter method
 	If IsKeyPressed(KEY_ONE) Then
-		SetTextureFilter(font.texture, FILTER_POINT)
+		SetTextureFilter(font.texture, TEXTURE_FILTER_POINT)
 		currentFontFilter = 0
 	Else If IsKeyPressed(KEY_TWO) Then
-		SetTextureFilter(font.texture, FILTER_BILINEAR)
+		SetTextureFilter(font.texture, TEXTURE_FILTER_BILINEAR)
 		currentFontFilter = 1
 	Else If IsKeyPressed(KEY_THREE) Then
 		' NOTE: Trilinear filter won't be noticed on 2D drawing
-		SetTextureFilter(font.texture, FILTER_TRILINEAR)
+		SetTextureFilter(font.texture, TEXTURE_FILTER_TRILINEAR)
 		currentFontFilter = 2
 	End If
 
@@ -66,12 +66,12 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 
 	' Load a dropped TTF file dynamically (at current fontSize)
 	If IsFileDropped() Then
-		Local droppedFiles:String[] = GetDroppedFiles()
+		Local droppedFiles:String[] = LoadDroppedFiles()
 
 		' NOTE: We only support first ttf file dropped
 		If ExtractExt(droppedFiles[0]) = "ttf" Then
 			UnloadFont(font)
-			font = LoadFontEx(droppedFiles[0], FontSize, 0, 0)
+			font = LoadFontEx(droppedFiles[0], Int(fontSize), 0, 0)
 		End If
 	End If
 	'----------------------------------------------------------------------------------

+ 2 - 0
examples/text/text_font_loading.bmx

@@ -22,6 +22,8 @@ Local fontBm:RFont = LoadFont("../../lib.mod/raylib/examples/text/resources/pixa
 ' NOTE: We define a font base size of 32 pixels tall and up-to 250 characters
 Local fontTtf:RFont = LoadFontEx("../../lib.mod/raylib/examples/text/resources/pixantiqua.ttf", 32, 0, 250)
 
+SetTextLineSpacing(16)         ' Set line spacing for multiline text (when line breaks are included '\n')
+
 Local useTtf:Int = False
 
 SetTargetFPS(60)               ' Set our game to run at 60 frames-per-second

+ 17 - 9
examples/text/text_font_sdf.bmx

@@ -3,9 +3,9 @@ SuperStrict
 Framework Ray.Lib
 Import Text.Format
 
-?win32
+?not opengles
 Const GLSL_VERSION:Int = 330
-?raspberrypi
+?opengles
 Const GLSL_VERSION:Int = 100
 ?
 
@@ -22,31 +22,39 @@ InitWindow(screenWidth, screenHeight, "raylib [text] example - SDF fonts")
 
 Local msg:String = "Signed Distance Fields"
 
+' Loading file to memory
+Local fileSize:Int
+Local fileData:Byte Ptr = LoadFileData("../../lib.mod/raylib/examples/text/resources/anonymous_pro_bold.ttf", fileSize)
+
 ' Default font generation from TTF font
 Local fontDefault:RFont
 fontDefault.baseSize = 16
-fontDefault.charsCount = 95
+fontDefault.glyphCount = 95
+
+' Loading font data from memory data
 ' Parameters > font size: 16, no chars array provided (0), chars count: 95 (autogenerate chars array)
-fontDefault.chars = LoadFontData("../../lib.mod/raylib/examples/text/resources/AnonymousPro-Bold.ttf", 16, 0, 95, FONT_DEFAULT)
+fontDefault.glyphs = LoadFontData(fileData, fileSize, 16, 0, 95, FONT_DEFAULT)
 ' Parameters > chars count: 95, font size: 16, chars padding in image: 4 px, pack method: 0 (default)
-Local atlas:RImage  = GenImageFontAtlas(fontDefault.chars, Varptr fontDefault.recs, 95, 16, 4, 0)
+Local atlas:RImage  = GenImageFontAtlas(fontDefault.glyphs, Varptr fontDefault.recs, 95, 16, 4, 0)
 fontDefault.texture = LoadTextureFromImage(atlas)
 UnloadImage(atlas)
 
 ' SDF font generation from TTF font
 Local fontSDF:RFont
 fontSDF.baseSize = 16
-fontSDF.charsCount = 95
+fontSDF.glyphCount = 95
 ' Parameters > font size: 16, no chars array provided (0), chars count: 0 (defaults to 95)
-fontSDF.chars = LoadFontData("../../lib.mod/raylib/examples/text/resources/AnonymousPro-Bold.ttf", 16, 0, 0, FONT_SDF)
+fontSDF.glyphs = LoadFontData(fileData, fileSize, 16, 0, 0, FONT_SDF)
 ' Parameters > chars count: 95, font size: 16, chars padding in image: 0 px, pack method: 1 (Skyline algorythm)
-atlas = GenImageFontAtlas(fontSDF.chars, Varptr fontSDF.recs, 95, 16, 0, 1)
+atlas = GenImageFontAtlas(fontSDF.glyphs, Varptr fontSDF.recs, 95, 16, 0, 1)
 fontSDF.texture = LoadTextureFromImage(atlas)
 UnloadImage(atlas)
 
+UnloadFileData(fileData)      ' Free memory from loaded file
+
 ' Load SDF required shader (we use default vertex shader)
 Local shader:RShader = LoadShader(0, "../../lib.mod/raylib/examples/text/resources/shaders/glsl" + GLSL_VERSION + "/sdf.fs")
-SetTextureFilter(fontSDF.texture, FILTER_BILINEAR)    ' Required for SDF font
+SetTextureFilter(fontSDF.texture, TEXTURE_FILTER_BILINEAR)    ' Required for SDF font
 
 Local fontPosition:RVector2 = New RVector2(40, screenHeight/2 - 50)
 Local textSize:RVector2 = New RVector2(0.0, 0.0)

+ 14 - 10
examples/text/text_input_box.bmx

@@ -14,7 +14,7 @@ Const screenHeight:Int = 450
 
 InitWindow(screenWidth, screenHeight, "raylib [text] example - input box")
 
-Local name:Byte[MAX_INPUT_CHARS + 1]      ' NOTE: One extra space required for line ending char '\0'
+Local name:String
 Local letterCount:Int = 0
 
 Local textBox:RRectangle = New RRectangle(screenWidth/2 - 100, 180, 225, 50)
@@ -22,7 +22,7 @@ Local mouseOnText:Int = False
 
 Local framesCounter:Int = 0
 
-SetTargetFPS(10)               ' Set our game to run at 60 frames-per-second
+SetTargetFPS(60)               ' Set our game to run at 60 frames-per-second
 '--------------------------------------------------------------------------------------
 
 ' Main game loop
@@ -36,14 +36,17 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 	End If
 
 	If mouseOnText Then
+		' Set the window's cursor to the I-Beam
+		SetMouseCursor(MOUSE_CURSOR_IBEAM)
+
 		' Get pressed key (character) on the queue
 		Local key:Int = GetKeyPressed()
 
 		' Check if more characters have been pressed on the same frame
-		While key >= 32
+		While key > 0
 			' NOTE: Only allow keys in range [32..125]
 			If (key >= 32) And (key <= 125) And (letterCount < MAX_INPUT_CHARS) Then
-				name[letterCount] = key
+				name :+ Chr(key)
 				letterCount :+ 1
 			End If
 			
@@ -57,8 +60,10 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 				letterCount = 0
 			End If
 
-			name[letterCount] = 0
+			name = name[0..letterCount]
 		End If
+	Else
+		SetMouseCursor(MOUSE_CURSOR_DEFAULT)
 	End If
 
 	If mouseOnText Then
@@ -78,13 +83,12 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 
 		DrawRectangleRec(textBox, LIGHTGRAY)
 		If mouseOnText Then
-			DrawRectangleLines(textBox.x, textBox.y, textBox.width, textBox.height, RED)
+			DrawRectangleLines(Int(textBox.x), Int(textBox.y), Int(textBox.width), Int(textBox.height), RED)
 		Else
-			DrawRectangleLines(textBox.x, textBox.y, textBox.width, textBox.height, DARKGRAY)
+			DrawRectangleLines(Int(textBox.x), Int(textBox.y), Int(textBox.width), Int(textBox.height), DARKGRAY)
 		End If
 
-		Local s:String = String.FromCString(name)
-		DrawText(s, textBox.x + 5, textBox.y + 8, 40, MAROON)
+		DrawText(name, Int(textBox.x + 5), Int(textBox.y + 8), 40, MAROON)
 
 		DrawText(formatter.Clear().Arg(letterCount).Arg(MAX_INPUT_CHARS).Format(), 315, 250, 20, DARKGRAY)
 
@@ -92,7 +96,7 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 			If letterCount < MAX_INPUT_CHARS Then
 				' Draw blinking underscore char
 				If ((framesCounter/20) Mod 2) = 0 Then
-					DrawText("_", textBox.x + 8 + MeasureText(s, 40), textBox.y + 12, 40, MAROON)
+					DrawText("_", Int(textBox.x + 8 + MeasureText(name, 40)), Int(textBox.y + 12), 40, MAROON)
 				End If
 			Else
 				DrawText("Press BACKSPACE to delete chars...", 230, 300, 20, GRAY)

+ 156 - 1
examples/text/text_rectangle_bounds.bmx

@@ -99,7 +99,7 @@ While Not WindowShouldClose()        ' Detect window close button or ESC key
 		DrawRectangleLinesEx(container, 3, borderColor) ' Draw container border
 
 		' Draw text in container (add some padding)
-		DrawTextRec(font, Text, New RRectangle(container.x + 4, container.y + 4, container.width - 4, container.height - 4), 20.0, 2.0, wordWrap, GRAY)
+		DrawTextBoxed(font, Text, New RRectangle(container.x + 4, container.y + 4, container.width - 4, container.height - 4), 20.0, 2.0, wordWrap, GRAY)
 
 		DrawRectangleRec(resizer, borderColor)         ' Draw the resize box
 
@@ -126,3 +126,158 @@ Wend
 '--------------------------------------------------------------------------------------
 CloseWindow()        ' Close window and OpenGL context
 '--------------------------------------------------------------------------------------
+
+' Draw text using font inside rectangle limits
+Function DrawTextBoxed(font:RFont, text:String, rec:RRectangle, fontSize:Float, spacing:Float, wordWrap:Int, tint:RColor)   ' Draw text using font inside rectangle limits
+	DrawTextBoxedSelectable(font, text, rec, fontSize, spacing, wordWrap, tint, 0, 0, WHITE, WHITE)
+End Function
+
+' Draw text using font inside rectangle limits with support for text selection
+Function DrawTextBoxedSelectable(font:RFont, text:String, rec:RRectangle, fontSize:Float, spacing:Float, wordWrap:Int, tint:RColor, selectStart:Int, selectLength:Int, selectTint:RColor, selectBackTint:RColor);    ' Draw text using font inside rectangle limits with support for text selection
+	
+	Local length:Int = text.Length ' Total length in bytes of the text, scanned by codepoints in loop
+
+	Local textOffsetY:Float = 0.0 ' Offset between lines (on line break '\n')
+	Local textOffsetX:Float = 0.0 ' Offset X to next character to draw
+
+	Local scaleFactor:Float = fontSize/font.baseSize ' Character rectangle scaling factor
+
+	' Word/character wrapping mechanism variables
+	Const MEASURE_STATE:Int = 0
+	Const DRAW_STATE:Int = 1
+
+	Local state:Int
+	If wordWrap Then
+		state = MEASURE_STATE
+	Else
+		state = DRAW_STATE
+	End If
+
+	Local startLine:Int = -1 ' Index where to begin drawing (where a line begins)
+	Local endLine:Int = -1 ' Index where to stop drawing (where a line ends)
+	Local lastk:Int = -1 ' Holds last value of the character position
+
+	Local k:Int = 0
+	For Local i:Int = 0 Until length
+		k :+ 1
+
+		' Get next codepoint from byte string and glyph index in font
+		'Local codepointByteCount:Int = 0
+		Local codepoint:Int = text[i]
+		Local index:Int = GetGlyphIndex(font, codepoint)
+
+		' NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
+		' but we need to draw all of the bad bytes using the '?' symbol moving one byte
+		'If codepoint = $3f Then
+		'	codepointByteCount = 1
+		'End IF
+
+		'i :+ (codepointByteCount - 1)
+
+		Local glyphWidth:Float = 0.0
+		If codepoint <> Asc("~n") Then
+			
+			If font.glyphs[index].advanceX = 0 Then
+				glyphWidth = font.recs[index].width*scaleFactor
+			Else
+				glyphWidth = font.glyphs[index].advanceX*scaleFactor
+			End If
+
+			If i + 1 < length Then
+				glyphWidth :+ glyphWidth + spacing
+			End If
+		End If
+
+		' NOTE: When wordWrap is ON we first measure how much of the text we can draw before going outside of the rec container
+		' We store this info in startLine and endLine, then we change states, draw the text between those two variables
+		' and change states again and again recursively until the end of the text (or until we get outside of the container).
+		' When wordWrap is OFF we don't need the measure state so we go to the drawing state immediately
+		' and begin drawing on the next line before we can get outside the container.
+		If state = MEASURE_STATE Then
+			If codepoint = Asc(" ") Or codepoint = Asc("~t") Or codepoint = Asc("~n") Then
+				endLine = i
+			End If
+
+			If textOffsetX + glyphWidth > rec.width Then
+				If endLine < 1 Then
+					endLine = i
+				End If
+				If i = endLine Then
+					endLine :- 1
+				End If
+				If startLine + 1 = endLine Then
+					endLine = i - 1
+				End IF
+
+				state = Not state
+			Else If i + 1 = length Then
+				endLine = i
+				state = Not state
+			Else If codepoint = Asc("~n") Then
+				state = Not state
+			End If
+
+			If state = DRAW_STATE Then
+				textOffsetX = 0
+				i = startLine
+				glyphWidth = 0
+
+				' Save character position when we switch states
+				Local tmp:Int = lastk
+				lastk = k - 1
+				k = tmp
+			End If
+		Else
+			If codepoint = Asc("~n") Then
+				If Not wordWrap Then
+					textOffsetY :+ (font.baseSize + font.baseSize/2)*scaleFactor
+					textOffsetX = 0
+				End If
+			Else
+				If Not wordWrap And textOffsetX + glyphWidth > rec.width Then
+					textOffsetY :+ (font.baseSize + font.baseSize/2)*scaleFactor
+					textOffsetX = 0
+				End If
+
+				' When text overflows rectangle height limit, just stop drawing
+				If textOffsetY + font.baseSize*scaleFactor > rec.height Then
+					Exit
+				End If
+
+				' Draw selection background
+				Local isGlyphSelected:Int = False
+				If selectStart >= 0 And k >= selectStart And k < selectStart + selectLength Then
+					DrawRectangleRec(New RRectangle(rec.x + textOffsetX - 1, rec.y + textOffsetY, glyphWidth, font.baseSize*scaleFactor), selectBackTint)
+					isGlyphSelected = True
+				End If
+
+				' Draw current character glyph
+				If codepoint <> Asc(" ") And codepoint <> Asc("~t") Then
+					Local t:RColor
+					If isGlyphSelected Then
+						t = selectTint
+					Else
+						t = tint
+					End If
+					DrawTextCodepoint(font, codepoint, New RVector2(rec.x + textOffsetX, rec.y + textOffsetY), fontSize, t)
+				End If
+			End If
+
+			If wordWrap And i = endLine Then
+				textOffsetY :+ (font.baseSize + font.baseSize/2)*scaleFactor
+				textOffsetX = 0
+				startLine = endLine
+				endLine = -1
+				glyphWidth = 0
+				selectStart :+ lastk - k
+				k = lastk
+
+				state = Not state
+			End If
+		End If
+
+		if (textOffsetX <> 0) Or (codepoint <> Asc(" ")) Then
+			textOffsetX :+ glyphWidth;  ' avoid leading spaces
+		End If
+	Next
+End Function

+ 83 - 0
examples/textures/textures_blend_modes.bmx

@@ -0,0 +1,83 @@
+SuperStrict
+
+Framework Ray.Lib
+
+' Initialization
+'--------------------------------------------------------------------------------------
+Const screenWidth:Int = 800
+Const screenHeight:Int = 450
+
+InitWindow(screenWidth, screenHeight, "raylib [textures] example - blend modes")
+
+' NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
+
+Local bgImage:RImage = LoadImage("../../lib.mod/raylib/examples/textures/resources/cyberpunk_street_background.png") ' Loaded in CPU memory (RAM)
+Local bgTexture:RTexture2D = LoadTextureFromImage(bgImage) ' Image converted to texture, GPU memory (VRAM)
+
+Local fgImage:RImage = LoadImage("../../lib.mod/raylib/examples/textures/resources/cyberpunk_street_foreground.png") ' Loaded in CPU memory (RAM)
+Local fgTexture:RTexture2D = LoadTextureFromImage(fgImage) ' Image converted to texture, GPU memory (VRAM)
+
+' Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM
+UnloadImage(bgImage)
+UnloadImage(fgImage)
+
+Const blendCountMax:Int = 4
+Local blendMode:Int = 0
+
+SetTargetFPS(60) ' Set our game to run at 60 frames-per-second
+
+'---------------------------------------------------------------------------------------
+
+' Main game loop
+While Not WindowShouldClose() ' Detect window close button or ESC key
+	' Update
+
+	If IsKeyPressed(KEY_SPACE) Then
+		If blendMode >= (blendCountMax - 1) Then
+			blendMode = 0
+		Else
+			blendMode :+ 1
+		End If
+	End If
+
+
+	' Draw
+	'----------------------------------------------------------------------------------
+
+	BeginDrawing()
+
+		ClearBackground(RAYWHITE)
+
+		DrawTexture(bgTexture, screenWidth/2 - bgTexture.width/2, screenHeight/2 - bgTexture.height/2, WHITE)
+
+		' Apply the blend mode and then draw the foreground texture
+		BeginBlendMode(blendMode)
+			DrawTexture(fgTexture, screenWidth/2 - fgTexture.width/2, screenHeight/2 - fgTexture.height/2, WHITE)
+		EndBlendMode()
+
+		' Draw the texts
+		DrawText("Press SPACE to change blend modes.", 310, 350, 10, GRAY)
+
+		Select blendMode
+			Case BLEND_ALPHA
+				DrawText("Current: BLEND_ALPHA", (screenWidth / 2) - 60, 370, 10, GRAY)
+			Case BLEND_ADDITIVE
+				DrawText("Current: BLEND_ADDITIVE", (screenWidth / 2) - 60, 370, 10, GRAY)
+			Case BLEND_MULTIPLIED
+				DrawText("Current: BLEND_MULTIPLIED", (screenWidth / 2) - 60, 370, 10, GRAY)
+			Case BLEND_ADD_COLORS
+				DrawText("Current: BLEND_ADD_COLORS", (screenWidth / 2) - 60, 370, 10, GRAY)
+		End Select
+
+		DrawText("(c) Cyberpunk Street Environment by Luis Zuno (@ansimuz)", screenWidth - 330, screenHeight - 20, 10, GRAY)
+
+	EndDrawing()
+
+Wend
+
+' De-Initialization
+'--------------------------------------------------------------------------------------
+UnloadTexture(fgTexture)  ' Unload foreground texture
+UnloadTexture(bgTexture)  ' Unload background texture
+
+CloseWindow()             ' Close window and OpenGL context

+ 22 - 12
examples/textures/textures_image_generation.bmx

@@ -2,7 +2,7 @@ SuperStrict
 
 Framework Ray.Lib
 
-Const NUM_TEXTURES:Int = 7      ' Currently we have 7 generation algorithms
+Const NUM_TEXTURES:Int = 9      ' Currently we have 9 generation algorithms
 
 ' Initialization
 '--------------------------------------------------------------------------------------
@@ -11,9 +11,11 @@ Const screenHeight:Int = 450
 
 InitWindow(screenWidth, screenHeight, "raylib [textures] example - procedural images generation")
 
-Local verticalGradient:RImage = GenImageGradientV(screenWidth, screenHeight, RED, BLUE)
-Local horizontalGradient:RImage = GenImageGradientH(screenWidth, screenHeight, RED, BLUE)
+Local verticalGradient:RImage = GenImageGradientLinear(screenWidth, screenHeight, 0, RED, BLUE)
+Local horizontalGradient:RImage = GenImageGradientLinear(screenWidth, screenHeight, 90, RED, BLUE)
+Local diagonalGradient:RImage = GenImageGradientLinear(screenWidth, screenHeight, 45, RED, BLUE)
 Local radialGradient:RImage = GenImageGradientRadial(screenWidth, screenHeight, 0.0, WHITE, BLACK)
+Local squareGradient:RImage = GenImageGradientSquare(screenWidth, screenHeight, 0.0, WHITE, BLACK)
 Local checked:RImage = GenImageChecked(screenWidth, screenHeight, 32, 32, RED, BLUE)
 Local whiteNoise:RImage = GenImageWhiteNoise(screenWidth, screenHeight, 0.5)
 Local perlinNoise:RImage = GenImagePerlinNoise(screenWidth, screenHeight, 50, 50, 4.0)
@@ -23,16 +25,20 @@ Local textures:RTexture2D[NUM_TEXTURES]
 
 textures[0] = LoadTextureFromImage(verticalGradient)
 textures[1] = LoadTextureFromImage(horizontalGradient)
-textures[2] = LoadTextureFromImage(radialGradient)
-textures[3] = LoadTextureFromImage(checked)
-textures[4] = LoadTextureFromImage(whiteNoise)
-textures[5] = LoadTextureFromImage(perlinNoise)
-textures[6] = LoadTextureFromImage(cellular)
+textures[2] = LoadTextureFromImage(diagonalGradient)
+textures[3] = LoadTextureFromImage(radialGradient)
+textures[4] = LoadTextureFromImage(squareGradient)
+textures[5] = LoadTextureFromImage(checked)
+textures[6] = LoadTextureFromImage(whiteNoise)
+textures[7] = LoadTextureFromImage(perlinNoise)
+textures[8] = LoadTextureFromImage(cellular)
 
 ' Unload image data (CPU RAM)
 UnloadImage(verticalGradient)
 UnloadImage(horizontalGradient)
+UnloadImage(diagonalGradient)
 UnloadImage(radialGradient)
+UnloadImage(squareGradient)
 UnloadImage(checked)
 UnloadImage(whiteNoise)
 UnloadImage(perlinNoise)
@@ -70,14 +76,18 @@ While Not WindowShouldClose()
 			Case 1
 				DrawText("HORIZONTAL GRADIENT", 540, 10, 20, RAYWHITE)
 			Case 2
-				DrawText("RADIAL GRADIENT", 580, 10, 20, LIGHTGRAY)
+				DrawText("DIAGONAL GRADIENT", 540, 10, 20, RAYWHITE)
 			Case 3
-				DrawText("CHECKED", 680, 10, 20, RAYWHITE)
+				DrawText("RADIAL GRADIENT", 580, 10, 20, LIGHTGRAY)
 			Case 4
-				DrawText("WHITE NOISE", 640, 10, 20, RED)
+				DrawText("SQUARE GRADIENT", 580, 10, 20, RAYWHITE)
 			Case 5
-				DrawText("PERLIN NOISE", 630, 10, 20, RAYWHITE)
+				DrawText("CHECKED", 680, 10, 20, RAYWHITE)
 			Case 6
+				DrawText("WHITE NOISE", 640, 10, 20, RED)
+			Case 7
+				DrawText("PERLIN NOISE", 630, 10, 20, RAYWHITE)
+			Case 8
 				DrawText("CELLULAR", 670, 10, 20, RAYWHITE)
 		End Select
 

+ 2 - 1
examples/textures/textures_image_loading.bmx

@@ -13,8 +13,9 @@ InitWindow(screenWidth, screenHeight, "raylib [textures] example - image loading
 
 Local image:RImage = LoadImage("../../lib.mod/raylib/examples/textures/resources/raylib_logo.png")     ' Loaded in CPU memory (RAM)
 Local texture:RTexture2D = LoadTextureFromImage(image)          ' Image converted to texture, GPU memory (VRAM)
-
 UnloadImage(image)   ' Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM
+
+SetTargetFPS(60)     ' Set our game to run at 60 frames-per-second
 '---------------------------------------------------------------------------------------
 
 ' Main game loop

+ 26 - 18
examples/textures/textures_image_processing.bmx

@@ -2,7 +2,7 @@ SuperStrict
 
 Framework Ray.Lib
 
-Const NUM_PROCESSES:Int = 8
+Const NUM_PROCESSES:Int = 9
 
 Local processText:String[] = [ ..
     "NO PROCESSING", ..
@@ -11,6 +11,7 @@ Local processText:String[] = [ ..
     "COLOR INVERT", ..
     "COLOR CONTRAST", ..
     "COLOR BRIGHTNESS", ..
+	"GAUSSIAN BLUR", ..
     "FLIP VERTICAL", ..
     "FLIP HORIZONTAL"]
 
@@ -23,9 +24,11 @@ InitWindow(screenWidth, screenHeight, "raylib [textures] example - image process
 
 ' NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
 
-Local image:RImage = LoadImage("../../lib.mod/raylib/examples/textures/resources/parrots.png")   ' Loaded in CPU memory (RAM)
-ImageFormat(image, UNCOMPRESSED_R8G8B8A8)         ' Format image to RGBA 32bit (required for texture update) <-- ISSUE
-Local texture:RTexture2D = LoadTextureFromImage(image)    ' Image converted to texture, GPU memory (VRAM)
+Local imOrigin:RImage = LoadImage("../../lib.mod/raylib/examples/textures/resources/parrots.png")   ' Loaded in CPU memory (RAM)
+ImageFormat(imOrigin, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)         ' Format image to RGBA 32bit (required for texture update) <-- ISSUE
+Local texture:RTexture2D = LoadTextureFromImage(imOrigin)    ' Image converted to texture, GPU memory (VRAM)
+
+Local imCopy:RImage = ImageCopy(imOrigin)
 
 Local currentProcess:Int = NONE
 Local textureReload:Int = False
@@ -57,33 +60,36 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 		textureReload = True
 	End If
 
+	' Reload texture when required
 	If textureReload Then
-		UnloadImage(image)                         ' Unload current image data
-		image = LoadImage("../../lib.mod/raylib/examples/textures/resources/parrots.png") ' Re-load image data
+		UnloadImage(imCopy)                         ' Unload current image data
+		imCopy = ImageCopy(imOrigin)                ' Copy image data to work with
 
 		' NOTE: Image processing is a costly CPU process to be done every frame,
 		' If image processing is required in a frame-basis, it should be done
 		' with a texture and by shaders
 		Select currentProcess
 			Case COLOR_GRAYSCALE
-				ImageColorGrayscale(image)
+				ImageColorGrayscale(imCopy)
 			Case COLOR_TINT
-				ImageColorTint(image, GREEN)
+				ImageColorTint(imCopy, GREEN)
 			Case COLOR_INVERT
-				ImageColorInvert(image)
+				ImageColorInvert(imCopy)
 			Case COLOR_CONTRAST
-				ImageColorContrast(image, -40)
+				ImageColorContrast(imCopy, -40)
 			Case COLOR_BRIGHTNESS
-				ImageColorBrightness(image, -80)
+				ImageColorBrightness(imCopy, -80)
+			Case GAUSSIAN_BLUR
+				ImageBlurGaussian(imCopy, 10)
 			Case FLIP_VERTICAL
-				ImageFlipVertical(image)
+				ImageFlipVertical(imCopy)
 			Case FLIP_HORIZONTAL
-				ImageFlipHorizontal(image)
+				ImageFlipHorizontal(imCopy)
 		End Select
 
-		Local pixels:RColor Ptr = GetImageData(image)        ' Get pixel data from image (RGBA 32bit)
+		Local pixels:RColor Ptr = LoadImageColors(imCopy)        ' Load pixel data from image (RGBA 32bit)
 		UpdateTexture(texture, pixels)             ' Update texture with new image data
-		RLFree(pixels)                               ' Unload pixels data from RAM
+		UnloadImageColors(pixels)                               ' Unload pixels data from RAM
 
 		textureReload = False
 	End If
@@ -124,7 +130,8 @@ Wend
 ' De-Initialization
 '--------------------------------------------------------------------------------------
 UnloadTexture(texture)       ' Unload texture from VRAM
-UnloadImage(image)           ' Unload image from RAM
+UnloadImage(imOrigin)           ' Unload image-origin from RAM
+UnloadImage(imCopy)           ' Unload image-copy from RAM
 
 CloseWindow()                ' Close window and OpenGL context
 '--------------------------------------------------------------------------------------
@@ -135,5 +142,6 @@ Const COLOR_TINT:Int = 2
 Const COLOR_INVERT:Int = 3
 Const COLOR_CONTRAST:Int = 4
 Const COLOR_BRIGHTNESS:Int = 5
-Const FLIP_VERTICAL:Int = 6
-Const FLIP_HORIZONTAL:Int = 7
+Const GAUSSIAN_BLUR:Int = 6
+Const FLIP_VERTICAL:Int = 7
+Const FLIP_HORIZONTAL:Int = 8

+ 1 - 1
examples/textures/textures_image_text.bmx

@@ -15,7 +15,7 @@ Local parrots:RImage = LoadImage("../../lib.mod/raylib/examples/textures/resourc
 Local font:RFont = LoadFontEx("../../lib.mod/raylib/examples/textures/resources/KAISG.ttf", 64, 0, 0)
 
 ' Draw over image using custom font
-ImageDrawTextEx(parrots, New RVector2(20.0, 20.0), font, "[Parrots font drawing]", Float(font.baseSize), 0.0, RED)
+ImageDrawTextEx(parrots, font, "[Parrots font drawing]", New RVector2(20.0, 20.0), Float(font.baseSize), 0.0, RED)
 
 Local texture:RTexture2D  = LoadTextureFromImage(parrots)  ' Image converted to texture, uploaded to GPU memory (VRAM)
 UnloadImage(parrots)   ' Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM

+ 10 - 3
examples/textures/textures_mouse_painting.bmx

@@ -32,6 +32,7 @@ Local colorSelected:Int = 0
 Local colorSelectedPrev:Int = colorSelected
 Local colorMouseHover:Int = 0
 Local brushSize:Int = 20
+Local mouseWasPressed:Int = False
 
 Local btnSaveRec:RRectangle = New RRectangle(750, 10, 40, 30)
 Local btnSaveMouseHover:Int = False
@@ -111,7 +112,12 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 	End If
 
 	If IsMouseButtonDown(MOUSE_RIGHT_BUTTON) Then
-		colorSelected = 0
+		If Not mouseWasPressed Then
+			colorSelectedPrev = colorSelected
+			colorSelected = 0
+		End If
+
+		mouseWasPressed = True
 		
 		' Erase circle from render texture
 		BeginTextureMode(target)
@@ -119,8 +125,9 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 			DrawCircle(Int(mousePos.x), Int(mousePos.y), brushSize, colors[0])
 		End If
 		EndTextureMode()
-	Else
+	Else If IsMouseButtonReleased(MOUSE_BUTTON_RIGHT) And mouseWasPressed Then
 		colorSelected = colorSelectedPrev
+		mouseWasPressed = False
 	End If
 	
 	' Check mouse hover save button
@@ -133,7 +140,7 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 	' Image saving logic
 	' NOTE: Saving painted texture to a default named image
 	If (btnSaveMouseHover And IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) Or IsKeyPressed(KEY_S) Then
-		Local image:RImage = GetTextureData(target.texture)
+		Local image:RImage = LoadImageFromTexture(target.texture)
 		ImageFlipVertical(image)
 		ExportImage(image, "my_amazing_texture_painting.png")
 		UnloadImage(image)

+ 4 - 4
examples/textures/textures_npatch_drawing.bmx

@@ -22,14 +22,14 @@ Local dstRecH:RRectangle = New RRectangle(160.0, 93.0, 32.0, 32.0)
 Local dstRecV:RRectangle = New RRectangle(92.0, 160.0, 32.0, 32.0)
 
 ' A 9-patch (NPT_9PATCH) changes its sizes in both axis
-Local ninePatchInfo1:RNPatchInfo = New RNPatchInfo(New RRectangle(0.0, 0.0, 64.0, 64.0), 12, 40, 12, 12, NPT_9PATCH)
-Local ninePatchInfo2:RNPatchInfo = New RNPatchInfo(New RRectangle(0.0, 128.0, 64.0, 64.0), 16, 16, 16, 16, NPT_9PATCH)
+Local ninePatchInfo1:RNPatchInfo = New RNPatchInfo(New RRectangle(0.0, 0.0, 64.0, 64.0), 12, 40, 12, 12, NPATCH_NINE_PATCH)
+Local ninePatchInfo2:RNPatchInfo = New RNPatchInfo(New RRectangle(0.0, 128.0, 64.0, 64.0), 16, 16, 16, 16, NPATCH_NINE_PATCH)
 
 ' A horizontal 3-patch (NPT_3PATCH_HORIZONTAL) changes its sizes along the x axis only
-Local h3PatchInfo:RNPatchInfo = New RNPatchInfo(New RRectangle(0.0, 64.0, 64.0, 64.0), 8, 8, 8, 8, NPT_3PATCH_HORIZONTAL)
+Local h3PatchInfo:RNPatchInfo = New RNPatchInfo(New RRectangle(0.0, 64.0, 64.0, 64.0), 8, 8, 8, 8, NPATCH_THREE_PATCH_HORIZONTAL)
 
 ' A vertical 3-patch (NPT_3PATCH_VERTICAL) changes its sizes along the y axis only
-Local v3PatchInfo:RNPatchInfo = New RNPatchInfo(New RRectangle(0.0, 192.0, 64.0, 64.0), 6, 6, 6, 6, NPT_3PATCH_VERTICAL)
+Local v3PatchInfo:RNPatchInfo = New RNPatchInfo(New RRectangle(0.0, 192.0, 64.0, 64.0), 6, 6, 6, 6, NPATCH_THREE_PATCH_VERTICAL)
 
 SetTargetFPS(60)
 '---------------------------------------------------------------------------------------

+ 4 - 4
examples/textures/textures_particles_blending.bmx

@@ -26,7 +26,7 @@ Next
 
 Local gravity:Float = 3.0
 
-Local smoke:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/textures/resources/smoke.png")
+Local smoke:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/textures/resources/spark_flame.png")
 
 Local blending:Int = BLEND_ALPHA
 
@@ -53,14 +53,14 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 
 	For Local i:Int = 0 Until MAX_PARTICLES
 		If mouseTail[i].active Then
-			mouseTail[i].position.y :+ gravity
-			mouseTail[i].alpha :- 0.01
+			mouseTail[i].position.y :+ gravity/2
+			mouseTail[i].alpha :- 0.005
 
 			If mouseTail[i].alpha <= 0.0 Then
 				mouseTail[i].active = False
 			End If
 
-			mouseTail[i].Rotation :+ 5.0
+			mouseTail[i].Rotation :+ 2.0
 		End If
 	Next
 

+ 3 - 3
examples/textures/textures_raw_data.bmx

@@ -12,7 +12,7 @@ InitWindow(screenWidth, screenHeight, "raylib [textures] example - texture from
 ' NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
 
 ' Load RAW image data (512x512, 32bit RGBA, no file header)
-Local fudesumiRaw:RImage = LoadImageRaw("../../lib.mod/raylib/examples/textures/resources/fudesumi.raw", 384, 512, UNCOMPRESSED_R8G8B8A8, 0)
+Local fudesumiRaw:RImage = LoadImageRaw("../../lib.mod/raylib/examples/textures/resources/fudesumi.raw", 384, 512, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 0)
 Local fudesumi:RTexture2D = LoadTextureFromImage(fudesumiRaw)  ' Upload CPU (RAM) image to GPU (VRAM)
 UnloadImage(fudesumiRaw)                                ' Unload CPU (RAM) image data
 
@@ -34,9 +34,9 @@ For Local y:Int = 0 Until height
 Next
 
 ' Load pixels data into an image structure and create texture
-Local checkedIm:RImage = LoadImageEx(pixels, width, height)
+Local checkedIm:RImage = New RImage(pixels, width, height, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) ' We can assign pixels directly to data
 Local checked:RTexture2D = LoadTextureFromImage(checkedIm)
-UnloadImage(checkedIm)         ' Unload CPU (RAM) image data
+'UnloadImage(checkedIm)         ' Unload CPU (RAM) image data
 
 
 '---------------------------------------------------------------------------------------

+ 0 - 96
examples/textures/textures_rectangle.bmx

@@ -1,96 +0,0 @@
-SuperStrict
-
-Framework Ray.Lib
-Import Text.Format
-
-
-Const MAX_FRAME_SPEED:Int = 15
-Const MIN_FRAME_SPEED:Int = 1
-
-Local formatter:TFormatter = TFormatter.Create("%02i FPS")
-
-' Initialization
-'--------------------------------------------------------------------------------------
-Const screenWidth:Int = 800
-Const screenHeight:Int = 450
-
-InitWindow(screenWidth, screenHeight, "raylib [texture] example - texture rectangle")
-
-' NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
-Local scarfy:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/textures/resources/scarfy.png")        ' Texture loading
-
-Local position:RVector2 = New RVector2(350.0, 280.0)
-Local frameRec:RRectangle = New RRectangle(0.0, 0.0, scarfy.width/6.0, scarfy.height)
-Local currentFrame:Int = 0
-
-Local framesCounter:Int = 0
-Local framesSpeed:Int = 8            ' Number of spritesheet frames shown by second
-
-SetTargetFPS(60)               ' Set our game to run at 60 frames-per-second
-'--------------------------------------------------------------------------------------
-
-' Main game loop
-While Not WindowShouldClose()    ' Detect window close button or ESC key
-	' Update
-	'----------------------------------------------------------------------------------
-	framesCounter :+ 1
-
-	If framesCounter >= (60/framesSpeed) Then
-		framesCounter = 0
-		currentFrame :+ 1
-
-		If currentFrame > 5 Then
-			currentFrame = 0
-		End If
-
-		frameRec.x = currentFrame*scarfy.width/6.0
-	End If
-
-	If IsKeyPressed(KEY_RIGHT) Then
-		framesSpeed :+ 1
-	Else If IsKeyPressed(KEY_LEFT) Then
-		framesSpeed :- 1
-	End If
-
-	If framesSpeed > MAX_FRAME_SPEED Then
-		framesSpeed = MAX_FRAME_SPEED
-	Else If framesSpeed < MIN_FRAME_SPEED Then
-		framesSpeed = MIN_FRAME_SPEED
-	End If
-	'----------------------------------------------------------------------------------
-
-	' Draw
-	'----------------------------------------------------------------------------------
-	BeginDrawing()
-
-		ClearBackground(RAYWHITE)
-
-		DrawTexture(scarfy, 15, 40, WHITE)
-		DrawRectangleLines(15, 40, scarfy.width, scarfy.height, LIME)
-		DrawRectangleLines(Int(15 + frameRec.x), Int(40 + frameRec.y), Int(frameRec.width), Int(frameRec.height), RED)
-
-		DrawText("FRAME SPEED: ", 165, 210, 10, DARKGRAY)
-		DrawText(formatter.Clear().Arg(framesSpeed).Format(), 575, 210, 10, DARKGRAY)
-		DrawText("PRESS RIGHT/LEFT KEYS to CHANGE SPEED!", 290, 240, 10, DARKGRAY)
-
-		For Local i:Int = 0 Until MAX_FRAME_SPEED
-			If i < framesSpeed Then
-				DrawRectangle(250 + 21*i, 205, 20, 20, RED)
-			End If
-			DrawRectangleLines(250 + 21*i, 205, 20, 20, MAROON)
-		Next
-
-		DrawTextureRec(scarfy, frameRec, position, WHITE)  ' Draw part of the texture
-
-		DrawText("(c) Scarfy sprite by Eiden Marsal", screenWidth - 200, screenHeight - 20, 10, GRAY)
-
-	EndDrawing()
-	'----------------------------------------------------------------------------------
-Wend
-
-' De-Initialization
-'--------------------------------------------------------------------------------------
-UnloadTexture(scarfy)       ' Texture unloading
-
-CloseWindow()                ' Close window and OpenGL context
-'--------------------------------------------------------------------------------------

+ 6 - 6
examples/textures/textures_sprite_explosion.bmx

@@ -3,8 +3,8 @@ SuperStrict
 Framework Ray.Lib
 Import Ray.Audio
 
-Const NUM_FRAMES:Int = 8
-Const NUM_LINES:Int = 6
+Const NUM_FRAMES_PER_LINE:Int = 5
+Const NUM_LINES:Int = 5
 
 ' Initialization
 '--------------------------------------------------------------------------------------
@@ -22,8 +22,8 @@ Local fxBoom:RSound = LoadSound("../../lib.mod/raylib/examples/textures/resource
 Local explosion:RTexture2D = LoadTexture("../../lib.mod/raylib/examples/textures/resources/explosion.png")
 
 ' Init variables for animation
-Local frameWidth:Int = explosion.width/NUM_FRAMES    ' Sprite one frame rectangle width
-Local frameHeight:Int = explosion.height/NUM_LINES   ' Sprite one frame rectangle height
+Local frameWidth:Int = explosion.width/NUM_FRAMES_PER_LINE    ' Sprite one frame rectangle width
+Local frameHeight:Int = explosion.height/NUM_LINES            ' Sprite one frame rectangle height
 Local currentFrame:Int = 0
 Local currentLine:Int = 0
 
@@ -33,7 +33,7 @@ Local position:RVector2 = New RVector2(0.0, 0.0)
 Local active:Int = False
 Local framesCounter:Int = 0
 
-SetTargetFPS(120)
+SetTargetFPS(60)
 '--------------------------------------------------------------------------------------
 
 ' Main game loop
@@ -59,7 +59,7 @@ While Not WindowShouldClose()    ' Detect window close button or ESC key
 		If framesCounter > 2 Then
 			currentFrame :+ 1
 
-			If currentFrame >= NUM_FRAMES Then
+			If currentFrame >= NUM_FRAMES_PER_LINE Then
 				currentFrame = 0
 				currentLine :+ 1
 

+ 3 - 1
examples/textures/textures_to_image.bmx

@@ -15,11 +15,13 @@ Local image:RImage = LoadImage("../../lib.mod/raylib/examples/textures/resources
 Local texture:RTexture2D = LoadTextureFromImage(image)       ' Image converted to texture, GPU memory (RAM -> VRAM)
 UnloadImage(image)                                    ' Unload image data from CPU memory (RAM)
 
-image = GetTextureData(texture)                       ' Retrieve image data from GPU memory (VRAM -> RAM)
+image = LoadImageFromTexture(texture)                       ' Retrieve image data from GPU memory (VRAM -> RAM)
 UnloadTexture(texture)                                ' Unload texture from GPU memory (VRAM)
 
 texture = LoadTextureFromImage(image)                 ' Recreate texture from retrieved image data (RAM -> VRAM)
 UnloadImage(image)                                    ' Unload retrieved image data from CPU memory (RAM)
+
+SetTargetFPS(60)                 ' Set our game to run at 60 frames-per-second
 '---------------------------------------------------------------------------------------
 
 ' Main game loop

+ 68 - 56
gui.mod/common.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2020 Bruce A Henderson
+' Copyright (c) 2024 Bruce A Henderson
 '
 ' This software is provided 'as-is', without any express or implied
 ' warranty. In no event will the authors be held liable for any damages
@@ -30,8 +30,9 @@ Extern
 	Function bmx_raygui_GuiDisable()="GuiDisable"
 	Function bmx_raygui_GuiLock()="GuiLock"
 	Function bmx_raygui_GuiUnlock()="GuiUnlock"
-	Function bmx_raygui_GuiFade(alpha:Float)="GuiFade"
-
+	Function bmx_raygui_GuiIsLocked:Int()="GuiIsLocked"
+	Function bmx_raygui_GuiSetAlpha(alpha:Float)="GuiSetAlpha"
+	' Function bmx_raygui_GuiFade(alpha:Float)="GuiFade"
 	Function bmx_raygui_GuiSetState(state:Int)="GuiSetState"
 	Function bmx_raygui_GuiGetState:Int()="GuiGetState"
 
@@ -41,48 +42,59 @@ Extern
 	Function bmx_raygui_GuiSetStyle(control:Int, property:Int, value:Int)="GuiSetStyle"
 	Function bmx_raygui_GuiGetStyle:Int(control:Int, property:Int)="GuiGetStyle"
 
+	Function bmx_raygui_GuiLoadStyle(fileName:Byte Ptr)="GuiLoadStyle"
+	Function bmx_raygui_GuiLoadStyleDefault()="GuiLoadStyleDefault"		
+	
+	Function bmx_raygui_GuiEnableTooltip()="GuiEnableTooltip"
+	Function bmx_raygui_GuiDisableTooltip()="GuiDisableTooltip"
+	Function bmx_raygui_GuiSetTooltip(text:Byte Ptr)="GuiSetTooltip"
+
+	Function bmx_raygui_GuiIconText:Byte Ptr(iconId:Int, txt:Byte Ptr)="GuiIconText"
+	Function bmx_raygui_GuiDrawIcon(iconId:Int, position:RVector2, pixelSize:Int, color:RColor)="GuiDrawIcon"
+		
 	Function bmx_raygui_GuiWindowBox:Int(bounds:RRectangle, title:Byte Ptr)="GuiWindowBox"
 	Function bmx_raygui_GuiGroupBox(bounds:RRectangle, txt:Byte Ptr)="GuiGroupBox"
 	Function bmx_raygui_GuiLine(bounds:RRectangle, txt:Byte Ptr)="GuiLine"
 	Function bmx_raygui_GuiPanel(bounds:RRectangle)="GuiPanel"
+	Function bmx_raygui_GuiTabBar:Int(bounds:RRectangle, tabs:String[], active:Int Var)
 	Function bmx_raygui_GuiScrollPanel:RRectangle(bounds:RRectangle, content:RRectangle, scroll:RVector2 Var)="GuiScrollPanel"
 
 	Function bmx_raygui_GuiLabel(bounds:RRectangle, txt:Byte Ptr)="GuiLabel"
 	Function bmx_raygui_GuiButton:Int(bounds:RRectangle, txt:Byte Ptr)="GuiButton"
 	Function bmx_raygui_GuiLabelButton:Int(bounds:RRectangle, txt:Byte Ptr)="GuiLabelButton"
-	Function bmx_raygui_GuiImageButton:Int(bounds:RRectangle, txt:Byte Ptr, texture:RTexture2D)="GuiImageButton"
-	Function bmx_raygui_GuiImageButtonEx:Int(bounds:RRectangle, txt:Byte Ptr, texture:RTexture2D, texSource:RRectangle)="GuiImageButtonEx"
-	Function bmx_raygui_GuiToggle:Int(bounds:RRectangle, txt:Byte Ptr, active:Int)="GuiToggle"
-	Function bmx_raygui_GuiToggleGroup:Int(bounds:RRectangle, txt:Byte Ptr, active:Int)="GuiToggleGroup"
-	Function bmx_raygui_GuiCheckBox:Int(bounds:RRectangle, txt:Byte Ptr, checked:Int)="GuiCheckBox"
-	Function bmx_raygui_GuiComboBox:Int(bounds:RRectangle, txt:Byte Ptr, active:Int)="GuiComboBox"
+	' Function bmx_raygui_GuiImageButton:Int(bounds:RRectangle, txt:Byte Ptr, texture:RTexture2D)="GuiImageButton"
+	' Function bmx_raygui_GuiImageButtonEx:Int(bounds:RRectangle, txt:Byte Ptr, texture:RTexture2D, texSource:RRectangle)="GuiImageButtonEx"
+	Function bmx_raygui_GuiToggle:Int(bounds:RRectangle, txt:Byte Ptr, active:Int Var)="GuiToggle"
+	Function bmx_raygui_GuiToggleGroup:Int(bounds:RRectangle, txt:Byte Ptr, active:Int Var)="GuiToggleGroup"
+	Function bmx_raygui_GuiToggleSlider:Int(bounds:RRectangle, txt:Byte Ptr, active:Int Var)="GuiToggleSlider"
+	Function bmx_raygui_GuiCheckBox:Int(bounds:RRectangle, txt:Byte Ptr, checked:Int Var)="GuiCheckBox"
+	Function bmx_raygui_GuiComboBox:Int(bounds:RRectangle, txt:Byte Ptr, active:Int Var)="GuiComboBox"
+
 	Function bmx_raygui_GuiDropdownBox:Int(bounds:RRectangle, txt:Byte Ptr, active:Int Var, editMode:Int)="GuiDropdownBox"
 	Function bmx_raygui_GuiSpinner:Int(bounds:RRectangle, txt:Byte Ptr, value:Int Var, minValue:Int, maxValue:Int, editMode:Int)="GuiSpinner"
 	Function bmx_raygui_GuiValueBox:Int(bounds:RRectangle, txt:Byte Ptr, value:Int Var, minValue:Int, maxValue:Int, editMode:Int)="GuiValueBox"
+	Function bmx_raygui_GuiValueBoxFloat:Int(bounds:RRectangle, txt:Byte Ptr, textValue:Byte Ptr, value:Float Var, editMode:Int)="GuiValueBoxFloat"
 	Function bmx_raygui_GuiTextBox:Int(bounds:RRectangle, txt:Byte Ptr, textSize:Int, editMode:Int)="GuiTextBox"
-	Function bmx_raygui_GuiTextBoxMulti:Int(bounds:RRectangle, txt:Byte Ptr, textSize:Int, editMode:Int)="GuiTextBoxMulti"
-	Function bmx_raygui_GuiSlider:Float(bounds:RRectangle, txtLeft:Byte Ptr, txtRight:Byte Ptr, value:Float, minValue:Float, maxValue:Float)="GuiSlider"
-	Function bmx_raygui_GuiSliderBar:Float(bounds:RRectangle, txtLeft:Byte Ptr, txtRight:Byte Ptr, value:Float, minValue:Float, maxValue:Float)="GuiSliderBar"
-	Function bmx_raygui_GuiProgressBar:Float(bounds:RRectangle, txtLeft:Byte Ptr, txtRight:Byte Ptr, value:Float, minValue:Float, maxValue:Float)="GuiProgressBar"
+
+	' Function bmx_raygui_GuiTextBoxMulti:Int(bounds:RRectangle, txt:Byte Ptr, textSize:Int, editMode:Int)="GuiTextBoxMulti"
+	Function bmx_raygui_GuiSlider:Int(bounds:RRectangle, txtLeft:Byte Ptr, txtRight:Byte Ptr, value:Float Var, minValue:Float, maxValue:Float)="GuiSlider"
+	Function bmx_raygui_GuiSliderBar:Int(bounds:RRectangle, txtLeft:Byte Ptr, txtRight:Byte Ptr, value:Float Var, minValue:Float, maxValue:Float)="GuiSliderBar"
+	Function bmx_raygui_GuiProgressBar:Int(bounds:RRectangle, txtLeft:Byte Ptr, txtRight:Byte Ptr, value:Float Var, minValue:Float, maxValue:Float)="GuiProgressBar"
 	Function bmx_raygui_GuiStatusBar(bounds:RRectangle, txt:Byte Ptr)="GuiStatusBar"
 	Function bmx_raygui_GuiDummyRec(bounds:RRectangle, txt:Byte Ptr)="GuiDummyRec"
-	Function bmx_raygui_GuiScrollBar:Int(bounds:RRectangle, value:Int, minValue:Int, maxValue:Int)="GuiScrollBar"
+	' Function bmx_raygui_GuiScrollBar:Int(bounds:RRectangle, value:Int, minValue:Int, maxValue:Int)="GuiScrollBar"
 	Function bmx_raygui_GuiGrid:RVector2(bounds:RRectangle, spacing:Float, subdivs:Int)="GuiGrid"
 
-	Function bmx_raygui_GuiListView:Int(bounds:RRectangle, txt:Byte Ptr, scrollIndex:Int Var, active:Int)="GuiListView"
+	Function bmx_raygui_GuiListView:Int(bounds:RRectangle, txt:Byte Ptr, scrollIndex:Int Var, active:Int Var)="GuiListView"
 	Function bmx_raygui_GuiListViewEx:Int(bounds:RRectangle, txt:Size_T Ptr, count:Int, focus:Int Var, scrollIndex:Int Var, active:Int)="GuiListViewEx"
 	Function bmx_raygui_GuiMessageBox:Int(bounds:RRectangle, title:Byte Ptr, message:Byte Ptr, buttons:Byte Ptr)="GuiMessageBox"
-	Function bmx_raygui_GuiColorPicker:RColor(bounds:RRectangle, color:RColor)="GuiColorPicker"
-	Function bmx_raygui_GuiTextInputBox:Int(bounds:RRectangle, title:Byte Ptr, message:Byte Ptr, buttons:Byte Ptr, txt:Byte Ptr)="GuiTextInputBox"
-
-	Function bmx_raygui_GuiLoadStyle(fileName:Byte Ptr)="GuiLoadStyle"
-	Function bmx_raygui_GuiLoadStyleDefault()="GuiLoadStyleDefault"
-
-	Function bmx_raygui_GuiIconText:Byte Ptr(iconId:Int, txt:Byte Ptr)="GuiIconText"
-	Function bmx_raygui_GuiDrawIcon(iconId:Int, position:RVector2, pixelSize:Int, color:RColor)="GuiDrawIcon"
-	
-	Function bmx_raygui_GuiColorBarAlpha:Float(bounds:RRectangle, alpha:Float)="GuiColorBarAlpha"
-	Function bmx_raygui_GuiColorBarHue:Float(bounds:RRectangle, value:Float)="GuiColorBarHue"
+	Function bmx_raygui_GuiTextInputBox:Int(bounds:RRectangle, title:Byte Ptr, message:Byte Ptr, buttons:Byte Ptr, txt:Byte Ptr, textMaxSize:Int, secretViewActive:Int Var)="GuiTextInputBox"
+	Function bmx_raygui_GuiColorPicker:Int(bounds:RRectangle, text:Byte Ptr, color:RColor Var)="GuiColorPicker"
+	Function bmx_raygui_GuiColorPanel:Int(bounds:RRectangle, text:Byte Ptr, color:RColor Var)="GuiColorPanel"
+	Function bmx_raygui_GuiColorBarAlpha:Float(bounds:RRectangle, text:Byte Ptr, alpha:Float Var)="GuiColorBarAlpha"
+	Function bmx_raygui_GuiColorBarHue:Float(bounds:RRectangle, text:Byte Ptr, value:Float Var)="GuiColorBarHue"
+	Function bmx_raygui_GuiColorPickerHSV:Int(bounds:RRectangle, text:Byte Ptr, colorHsv:RVector3 Var)="GuiColorPickerHSV"
+	Function bmx_raygui_GuiColorPanelHSV:Int(bounds:RRectangle, text:Byte Ptr, colorHsv:RVector3 Var)="GuiColorPanelHSV"
 End Extern
 
 Const GUI_DEFAULT:Int = 0
@@ -187,7 +199,7 @@ Const RICON_FOLDER_SAVE:Int = 4
 Const RICON_FILE_OPEN:Int = 5
 Const RICON_FILE_SAVE:Int = 6
 Const RICON_FILE_EXPORT:Int = 7
-Const RICON_FILE_NEW:Int = 8
+Const RICON_FILE_ADD:Int = 8
 Const RICON_FILE_DELETE:Int = 9
 Const RICON_FILETYPE_TEXT:Int = 10
 Const RICON_FILETYPE_AUDIO:Int = 11
@@ -379,35 +391,35 @@ Const RICON_LAYERS_VISIBLE:Int = 196
 Const RICON_LAYERS:Int = 197
 Const RICON_WINDOW:Int = 198
 Const RICON_HIDPI:Int = 199
-Const RICON_200:Int = 200
-Const RICON_201:Int = 201
-Const RICON_202:Int = 202
-Const RICON_203:Int = 203
-Const RICON_204:Int = 204
-Const RICON_205:Int = 205
-Const RICON_206:Int = 206
-Const RICON_207:Int = 207
-Const RICON_208:Int = 208
-Const RICON_209:Int = 209
-Const RICON_210:Int = 210
-Const RICON_211:Int = 211
-Const RICON_212:Int = 212
-Const RICON_213:Int = 213
-Const RICON_214:Int = 214
-Const RICON_215:Int = 215
-Const RICON_216:Int = 216
-Const RICON_217:Int = 217
-Const RICON_218:Int = 218
-Const RICON_219:Int = 219
-Const RICON_220:Int = 220
-Const RICON_221:Int = 221
-Const RICON_222:Int = 222
-Const RICON_223:Int = 223
-Const RICON_224:Int = 224
-Const RICON_225:Int = 225
-Const RICON_226:Int = 226
-Const RICON_227:Int = 227
-Const RICON_228:Int = 228
+Const RICON_FILETYPE_BINARY:Int = 200
+Const RICON_HEX:Int = 201
+Const RICON_SHIELD:Int = 202
+Const RICON_FILE_NEW:Int = 203
+Const RICON_FOLDER_ADD:Int = 204
+Const RICON_ALARM:Int = 205
+Const RICON_CPU:Int = 206
+Const RICON_ROM:Int = 207
+Const RICON_STEP_OVER:Int = 208
+Const RICON_STEP_INTO:Int = 209
+Const RICON_STEP_OUT:Int = 210
+Const RICON_RESTART:Int = 211
+Const RICON_BREAKPOINT_ON:Int = 212
+Const RICON_BREAKPOINT_OFF:Int = 213
+Const RICON_BURGER_MENU:Int = 214
+Const RICON_CASE_SENSITIVE:Int = 215
+Const RICON_REG_EXP:Int = 216
+Const RICON_FOLDER:Int = 217
+Const RICON_FILE:Int = 218
+Const RICON_SAND_TIMER:Int = 219
+Const RICON_WARNING:Int = 220
+Const RICON_HELP_BOX:Int = 221
+Const RICON_INFO_BOX:Int = 222
+Const RICON_PRIORITY:Int = 223
+Const RICON_LAYERS_ISO:Int = 224
+Const RICON_LAYERS2:Int = 225
+Const RICON_MLAYERS:Int = 226
+Const RICON_MAPS:Int = 227
+Const RICON_HOT:Int = 228
 Const RICON_229:Int = 229
 Const RICON_230:Int = 230
 Const RICON_231:Int = 231

+ 24 - 1
gui.mod/glue.c

@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2020 Bruce A Henderson
+  Copyright (c) 2024 Bruce A Henderson
 
   This software is provided 'as-is', without any express or implied
   warranty. In no event will the authors be held liable for any damages
@@ -23,3 +23,26 @@
 #define RAYGUI_IMPLEMENTATION
 #define RAYGUI_SUPPORT_ICONS
 #include "raygui.h"
+
+#include "brl.mod/blitz.mod/blitz.h"
+
+int bmx_raygui_GuiTabBar(Rectangle bounds, BBArray * p, int * active) {
+
+    int n=p->scales[0];
+	BBString **s=(BBString**)BBARRAYDATA( p,p->dims );
+
+    const char **text = (const char **)malloc(n * sizeof(char *));
+    for( int i=0;i<n;++i ){
+        text[i] = bbStringToUTF8String(s[i]);
+    }
+
+    int res = GuiTabBar(bounds, text, n, active);
+
+	for( int i=0;i<n;++i ){
+		bbMemFree( (void*)text[i] );
+	}
+
+    free( text );
+
+    return res;
+}

+ 164 - 86
gui.mod/gui.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2020 Bruce A Henderson
+' Copyright (c) 2024 Bruce A Henderson
 '
 ' This software is provided 'as-is', without any express or implied
 ' warranty. In no event will the authors be held liable for any damages
@@ -26,11 +26,13 @@ bbdoc: RayGui - Simple and Easy-to-use Immediate-mode Gui
 End Rem
 Module Ray.GUI
 
-ModuleInfo "Version: 1.01"
+ModuleInfo "Version: 1.02"
 ModuleInfo "License: zlib"
-ModuleInfo "Copyright: Wrapper - 2020 Bruce A Henderson"
+ModuleInfo "Copyright: Wrapper - 2024 Bruce A Henderson"
 ModuleInfo "Copyright: raylib - 2013-2020 Ramon Santamaria"
 
+ModuleInfo "History: 1.02"
+ModuleInfo "History: Update to latest raygui.1e03efc."
 ModuleInfo "History: 1.01"
 ModuleInfo "History: Update to latest raygui.b2974f3."
 ModuleInfo "History: 1.00"
@@ -89,13 +91,27 @@ Function GuiUnlock()
 End Function
 
 Rem
-bbdoc: Sets gui controls alpha (global state).
-About: @alpha goes from 0.0. to 1.0.
+bbdoc: Checks if gui is locked (global state)
 End Rem
-Function GuiFade(alpha:Float)
-	bmx_raygui_GuiFade(alpha)
+Function GuiIsLocked:Int()
+	Return bmx_raygui_GuiIsLocked()
 End Function
 
+Rem
+bbdoc: Sets gui controls alpha (global state), alpha goes from 0.0f to 1.0f
+End Rem
+Function GuiSetAlpha(alpha:Float)
+	bmx_raygui_GuiSetAlpha(alpha)
+End Function
+
+' Rem
+' bbdoc: Sets gui controls alpha (global state).
+' About: @alpha goes from 0.0. to 1.0.
+' End Rem
+' Function GuiFade(alpha:Float)
+' 	bmx_raygui_GuiFade(alpha)
+' End Function
+
 
 Rem
 bbdoc: Sets gui state (global state).
@@ -111,6 +127,7 @@ Function GuiGetState:Int()
 	Return bmx_raygui_GuiGetState()
 End Function
 
+' Font set/get functions
 Rem
 bbdoc: Sets gui custom font (global state).
 End Rem
@@ -140,6 +157,35 @@ Function GuiGetStyle:Int(control:Int, property:Int)
 	Return bmx_raygui_GuiGetStyle(control, property)
 End Function
 
+' Styles loading functions
+Function GuiLoadStyle(fileName:String)
+	Local length:Size_T = fileName.length * 3 + 1
+	Local f:Byte Ptr = StackAlloc(length)
+	fileName.ToUTF8StringBuffer(f, length)
+
+	bmx_raygui_GuiLoadStyle(f)
+End Function
+
+Function GuiLoadStyleDefault()
+	bmx_raygui_GuiLoadStyleDefault()
+End Function
+
+' Tooltips management functions
+Function GuiEnableTooltip()
+	bmx_raygui_GuiEnableTooltip()
+End Function
+
+Function GuiDisableTooltip()
+	bmx_raygui_GuiDisableTooltip()
+End Function
+
+Function GuiSetTooltip(text:String)
+	Local length:Size_T = text.length * 3 + 1
+	Local t:Byte Ptr = StackAlloc(length)
+	text.ToUTF8StringBuffer(t, length)
+	bmx_raygui_GuiSetTooltip(t)
+End Function
+
 
 ' Container/separator controls, useful for controls organization
 Rem
@@ -236,36 +282,36 @@ Function GuiLabelButton:Int(bounds:RRectangle, txt:String)
 	Return bmx_raygui_GuiLabelButton(bounds:RRectangle, t)
 End Function
 
-Rem
-bbdoc: Image button control, which returns #True when clicked.
-End Rem
-Function GuiImageButton:Int(bounds:RRectangle, txt:String, texture:RTexture2D)
-	Local t:Byte Ptr
-	If txt Then
-		Local length:Size_T = txt.length * 3 + 1
-		t = StackAlloc(length)
-		txt.ToUTF8StringBuffer(t, length)
-	End If
-	Return bmx_raygui_GuiImageButton(bounds, t, texture)
-End Function
-
-Rem
-bbdoc: Image button extended control, which returns #True when clicked.
-End Rem
-Function GuiImageButtonEx:Int(bounds:RRectangle, txt:String, texture:RTexture2D, texSource:RRectangle)
-	Local t:Byte Ptr
-	If txt Then
-		Local length:Size_T = txt.length * 3 + 1
-		t = StackAlloc(length)
-		txt.ToUTF8StringBuffer(t, length)
-	End If
-	Return bmx_raygui_GuiImageButtonEx(bounds, t, texture, texSource)
-End Function
+' Rem
+' bbdoc: Image button control, which returns #True when clicked.
+' End Rem
+' Function GuiImageButton:Int(bounds:RRectangle, txt:String, texture:RTexture2D)
+' 	Local t:Byte Ptr
+' 	If txt Then
+' 		Local length:Size_T = txt.length * 3 + 1
+' 		t = StackAlloc(length)
+' 		txt.ToUTF8StringBuffer(t, length)
+' 	End If
+' 	Return bmx_raygui_GuiImageButton(bounds, t, texture)
+' End Function
+
+' Rem
+' bbdoc: Image button extended control, which returns #True when clicked.
+' End Rem
+' Function GuiImageButtonEx:Int(bounds:RRectangle, txt:String, texture:RTexture2D, texSource:RRectangle)
+' 	Local t:Byte Ptr
+' 	If txt Then
+' 		Local length:Size_T = txt.length * 3 + 1
+' 		t = StackAlloc(length)
+' 		txt.ToUTF8StringBuffer(t, length)
+' 	End If
+' 	Return bmx_raygui_GuiImageButtonEx(bounds, t, texture, texSource)
+' End Function
 
 Rem
 bbdoc: Toggle Button control, which returns #True when active.
 End Rem
-Function GuiToggle:Int(bounds:RRectangle, txt:String, active:Int)
+Function GuiToggle:Int(bounds:RRectangle, txt:String, active:Int Var)
 	Local t:Byte Ptr
 	If txt Then
 		Local length:Size_T = txt.length * 3 + 1
@@ -278,7 +324,7 @@ End Function
 Rem
 bbdoc: Toggle Group control, which returns active toggle index.
 End Rem
-Function GuiToggleGroup:Int(bounds:RRectangle, txt:String, active:Int)
+Function GuiToggleGroup:Int(bounds:RRectangle, txt:String, active:Int Var)
 	Local t:Byte Ptr
 	If txt Then
 		Local length:Size_T = txt.length * 3 + 1
@@ -291,7 +337,7 @@ End Function
 Rem
 bbdoc: Check Box control, which returns #True when active.
 End Rem
-Function GuiCheckBox:Int(bounds:RRectangle, txt:String, checked:Int)
+Function GuiCheckBox:Int(bounds:RRectangle, txt:String, checked:Int Var)
 	Local t:Byte Ptr
 	If txt Then
 		Local length:Size_T = txt.length * 3 + 1
@@ -304,7 +350,7 @@ End Function
 Rem
 bbdoc: Combo Box control, which returns selected item index.
 End Rem
-Function GuiComboBox:Int(bounds:RRectangle, txt:String, active:Int)
+Function GuiComboBox:Int(bounds:RRectangle, txt:String, active:Int Var)
 	Local t:Byte Ptr
 	If txt Then
 		Local length:Size_T = txt.length * 3 + 1
@@ -367,23 +413,23 @@ Function GuiTextBox:Int(bounds:RRectangle, txt:String Var, textSize:Int, editMod
 	Return res
 End Function
 
-Rem
-bbdoc: Text Box control with multiple lines
-End Rem
-Function GuiTextBoxMulti:Int(bounds:RRectangle, txt:String Var, textSize:Int, editMode:Int)
-	Local length:Size_T = Min(textSize, txt.length * 3 + 1)
-	Local t:Byte Ptr = StackAlloc(textSize)
-	MemClear(t, Size_T(textSize))
-	txt.ToUTF8StringBuffer(t, length)
-	Local res:Int = bmx_raygui_GuiTextBoxMulti(bounds, t, textSize, editMode)
-	txt = String.FromUTF8String(t)
-	Return res
-End Function
+' Rem
+' bbdoc: Text Box control with multiple lines
+' End Rem
+' Function GuiTextBoxMulti:Int(bounds:RRectangle, txt:String Var, textSize:Int, editMode:Int)
+' 	Local length:Size_T = Min(textSize, txt.length * 3 + 1)
+' 	Local t:Byte Ptr = StackAlloc(textSize)
+' 	MemClear(t, Size_T(textSize))
+' 	txt.ToUTF8StringBuffer(t, length)
+' 	Local res:Int = bmx_raygui_GuiTextBoxMulti(bounds, t, textSize, editMode)
+' 	txt = String.FromUTF8String(t)
+' 	Return res
+' End Function
 
 Rem
-bbdoc: Slider control, which returns the selected value.
+bbdoc: Slider control.
 End Rem
-Function GuiSlider:Float(bounds:RRectangle, txtLeft:String, txtRight:String, value:Float, minValue:Float, maxValue:Float)
+Function GuiSlider:Int(bounds:RRectangle, txtLeft:String, txtRight:String, value:Float Var, minValue:Float, maxValue:Float)
 	Local length:Size_T = txtLeft.length * 3 + 1
 	Local tl:Byte Ptr = StackAlloc(length)
 	txtLeft.ToUTF8StringBuffer(tl, length)
@@ -396,9 +442,9 @@ Function GuiSlider:Float(bounds:RRectangle, txtLeft:String, txtRight:String, val
 End Function
 
 Rem
-bbdoc: Slider Bar control, which returns the selected value.
+bbdoc: Slider Bar control.
 End Rem
-Function GuiSliderBar:Float(bounds:RRectangle, txtLeft:String, txtRight:String, value:Float, minValue:Float, maxValue:Float)
+Function GuiSliderBar:Int(bounds:RRectangle, txtLeft:String, txtRight:String, value:Float Var, minValue:Float, maxValue:Float)
 	Local length:Size_T = txtLeft.length * 3 + 1
 	Local tl:Byte Ptr = StackAlloc(length)
 	txtLeft.ToUTF8StringBuffer(tl, length)
@@ -413,7 +459,7 @@ End Function
 Rem
 bbdoc: Progress Bar control, which shows current progress value.
 End Rem
-Function GuiProgressBar:Float(bounds:RRectangle, txtLeft:String, txtRight:String, value:Float, minValue:Float, maxValue:Float)
+Function GuiProgressBar:Int(bounds:RRectangle, txtLeft:String, txtRight:String, value:Float Var, minValue:Float, maxValue:Float)
 	Local tl:Byte Ptr
 	Local length:Size_T
 	If txtLeft Then
@@ -458,12 +504,12 @@ Function GuiDummyRec(bounds:RRectangle, txt:String)
 	bmx_raygui_GuiDummyRec(bounds, t)
 End Function
 
-Rem
-bbdoc: Scroll Bar control.
-End Rem
-Function GuiScrollBar:Int(bounds:RRectangle, value:Int, minValue:Int, maxValue:Int)
-	Return bmx_raygui_GuiScrollBar(bounds, value, minValue, maxValue)
-End Function
+' Rem
+' bbdoc: Scroll Bar control.
+' End Rem
+' Function GuiScrollBar:Int(bounds:RRectangle, value:Int, minValue:Int, maxValue:Int)
+' 	Return bmx_raygui_GuiScrollBar(bounds, value, minValue, maxValue)
+' End Function
 
 Rem
 bbdoc: Grid control.
@@ -477,7 +523,7 @@ End Function
 Rem
 bbdoc: List View control, which returns selected list item index.
 End Rem
-Function GuiListView:Int(bounds:RRectangle, txt:String, scrollIndex:Int Var, active:Int)
+Function GuiListView:Int(bounds:RRectangle, txt:String, scrollIndex:Int Var, active:Int Var)
 	Local t:Byte Ptr
 	If txt Then
 		Local length:Size_T = txt.length * 3 + 1
@@ -490,12 +536,12 @@ End Function
 Rem
 bbdoc: List View with extended parameters.
 End Rem
-Function GuiListViewEx:Int(bounds:RRectangle, txt:String[], focus:Int Var, scrollIndex:Int Var, active:Int)
+Function GuiListViewEx:Int(bounds:RRectangle, txt:String[], scrollIndex:Int Var, active:Int Var, focus:Int Var)
 	Local list:Byte Ptr Ptr = StackAlloc(Size_T(txt.length * 8))
 	For Local i:Int = 0 Until txt.length
 		list[i] = txt[i].ToUTF8String()
 	Next
-	Local res:Int = bmx_raygui_GuiListViewEx(bounds, list, txt.length, focus, scrollIndex, active)
+	Local res:Int = bmx_raygui_GuiListViewEx(bounds, list, txt.length, scrollIndex, active, focus)
 	For Local i:Int = 0 Until txt.length
 		MemFree(list[i])
 	Next
@@ -524,14 +570,26 @@ End Function
 Rem
 bbdoc: Color Picker control.
 End Rem
-Function GuiColorPicker:RColor(bounds:RRectangle, color:RColor)
-	Return bmx_raygui_GuiColorPicker(bounds, color)
+Function GuiColorPicker:Int(bounds:RRectangle, text:String, color:RColor Var)
+	Local length:Size_T = text.length * 3 + 1
+	Local t:Byte Ptr = StackAlloc(length)
+	text.ToUTF8StringBuffer(t, length)
+
+	Return bmx_raygui_GuiColorPicker(bounds, t, color)
+End Function
+
+Function GuiColorPanel:Int(bounds:RRectangle, text:String, color:RColor Var)
+	Local length:Size_T = text.length * 3 + 1
+	Local t:Byte Ptr = StackAlloc(length)
+	text.ToUTF8StringBuffer(t, length)
+
+	Return bmx_raygui_GuiColorPanel(bounds, t, color)
 End Function
 
 Rem
 bbdoc: Text Input Box control, asks for text.
 End Rem
-Function GuiTextInputBox:Int(bounds:RRectangle, title:String, message:String, buttons:String, txt:String Var)
+Function GuiTextInputBox:Int(bounds:RRectangle, title:String, message:String, buttons:String, txt:String Var, textMaxSize:Int, secretViewActive:Int Var)
 	Local length:Size_T = title.length * 3 + 1
 	Local t:Byte Ptr = StackAlloc(length)
 	title.ToUTF8StringBuffer(t, length)
@@ -544,14 +602,14 @@ Function GuiTextInputBox:Int(bounds:RRectangle, title:String, message:String, bu
 	Local b:Byte Ptr = StackAlloc(length)
 	buttons.ToUTF8StringBuffer(b, length)
 
-	Local t2:Byte Ptr = StackAlloc(256)
+	Local t2:Byte Ptr = StackAlloc(textMaxSize)
 	If txt Then
 		length = txt.length * 3 + 1
 		txt.ToUTF8StringBuffer(t2, length)
 	Else
 		t2[0] = 0
 	End If
-	Local res:Int = bmx_raygui_GuiTextInputBox(bounds, t, m, b, t2)
+	Local res:Int = bmx_raygui_GuiTextInputBox(bounds, t, m, b, t2, textMaxSize, secretViewActive)
 	txt = String.FromUTF8String(t2)
 	
 	Return res
@@ -559,23 +617,23 @@ End Function
 
 
 ' Styles loading functions
-Rem
-bbdoc: Loads a style file (.rgs).
-End Rem
-Function GuiLoadStyle(fileName:String)
-	Local length:Size_T = fileName.length * 3 + 1
-	Local f:Byte Ptr = StackAlloc(length)
-	fileName.ToUTF8StringBuffer(f, length)
+' Rem
+' bbdoc: Loads a style file (.rgs).
+' End Rem
+' Function GuiLoadStyle(fileName:String)
+' 	Local length:Size_T = fileName.length * 3 + 1
+' 	Local f:Byte Ptr = StackAlloc(length)
+' 	fileName.ToUTF8StringBuffer(f, length)
 
-	bmx_raygui_GuiLoadStyle(f)
-End Function
+' 	bmx_raygui_GuiLoadStyle(f)
+' End Function
 
-Rem
-bbdoc: Loads style default over global style.
-End Rem
-Function GuiLoadStyleDefault()
-	bmx_raygui_GuiLoadStyleDefault()
-End Function
+' Rem
+' bbdoc: Loads style default over global style.
+' End Rem
+' Function GuiLoadStyleDefault()
+' 	bmx_raygui_GuiLoadStyleDefault()
+' End Function
 
 Rem
 bbdoc: Gets text with icon id prepended.
@@ -602,14 +660,34 @@ Rem
 bbdoc: Color Bar Alpha control.
 about: Returns alpha value normalized `[0..1]`.
 End Rem
-Function GuiColorBarAlpha:Float(bounds:RRectangle, alpha:Float)
-	Return bmx_raygui_GuiColorBarAlpha(bounds, alpha)
+Function GuiColorBarAlpha:Int(bounds:RRectangle, text:String, alpha:Float Var)
+	Local length:Size_T = text.length * 3 + 1
+	Local t:Byte Ptr = StackAlloc(length)
+	text.ToUTF8StringBuffer(t, length)
+	Return bmx_raygui_GuiColorBarAlpha(bounds, t, alpha)
 End Function
 
 Rem
 bbdoc: Color Bar Hue control.
 about: Returns hue value normalized `[0..1]`.
 End Rem
-Function GuiColorBarHue:Float(bounds:RRectangle, value:Float)
-	Return bmx_raygui_GuiColorBarHue(bounds, value)
+Function GuiColorBarHue:Int(bounds:RRectangle, text:String, value:Float Var)
+	Local length:Size_T = text.length * 3 + 1
+	Local t:Byte Ptr = StackAlloc(length)
+	text.ToUTF8StringBuffer(t, length)
+	Return bmx_raygui_GuiColorBarHue(bounds, t, value)
+End Function
+
+Function GuiColorPickerHSV:Int(bounds:RRectangle, text:String, colorHsv:RVector3 Var)
+	Local length:Size_T = text.length * 3 + 1
+	Local t:Byte Ptr = StackAlloc(length)
+	text.ToUTF8StringBuffer(t, length)
+	Return bmx_raygui_GuiColorPickerHSV(bounds, t, colorHsv)
+End Function
+
+Function GuiColorPanelHSV:Int(bounds:RRectangle, text:String, colorHsv:RVector3)
+	Local length:Size_T = text.length * 3 + 1
+	Local t:Byte Ptr = StackAlloc(length)
+	text.ToUTF8StringBuffer(t, length)
+	Return bmx_raygui_GuiColorPanelHSV(bounds, t, colorHsv)
 End Function

+ 0 - 1
gui.mod/raygui/.gitattributes

@@ -1 +0,0 @@
-*.h linguist-language=C

+ 0 - 12
gui.mod/raygui/.github/FUNDING.yml

@@ -1,12 +0,0 @@
-# These are supported funding model platforms
-
-github: raysan5
-patreon: # Replace with a single Patreon username
-open_collective: # Replace with a single Open Collective username
-ko_fi: # Replace with a single Ko-fi username
-tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
-community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
-liberapay: # Replace with a single Liberapay username
-issuehunt: # Replace with a single IssueHunt username
-otechie: # Replace with a single Otechie username
-custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

+ 0 - 62
gui.mod/raygui/.gitignore

@@ -1,62 +0,0 @@
-# Object files
-*.o
-*.ko
-*.obj
-*.elf
-
-# Precompiled Headers
-*.gch
-*.pch
-
-# Libraries
-*.lib
-*.a
-*.la
-*.lo
-
-# Shared objects (inc. Windows DLLs)
-*.dll
-*.so
-*.so.*
-*.dylib
-
-# Executables
-*.exe
-*.out
-*.app
-*.i*86
-*.x86_64
-*.hex
-
-# Debug files
-*.dSYM/
-*.su
-
-# VSCode files
-.vscode/
-
-
-# Ignore files build by Visual Studio
-[Dd]ebug
-[Rr]elease
-*.vs
-*.obj
-*.pdb
-*.aps
-*.user
-# *.vcproj
-# *.vcxproj*
-# *.sln
-*.vspscc
-*_i.c
-*.i
-*.icf
-*_p.c
-*.ncb
-*.suo
-*.tlb
-*.tlh
-*.bak
-*.cache
-*.ilk
-*.log

+ 1 - 1
gui.mod/raygui/LICENSE

@@ -1,6 +1,6 @@
 zlib License
 	
-Copyright (c) 2014-2020 Ramon Santamaria (@raysan5)
+Copyright (c) 2014-2024 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.

+ 122 - 32
gui.mod/raygui/README.md

@@ -1,73 +1,163 @@
 <img align="left" src="logo/raygui_256x256.png" width=256>
 
-**raygui** is a simple and easy-to-use immediate-mode-gui library.
+**raygui is a simple and easy-to-use immediate-mode-gui library.**
 
-raygui was initially inspired by [Unity IMGUI](https://docs.unity3d.com/Manual/GUIScriptingGuide.html) (immediate mode GUI API).
+`raygui` was originally inspired by [Unity IMGUI](https://docs.unity3d.com/Manual/GUIScriptingGuide.html) (immediate mode GUI API).
 
-raygui was originated as an auxiliar module for [raylib](https://github.com/raysan5/raylib) to create simple GUI interfaces using raylib graphic style (simple colors, plain rectangular shapes, wide borders...).
+`raygui` was designed as an auxiliary module for [raylib](https://github.com/raysan5/raylib) to create simple GUI interfaces using raylib graphic style (simple colors, plain rectangular shapes, wide borders...) but it can be adapted to other engines/frameworks.
 
-raygui is intended for **tools development**; it has already been used to develop the following tools: [rFXGen](https://github.com/raysan5/rfxgen), [rTexViewer](https://raylibtech.itch.io/rtexviewer), [rTexPacker](https://raylibtech.itch.io/rtexpacker) [rGuiStyler](https://raylibtech.itch.io/rguistyler), [rGuiLayout](https://raylibtech.itch.io/rguilayout) and [rGuiIcons](https://raylibtech.itch.io/rguiicons)
+`raygui` is intended for **tools development**; it has already been used to develop [multiple published tools](https://raylibtech.itch.io).
 
 <br>
 
-## raygui provided controls
+**WARNING: Latest `raygui` from master branch is always aligned with latest `raylib` from master branch. Make sure to use the appropiate versions.**
 
-#### Container/separator controls
+**WARNING: Latest `raygui 4.0` is an API-BREAKING redesign from previous versions (3.x), now all functions are more consistent and coherent, you can read the details about this breaking change in issue [283](https://github.com/raysan5/raygui/issues/283)**
+
+*NOTE: raygui is a single-file header-only library (despite its internal dependency on raylib), so, functions definition AND implementation reside in the same file `raygui.h`, when including `raygui.h` in a module, `RAYGUI_IMPLEMENTATION` must be previously defined to include the implementation part of `raygui.h` BUT only in one compilation unit, other modules could also include `raygui.h` but `RAYGUI_IMPLEMENTATION` must not be defined again.*
+
+## features
+
+ - **Immediate-mode gui, no retained data**
+ - **+25** controls provided (basic and advanced)
+ - Powerful **styling system** for colors, font and metrics
+ - Standalone usage mode supported (for other graphic libs)
+ - **Icons support**, embedding a complete 1-bit icons pack
+ - Multiple **tools** provided for raygui development
+
+## code sample
+```c
+#include "raylib.h"
+
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h"
+
+int main()
+{
+    InitWindow(400, 200, "raygui - controls test suite");
+    SetTargetFPS(60);
+
+    bool showMessageBox = false;
+
+    while (!WindowShouldClose())
+    {
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+            ClearBackground(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));
+
+            if (GuiButton((Rectangle){ 24, 24, 120, 30 }, "#191#Show Message")) showMessageBox = true;
+
+            if (showMessageBox)
+            {
+                int result = GuiMessageBox((Rectangle){ 85, 70, 250, 100 },
+                    "#191#Message Box", "Hi! This is a message!", "Nice;Cool");
+
+                if (result >= 0) showMessageBox = false;
+            }
+
+        EndDrawing();
+    }
+
+    CloseWindow();
+    return 0;
+}
+```
+![screenshot000](https://github.com/raysan5/raygui/assets/5766837/170e2bce-b7ca-49dc-a263-32b673376546)
+
+## raygui controls
+
+### basic controls
 ```
-WindowBox   |  GroupBox    |  Line        |  Panel
+Label       |  Button      |  LabelButton |  Toggle      |  ToggleGroup  |  ToggleSlider
+CheckBox    |  ComboBox    |  DropdownBox |  TextBox     |  ValueBox     |  Spinner
+Slider      |  SliderBar   |  ProgressBar |  StatusBar   |  DummyRec     |  Grid
 ```
-#### Basic controls
+### container/separator controls
 ```
-Label       |  Button      |  LabelButton |  ImageButton  |  Toggle      |  ToggleGroup |  CheckBox
-ComboBox    |  DropdownBox |  TextBox     |  TextBoxMulti |  ValueBox    |  Spinner     |  Slider   
-SliderBar   |  ProgressBar |  StatusBar   |  ScrollBar    |  ScrollPanel |  DummyRec    |  Grid
+WindowBox   |  GroupBox    |  Line        |  Panel       |  ScrollPanel  | TabBar
 ```
-#### Advance controls
+### advanced controls
 ```
 ListView    |  ColorPicker |  MessageBox  |  TextInputBox
 ```
 
+
 ## raygui styles
 
-raygui comes with a [default](styles/default) style automatically loaded at runtime:
+`raygui` comes with a [default](styles/default) style automatically loaded at runtime:
 
-![raygui default style](styles/default/style_table.png)
+![raygui default style](styles/default/style_default.png)
 
 Some additional styles are also provided for convenience, just check [styles directory](styles) for details:
 
 ![raygui additional styles](images/raygui_style_table_multi.png)
 
-Custom styles can also be created very easily using [rGuiStyler](https://raylibtech.itch.io/rguistyler) tool. 
+Custom styles can also be created very easily using [rGuiStyler](https://raylibtech.itch.io/rguistyler) tool.
 
 Styles can be loaded at runtime using raygui `GuiLoadStyle()` function. Simple and easy-to-use.
 
-![rGuiStyler v3.1](images/rguistyler_v300.png)
-
-*rGuiStyler v3.1 - raygui styles editor, useful to create custom styles*
- 
 ## raygui icons
 
-`raygui` supports custom icons provided as an external array of data. To support icons just define `RAYGUI_SUPPORT_ICONS` before including `raygui`. 
-
-A set of custom handcrafter icons is provided in [`riconsdata`](src/riconsdata.h). This set of icons can be created and customized using [rGuiIcons](https://raylibtech.itch.io/rguiicons) tool.  
+`raygui` supports custom icons, by default, a predefined set of icons is provided inside `raygui` as an array of binary data; it contains **256 possible icons** defined as **16x16 pixels** each; each pixel is codified using **1-bit**. The total size of the array is `2048 bytes`.
 
 <img align="right" src="images/raygui_ricons.png">
 
+To use any of those icons just prefix the *#iconId#* number to **any text** written within `raygui` controls:
 ```c
-#define RAYGUI_IMPLEMENTATION
-#define RAYGUI_SUPPORT_ICONS
-#include "raygui.h"
-```
-To use any of those icons in your gui, just preprend *iconId* to any text written within `raygui` controls:
-```c
-if (GuiButton(rec, "#05#Open Image") { /* ACTION */ }
+if (GuiButton(rec, "#05#Open Image")) { /* ACTION */ }
 ```
-or use the provided `GuiIconText()` function to prepend it automatically, using a clearer identifier.
+It's also possible to use the provided `GuiIconText()` function to prefix it automatically, using a clearer identifier (defined in `raygui.h`).
 ```c
 if (GuiButton(rec, GuiIconText(RICON_FILE_OPEN, "Open Image"))) { /* ACTION */ }
 ```
+Provided set of icons can be reviewed and customized using [rGuiIcons](https://raylibtech.itch.io/rguiicons) tool.
+
+## raygui support tools
+
+ - [**rGuiStyler**](https://raylibtech.itch.io/rguistyler) - A simple and easy-to-use raygui styles editor.
+
+   ![rGuiStyler v3.1](images/rguistyler_v300.png)
+
+ - [**rGuiIcons**](https://raylibtech.itch.io/rguiicons) - A simple and easy-to-use raygui icons editor.
+
+   ![rGuiIcons v1.0](images/rguiicons_v100.png)
+
+ - [**rGuiLayout**](https://raylibtech.itch.io/rguilayout) - A simple and easy-to-use raygui layouts editor.
+
+   ![rGuiLayout v2.2](images/rguilayout_v220.png)
+
+## building
+
+`raygui` is intended to be used as a portable single-file header-only library, to be directly integrated into any C/C++ codebase but some users could require a shared/dynamic version of the library, for example, to create bindings:
+
+ - **Windows (MinGW, GCC)**
+```
+copy src/raygui.h src/raygui.c
+gcc -o src/raygui.dll src/raygui.c -shared -DRAYGUI_IMPLEMENTATION -DBUILD_LIBTYPE_SHARED -static-libgcc -lopengl32 -lgdi32 -lwinmm -Wl,--out-implib,src/librayguidll.a
+```
+
+ - **Windows (MSVC)**
+```
+copy src\raygui.h src\raygui.c
+cl /O2 /I../raylib/src/ /D_USRDLL /D_WINDLL /DRAYGUI_IMPLEMENTATION /DBUILD_LIBTYPE_SHARED src/raygui.c /LD /Feraygui.dll /link /LIBPATH ../raylib/build/raylib/Release/raylib.lib /subsystem:windows /machine:x64
+```
+
+ - **Linux (GCC)**
+```
+mv src/raygui.h src/raygui.c
+gcc -o raygui.so src/raygui.c -shared -fpic -DRAYGUI_IMPLEMENTATION -lraylib -lGL -lm -lpthread -ldl -lrt -lX11
+mv src/raygui.c src/raygui.h
+```
+
+- **Mac (clang, homebrew installed raylib)**
+```
+cp src/raygui.h src/raygui.c
+brew install raylib
+gcc -o raygui.dynlib src/raygui.c -shared -fpic -DRAYGUI_IMPLEMENTATION -framework OpenGL -lm -lpthread -ldl $(pkg-config --libs --cflags raylib)
+```
+
 
-license
--------
+## license
 
 raygui is licensed under an unmodified zlib/libpng license, which is an OSI-certified, BSD-like license that allows static linking with closed source software. Check [LICENSE](LICENSE) for further details.

+ 12 - 7
gui.mod/raygui/examples/Makefile

@@ -319,7 +319,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
     ifeq ($(PLATFORM_OS),OSX)
         # Libraries for OSX 10.9 desktop compiling
         # NOTE: Required packages: libopenal-dev libegl1-mesa-dev
-        LDLIBS = -lraylib -framework OpenGL -framework OpenAL -framework Cocoa
+        LDLIBS = -lraylib -framework OpenGL -framework Cocoa -framework IOKit -framework CoreAudio -framework CoreVideo
     endif
     ifeq ($(PLATFORM_OS),BSD)
         # Libraries for FreeBSD, OpenBSD, NetBSD, DragonFly desktop compiling
@@ -337,7 +337,7 @@ endif
 ifeq ($(PLATFORM),PLATFORM_RPI)
     # Libraries for Raspberry Pi compiling
     # NOTE: Required packages: libasound2-dev (ALSA)
-    LDLIBS = -lraylib -lbrcmGLESv2 -lbrcmEGL -lpthread -lrt -lm -lbcm_host -ldl
+    LDLIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -ldrm -lgbm -ldl
 endif
 ifeq ($(PLATFORM),PLATFORM_WEB)
     # Libraries for web (HTML5) compiling
@@ -348,11 +348,16 @@ endif
 EXAMPLES = \
     controls_test_suite/controls_test_suite \
     custom_file_dialog/custom_file_dialog \
+    custom_input_box/custom_input_box\
     image_exporter/image_exporter \
-    image_raw_importer/image_raw_importer \
+    image_importer_raw/image_importer_raw \
+    property_list/property_list \
     portable_window/portable_window \
-    scroll_panel/gui_scroll_panel \
-    text_box_selection/gui_text_box
+    scroll_panel/scroll_panel \
+    style_selector/style_selector \
+    custom_sliders/custom_sliders \
+    animation_curve/animation_curve \
+    floating_window/floating_window \
 
 CURRENT_MAKEFILE = $(lastword $(MAKEFILE_LIST))
 
@@ -371,7 +376,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
 		del *.o *.exe /s
     endif
     ifeq ($(PLATFORM_OS),LINUX)
-	find -type f -executable | xargs file -i | grep -E 'x-object|x-archive|x-sharedlib|x-executable' | rev | cut -d ':' -f 2- | rev | xargs rm -fv
+		rm -f $(EXAMPLES)
     endif
     ifeq ($(PLATFORM_OS),OSX)
 		find . -type f -perm +ugo+x -delete
@@ -385,4 +390,4 @@ endif
 ifeq ($(PLATFORM),PLATFORM_WEB)
 	del *.o *.html *.js
 endif
-	@echo Cleaning done
+	@echo Cleaning done

+ 477 - 0
gui.mod/raygui/examples/animation_curve/animation_curve.c

@@ -0,0 +1,477 @@
+/*******************************************************************************************
+*
+*   Animation curves - An example demo for animation curves
+*
+*   DEPENDENCIES:
+*       raylib 4.0  - Windowing/input management and drawing.
+*       raygui 3.0  - Immediate-mode GUI controls.
+*
+*   COMPILATION (Windows - MinGW):
+*       gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
+*
+*   LICENSE: zlib/libpng
+*
+*   Copyright (c) 2023 Pierre Jaffuer (@smallcluster)
+*
+**********************************************************************************************/
+
+#include "raylib.h"
+
+#define RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT 24
+#define RAYGUI_IMPLEMENTATION
+#include "../../src/raygui.h"
+
+// raygui embedded styles
+#include "../styles/style_cyber.h"       // raygui style: cyber
+#include "../styles/style_jungle.h"      // raygui style: jungle
+#include "../styles/style_lavanda.h"     // raygui style: lavanda
+#include "../styles/style_dark.h"        // raygui style: dark
+#include "../styles/style_bluish.h"      // raygui style: bluish
+#include "../styles/style_terminal.h"    // raygui style: terminal
+
+#undef RAYGUI_IMPLEMENTATION            // Avoid including raygui implementation again
+
+#define GUI_CURVE_EDITOR_IMPLEMENTATION
+#include "gui_curve_editor.h"
+
+//------------------------------------------------------------------------------------
+// Helper function
+//------------------------------------------------------------------------------------
+void LoadCurveDefaults(GuiCurveEditorState curves[]);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main()
+{
+    // Initialization
+    //---------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 540;
+
+    InitWindow(screenWidth, screenHeight, "raygui - animation curves");
+    SetTargetFPS(60);
+
+    // Gui style
+    GuiLoadStyleDefault();
+    int visualStyleActive = 0;
+    int prevVisualStyleActive = 0;
+
+    float fontSize = GuiGetStyle(DEFAULT, TEXT_SIZE);
+    const float margin = 8;
+
+    // Gui states
+    Vector2 scrollOffset = (Vector2){ 0, 0 };
+    Rectangle contentRect = (Rectangle){ 0, 0, 0, 0 };
+    bool moveSlider = false;
+    bool sectionActive[5] = { 0 };
+    sectionActive[0] = true;
+    const char *sectionNames[5] = { "X Position", "Y Position", "Width", "Height", "Rotation" };
+    bool editValueBox[5][4] = { 0 };
+    char *valTextBox[5][4][20] = { 0 };
+    bool playAnimation = true;
+    bool showHelp = true;
+
+    Rectangle settingsRect = (Rectangle){ screenWidth - screenWidth/3, 0, screenWidth/3, screenHeight };
+
+    // Animation curves
+    // 0 -> Ball X position
+    // 1 -> Ball Y position
+    // 2 -> Ball Width
+    // 3 -> Ball Height
+    // 4 -> Ball rotation
+    GuiCurveEditorState curves[5] = { 0 };
+    LoadCurveDefaults(curves);
+
+    // Animation time
+    float time = 0.0f;
+    float animationTime = 4.0f;
+
+    //SetTargetFPS(60);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        if (playAnimation) time += GetFrameTime();
+
+        // Reset timer
+        if (time > animationTime) time = 0;
+
+        // Ball animation
+        const float t = time/animationTime;
+        Vector2 ballPos = (Vector2){ GuiCurveEval(&curves[0], t), GuiCurveEval(&curves[1], t) };
+        Vector2 ballSize = (Vector2){ GuiCurveEval(&curves[2], t), GuiCurveEval(&curves[3], t) };
+        float ballRotation = GuiCurveEval(&curves[4], t);
+
+        // Update style
+        if (visualStyleActive != prevVisualStyleActive)
+        {
+            switch (visualStyleActive)
+            {
+                case 0: GuiLoadStyleDefault(); break;
+                case 1: GuiLoadStyleJungle(); break;
+                case 2: GuiLoadStyleLavanda(); break;
+                case 3: GuiLoadStyleDark(); break;
+                case 4: GuiLoadStyleBluish(); break;
+                case 5: GuiLoadStyleCyber(); break;
+                case 6: GuiLoadStyleTerminal(); break;
+                default: break;
+            }
+
+            fontSize = GuiGetStyle(DEFAULT, TEXT_SIZE);
+            prevVisualStyleActive = visualStyleActive;
+        }
+
+        // Update settings panel rect
+        Rectangle sliderRect = (Rectangle){ settingsRect.x - 4, settingsRect.y, 4, settingsRect.height };
+        if (CheckCollisionPointRec(GetMousePosition(), sliderRect) && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) moveSlider = true;
+        if (IsMouseButtonUp(MOUSE_BUTTON_LEFT)) moveSlider = false;
+
+        if (moveSlider)
+        {
+            settingsRect.x = GetMouseX();
+
+            // Minimum-Maximum size
+            if (settingsRect.x > (screenWidth - 4)) settingsRect.x = screenWidth - 4;
+            else if (settingsRect.x < 4) settingsRect.x = 4;
+
+            settingsRect.width = screenWidth - settingsRect.x;
+        }
+
+
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+            ClearBackground(GetColor( GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));
+
+            // Scene
+            //----------------------------------------------------------------------------------
+            DrawRectangle(curves[0].start, curves[1].end, curves[0].end-curves[0].start, curves[1].start-curves[1].end, BLUE);  // Sky
+
+            DrawRectangle(curves[0].start, curves[1].start, curves[0].end-curves[0].start, 32, DARKGREEN);  // Ground
+
+            BeginScissorMode(curves[0].start, curves[1].end, curves[0].end-curves[0].start, curves[1].start-curves[1].end+32);
+
+                DrawRectanglePro((Rectangle){ballPos.x, ballPos.y, ballSize.x, ballSize.y}, (Vector2){ballSize.x/2.f,ballSize.y/2.f}, ballRotation, PINK);  // Ball
+
+                DrawLine(ballPos.x, ballPos.y, ballPos.x + cosf(ballRotation*DEG2RAD)*ballSize.x, ballPos.y +sinf(ballRotation*DEG2RAD)*ballSize.y, RED);
+                DrawLine(ballPos.x, ballPos.y, ballPos.x + cosf((ballRotation+90)*DEG2RAD)*ballSize.x, ballPos.y +sinf((ballRotation+90)*DEG2RAD)*ballSize.y, GREEN);
+
+            EndScissorMode();
+
+            // Bounds
+            DrawRectangleLines(curves[0].start, curves[1].end, curves[0].end-curves[0].start, curves[1].start-curves[1].end+32, GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL)));
+            //----------------------------------------------------------------------------------
+
+            // GUI
+            //----------------------------------------------------------------------------------
+            if (showHelp)
+            {
+                if (GuiWindowBox((Rectangle) {margin, margin, settingsRect.x-2*margin, curves[1].end-2*margin}, "help")) showHelp = false;
+
+                Rectangle helpTextRect = (Rectangle) { 2*margin, 2*margin+RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT, settingsRect.x - 4 - 4*margin, 0 };
+                GuiLabel((Rectangle) {helpTextRect.x, helpTextRect.y+helpTextRect.height, helpTextRect.width, fontSize}, "Curve widget controls:");
+                helpTextRect.height += fontSize+margin;
+                GuiLabel((Rectangle) {helpTextRect.x, helpTextRect.y+helpTextRect.height, helpTextRect.width, fontSize}, "- Left click to move/add point or move tangents");
+                helpTextRect.height += fontSize+margin/2;
+                GuiLabel((Rectangle) {helpTextRect.x, helpTextRect.y+helpTextRect.height, helpTextRect.width, fontSize}, "- While moving a tangent, hold SHIFT to disable tangent symetry");
+                helpTextRect.height += fontSize+margin/2;
+                GuiLabel((Rectangle) {helpTextRect.x, helpTextRect.y+helpTextRect.height, helpTextRect.width, fontSize}, "- Right click to remove a point");
+                helpTextRect.height += fontSize+margin/2;
+                DrawRectangleGradientV(margin, margin+curves[1].end - 2*margin, settingsRect.x - 2*margin, 12, (Color){ 0,0,0,100 }, BLANK);
+            }
+
+            // Settings panel
+            GuiScrollPanel(settingsRect, "Settings", contentRect, &scrollOffset, NULL);
+
+            BeginScissorMode(settingsRect.x, settingsRect.y+RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT, settingsRect.width, settingsRect.height);
+
+            // Rebuild the content Rect
+            contentRect = (Rectangle){ settingsRect.x + margin, RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT+margin, settingsRect.width - 2*margin - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), 0 };
+
+            // Help button
+            if (GuiButton((Rectangle){ contentRect.x, contentRect.y + contentRect.height + scrollOffset.y, contentRect.width, 1.5*fontSize }, GuiIconText(showHelp? ICON_EYE_ON : ICON_EYE_OFF, "Curve controls help"))) showHelp = !showHelp;
+
+            contentRect.height += 1.5*fontSize + margin;
+
+            // Animation Time slider
+            GuiSlider((Rectangle){ contentRect.x, contentRect.y+contentRect.height+scrollOffset.y, contentRect.width/2, fontSize }, NULL, TextFormat("Animation Time: %.2fs", animationTime), &animationTime, 1, 8);
+            contentRect.height += fontSize + margin;
+
+            // Load default curves
+            if (GuiButton((Rectangle){ contentRect.x, contentRect.y+contentRect.height+scrollOffset.y, contentRect.width, 1.5*fontSize }, "Load default"))
+            {
+                LoadCurveDefaults(curves);
+                animationTime = 4.0f;
+                time = 0.0f;
+            }
+            contentRect.height += 1.5f*fontSize + margin;
+
+            // Styles
+            GuiLabel((Rectangle){ contentRect.x, contentRect.y + contentRect.height + scrollOffset.y, contentRect.width, fontSize }, "Style:");
+            contentRect.height += fontSize;
+            GuiComboBox((Rectangle){contentRect.x, contentRect.y+contentRect.height+scrollOffset.y, contentRect.width, 1.5*fontSize }, "default;Jungle;Lavanda;Dark;Bluish;Cyber;Terminal", &visualStyleActive);
+            contentRect.height += 1.5f*fontSize + margin;
+
+            // Draw curves with their controls
+            //----------------------------------------------------------------------------------
+            for (int i = 0; i < 5; i++)
+            {
+                // Collapsing section
+                Rectangle headerRect = (Rectangle){ contentRect.x, contentRect.y + contentRect.height+scrollOffset.y, contentRect.width, 1.5f*fontSize };
+                GuiStatusBar(headerRect, NULL);
+
+                if (GuiLabelButton(headerRect, GuiIconText(sectionActive[i] ? ICON_ARROW_DOWN_FILL : ICON_ARROW_RIGHT_FILL, sectionNames[i]))) sectionActive[i] = !sectionActive[i];
+
+                contentRect.height += 1.5f*fontSize + margin;
+
+                // Skip this section
+                if (!sectionActive[i]) continue;
+
+                // Draw curve control
+                Rectangle curveRect = (Rectangle){ contentRect.x, contentRect.y+contentRect.height + scrollOffset.y, contentRect.width, fontSize*12 };
+                EndScissorMode(); // Stop clipping from setting rect
+
+                // Curves can leaks from control boundary... scissor it !
+                BeginScissorMode(curveRect.x, curveRect.y, curveRect.width, curveRect.height);
+                    GuiCurveEditor(&curves[i], curveRect);
+                EndScissorMode();
+
+                // Resume clipping from setting rect
+                BeginScissorMode(settingsRect.x, settingsRect.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT, settingsRect.width, settingsRect.height);
+                contentRect.height += fontSize*12 + margin;
+
+                // Draw selected point controls
+                GuiCurveEditorPoint *p = &(curves[i].points[curves[i].selectedIndex]);
+                GuiCheckBox((Rectangle){ contentRect.x, contentRect.y + contentRect.height + scrollOffset.y, 1.5f*fontSize, 1.5f*fontSize }, "Left Linear", &p->leftLinear);
+                GuiCheckBox((Rectangle){ contentRect.x+contentRect.width/2, contentRect.y + contentRect.height + scrollOffset.y, 1.5f*fontSize, 1.5f*fontSize }, "Right Linear", &p->rightLinear);
+                contentRect.height += 1.5f*fontSize + margin;
+
+                // Positions
+                GuiLabel((Rectangle){ contentRect.x, contentRect.y + contentRect.height + scrollOffset.y, contentRect.width, fontSize }, "Position");
+                contentRect.height += fontSize;
+
+                if (!editValueBox[i][0]) gcvt(p->position.x, 6, (char *)valTextBox[i][0]);  // Transform x position to string
+
+                if (!editValueBox[i][1]) gcvt(curves[i].start + (curves[i].end-curves[i].start)*p->position.y, 6, (char *)valTextBox[i][1]); // Transform y position to string
+
+                // X pos
+                if (GuiTextBox((Rectangle){ contentRect.x, contentRect.y + contentRect.height + scrollOffset.y, contentRect.width/2-margin, 1.5f*fontSize }, (char *)valTextBox[i][0], 20, editValueBox[i][0]))
+                {
+                    editValueBox[i][0] = !editValueBox[i][0];
+
+                    // Input ended
+                    if (!editValueBox[i][0])
+                    {
+                        // Try to convert text to float and assign it to the point
+                        char *endPtr = NULL;
+                        double value = strtod((char *)valTextBox[i][0], &endPtr);
+
+                        if (endPtr != (char *)valTextBox[i][0]) p->position.x = (value < 0)? 0 : (value > 1)? 1 : value;
+                    }
+                }
+
+                // Y pos
+                if (GuiTextBox((Rectangle){ contentRect.x + contentRect.width/2, contentRect.y + contentRect.height + scrollOffset.y, contentRect.width/2.0f, 1.5f*fontSize }, (char *)valTextBox[i][1], 20, editValueBox[i][1]))
+                {
+                    editValueBox[i][1] = !editValueBox[i][1];
+
+                    // Input ended
+                    if (!editValueBox[i][1])
+                    {
+                        // Try to convert text to float and assign it to the point
+                        char *endPtr = NULL;
+                        double value = strtod((char *)valTextBox[i][1], &endPtr);
+
+                        if (endPtr != (char *)valTextBox[i][1])
+                        {
+                            float normalizedVal = (value - curves[i].start)/(curves[i].end - curves[i].start);
+                            p->position.y = (normalizedVal < 0)? 0 : (normalizedVal > 1)? 1 : normalizedVal;
+                        }
+                    }
+
+                }
+
+                contentRect.height += 1.5f*fontSize + margin;
+
+                // Tangents
+                GuiLabel((Rectangle){ contentRect.x, contentRect.y + contentRect.height + scrollOffset.y, contentRect.width, fontSize }, "Tangents");
+                contentRect.height += fontSize;
+
+                if (!editValueBox[i][2]) gcvt(p->tangents.x, 6, (char *)valTextBox[i][2]); // Transform left tangent to string
+
+                if (!editValueBox[i][3]) gcvt(p->tangents.y, 6, (char *)valTextBox[i][3]);   // Transform right tangent to string
+
+                // Left tan
+                if (GuiTextBox((Rectangle){ contentRect.x, contentRect.y + contentRect.height + scrollOffset.y, contentRect.width/2 - margin, 1.5f*fontSize }, (char *)valTextBox[i][2], 20, editValueBox[i][2]))
+                {
+                    editValueBox[i][2] = !editValueBox[i][2];
+
+                    // Input ended
+                    if (!editValueBox[i][2])
+                    {
+                        // Try to convert text to float and assign it to the point
+                        char *endPtr = NULL;
+                        double value = strtod((char *)valTextBox[i][2], &endPtr);
+                        if (endPtr != (char *)valTextBox[i][2]) p->tangents.x = value;
+                    }
+                }
+
+                // Right tan
+                if (GuiTextBox((Rectangle){ contentRect.x + contentRect.width/2.0f, contentRect.y + contentRect.height + scrollOffset.y, contentRect.width/2.0f, 1.5f*fontSize }, (char *)valTextBox[i][3], 20, editValueBox[i][3]))
+                {
+                    editValueBox[i][3] = !editValueBox[i][3];
+
+                    // Input ended
+                    if (!editValueBox[i][3])
+                    {
+                        // Try to convert text to float and assign it to the point
+                        char *endPtr = NULL;
+                        double value = strtod((char *)valTextBox[i][3], &endPtr);
+                        if (endPtr != (char *)valTextBox[i][3]) p->tangents.y = value;
+                    }
+                }
+
+                contentRect.height += 1.5*fontSize + margin;
+            }
+
+            contentRect.height += margin;
+
+            EndScissorMode();
+
+            // Settings panel shadow
+            DrawRectangleGradientH(settingsRect.x - 12, 0, 12, settingsRect.height, BLANK, (Color){ 0, 0, 0, 100 });
+
+            // Slider
+            if (moveSlider) DrawRectangle(sliderRect.x, sliderRect.y, sliderRect.width, sliderRect.height, GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_PRESSED)));
+            else if(CheckCollisionPointRec(GetMousePosition(), sliderRect)) DrawRectangle(sliderRect.x, sliderRect.y, sliderRect.width, sliderRect.height, GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_FOCUSED)));
+
+            // Draw Time controls
+            //----------------------------------------------------------------------------------
+            Rectangle timeLineRect = (Rectangle){ 0, screenHeight-4*fontSize, settingsRect.x, 4*fontSize };
+            GuiPanel((Rectangle){ timeLineRect.x, timeLineRect.y, timeLineRect.width, 2*fontSize }, NULL);
+            GuiLabel((Rectangle){ timeLineRect.x, timeLineRect.y, timeLineRect.width, 2*fontSize }, TextFormat("Normalized Time: %.3f", time/animationTime));
+            if (GuiButton((Rectangle){ timeLineRect.x+timeLineRect.width/2 - 2*fontSize - margin/4, timeLineRect.y, 2*fontSize, 2*fontSize }, GuiIconText((playAnimation? ICON_PLAYER_PAUSE : ICON_PLAYER_PLAY), ""))) playAnimation = !playAnimation;
+
+            if (GuiButton((Rectangle){ timeLineRect.x+timeLineRect.width/2 + margin/4, timeLineRect.y, 2*fontSize, 2*fontSize }, GuiIconText(ICON_PLAYER_STOP, "")))
+            {
+                playAnimation = false;
+                time = 0;
+            }
+
+            float animTime = time/animationTime;
+            GuiSlider((Rectangle){timeLineRect.x, timeLineRect.y + 2*fontSize, timeLineRect.width, timeLineRect.height - 2*fontSize }, NULL, NULL, &animTime, 0, 1);
+            time = animationTime*animTime;
+
+            // Time panel shadow
+            DrawRectangleGradientV(timeLineRect.x, timeLineRect.y - 12, timeLineRect.width, 12, BLANK, (Color){ 0, 0, 0, 100 });
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    CloseWindow();              // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
+
+void LoadCurveDefaults(GuiCurveEditorState curves[])
+{
+    // X pos
+    curves[0].start = 28;
+    curves[0].end = 506;
+    curves[0].numPoints = 4;
+    curves[0].selectedIndex = 0;
+    curves[0].editLeftTangent = false;
+    curves[0].editRightTangent = false;
+    curves[0].points[0].position =(Vector2) {0.000000, 0.000000}; curves[0].points[0].tangents = (Vector2) {0.000000, 1.515101};  curves[0].points[0].leftLinear =   1;curves[0].points[0].rightLinear =  1;
+    curves[0].points[1].position =(Vector2) {0.422414, 0.640000}; curves[0].points[1].tangents = (Vector2) {-2.824348, -4.494999};curves[0].points[1].leftLinear =   0;curves[0].points[1].rightLinear =  0;
+    curves[0].points[2].position =(Vector2) {0.732759, 0.210000}; curves[0].points[2].tangents = (Vector2) {0.000000, 2.956133};  curves[0].points[2].leftLinear =   0;curves[0].points[2].rightLinear =  1;
+    curves[0].points[3].position =(Vector2) {1.000000, 1.000000}; curves[0].points[3].tangents = (Vector2) {2.956133, 0.000000};  curves[0].points[3].leftLinear =   1;curves[0].points[3].rightLinear =  1;
+
+    // Y pos
+    curves[1].start = 405;
+    curves[1].end = 135;
+    curves[1].numPoints = 7;
+    curves[1].selectedIndex = 0;
+    curves[1].editLeftTangent = false;
+    curves[1].editRightTangent = false;
+    curves[1].points[0].position = (Vector2) {0.000000, 1.000000};curves[1].points[0].tangents = (Vector2) { 0.000000  , 0.000000};curves[1].points[0].leftLinear =  0;curves[1].points[0].rightLinear =  0;
+    curves[1].points[1].position = (Vector2) {0.140000, 0.000000};curves[1].points[1].tangents = (Vector2) {-10.000000 ,10.000000};curves[1].points[1].leftLinear =  0;curves[1].points[1].rightLinear =  0;
+    curves[1].points[2].position = (Vector2) {0.450000, 0.000000};curves[1].points[2].tangents = (Vector2) {-10.000000 ,10.000000};curves[1].points[2].leftLinear =  0;curves[1].points[2].rightLinear =  0;
+    curves[1].points[3].position = (Vector2) {0.670000, 0.000000};curves[1].points[3].tangents = (Vector2) {-10.000000 ,10.000000};curves[1].points[3].leftLinear =  0;curves[1].points[3].rightLinear =  0;
+    curves[1].points[4].position = (Vector2) {0.830000, 0.000000};curves[1].points[4].tangents = (Vector2) {-10.000000 ,10.000000};curves[1].points[4].leftLinear =  0;curves[1].points[4].rightLinear =  0;
+    curves[1].points[5].position = (Vector2) {0.940000, 0.000000};curves[1].points[5].tangents = (Vector2) {-10.000000 ,10.000000};curves[1].points[5].leftLinear =  0;curves[1].points[5].rightLinear =  0;
+    curves[1].points[6].position = (Vector2) {1.000000, 0.000000};curves[1].points[6].tangents = (Vector2) {-10.000000 , 0.000000};curves[1].points[6].leftLinear =  0;curves[1].points[6].rightLinear =  0;
+
+    // X size
+    curves[2].start = 1;
+    curves[2].end = 64;
+    curves[2].numPoints = 16;
+    curves[2].selectedIndex = 0;
+    curves[2].editLeftTangent = false;
+    curves[2].editRightTangent = false;
+    curves[2].points[0].position =  (Vector2) {0.000000, 0.492063}; curves[2].points[0].tangents =  (Vector2) {0,0}; curves[2].points[0].leftLinear =  0; curves[2].points[0].rightLinear =  0;
+    curves[2].points[1].position =  (Vector2) {0.130000, 0.492063}; curves[2].points[1].tangents =  (Vector2) {0,0}; curves[2].points[1].leftLinear =  0; curves[2].points[1].rightLinear =  0;
+    curves[2].points[2].position =  (Vector2) {0.140000, 0.746032}; curves[2].points[2].tangents =  (Vector2) {0,0}; curves[2].points[2].leftLinear =  0; curves[2].points[2].rightLinear =  0;
+    curves[2].points[3].position =  (Vector2) {0.150000, 0.492063}; curves[2].points[3].tangents =  (Vector2) {0,0}; curves[2].points[3].leftLinear =  0; curves[2].points[3].rightLinear =  0;
+    curves[2].points[4].position =  (Vector2) {0.440000, 0.490000}; curves[2].points[4].tangents =  (Vector2) {0,0}; curves[2].points[4].leftLinear =  0; curves[2].points[4].rightLinear =  0;
+    curves[2].points[5].position =  (Vector2) {0.450000, 0.682540}; curves[2].points[5].tangents =  (Vector2) {0,0}; curves[2].points[5].leftLinear =  0; curves[2].points[5].rightLinear =  0;
+    curves[2].points[6].position =  (Vector2) {0.460000, 0.480000}; curves[2].points[6].tangents =  (Vector2) {0,0}; curves[2].points[6].leftLinear =  0; curves[2].points[6].rightLinear =  0;
+    curves[2].points[7].position =  (Vector2) {0.660000, 0.492063}; curves[2].points[7].tangents =  (Vector2) {0,0}; curves[2].points[7].leftLinear =  0; curves[2].points[7].rightLinear =  0;
+    curves[2].points[8].position =  (Vector2) {0.670000, 0.619048}; curves[2].points[8].tangents =  (Vector2) {0,0}; curves[2].points[8].leftLinear =  0; curves[2].points[8].rightLinear =  0;
+    curves[2].points[9].position =  (Vector2) {0.680000, 0.492063}; curves[2].points[9].tangents =  (Vector2) {0,0}; curves[2].points[9].leftLinear =  0; curves[2].points[9].rightLinear =  0;
+    curves[2].points[10].position = (Vector2) {0.820000, 0.492063}; curves[2].points[10].tangents = (Vector2) {0,0}; curves[2].points[10].leftLinear = 0; curves[2].points[10].rightLinear = 0;
+    curves[2].points[11].position = (Vector2) {0.830000, 0.619048}; curves[2].points[11].tangents = (Vector2) {0,0}; curves[2].points[11].leftLinear = 0; curves[2].points[11].rightLinear = 0;
+    curves[2].points[12].position = (Vector2) {0.840000, 0.492063}; curves[2].points[12].tangents = (Vector2) {0,0}; curves[2].points[12].leftLinear = 0; curves[2].points[12].rightLinear = 0;
+    curves[2].points[13].position = (Vector2) {0.930000, 0.492063}; curves[2].points[13].tangents = (Vector2) {0,0}; curves[2].points[13].leftLinear = 0; curves[2].points[13].rightLinear = 0;
+    curves[2].points[14].position = (Vector2) {0.940000, 0.619048}; curves[2].points[14].tangents = (Vector2) {0,0}; curves[2].points[14].leftLinear = 0; curves[2].points[14].rightLinear = 0;
+    curves[2].points[15].position = (Vector2) {0.950000, 0.492063}; curves[2].points[15].tangents = (Vector2) {0,0}; curves[2].points[15].leftLinear = 0; curves[2].points[15].rightLinear = 0;
+
+    // Y Size
+    curves[3].start = 1;
+    curves[3].end = 64;
+    curves[3].numPoints = 16;
+    curves[3].selectedIndex = 0;
+    curves[3].editLeftTangent = false;
+    curves[3].editRightTangent = false;
+    curves[3].points[0].position =  (Vector2) {0.000000, 0.492063};curves[3].points[0].tangents =  (Vector2) {0,0};curves[3].points[0].leftLinear =  0;curves[3].points[0].rightLinear =  0;
+    curves[3].points[1].position =  (Vector2) {0.130000, 0.492063};curves[3].points[1].tangents =  (Vector2) {0,0};curves[3].points[1].leftLinear =  0;curves[3].points[1].rightLinear =  0;
+    curves[3].points[2].position =  (Vector2) {0.140000, 0.238095};curves[3].points[2].tangents =  (Vector2) {0,0};curves[3].points[2].leftLinear =  0;curves[3].points[2].rightLinear =  0;
+    curves[3].points[3].position =  (Vector2) {0.150000, 0.492063};curves[3].points[3].tangents =  (Vector2) {0,0};curves[3].points[3].leftLinear =  0;curves[3].points[3].rightLinear =  0;
+    curves[3].points[4].position =  (Vector2) {0.440000, 0.492063};curves[3].points[4].tangents =  (Vector2) {0,0};curves[3].points[4].leftLinear =  0;curves[3].points[4].rightLinear =  0;
+    curves[3].points[5].position =  (Vector2) {0.450000, 0.301587};curves[3].points[5].tangents =  (Vector2) {0,0};curves[3].points[5].leftLinear =  0;curves[3].points[5].rightLinear =  0;
+    curves[3].points[6].position =  (Vector2) {0.460000, 0.492063};curves[3].points[6].tangents =  (Vector2) {0,0};curves[3].points[6].leftLinear =  0;curves[3].points[6].rightLinear =  0;
+    curves[3].points[7].position =  (Vector2) {0.660000, 0.492063};curves[3].points[7].tangents =  (Vector2) {0,0};curves[3].points[7].leftLinear =  0;curves[3].points[7].rightLinear =  0;
+    curves[3].points[8].position =  (Vector2) {0.670000, 0.365079};curves[3].points[8].tangents =  (Vector2) {0,0};curves[3].points[8].leftLinear =  0;curves[3].points[8].rightLinear =  0;
+    curves[3].points[9].position =  (Vector2) {0.680000, 0.492063};curves[3].points[9].tangents =  (Vector2) {0,0};curves[3].points[9].leftLinear =  0;curves[3].points[9].rightLinear =  0;
+    curves[3].points[10].position = (Vector2) {0.820000, 0.492063};curves[3].points[10].tangents = (Vector2) {0,0};curves[3].points[10].leftLinear = 0;curves[3].points[10].rightLinear = 0;
+    curves[3].points[11].position = (Vector2) {0.830000, 0.365079};curves[3].points[11].tangents = (Vector2) {0,0};curves[3].points[11].leftLinear = 0;curves[3].points[11].rightLinear = 0;
+    curves[3].points[12].position = (Vector2) {0.840000, 0.492063};curves[3].points[12].tangents = (Vector2) {0,0};curves[3].points[12].leftLinear = 0;curves[3].points[12].rightLinear = 0;
+    curves[3].points[13].position = (Vector2) {0.930000, 0.492063};curves[3].points[13].tangents = (Vector2) {0,0};curves[3].points[13].leftLinear = 0;curves[3].points[13].rightLinear = 0;
+    curves[3].points[14].position = (Vector2) {0.940000, 0.365079};curves[3].points[14].tangents = (Vector2) {0,0};curves[3].points[14].leftLinear = 0;curves[3].points[14].rightLinear = 0;
+    curves[3].points[15].position = (Vector2) {0.950000, 0.507937};curves[3].points[15].tangents = (Vector2) {0,0};curves[3].points[15].leftLinear = 0;curves[3].points[15].rightLinear = 0;
+
+    // Rotation
+    curves[4].start = -360;
+    curves[4].end = 360;
+    curves[4].numPoints = 9;
+    curves[4].selectedIndex = 0;
+    curves[4].editLeftTangent = false;
+    curves[4].editRightTangent = false;
+    curves[4].points[0].position =  (Vector2) {0.140000, 0.500000};curves[4].points[0].tangents =  (Vector2) {0,0};curves[4].points[0].leftLinear =  0;curves[4].points[0].rightLinear =  0;
+    curves[4].points[1].position =  (Vector2) {0.450000, 0.500000};curves[4].points[1].tangents =  (Vector2) {0,0};curves[4].points[1].leftLinear =  0;curves[4].points[1].rightLinear =  0;
+    curves[4].points[2].position =  (Vector2) {0.670000, 0.500000};curves[4].points[2].tangents =  (Vector2) {0,0};curves[4].points[2].leftLinear =  0;curves[4].points[2].rightLinear =  0;
+    curves[4].points[3].position =  (Vector2) {0.830000, 0.500000};curves[4].points[3].tangents =  (Vector2) {0,0};curves[4].points[3].leftLinear =  0;curves[4].points[3].rightLinear =  0;
+    curves[4].points[4].position =  (Vector2) {0.940000, 0.500000};curves[4].points[4].tangents =  (Vector2) {0,0};curves[4].points[4].leftLinear =  0;curves[4].points[4].rightLinear =  0;
+    curves[4].points[5].position =  (Vector2) {1.000000, 0.500000};curves[4].points[5].tangents =  (Vector2) {0,0};curves[4].points[5].leftLinear =  0;curves[4].points[5].rightLinear =  0;
+    curves[4].points[6].position =  (Vector2) {0.000000, 0.472222};curves[4].points[6].tangents =  (Vector2) {0,0};curves[4].points[6].leftLinear =  0;curves[4].points[6].rightLinear =  0;
+    curves[4].points[7].position =  (Vector2) {0.302752, 0.527778};curves[4].points[7].tangents =  (Vector2) {0,0};curves[4].points[7].leftLinear =  0;curves[4].points[7].rightLinear =  0;
+    curves[4].points[8].position =  (Vector2) {0.577982, 0.472222};curves[4].points[8].tangents =  (Vector2) {0,0};curves[4].points[8].leftLinear =  0;curves[4].points[8].rightLinear =  0;
+}

+ 543 - 0
gui.mod/raygui/examples/animation_curve/gui_curve_editor.h

@@ -0,0 +1,543 @@
+/*******************************************************************************************
+*
+*   CurveEdit v1.0 - A cubic Hermite editor for making animation curves
+*
+*   MODULE USAGE:
+*       #define GUI_CURVE_EDITOR_IMPLEMENTATION
+*       #include "gui_curve_edit.h"
+*
+*       INIT: GuiCurveEditState state = InitCurveEdit();
+*       EVALUATE: float y = EvalGuiCurve(&state, t); // 0 <= t <= 1
+*       DRAW: BeginScissorMode(bounds.x,bounds.y,bounds.width,bounds.height);
+*               GuiCurveEdit(&state, bounds, pointSize);
+*             EndScissorMode();
+*
+*   NOTE: See 'Module Structures Declaration' section for more informations.
+*
+*   NOTE: This module uses functions of the stdlib:
+*       - qsort
+*
+*   NOTE: Built-in interactions:
+*       - Left click to move/add point or move tangents
+*       - While moving a tangent, hold (left/right) SHIFT to disable tangent symetry
+*       - Right click to remove a point
+*
+*
+*   LICENSE: zlib/libpng
+*
+*   Copyright (c) 2023 Pierre Jaffuer (@smallcluster)
+*
+*   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.
+*
+**********************************************************************************************/
+
+#include "raylib.h"
+
+#ifndef GUI_CURVE_EDITOR_H
+#define GUI_CURVE_EDITOR_H
+
+
+#ifndef GUI_CURVE_EDITOR_MAX_POINTS
+    #define GUI_CURVE_EDITOR_MAX_POINTS 30
+#endif
+
+//----------------------------------------------------------------------------------
+// Module Structures Declaration
+//----------------------------------------------------------------------------------
+
+typedef struct {
+    Vector2 position;   // In normalized space [0.0f, 1.0f]
+    Vector2 tangents;   // The derivatives (left/right) of the 1D curve
+
+    // Let the curve editor calculate tangents to linearize part of the curve
+    bool leftLinear;
+    bool rightLinear;
+} GuiCurveEditorPoint;
+
+typedef struct {
+    float start;        // Value at y = 0
+    float end;          // Value at y = 1
+
+    // Always valid (unless you manualy change state's point array). Make sure to set it to -1 before init
+    int selectedIndex;
+
+    // Unsorted array with at least one point (constant curve)
+    GuiCurveEditorPoint points[GUI_CURVE_EDITOR_MAX_POINTS];
+    int numPoints;
+
+    // Private variables
+    bool editLeftTangent;
+    bool editRightTangent;
+    Vector2 mouseOffset;
+} GuiCurveEditorState;
+
+
+#ifdef __cplusplus
+extern "C" {            // Prevents name mangling of functions
+#endif
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+//----------------------------------------------------------------------------------
+GuiCurveEditorState InitGuiCurveEditor();     // Initialize curve editor state
+void GuiCurveEditor(GuiCurveEditorState *state, Rectangle bounds);  // Draw and update curve control
+
+// 1D Interpolation
+// Returns the y value (in [start, end]) of the curve at x = t
+// t must be normalized [0.f, 1.f]
+float GuiCurveEval(GuiCurveEditorState *state, float t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // GUI_CURVE_EDITOR_H
+
+/***********************************************************************************
+*
+*   GUI_CURVE_EDITOR IMPLEMENTATION
+*
+************************************************************************************/
+#if defined(GUI_CURVE_EDITOR_IMPLEMENTATION)
+
+#include "../../src/raygui.h" // Change this to fit your project
+
+#include "stdlib.h" // Required for qsort
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+GuiCurveEditorState InitGuiCurveEditor()
+{
+    GuiCurveEditorState state = { 0 };
+
+    state.start = 0;
+    state.end = 1;
+    state.selectedIndex = 0;
+    state.editLeftTangent = false;
+    state.editRightTangent = false;
+    state.mouseOffset = (Vector2){ 0.0f, 0.0f };
+
+    // At least one point (AVG by default)
+    state.numPoints = 1;
+    state.points[0].position = (Vector2){ 0.5f, 0.5f };
+    state.points[0].tangents = (Vector2){ 0.0f, 0.0f };
+    state.points[0].leftLinear = false;
+    state.points[0].rightLinear = false;
+
+    return state;
+}
+
+static int CompareGuiCurveEditPointPtr(const void *a, const void *b)
+{
+    float fa = (*(GuiCurveEditorPoint**)a)->position.x;
+    float fb = (*(GuiCurveEditorPoint**)b)->position.x;
+
+    return ((fa > fb) - (fa < fb));
+}
+
+float GuiCurveEval(GuiCurveEditorState *state, float t)
+{
+    // Sort points
+    GuiCurveEditorPoint* sortedPoints[GUI_CURVE_EDITOR_MAX_POINTS];
+
+    for (int i=0; i < state->numPoints; i++) sortedPoints[i] = &state->points[i];
+
+    qsort(sortedPoints, state->numPoints, sizeof(GuiCurveEditorPoint*), CompareGuiCurveEditPointPtr);
+
+    if (state->numPoints == 0) return state->start;
+
+    // Constants part on edges
+    if (t <= sortedPoints[0]->position.x) return state->start + (state->end-state->start)*sortedPoints[0]->position.y;
+    if (t >= sortedPoints[state->numPoints-1]->position.x) return state->start + (state->end-state->start)*sortedPoints[state->numPoints-1]->position.y;
+
+    // Find curve portion
+    for (int i=0; i < state->numPoints-1; i++)
+    {
+        const GuiCurveEditorPoint *p1 = sortedPoints[i];
+        const GuiCurveEditorPoint *p2 = sortedPoints[i+1];
+
+        // Skip this range
+        if (!((t >= p1->position.x) && (t < p2->position.x)) || (p1->position.x == p2->position.x)) continue;
+
+        float scale = (p2->position.x-p1->position.x);
+        float T = (t-p1->position.x)/scale;
+        float startTangent = scale*p1->tangents.y;
+        float endTangent = scale*p2->tangents.x;
+        float T2 = T*T;
+        float T3 = T*T*T;
+
+        return (state->start + (state->end-state->start)*((2*T3 - 3*T2 + 1)*p1->position.y + (T3 - 2*T2 + T)*startTangent + (3*T2 - 2*T3)*p2->position.y + (T3 - T2)*endTangent));
+    }
+
+    return state->start;
+}
+
+void GuiCurveEditor(GuiCurveEditorState *state, Rectangle bounds)
+{
+    // CONST
+    //----------------------------------------------------------------------------------
+    const float pointSize = 10.0f;
+    const float fontSize = GuiGetStyle(DEFAULT, TEXT_SIZE);
+    const float handleLength = pointSize*2.5f;
+    const float handleSize = pointSize/1.5f;
+
+    const Rectangle innerBounds = (Rectangle){ bounds.x + fontSize, bounds.y + fontSize, bounds.width - 2*fontSize, bounds.height - 2*fontSize };
+    const Vector2 mouse = GetMousePosition();
+    const Vector2 mouseLocal = (Vector2){ (mouse.x - innerBounds.x)/innerBounds.width, (innerBounds.y + innerBounds.height-mouse.y)/innerBounds.height};
+    //----------------------------------------------------------------------------------
+
+    // UPDATE STATE
+    //----------------------------------------------------------------------------------
+    // Find first point under mouse (-1 if not found)
+    int hoveredPointIndex = -1;
+    for (int i = 0; i < state->numPoints; i++)
+    {
+        const GuiCurveEditorPoint *p = &state->points[i];
+        const Vector2 screenPos = (Vector2){ p->position.x*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height-p->position.y*innerBounds.height };
+        const Rectangle pointRect = (Rectangle){ screenPos.x - pointSize/2.0f, screenPos.y - pointSize/2.0f, pointSize, pointSize };
+
+        if (CheckCollisionPointRec(mouse, pointRect))
+        {
+            hoveredPointIndex = i;
+            break;
+        }
+    }
+
+    // Unselect tangents
+    if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT))
+    {
+        state->editLeftTangent = false;
+        state->editRightTangent = false;
+    }
+
+    // Select a tangent if possible
+    if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && (state->selectedIndex != -1) && CheckCollisionPointRec(mouse, bounds))
+    {
+        const GuiCurveEditorPoint* p = &state->points[state->selectedIndex];
+        const Vector2 screenPos = (Vector2){ p->position.x*innerBounds.width+innerBounds.x, innerBounds.y+innerBounds.height-p->position.y*innerBounds.height };
+
+        // Left control
+        Vector2 target = (Vector2){ (p->position.x-1)*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - (p->position.y-p->tangents.x)*innerBounds.height };
+        Vector2 dir = (Vector2){ target.x-screenPos.x, target.y-screenPos.y };
+        float d = sqrt(dir.x*dir.x + dir.y*dir.y);
+        Vector2 control = (Vector2){ screenPos.x + dir.x/d*handleLength, screenPos.y + dir.y/d*handleLength };
+        Rectangle controlRect = (Rectangle){ control.x - handleSize/2.0f, control.y - handleSize/2.0f, handleSize, handleSize };
+
+        // Edit left tangent
+        if (CheckCollisionPointRec(mouse, controlRect)) state->editLeftTangent = true;
+
+        // Right control
+        target = (Vector2){ (p->position.x + 1)*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - (p->position.y + p->tangents.y)*innerBounds.height };
+        dir = (Vector2){ target.x-screenPos.x, target.y-screenPos.y };
+        d = sqrt(dir.x*dir.x + dir.y*dir.y);
+        control = (Vector2){ screenPos.x + dir.x/d*handleLength, screenPos.y + dir.y/d*handleLength };
+        controlRect = (Rectangle){ control.x - handleSize/2.0f, control.y - handleSize/2.0f, handleSize, handleSize };
+
+        // Edit right tangent
+        if (CheckCollisionPointRec(mouse, controlRect)) state->editRightTangent = true;
+    }
+
+    // Move tangents
+    if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) && state->editRightTangent)
+    {
+        // editRightTangent == true implies selectedIndex != -1
+        GuiCurveEditorPoint *p = &state->points[state->selectedIndex];
+        const Vector2 dir = (Vector2){ mouseLocal.x - p->position.x, mouseLocal.y - p->position.y};
+
+        // Calculate right tangent slope
+        p->tangents.y = (dir.x < 0.001f)? dir.y/0.001f : dir.y/dir.x;
+        p->rightLinear = false; // Stop right linearization update
+
+        // Tangents are symetric by default unless SHIFT is pressed
+        if (!(IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT)))
+        {
+            p->tangents.x = p->tangents.y;
+            p->leftLinear = false; // Stop left linearization update
+        }
+
+    }
+    else if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) && state->editLeftTangent)
+    {
+        // editLeftTangent == true implies selectedIndex != -1
+        GuiCurveEditorPoint *p = &state->points[state->selectedIndex];
+        const Vector2 dir = (Vector2){ mouseLocal.x - p->position.x, mouseLocal.y - p->position.y };
+
+        // Calculate left tangent slope
+        p->tangents.x = (dir.x > -0.001f)? dir.y/(-0.001f) : dir.y/dir.x;
+        p->leftLinear = false; // Stop left linearization update
+
+        // Tangents are symetric by default unless SHIFT is pressed
+        if (!(IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT)))
+        {
+            p->tangents.y = p->tangents.x;
+            p->rightLinear = false; // Stop right linearization update
+        }
+    }
+    // Select a point
+    else if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && (hoveredPointIndex != -1) && CheckCollisionPointRec(mouse, bounds))
+    {
+        state->selectedIndex = hoveredPointIndex;
+        const GuiCurveEditorPoint *p = &state->points[state->selectedIndex];
+        state->mouseOffset = (Vector2){ p->position.x - mouseLocal.x, p->position.y - mouseLocal.y };
+    }
+    // Remove a point (check against bounds)
+    else if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT) && (hoveredPointIndex != -1) && CheckCollisionPointRec(mouse, bounds) && (state->numPoints > 1))
+    {
+        // Deselect everything
+        state->selectedIndex = 0; // select first point by default
+        state->editLeftTangent = false;
+        state->editRightTangent = false;
+
+        // Remove point
+        state->numPoints -= 1;
+        for (int i = hoveredPointIndex; i < state->numPoints; i++) state->points[i] = state->points[i+1];
+    }
+    // Add a point (check against innerBounds)
+    else if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && CheckCollisionPointRec(mouse, innerBounds) && (state->numPoints < GUI_CURVE_EDITOR_MAX_POINTS))
+    {
+        state->editLeftTangent = false;
+        state->editRightTangent = false;
+
+        // Create new point
+        GuiCurveEditorPoint p;
+        p.tangents = (Vector2){ 0.0f, 0.0f };
+        p.position = mouseLocal;
+        p.leftLinear = false;
+        p.rightLinear = false;
+
+        // Append point
+        state->points[state->numPoints] = p;
+        state->selectedIndex = state->numPoints; // select new point
+        state->numPoints += 1;
+
+        // Point is add on mouse pos
+        state->mouseOffset = (Vector2){ 0, 0 };
+    }
+    // Move selected point
+    else if ((state->selectedIndex != -1) && IsMouseButtonDown(MOUSE_BUTTON_LEFT) && CheckCollisionPointRec(mouse, bounds))
+    {
+        GuiCurveEditorPoint *p = &state->points[state->selectedIndex];
+
+        // use mouse offset on click to prevent point teleporting to mouse
+        const Vector2 newLocalPos = (Vector2){ mouseLocal.x + state->mouseOffset.x, mouseLocal.y + state->mouseOffset.y };
+
+        // Clamp to innerbounds
+        p->position.x = (newLocalPos.x < 0)? 0 : ((newLocalPos.x > 1)? 1 : newLocalPos.x);
+        p->position.y = (newLocalPos.y < 0)? 0 : ((newLocalPos.y > 1)? 1 : newLocalPos.y);
+    }
+
+    // Sort points
+    GuiCurveEditorPoint *sortedPoints[GUI_CURVE_EDITOR_MAX_POINTS] = { 0 };
+    for (int i = 0; i < state->numPoints; i++) sortedPoints[i] = &state->points[i];
+    qsort(sortedPoints, state->numPoints, sizeof(GuiCurveEditorPoint*), CompareGuiCurveEditPointPtr);
+
+    // Update linear tangents
+    for (int i = 0; i < state->numPoints; i++)
+    {
+        GuiCurveEditorPoint *p = sortedPoints[i];
+
+        // Left tangent
+        if ((i > 0) && p->leftLinear)
+        {
+            const GuiCurveEditorPoint *p2 = sortedPoints[i - 1];
+            Vector2 dir = (Vector2){ p2->position.x - p->position.x, p2->position.y - p->position.y };
+            p->tangents.x = (dir.x == 0)? 0 : dir.y/dir.x;
+        }
+
+        // Right tangent
+        if ((i < state->numPoints - 1) && p->rightLinear)
+        {
+            const GuiCurveEditorPoint *p2 = sortedPoints[i + 1];
+            Vector2 dir = (Vector2){ p2->position.x - p->position.x, p2->position.y - p->position.y };
+            p->tangents.y = (dir.x == 0)? 0 : dir.y/dir.x;
+        }
+    }
+    //----------------------------------------------------------------------------------
+
+    // DRAWING
+    //----------------------------------------------------------------------------------
+    DrawRectangle(bounds.x, bounds.y, bounds.width, bounds.height, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));
+
+    // Draw grid
+    // H lines
+    const Color lineColor = GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL));
+    DrawLine(bounds.x, innerBounds.y, bounds.x+bounds.width, innerBounds.y, lineColor); // end
+    DrawLine(bounds.x, innerBounds.y+innerBounds.height/2, bounds.x+bounds.width, innerBounds.y+innerBounds.height/2, lineColor); // avg
+    DrawLine(bounds.x, innerBounds.y+innerBounds.height, bounds.x+bounds.width, innerBounds.y+innerBounds.height, lineColor); // start
+
+    // V lines
+    DrawLine(innerBounds.x, bounds.y, innerBounds.x, bounds.y+bounds.height, lineColor); // 0
+    DrawLine(innerBounds.x + innerBounds.width/4, bounds.y, innerBounds.x + innerBounds.width/4, bounds.y + bounds.height, lineColor); // 0.25
+    DrawLine(innerBounds.x + innerBounds.width/2, bounds.y, innerBounds.x + innerBounds.width/2, bounds.y + bounds.height, lineColor); // 0.5
+    DrawLine(innerBounds.x + 3*innerBounds.width/4, bounds.y, innerBounds.x + 3*innerBounds.width/4, bounds.y + bounds.height, lineColor); // 0.75
+    DrawLine(innerBounds.x + innerBounds.width, bounds.y, innerBounds.x + innerBounds.width, bounds.y + bounds.height, lineColor); // 1
+
+    Font font = GuiGetFont();
+    // V labels
+    DrawTextEx(font, "0", (Vector2){ innerBounds.x, bounds.y + bounds.height-fontSize}, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
+    DrawTextEx(font, "0.25", (Vector2){ innerBounds.x + innerBounds.width/4.0f, bounds.y + bounds.height - fontSize}, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
+    DrawTextEx(font, "0.5", (Vector2){ innerBounds.x + innerBounds.width/2.0f, bounds.y + bounds.height - fontSize}, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
+    DrawTextEx(font, "0.75", (Vector2){ innerBounds.x + 3.0f*innerBounds.width/4.0f, bounds.y + bounds.height-fontSize}, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
+    DrawTextEx(font, "1", (Vector2){ innerBounds.x + innerBounds.width, bounds.y+bounds.height - fontSize}, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
+
+    // H labels
+    DrawTextEx(font, TextFormat("%.2f", state->start), (Vector2){ innerBounds.x, innerBounds.y - fontSize+innerBounds.height }, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
+    DrawTextEx(font, TextFormat("%.2f", state->start + (state->end-state->start)/2.f), (Vector2){ innerBounds.x, innerBounds.y - fontSize + innerBounds.height/2.0f }, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
+    DrawTextEx(font, TextFormat("%.2f", state->end), (Vector2){ innerBounds.x, innerBounds.y }, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
+
+    // Draw contours
+    if (CheckCollisionPointRec(mouse, bounds)) DrawRectangleLines(bounds.x, bounds.y, bounds.width, bounds.height, GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_FOCUSED)));
+    else DrawRectangleLines(bounds.x, bounds.y, bounds.width, bounds.height, GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL)));
+
+    // Draw points
+    for (int i = 0; i < state->numPoints; i++)
+    {
+        const GuiCurveEditorPoint *p = sortedPoints[i];
+
+        const Vector2 screenPos = (Vector2){ p->position.x*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - p->position.y*innerBounds.height };
+        const Rectangle pointRect = (Rectangle){ screenPos.x - pointSize/2.0f, screenPos.y - pointSize/2.0f, pointSize, pointSize };
+
+        Color pointColor = { 0 };
+        Color pointBorderColor = { 0 };
+
+        // Draw point
+        if (&state->points[state->selectedIndex] == p)
+        {
+            // Draw left handle
+            if (i > 0)
+            {
+                const Vector2 target = (Vector2){ (p->position.x - 1)*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - (p->position.y - p->tangents.x)*innerBounds.height };
+                const Vector2 dir = (Vector2){ target.x - screenPos.x, target.y - screenPos.y };
+                const float d = sqrt(dir.x*dir.x + dir.y*dir.y);
+                const Vector2 control = (Vector2){ screenPos.x + dir.x/d*handleLength, screenPos.y + dir.y/d*handleLength };
+                const Rectangle controlRect = (Rectangle){ control.x - handleSize/2.0f, control.y - handleSize/2.0f, handleSize, handleSize };
+
+                Color controlColor = { 0 };
+
+                if (state->editLeftTangent)
+                {
+                    controlColor = GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_PRESSED));
+                }
+                else if (CheckCollisionPointRec(mouse, controlRect))
+                {
+                    controlColor = GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_FOCUSED));
+                }
+                else
+                {
+                    controlColor = GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL));
+                }
+
+                DrawLine(screenPos.x,screenPos.y, control.x, control.y, controlColor);
+                DrawRectangle(controlRect.x, controlRect.y, controlRect.width, controlRect.height, controlColor);
+                DrawRectangleLines(controlRect.x, controlRect.y, controlRect.width, controlRect.height, controlColor);
+            }
+
+            // Draw right handle
+            if (i < state->numPoints - 1)
+            {
+                const Vector2 target = (Vector2){ (p->position.x + 1)*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - (p->position.y + p->tangents.y)*innerBounds.height };
+                const Vector2 dir = (Vector2){ target.x - screenPos.x, target.y - screenPos.y };
+                const float d = sqrt(dir.x*dir.x + dir.y*dir.y);
+                const Vector2 control = (Vector2){ screenPos.x + dir.x/d*handleLength, screenPos.y + dir.y/d*handleLength };
+                const Rectangle controlRect = (Rectangle){ control.x - handleSize/2.0f, control.y - handleSize/2.0f, handleSize, handleSize };
+
+                Color controlColor = { 0 };
+
+                if (state->editRightTangent)
+                {
+                    controlColor = GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_PRESSED));
+                }
+                else if (CheckCollisionPointRec(mouse, controlRect))
+                {
+                    controlColor = GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_FOCUSED));
+                }
+                else
+                {
+                    controlColor = GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL));
+                }
+
+                DrawLine(screenPos.x,screenPos.y, control.x, control.y, controlColor);
+                DrawRectangle(controlRect.x, controlRect.y, controlRect.width, controlRect.height, controlColor);
+                DrawRectangleLines(controlRect.x, controlRect.y, controlRect.width, controlRect.height, controlColor);
+            }
+
+            pointColor = GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_PRESSED));
+            pointBorderColor = GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL));
+
+        }
+        else if (&state->points[hoveredPointIndex] == p)
+        {
+            pointColor = GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_FOCUSED));
+            pointBorderColor = GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL));
+        }
+        else
+        {
+            pointColor = GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL));
+            pointBorderColor = GetColor(GuiGetStyle(BUTTON, BORDER_COLOR_NORMAL));
+        }
+
+        DrawRectangle(pointRect.x, pointRect.y, pointRect.width, pointRect.height, pointColor);
+        DrawRectangleLines(pointRect.x, pointRect.y, pointRect.width, pointRect.height, pointBorderColor);
+    }
+
+    // Draw curve
+    Color curveColor = GetColor(GuiGetStyle(LABEL,  TEXT_COLOR_FOCUSED));
+
+    if (state->numPoints == 1)
+    {
+        const GuiCurveEditorPoint *p = sortedPoints[0];
+        const Vector2 screenPos = (Vector2){ p->position.x*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - p->position.y*innerBounds.height };
+        DrawLine(innerBounds.x, screenPos.y, innerBounds.x+innerBounds.width, screenPos.y, curveColor);
+    }
+    else
+    {
+        for (int i = 0; i < state->numPoints - 1; i++)
+        {
+            const GuiCurveEditorPoint *p1 = sortedPoints[i];
+            const GuiCurveEditorPoint *p2 = sortedPoints[i + 1];
+            const Vector2 screenPos1 = (Vector2){ p1->position.x*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - p1->position.y*innerBounds.height };
+            const Vector2 screenPos2 = (Vector2){ p2->position.x*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - p2->position.y*innerBounds.height };
+
+            // Constant on edge
+            if ((screenPos1.x > innerBounds.x) && (i == 0))
+            {
+                DrawLine(innerBounds.x, screenPos1.y, screenPos1.x, screenPos1.y, curveColor);
+            }
+            if ((screenPos2.x < innerBounds.x + innerBounds.width) && (i == (state->numPoints - 2)))
+            {
+                DrawLine(screenPos2.x, screenPos2.y, innerBounds.x+innerBounds.width, screenPos2.y, curveColor);
+            }
+
+            // Draw cubic Hermite curve
+            const float scale = (p2->position.x - p1->position.x)/3.0f;
+            const Vector2 offset1 = (Vector2){ scale, scale*p1->tangents.y };
+            // negative endTangent => top part => need to invert value to calculate offset
+            const Vector2 offset2 = (Vector2){ -scale, -scale*p2->tangents.x };
+
+            const Vector2 c1 = (Vector2){ p1->position.x + offset1.x, p1->position.y + offset1.y };
+            const Vector2 c2 = (Vector2){ p2->position.x + offset2.x, p2->position.y + offset2.y };
+
+            const Vector2 screenC1 = (Vector2){ c1.x*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - c1.y*innerBounds.height };
+            const Vector2 screenC2 = (Vector2){ c2.x*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - c2.y*innerBounds.height };
+
+            DrawSplineSegmentBezierCubic(screenPos1, screenC1, screenC2, screenPos2, 1, curveColor);
+        }
+    }
+}
+
+#endif // GUI_CURVE_EDITOR_IMPLEMENTATION
+

+ 165 - 94
gui.mod/raygui/examples/controls_test_suite/controls_test_suite.c

@@ -12,7 +12,6 @@
 *       - GuiComboBox()
 *       - GuiListView()
 *       - GuiToggleGroup()
-*       - GuiTextBoxMulti()
 *       - GuiColorPicker()
 *       - GuiSlider()
 *       - GuiSliderBar()
@@ -22,25 +21,36 @@
 *
 *
 *   DEPENDENCIES:
-*       raylib 2.6-dev  - Windowing/input management and drawing.
-*       raygui 2.6-dev  - Immediate-mode GUI controls.
+*       raylib 4.5          - Windowing/input management and drawing
+*       raygui 3.5          - Immediate-mode GUI controls with custom styling and icons
 *
 *   COMPILATION (Windows - MinGW):
 *       gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
 *
 *   LICENSE: zlib/libpng
 *
-*   Copyright (c) 2019 raylib technologies (@raylibtech)
+*   Copyright (c) 2016-2024 Ramon Santamaria (@raysan5)
 *
 **********************************************************************************************/
 
 #include "raylib.h"
 
+//#define RAYGUI_DEBUG_RECS_BOUNDS
+//#define RAYGUI_DEBUG_TEXT_BOUNDS
+
 #define RAYGUI_IMPLEMENTATION
-#define RAYGUI_SUPPORT_ICONS
+//#define RAYGUI_CUSTOM_ICONS     // It requires providing gui_icons.h in the same directory
+//#include "gui_icons.h"          // External icons data provided, it can be generated with rGuiIcons tool
 #include "../../src/raygui.h"
 
-#undef RAYGUI_IMPLEMENTATION            // Avoid including raygui implementation again
+// raygui embedded styles
+#include "../styles/style_cyber.h"             // raygui style: cyber
+#include "../styles/style_jungle.h"            // raygui style: jungle
+#include "../styles/style_lavanda.h"           // raygui style: lavanda
+#include "../styles/style_dark.h"              // raygui style: dark
+#include "../styles/style_bluish.h"            // raygui style: bluish
+#include "../styles/style_terminal.h"          // raygui style: terminal
+
 
 //------------------------------------------------------------------------------------
 // Program main entry point
@@ -49,9 +59,9 @@ int main()
 {
     // Initialization
     //---------------------------------------------------------------------------------------
-    int screenWidth = 690;
-    int screenHeight = 560;
-    
+    const int screenWidth = 960;
+    const int screenHeight = 560;
+
     InitWindow(screenWidth, screenHeight, "raygui - controls test suite");
     SetExitKey(0);
 
@@ -59,19 +69,22 @@ int main()
     //----------------------------------------------------------------------------------
     int dropdownBox000Active = 0;
     bool dropDown000EditMode = false;
-    
+
     int dropdownBox001Active = 0;
-    bool dropDown001EditMode = false;    
-    
+    bool dropDown001EditMode = false;
+
     int spinner001Value = 0;
     bool spinnerEditMode = false;
-    
+
     int valueBox002Value = 0;
     bool valueBoxEditMode = false;
-    
+
     char textBoxText[64] = "Text box";
     bool textBoxEditMode = false;
-    
+
+    char textBoxMultiText[1024] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n\nDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n\nThisisastringlongerthanexpectedwithoutspacestotestcharbreaksforthosecases,checkingifworkingasexpected.\n\nExcepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
+    bool textBoxMultiEditMode = false;
+
     int listViewScrollIndex = 0;
     int listViewActive = -1;
 
@@ -80,36 +93,42 @@ int main()
     int listViewExFocus = -1;
     const char *listViewExList[8] = { "This", "is", "a", "list view", "with", "disable", "elements", "amazing!" };
 
-    char multiTextBoxText[256] = "Multi text box";
-    bool multiTextBoxEditMode = false;
     Color colorPickerValue = RED;
-    
-    int sliderValue = 50;
-    int sliderBarValue = 60;
-    float progressValue = 0.4f;
-    
+
+    float sliderValue = 50.0f;
+    float sliderBarValue = 60;
+    float progressValue = 0.1f;
+
     bool forceSquaredChecked = false;
-    
+
     float alphaValue = 0.5f;
-    
-    int comboBoxActive = 1;
-    
+
+    //int comboBoxActive = 1;
+    int visualStyleActive = 0;
+    int prevVisualStyleActive = 0;
+
     int toggleGroupActive = 0;
-    
+    int toggleSliderActive = 0;
+
     Vector2 viewScroll = { 0, 0 };
     //----------------------------------------------------------------------------------
 
     // Custom GUI font loading
     //Font font = LoadFontEx("fonts/rainyhearts16.ttf", 12, 0, 0);
     //GuiSetFont(font);
-    
+
     bool exitWindow = false;
     bool showMessageBox = false;
-    
+
     char textInput[256] = { 0 };
-    bool showTextInputBox = false;
-    
     char textInputFileName[256] = { 0 };
+    bool showTextInputBox = false;
+
+    float alpha = 1.0f;
+
+    // DEBUG: Testing how those two properties affect all controls!
+    //GuiSetStyle(DEFAULT, TEXT_PADDING, 0);
+    //GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
 
     SetTargetFPS(60);
     //--------------------------------------------------------------------------------------
@@ -120,19 +139,51 @@ int main()
         // Update
         //----------------------------------------------------------------------------------
         exitWindow = WindowShouldClose();
-        
+
         if (IsKeyPressed(KEY_ESCAPE)) showMessageBox = !showMessageBox;
-        
+
         if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_S)) showTextInputBox = true;
-        
+
         if (IsFileDropped())
         {
-            int dropsCount = 0;
-            char **droppedFiles = GetDroppedFiles(&dropsCount);
-            
-            if ((dropsCount > 0) && IsFileExtension(droppedFiles[0], ".rgs")) GuiLoadStyle(droppedFiles[0]);
-            
-            ClearDroppedFiles();    // Clear internal buffers
+            FilePathList droppedFiles = LoadDroppedFiles();
+
+            if ((droppedFiles.count > 0) && IsFileExtension(droppedFiles.paths[0], ".rgs")) GuiLoadStyle(droppedFiles.paths[0]);
+
+            UnloadDroppedFiles(droppedFiles);    // Clear internal buffers
+        }
+
+        //alpha -= 0.002f;
+        if (alpha < 0.0f) alpha = 0.0f;
+        if (IsKeyPressed(KEY_SPACE)) alpha = 1.0f;
+
+        GuiSetAlpha(alpha);
+
+        //progressValue += 0.002f;
+        if (IsKeyPressed(KEY_LEFT)) progressValue -= 0.1f;
+        else if (IsKeyPressed(KEY_RIGHT)) progressValue += 0.1f;
+        if (progressValue > 1.0f) progressValue = 1.0f;
+        else if (progressValue < 0.0f) progressValue = 0.0f;
+
+        if (visualStyleActive != prevVisualStyleActive)
+        {
+            GuiLoadStyleDefault();
+
+            switch (visualStyleActive)
+            {
+                case 0: break;      // Default style
+                case 1: GuiLoadStyleJungle(); break;
+                case 2: GuiLoadStyleLavanda(); break;
+                case 3: GuiLoadStyleDark(); break;
+                case 4: GuiLoadStyleBluish(); break;
+                case 5: GuiLoadStyleCyber(); break;
+                case 6: GuiLoadStyleTerminal(); break;
+                default: break;
+            }
+
+            GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
+
+            prevVisualStyleActive = visualStyleActive;
         }
         //----------------------------------------------------------------------------------
 
@@ -141,97 +192,117 @@ int main()
         BeginDrawing();
 
             ClearBackground(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));
- 
+
             // raygui: controls drawing
             //----------------------------------------------------------------------------------
+            // Check all possible events that require GuiLock
             if (dropDown000EditMode || dropDown001EditMode) GuiLock();
-            //GuiDisable();
-            
+
             // First GUI column
-            //GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT);
-            forceSquaredChecked = GuiCheckBox((Rectangle){ 25, 108, 15, 15 }, "FORCE CHECK!", forceSquaredChecked);
-            
-            GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
-            //GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT);
+            //GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
+            GuiCheckBox((Rectangle){ 25, 108, 15, 15 }, "FORCE CHECK!", &forceSquaredChecked);
+
+            GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+            //GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
             if (GuiSpinner((Rectangle){ 25, 135, 125, 30 }, NULL, &spinner001Value, 0, 100, spinnerEditMode)) spinnerEditMode = !spinnerEditMode;
             if (GuiValueBox((Rectangle){ 25, 175, 125, 30 }, NULL, &valueBox002Value, 0, 100, valueBoxEditMode)) valueBoxEditMode = !valueBoxEditMode;
-            GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT);
+            GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
             if (GuiTextBox((Rectangle){ 25, 215, 125, 30 }, textBoxText, 64, textBoxEditMode)) textBoxEditMode = !textBoxEditMode;
-            
-            GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
-            
-            GuiSetTooltip("Save current file.");
-            if (GuiButton((Rectangle){ 25, 255, 125, 30 }, GuiIconText(RICON_FILE_SAVE, "Save File"))) showTextInputBox = true;
-            GuiClearTooltip();
-            
+
+            GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+
+            if (GuiButton((Rectangle){ 25, 255, 125, 30 }, GuiIconText(ICON_FILE_SAVE, "Save File"))) showTextInputBox = true;
+
             GuiGroupBox((Rectangle){ 25, 310, 125, 150 }, "STATES");
-            GuiLock();
-            GuiSetState(GUI_STATE_NORMAL); if (GuiButton((Rectangle){ 30, 320, 115, 30 }, "NORMAL")) { }
-            GuiSetState(GUI_STATE_FOCUSED); if (GuiButton((Rectangle){ 30, 355, 115, 30 }, "FOCUSED")) { }
-            GuiSetState(GUI_STATE_PRESSED); if (GuiButton((Rectangle){ 30, 390, 115, 30 }, "#15#PRESSED")) { }
-            GuiSetState(GUI_STATE_DISABLED); if (GuiButton((Rectangle){ 30, 425, 115, 30 }, "DISABLED")) { }
-            GuiSetState(GUI_STATE_NORMAL);
-            GuiUnlock();
-            
-            comboBoxActive = GuiComboBox((Rectangle){ 25, 470, 125, 30 }, "ONE;TWO;THREE;FOUR", comboBoxActive);
-            
+            //GuiLock();
+            GuiSetState(STATE_NORMAL); if (GuiButton((Rectangle){ 30, 320, 115, 30 }, "NORMAL")) { }
+            GuiSetState(STATE_FOCUSED); if (GuiButton((Rectangle){ 30, 355, 115, 30 }, "FOCUSED")) { }
+            GuiSetState(STATE_PRESSED); if (GuiButton((Rectangle){ 30, 390, 115, 30 }, "#15#PRESSED")) { }
+            GuiSetState(STATE_DISABLED); if (GuiButton((Rectangle){ 30, 425, 115, 30 }, "DISABLED")) { }
+            GuiSetState(STATE_NORMAL);
+            //GuiUnlock();
+
+            GuiComboBox((Rectangle){ 25, 480, 125, 30 }, "default;Jungle;Lavanda;Dark;Bluish;Cyber;Terminal", &visualStyleActive);
+
             // NOTE: GuiDropdownBox must draw after any other control that can be covered on unfolding
-            GuiSetStyle(DROPDOWNBOX, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT);
+            GuiUnlock();
+            GuiSetStyle(DROPDOWNBOX, TEXT_PADDING, 4);
+            GuiSetStyle(DROPDOWNBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
             if (GuiDropdownBox((Rectangle){ 25, 65, 125, 30 }, "#01#ONE;#02#TWO;#03#THREE;#04#FOUR", &dropdownBox001Active, dropDown001EditMode)) dropDown001EditMode = !dropDown001EditMode;
+            GuiSetStyle(DROPDOWNBOX, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+            GuiSetStyle(DROPDOWNBOX, TEXT_PADDING, 0);
 
-            GuiSetStyle(DROPDOWNBOX, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
             if (GuiDropdownBox((Rectangle){ 25, 25, 125, 30 }, "ONE;TWO;THREE", &dropdownBox000Active, dropDown000EditMode)) dropDown000EditMode = !dropDown000EditMode;
 
             // Second GUI column
-            listViewActive = GuiListView((Rectangle){ 165, 25, 140, 140 }, "Charmander;Bulbasaur;#18#Squirtel;Pikachu;Eevee;Pidgey", &listViewScrollIndex, listViewActive);
-            listViewExActive = GuiListViewEx((Rectangle){ 165, 180, 140, 200 }, listViewExList, 8, &listViewExFocus, &listViewExScrollIndex, listViewExActive);
+            GuiListView((Rectangle){ 165, 25, 140, 124 }, "Charmander;Bulbasaur;#18#Squirtel;Pikachu;Eevee;Pidgey", &listViewScrollIndex, &listViewActive);
+            GuiListViewEx((Rectangle){ 165, 162, 140, 184 }, listViewExList, 8, &listViewExScrollIndex, &listViewExActive, &listViewExFocus);
+
+            //GuiToggle((Rectangle){ 165, 400, 140, 25 }, "#1#ONE", &toggleGroupActive);
+            GuiToggleGroup((Rectangle){ 165, 360, 140, 24 }, "#1#ONE\n#3#TWO\n#8#THREE\n#23#", &toggleGroupActive);
+            //GuiDisable();
+            GuiSetStyle(SLIDER, SLIDER_PADDING, 2);
+            GuiToggleSlider((Rectangle){ 165, 480, 140, 30 }, "ON;OFF", &toggleSliderActive);
+            GuiSetStyle(SLIDER, SLIDER_PADDING, 0);
 
-            toggleGroupActive = GuiToggleGroup((Rectangle){ 165, 400, 140, 25 }, "#1#ONE\n#3#TWO\n#8#THREE\n#23#", toggleGroupActive);
-            
             // Third GUI column
-            if (GuiTextBoxMulti((Rectangle){ 320, 25, 225, 140 }, multiTextBoxText, 256, multiTextBoxEditMode)) multiTextBoxEditMode = !multiTextBoxEditMode;
-            colorPickerValue = GuiColorPicker((Rectangle){ 320, 185, 196, 192 }, colorPickerValue);
+            GuiPanel((Rectangle){ 320, 25, 225, 140 }, "Panel Info");
+            GuiColorPicker((Rectangle){ 320, 185, 196, 192 }, NULL, &colorPickerValue);
+
+            //GuiDisable();
+            GuiSlider((Rectangle){ 355, 400, 165, 20 }, "TEST", TextFormat("%2.2f", sliderValue), &sliderValue, -50, 100);
+            GuiSliderBar((Rectangle){ 320, 430, 200, 20 }, NULL, TextFormat("%i", (int)sliderBarValue), &sliderBarValue, 0, 100);
             
-            sliderValue = GuiSlider((Rectangle){ 355, 400, 165, 20 }, "TEST", TextFormat("%2.2f", (float)sliderValue), sliderValue, -50, 100);
-            sliderBarValue = GuiSliderBar((Rectangle){ 320, 430, 200, 20 }, NULL, TextFormat("%i", (int)sliderBarValue), sliderBarValue, 0, 100);
-            progressValue = GuiProgressBar((Rectangle){ 320, 460, 200, 20 }, NULL, NULL, progressValue, 0, 1);
+            GuiProgressBar((Rectangle){ 320, 460, 200, 20 }, NULL, TextFormat("%i%%", (int)(progressValue*100)), &progressValue, 0.0f, 1.0f);
+            GuiEnable();
 
             // NOTE: View rectangle could be used to perform some scissor test
-            Rectangle view = GuiScrollPanel((Rectangle){ 560, 25, 100, 160 }, (Rectangle){ 560, 25, 200, 400 }, &viewScroll);
-            
-            GuiStatusBar((Rectangle){ 0, GetScreenHeight() - 20, GetScreenWidth(), 20 }, "This is a status bar");
-            
-            alphaValue = GuiColorBarAlpha((Rectangle){ 320, 490, 200, 30 }, alphaValue);
+            Rectangle view = { 0 };
+            GuiScrollPanel((Rectangle){ 560, 25, 102, 354 }, NULL, (Rectangle){ 560, 25, 300, 1200 }, &viewScroll, &view);
+
+            Vector2 mouseCell = { 0 };
+            GuiGrid((Rectangle) { 560, 25 + 180 + 195, 100, 120 }, NULL, 20, 3, &mouseCell);
+
+            GuiColorBarAlpha((Rectangle){ 320, 490, 200, 30 }, NULL, &alphaValue);
+
+            GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_TOP);   // WARNING: Word-wrap does not work as expected in case of no-top alignment
+            GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_WORD);            // WARNING: If wrap mode enabled, text editing is not supported
+            if (GuiTextBox((Rectangle){ 678, 25, 258, 492 }, textBoxMultiText, 1024, textBoxMultiEditMode)) textBoxMultiEditMode = !textBoxMultiEditMode;
+            GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_NONE);
+            GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE);
+
+            GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
+            GuiStatusBar((Rectangle){ 0, (float)GetScreenHeight() - 20, (float)GetScreenWidth(), 20 }, "This is a status bar");
+            GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+            //GuiSetStyle(STATUSBAR, TEXT_INDENTATION, 20);
 
             if (showMessageBox)
             {
                 DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(RAYWHITE, 0.8f));
-                int result = GuiMessageBox((Rectangle){ GetScreenWidth()/2 - 125, GetScreenHeight()/2 - 50, 250, 100 }, GuiIconText(RICON_EXIT, "Close Window"), "Do you really want to exit?", "Yes;No"); 
-            
+                int result = GuiMessageBox((Rectangle){ (float)GetScreenWidth()/2 - 125, (float)GetScreenHeight()/2 - 50, 250, 100 }, GuiIconText(ICON_EXIT, "Close Window"), "Do you really want to exit?", "Yes;No");
+
                 if ((result == 0) || (result == 2)) showMessageBox = false;
                 else if (result == 1) exitWindow = true;
             }
-            
+
             if (showTextInputBox)
             {
                 DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(RAYWHITE, 0.8f));
-                int result = GuiTextInputBox((Rectangle){ GetScreenWidth()/2 - 120, GetScreenHeight()/2 - 60, 240, 140 }, GuiIconText(RICON_FILE_SAVE, "Save file as..."), "Introduce a save file name", "Ok;Cancel", textInput);
-                
+                int result = GuiTextInputBox((Rectangle){ (float)GetScreenWidth()/2 - 120, (float)GetScreenHeight()/2 - 60, 240, 140 }, GuiIconText(ICON_FILE_SAVE, "Save file as..."), "Introduce output file name:", "Ok;Cancel", textInput, 255, NULL);
+
                 if (result == 1)
                 {
                     // TODO: Validate textInput value and save
-                    
-                    strcpy(textInputFileName, textInput);
+
+                    TextCopy(textInputFileName, textInput);
                 }
-                
-                if ((result == 0) || (result == 1) || (result == 2)) 
+
+                if ((result == 0) || (result == 1) || (result == 2))
                 {
                     showTextInputBox = false;
-                    strcpy(textInput, "\0");
+                    TextCopy(textInput, "\0");
                 }
             }
-            
-            GuiUnlock();
             //----------------------------------------------------------------------------------
 
         EndDrawing();

二進制
gui.mod/raygui/examples/controls_test_suite/controls_test_suite.png


二進制
gui.mod/raygui/examples/controls_test_suite/fonts/FiveByFive10.ttf


二進制
gui.mod/raygui/examples/controls_test_suite/fonts/NorthernLights.ttf


二進制
gui.mod/raygui/examples/controls_test_suite/fonts/PIXEARG11.ttf


二進制
gui.mod/raygui/examples/controls_test_suite/fonts/PixelOperator8.ttf


二進制
gui.mod/raygui/examples/controls_test_suite/fonts/pixelpoiiz10.ttf


二進制
gui.mod/raygui/examples/controls_test_suite/fonts/prstartk8.ttf


二進制
gui.mod/raygui/examples/controls_test_suite/fonts/rainyhearts16.ttf


+ 71 - 0
gui.mod/raygui/examples/controls_test_suite/gui_value_box_float.c

@@ -0,0 +1,71 @@
+/*******************************************************************************************
+*
+*   raygui - controls test suite
+*
+*   COMPILATION (Windows - MinGW):
+*       gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
+*
+*   LICENSE: zlib/libpng
+*
+*   Copyright (c) 2016-2024 Ramon Santamaria (@raysan5)
+*
+**********************************************************************************************/
+
+#include "raylib.h"
+
+#define RAYGUI_IMPLEMENTATION
+#include "../../src/raygui.h"
+
+#include <stdio.h>
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main()
+{
+    // Initialization
+    //---------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raygui - controls test suite");
+
+    float valueBoxValue = 0.0f;
+    bool valueBoxEditMode = false;
+    char valueBoxTextValue[32] = { 0 };
+
+    SetTargetFPS(60);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));
+
+            if (GuiValueBoxFloat((Rectangle){ 25, 175, 125, 30 }, NULL, valueBoxTextValue, &valueBoxValue, valueBoxEditMode)) 
+            {
+                valueBoxEditMode = !valueBoxEditMode;
+                
+                printf("Value: %2.2f\n", valueBoxValue);
+            }
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseWindow();        // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}

+ 19 - 21
gui.mod/raygui/examples/custom_file_dialog/custom_file_dialog.c

@@ -3,28 +3,26 @@
 *   raygui - custom file dialog to load image
 *
 *   DEPENDENCIES:
-*       raylib 2.6-dev  - Windowing/input management and drawing.
-*       raygui 2.6-dev  - Immediate-mode GUI controls.
+*       raylib 4.0  - Windowing/input management and drawing.
+*       raygui 3.0  - Immediate-mode GUI controls.
 *
 *   COMPILATION (Windows - MinGW):
 *       gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
 *
 *   LICENSE: zlib/libpng
 *
-*   Copyright (c) 2019 raylib technologies (@raylibtech)
+*   Copyright (c) 2016-2024 Ramon Santamaria (@raysan5)
 *
 **********************************************************************************************/
 
 #include "raylib.h"
 
 #define RAYGUI_IMPLEMENTATION
-#define RAYGUI_SUPPORT_ICONS
 #include "../../src/raygui.h"
 
 #undef RAYGUI_IMPLEMENTATION            // Avoid including raygui implementation again
-
-#define GUI_FILE_DIALOG_IMPLEMENTATION
-#include "gui_file_dialog.h"
+#define GUI_WINDOW_FILE_DIALOG_IMPLEMENTATION
+#include "gui_window_file_dialog.h"
 
 //------------------------------------------------------------------------------------
 // Program main entry point
@@ -35,17 +33,17 @@ int main()
     //---------------------------------------------------------------------------------------
     int screenWidth = 800;
     int screenHeight = 560;
-    
+
     InitWindow(screenWidth, screenHeight, "raygui - custom modal dialog");
     SetExitKey(0);
 
     // Custom file dialog
-    GuiFileDialogState fileDialogState = InitGuiFileDialog();
+    GuiWindowFileDialogState fileDialogState = InitGuiWindowFileDialog(GetWorkingDirectory());
 
     bool exitWindow = false;
 
     char fileNameToLoad[512] = { 0 };
-    
+
     Texture texture = { 0 };
 
     SetTargetFPS(60);
@@ -57,17 +55,17 @@ int main()
         // Update
         //----------------------------------------------------------------------------------
         exitWindow = WindowShouldClose();
-        
+
         if (fileDialogState.SelectFilePressed)
         {
             // Load image file (if supported extension)
             if (IsFileExtension(fileDialogState.fileNameText, ".png"))
             {
-                strcpy(fileNameToLoad, TextFormat("%s/%s", fileDialogState.dirPathText, fileDialogState.fileNameText));
+                strcpy(fileNameToLoad, TextFormat("%s" PATH_SEPERATOR "%s", fileDialogState.dirPathText, fileDialogState.fileNameText));
                 UnloadTexture(texture);
                 texture = LoadTexture(fileNameToLoad);
             }
-            
+
             fileDialogState.SelectFilePressed = false;
         }
         //----------------------------------------------------------------------------------
@@ -77,23 +75,23 @@ int main()
         BeginDrawing();
 
             ClearBackground(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));
-            
+
             DrawTexture(texture, GetScreenWidth()/2 - texture.width/2, GetScreenHeight()/2 - texture.height/2 - 5, WHITE);
             DrawRectangleLines(GetScreenWidth()/2 - texture.width/2, GetScreenHeight()/2 - texture.height/2 - 5, texture.width, texture.height, BLACK);
- 
+
             DrawText(fileNameToLoad, 208, GetScreenHeight() - 20, 10, GRAY);
- 
+
             // raygui: controls drawing
             //----------------------------------------------------------------------------------
-            if (fileDialogState.fileDialogActive) GuiLock();
+            if (fileDialogState.windowActive) GuiLock();
+
+            if (GuiButton((Rectangle){ 20, 20, 140, 30 }, GuiIconText(ICON_FILE_OPEN, "Open Image"))) fileDialogState.windowActive = true;
 
-            if (GuiButton((Rectangle){ 20, 20, 140, 30 }, GuiIconText(RICON_FILE_OPEN, "Open Image"))) fileDialogState.fileDialogActive = true;
-            
             GuiUnlock();
-            
+
             // GUI: Dialog Window
             //--------------------------------------------------------------------------------
-            GuiFileDialog(&fileDialogState);
+            GuiWindowFileDialog(&fileDialogState);
             //--------------------------------------------------------------------------------
 
             //----------------------------------------------------------------------------------

+ 0 - 558
gui.mod/raygui/examples/custom_file_dialog/gui_file_dialog.h

@@ -1,558 +0,0 @@
-/*******************************************************************************************
-*
-*   FileDialog v1.0.0 - Modal file dialog to open/save files
-*
-*   MODULE USAGE:
-*       #define GUI_FILE_DIALOG_IMPLEMENTATION
-*       #include "gui_file_dialog.h"
-*
-*       INIT: GuiFileDialogState state = InitGuiFileDialog();
-*       DRAW: GuiFileDialog(&state);
-*
-*   NOTE: This module depends on some raylib file system functions:
-*       - GetDirectoryFiles()
-*       - ClearDirectoryFiles()
-*       - GetWorkingDirectory()
-*       - DirectoryExists()
-*       - FileExists()
-*
-*   LICENSE: Propietary License
-*
-*   Copyright (c) 2019 raylib technologies (@raylibtech). All Rights Reserved.
-*
-*   Unauthorized copying of this file, via any medium is strictly prohibited
-*   This project is proprietary and confidential unless the owner allows
-*   usage in any other form by expresely written permission.
-*
-**********************************************************************************************/
-
-#include "raylib.h"
-
-// WARNING: raygui implementation is expected to be defined before including this header
-#undef RAYGUI_IMPLEMENTATION
-#include "../../src/raygui.h"
-
-#ifndef GUI_FILE_DIALOG_H
-#define GUI_FILE_DIALOG_H
-
-typedef struct {
-    Vector2 position;
-    
-    bool fileDialogActive;
-    
-    bool dirPathEditMode;
-    char dirPathText[256];
-    
-    int filesListScrollIndex;
-    bool filesListEditMode;
-    int filesListActive;
-    
-    bool fileNameEditMode;
-    char fileNameText[256];
-    bool SelectFilePressed;
-    bool CancelFilePressed;
-    int fileTypeActive;
-
-    // Custom state variables (depend on development software)
-    // NOTE: This variables should be added manually if required
-    char **dirFiles;
-    int dirFilesCount;
-
-    char filterExt[256];
-    
-    char dirPathTextCopy[256];
-    char fileNameTextCopy[256];
-    
-    int prevFilesListActive;
-
-} GuiFileDialogState;
-
-#ifdef __cplusplus
-extern "C" {            // Prevents name mangling of functions
-#endif
-
-//----------------------------------------------------------------------------------
-// Defines and Macros
-//----------------------------------------------------------------------------------
-//...
-
-//----------------------------------------------------------------------------------
-// Types and Structures Definition
-//----------------------------------------------------------------------------------
-// ...
-
-//----------------------------------------------------------------------------------
-// Global Variables Definition
-//----------------------------------------------------------------------------------
-//...
-
-//----------------------------------------------------------------------------------
-// Module Functions Declaration
-//----------------------------------------------------------------------------------
-GuiFileDialogState InitGuiFileDialog(void);
-void GuiFileDialog(GuiFileDialogState *state);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // GUI_FILE_DIALOG_H
-
-/***********************************************************************************
-*
-*   GUI_FILE_DIALOG IMPLEMENTATION
-*
-************************************************************************************/
-#if defined(GUI_FILE_DIALOG_IMPLEMENTATION)
-
-#include "../../src/raygui.h"
-
-#include <string.h>     // Required for: strcpy()
-
-//----------------------------------------------------------------------------------
-// Defines and Macros
-//----------------------------------------------------------------------------------
-#define MAX_DIRECTORY_FILES    1024
-#define MAX_DIR_PATH_LENGTH    1024
-
-//----------------------------------------------------------------------------------
-// Types and Structures Definition
-//----------------------------------------------------------------------------------
-
-#if defined(USE_CUSTOM_LISTVIEW_FILEINFO)
-// Detailed file info type
-typedef struct FileInfo {
-    const char *name;
-    int size;
-    int modTime;
-    int type;
-    int icon;
-} FileInfo;
-#endif
-
-//----------------------------------------------------------------------------------
-// Global Variables Definition
-//----------------------------------------------------------------------------------
-char **dirFilesIcon = NULL;
-
-//----------------------------------------------------------------------------------
-// Internal Module Functions Definition
-//----------------------------------------------------------------------------------
-// Read all filenames from directory (supported file types)
-static char **ReadDirectoryFiles(const char *dir, int *filesCount, char *filterExt);
-
-#if defined(USE_CUSTOM_LISTVIEW_FILEINFO)
-// List View control for files info with extended parameters
-static int GuiListViewFiles(Rectangle bounds, FileInfo *files, int count, int *focus, int *scrollIndex, int active)
-#endif
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition
-//----------------------------------------------------------------------------------
-GuiFileDialogState InitGuiFileDialog(void)
-{
-    GuiFileDialogState state = { 0 };
-
-    state.position = (Vector2){ GetScreenWidth()/2 - 480/2, GetScreenHeight()/2 - 305/2 };
-    
-    state.fileDialogActive = false;
-    state.dirPathEditMode = false;
-    
-    state.filesListActive = -1;
-    state.prevFilesListActive = state.filesListActive;
-    state.filesListScrollIndex = 0;
-    
-    state.fileNameEditMode = false;
-
-    state.SelectFilePressed = false;
-    state.CancelFilePressed = false;
-
-    state.fileTypeActive = 0;
-
-    // Custom variables initialization
-    strcpy(state.dirPathText, GetWorkingDirectory());
-    strcpy(state.dirPathTextCopy, state.dirPathText);
-    
-    strcpy(state.filterExt, "all");
-
-    state.dirFilesCount = 0;
-    state.dirFiles = NULL;      // NOTE: Loaded lazily on window active
-    
-    strcpy(state.fileNameText, "\0");
-    strcpy(state.fileNameTextCopy, state.fileNameText);
-
-    return state;
-}
-
-void GuiFileDialog(GuiFileDialogState *state)
-{   
-    if (state->fileDialogActive)
-    {
-        // Load dirFilesIcon and state->dirFiles lazily on windows open
-        // NOTE: they are automatically unloaded at fileDialog closing
-        //------------------------------------------------------------------------------------
-        if (dirFilesIcon == NULL)
-        {
-            dirFilesIcon = (char **)RL_MALLOC(MAX_DIRECTORY_FILES*sizeof(char *));    // Max files to read
-            for (int i = 0; i < MAX_DIRECTORY_FILES; i++) dirFilesIcon[i] = (char *)calloc(MAX_DIR_PATH_LENGTH, 1);    // Max file name length
-        }
-    
-        if (state->dirFiles == NULL) state->dirFiles = ReadDirectoryFiles(state->dirPathText, &state->dirFilesCount, state->filterExt);
-        //------------------------------------------------------------------------------------
-
-        DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)), 0.85f));
-        state->fileDialogActive = !GuiWindowBox((Rectangle){ state->position.x + 0, state->position.y + 0, 480, 310 }, "#198#Select File Dialog");
-        
-        if (GuiButton((Rectangle){ state->position.x + 430, state->position.y + 35, 40, 25 }, "< .."))
-        {
-            // Move dir path one level up
-            strcpy(state->dirPathText, GetPrevDirectoryPath(state->dirPathText));
-            
-            // RL_FREE previous dirFiles (reloaded by ReadDirectoryFiles())
-            for (int i = 0; i < state->dirFilesCount; i++) RL_FREE(state->dirFiles[i]);
-            RL_FREE(state->dirFiles);
-            
-            // Read files in the new path
-            state->dirFiles = ReadDirectoryFiles(state->dirPathText, &state->dirFilesCount, state->filterExt);
-            
-            state->filesListActive = -1;
-            strcpy(state->fileNameText, "\0");
-            strcpy(state->fileNameTextCopy, state->fileNameText);
-        }
-        
-        if (GuiTextBox((Rectangle){ state->position.x + 10, state->position.y + 35, 410, 25 }, state->dirPathText, 256, state->dirPathEditMode)) 
-        {
-            if (state->dirPathEditMode)
-            {
-                // Verify if a valid path has been introduced
-                if (DirectoryExists(state->dirPathText))
-                {
-                    // RL_FREE previous dirFiles (reloaded by ReadDirectoryFiles())
-                    for (int i = 0; i < state->dirFilesCount; i++) RL_FREE(state->dirFiles[i]);
-                    RL_FREE(state->dirFiles);
-                    
-                    // Read files in new path
-                    state->dirFiles = ReadDirectoryFiles(state->dirPathText, &state->dirFilesCount, state->filterExt);
-                    
-                    strcpy(state->dirPathTextCopy, state->dirPathText);
-                }
-                else strcpy(state->dirPathText, state->dirPathTextCopy);
-            }
-            
-            state->dirPathEditMode = !state->dirPathEditMode;
-        }
-        
-        int prevTextAlignment = GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT);
-        int prevElementsHeight = GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
-        GuiSetStyle(LISTVIEW, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT);
-        GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 24);
-        
-        // TODO: ListViewElements should be aligned left
-        state->filesListActive = GuiListViewEx((Rectangle){ state->position.x + 10, state->position.y + 70, 460, 164 }, (const char **)dirFilesIcon, state->dirFilesCount, NULL, &state->filesListScrollIndex, state->filesListActive);
-        
-        GuiSetStyle(LISTVIEW, TEXT_ALIGNMENT, prevTextAlignment);
-        GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, prevElementsHeight);
-        
-        if ((state->filesListActive >= 0) && (state->filesListActive != state->prevFilesListActive))
-        {
-            strcpy(state->fileNameText, state->dirFiles[state->filesListActive]);
-
-            if (DirectoryExists(TextFormat("%s\\%s", state->dirPathText, state->fileNameText)))
-            {
-                if (TextIsEqual(state->fileNameText, "..")) strcpy(state->dirPathText, GetPrevDirectoryPath(state->dirPathText));
-                else strcpy(state->dirPathText, TextFormat("%s\\%s", state->dirPathText, state->fileNameText));
-                
-                strcpy(state->dirPathTextCopy, state->dirPathText);
-                
-                // RL_FREE previous dirFiles (reloaded by ReadDirectoryFiles())
-                for (int i = 0; i < state->dirFilesCount; i++) RL_FREE(state->dirFiles[i]);
-                RL_FREE(state->dirFiles);
-                
-                // Read files in new path
-                state->dirFiles = ReadDirectoryFiles(state->dirPathText, &state->dirFilesCount, state->filterExt);
-                
-                strcpy(state->dirPathTextCopy, state->dirPathText);
-                
-                state->filesListActive = -1;
-                strcpy(state->fileNameText, "\0");
-                strcpy(state->fileNameTextCopy, state->fileNameText);
-            }
-
-            state->prevFilesListActive = state->filesListActive;
-        }
-        
-        GuiLabel((Rectangle){ state->position.x + 10, state->position.y + 245, 68, 25 }, "File name:");
-        
-        if (GuiTextBox((Rectangle){ state->position.x + 75, state->position.y + 245, 275, 25 }, state->fileNameText, 128, state->fileNameEditMode)) 
-        {
-            if (state->fileNameText)
-            {
-                // Verify if a valid filename has been introduced
-                if (FileExists(TextFormat("%s/%s", state->dirPathText, state->fileNameText)))
-                {
-                    // Select filename from list view
-                    for (int i = 0; i < state->dirFilesCount; i++)
-                    {
-                        if (TextIsEqual(state->fileNameText, state->dirFiles[i]))
-                        {
-                            state->filesListActive = i;
-                            strcpy(state->fileNameTextCopy, state->fileNameText);
-                            break;
-                        }
-                    }
-                }
-                else 
-                {
-                    strcpy(state->fileNameText, state->fileNameTextCopy);
-                }
-            }
-            
-            state->fileNameEditMode = !state->fileNameEditMode;
-        }
-
-        state->fileTypeActive = GuiComboBox((Rectangle){ state->position.x + 75, state->position.y + 275, 275, 25 }, "All files", state->fileTypeActive);
-        GuiLabel((Rectangle){ state->position.x + 10, state->position.y + 275, 68, 25 }, "File filter:");
-        
-        state->SelectFilePressed = GuiButton((Rectangle){ state->position.x + 360, state->position.y + 245, 110, 25 }, "Select");
-        
-        if (state->SelectFilePressed) state->fileDialogActive = false;
-        
-        if (GuiButton((Rectangle){ state->position.x + 360, state->position.y + 275, 110, 25 }, "Cancel")) state->fileDialogActive = false;
-
-        // File dialog has been closed!
-        if (!state->fileDialogActive)
-        {
-            // RL_FREE dirFiles memory
-            for (int i = 0; i < state->dirFilesCount; i++) 
-            {
-                RL_FREE(state->dirFiles[i]);
-                RL_FREE(dirFilesIcon[i]);
-            }
-            
-            RL_FREE(state->dirFiles);
-            RL_FREE(dirFilesIcon);
-            
-            dirFilesIcon = NULL;
-            state->dirFiles = NULL;
-        }
-    }
-}
-
-// Read all filenames from directory (supported file types)
-static char **ReadDirectoryFiles(const char *dir, int *filesCount, char *filterExt)
-{
-    int validFilesCount = 0;
-    char **validFiles = (char **)RL_MALLOC(MAX_DIRECTORY_FILES*sizeof(char *));    // Max files to read
-    for (int i = 0; i < MAX_DIRECTORY_FILES; i++) validFiles[i] = (char *)RL_MALLOC(MAX_DIR_PATH_LENGTH);    // Max file name length
-    
-    int filterExtCount = 0;
-    const char **extensions = GuiTextSplit(filterExt, &filterExtCount, NULL);
-    bool filterExtensions = true;
-    
-    int dirFilesCount = 0;
-    char **files = GetDirectoryFiles(dir, &dirFilesCount);
-    
-    if (TextIsEqual(extensions[0], "all")) filterExtensions = false;
-
-    for (int i = 0; (i < dirFilesCount) && (validFilesCount < MAX_DIRECTORY_FILES); i++)
-    {
-        if (TextIsEqual(files[i], ".")) continue;
-        
-        if (!filterExtensions)
-        {
-            strcpy(validFiles[validFilesCount], files[i]);
-            
-            // Only filter files by extensions, directories should be available
-            if (DirectoryExists(TextFormat("%s\\%s", dir, files[i]))) strcpy(dirFilesIcon[validFilesCount], TextFormat("#%i#%s", 1, files[i]));
-            else 
-            {
-                // TODO: Assign custom filetype icons depending on file extension (image, audio, text, video, models...)
-                
-                if (IsFileExtension(files[i], ".png")) strcpy(dirFilesIcon[validFilesCount], TextFormat("#%i#%s", 12, files[i]));
-                else strcpy(dirFilesIcon[validFilesCount], TextFormat("#%i#%s", 10, files[i]));
-            }
-
-            validFilesCount++;
-        }
-        else
-        {
-            for (int j = 0; j < filterExtCount; j++)
-            {
-                // Check file type extensions supported
-                // NOTE: We just store valid files list
-                if (IsFileExtension(files[i], extensions[j]))
-                {
-                    // TODO: Assign custom filetype icons depending on file extension (image, audio, text, video, models...)
-
-                    if (IsFileExtension(files[i], ".png")) strcpy(dirFilesIcon[validFilesCount], TextFormat("#%i#%s", 12, files[i]));
-                    else strcpy(dirFilesIcon[validFilesCount], TextFormat("#%i#%s", 10, files[i]));
-                    
-                    validFilesCount++;
-                }
-            }
-        }
-    }
-    
-    // TODO: Sort files and directories: dir by name + files by name
-
-    ClearDirectoryFiles();
-    
-    *filesCount = validFilesCount;
-    return validFiles;
-}
-
-#if defined(USE_CUSTOM_LISTVIEW_FILEINFO)
-// List View control for files info with extended parameters
-static int GuiListViewFiles(Rectangle bounds, FileInfo *files, int count, int *focus, int *scrollIndex, int active)
-{
-    GuiControlState state = guiState;
-    int itemFocused = (focus == NULL)? -1 : *focus;
-    int itemSelected = active;
-    
-    // Check if we need a scroll bar
-    bool useScrollBar = false;
-    if ((GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING))*count > bounds.height) useScrollBar = true;
-    
-    // Define base item rectangle [0]
-    Rectangle itemBounds = { 0 };
-    itemBounds.x = bounds.x + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING);
-    itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH);
-    itemBounds.width = bounds.width - 2*GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) - GuiGetStyle(DEFAULT, BORDER_WIDTH);
-    itemBounds.height = GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT);
-    if (useScrollBar) itemBounds.width -= GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH);
-    
-    // Get items on the list
-    int visibleItems = bounds.height/(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING));
-    if (visibleItems > count) visibleItems = count;
-    
-    int startIndex = (scrollIndex == NULL)? 0 : *scrollIndex;
-    if ((startIndex < 0) || (startIndex > (count - visibleItems))) startIndex = 0;
-    int endIndex = startIndex + visibleItems;
-
-    // Update control
-    //--------------------------------------------------------------------
-    if ((state != GUI_STATE_DISABLED) && !guiLocked)
-    {
-        Vector2 mousePoint = GetMousePosition();
-        
-        // Check mouse inside list view
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            state = GUI_STATE_FOCUSED;
-            
-            // Check focused and selected item
-            for (int i = 0; i < visibleItems; i++)
-            {
-                if (CheckCollisionPointRec(mousePoint, itemBounds))
-                {
-                    itemFocused = startIndex + i;
-                    if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) itemSelected = startIndex + i;
-                    break;
-                }
-                
-                // Update item rectangle y position for next item
-                itemBounds.y += (GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING));
-            }
-            
-            if (useScrollBar)
-            {
-                int wheelMove = GetMouseWheelMove();
-                startIndex -= wheelMove;
-                    
-                if (startIndex < 0) startIndex = 0;
-                else if (startIndex > (count - visibleItems)) startIndex = count - visibleItems;
-
-                endIndex = startIndex + visibleItems;
-                if (endIndex > count) endIndex = count;
-            }
-        }
-        else itemFocused = -1;
-        
-        // Reset item rectangle y to [0]
-        itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH);
-    }
-    //--------------------------------------------------------------------
-    
-    // Draw control
-    //--------------------------------------------------------------------
-    DrawRectangleRec(bounds, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));     // Draw background
-    DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), guiAlpha));
-
-    // TODO: Draw list view header with file sections: icon+name | size | type | modTime
-    
-    // Draw visible items
-    for (int i = 0; i < visibleItems; i++)
-    {
-        if (state == GUI_STATE_DISABLED)
-        {
-            if ((startIndex + i) == itemSelected)
-            {
-                DrawRectangleRec(itemBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)), guiAlpha));
-                DrawRectangleLinesEx(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), guiAlpha));
-            }
-            
-            // TODO: Draw full file info line: icon+name | size | type | modTime 
-            
-            GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED)), guiAlpha));
-        }
-        else
-        {
-            if ((startIndex + i) == itemSelected)
-            {
-                // Draw item selected
-                DrawRectangleRec(itemBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)), guiAlpha));
-                DrawRectangleLinesEx(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), guiAlpha));
-                
-                GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)), guiAlpha));
-            }
-            else if ((startIndex + i) == itemFocused)
-            {
-                // Draw item focused
-                DrawRectangleRec(itemBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)), guiAlpha));
-                DrawRectangleLinesEx(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), guiAlpha));
-                
-                GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)), guiAlpha));
-            }
-            else
-            {
-                // Draw item normal
-                GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL)), guiAlpha));
-            }
-        }
-
-        // Update item rectangle y position for next item
-        itemBounds.y += (GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING));
-    }
-
-    if (useScrollBar)
-    {
-        Rectangle scrollBarBounds = { 
-            bounds.x + bounds.width - GuiGetStyle(LISTVIEW, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), 
-            bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH), (float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), 
-            bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) 
-        };
-
-        // Calculate percentage of visible items and apply same percentage to scrollbar
-        float percentVisible = (float)(endIndex - startIndex)/count;
-        float sliderSize = bounds.height*percentVisible;
-
-        int prevSliderSize = GuiGetStyle(SCROLLBAR, SLIDER_SIZE);   // Save default slider size
-        int prevScrollSpeed = GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed
-        GuiSetStyle(SCROLLBAR, SLIDER_SIZE, sliderSize);            // Change slider size
-        GuiSetStyle(SCROLLBAR, SCROLL_SPEED, count - visibleItems); // Change scroll speed
-
-        startIndex = GuiScrollBar(scrollBarBounds, startIndex, 0, count - visibleItems);
-
-        GuiSetStyle(SCROLLBAR, SCROLL_SPEED, prevScrollSpeed); // Reset scroll speed to default
-        GuiSetStyle(SCROLLBAR, SLIDER_SIZE, prevSliderSize); // Reset slider size to default
-    }
-    //--------------------------------------------------------------------
-    
-    if (focus != NULL) *focus = itemFocused;
-    if (scrollIndex != NULL) *scrollIndex = startIndex;
-    
-    return itemSelected;
-}
-#endif // USE_CUSTOM_LISTVIEW_FILEINFO
-
-#endif // GUI_FILE_DIALOG_IMPLEMENTATION

+ 625 - 0
gui.mod/raygui/examples/custom_file_dialog/gui_window_file_dialog.h

@@ -0,0 +1,625 @@
+/*******************************************************************************************
+*
+*   Window File Dialog v1.2 - Modal file dialog to open/save files
+*
+*   MODULE USAGE:
+*       #define GUI_WINDOW_FILE_DIALOG_IMPLEMENTATION
+*       #include "gui_window_file_dialog.h"
+*
+*       INIT: GuiWindowFileDialogState state = GuiInitWindowFileDialog();
+*       DRAW: GuiWindowFileDialog(&state);
+*
+*   NOTE: This module depends on some raylib file system functions:
+*       - LoadDirectoryFiles()
+*       - UnloadDirectoryFiles()
+*       - GetWorkingDirectory()
+*       - DirectoryExists()
+*       - FileExists()
+*
+*   LICENSE: zlib/libpng
+*
+*   Copyright (c) 2019-2024 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.
+*
+**********************************************************************************************/
+
+#include "raylib.h"
+
+#ifndef GUI_WINDOW_FILE_DIALOG_H
+#define GUI_WINDOW_FILE_DIALOG_H
+
+// Gui file dialog context data
+typedef struct {
+
+    // Window management variables
+    bool windowActive;
+    Rectangle windowBounds;
+    Vector2 panOffset;
+    bool dragMode;
+    bool supportDrag;
+
+    // UI variables
+    bool dirPathEditMode;
+    char dirPathText[1024];
+
+    int filesListScrollIndex;
+    bool filesListEditMode;
+    int filesListActive;
+
+    bool fileNameEditMode;
+    char fileNameText[1024];
+    bool SelectFilePressed;
+    bool CancelFilePressed;
+    int fileTypeActive;
+    int itemFocused;
+
+    // Custom state variables
+    FilePathList dirFiles;
+    char filterExt[256];
+    char dirPathTextCopy[1024];
+    char fileNameTextCopy[1024];
+
+    int prevFilesListActive;
+
+    bool saveFileMode;
+
+} GuiWindowFileDialogState;
+
+#ifdef __cplusplus
+extern "C" {            // Prevents name mangling of functions
+#endif
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+//...
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+// ...
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+//...
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+//----------------------------------------------------------------------------------
+GuiWindowFileDialogState InitGuiWindowFileDialog(const char *initPath);
+void GuiWindowFileDialog(GuiWindowFileDialogState *state);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // GUI_WINDOW_FILE_DIALOG_H
+
+/***********************************************************************************
+*
+*   GUI_WINDOW_FILE_DIALOG IMPLEMENTATION
+*
+************************************************************************************/
+#if defined(GUI_WINDOW_FILE_DIALOG_IMPLEMENTATION)
+
+#include "../../src/raygui.h"
+
+#include <string.h>     // Required for: strcpy()
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+#define MAX_DIRECTORY_FILES    2048
+#define MAX_ICON_PATH_LENGTH    512
+#ifdef _WIN32
+#define PATH_SEPERATOR "\\"
+#else
+#define PATH_SEPERATOR "/"
+#endif
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+#if defined(USE_CUSTOM_LISTVIEW_FILEINFO)
+// Detailed file info type
+typedef struct FileInfo {
+    const char *name;
+    int size;
+    int modTime;
+    int type;
+    int icon;
+} FileInfo;
+#else
+// Filename only
+typedef char *FileInfo;             // Files are just a path string
+#endif
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+FileInfo *dirFilesIcon = NULL;      // Path string + icon (for fancy drawing)
+
+//----------------------------------------------------------------------------------
+// Internal Module Functions Definition
+//----------------------------------------------------------------------------------
+// Read files in new path
+static void ReloadDirectoryFiles(GuiWindowFileDialogState *state);
+
+#if defined(USE_CUSTOM_LISTVIEW_FILEINFO)
+// List View control for files info with extended parameters
+static int GuiListViewFiles(Rectangle bounds, FileInfo *files, int count, int *focus, int *scrollIndex, int active);
+#endif
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+GuiWindowFileDialogState InitGuiWindowFileDialog(const char *initPath)
+{
+    GuiWindowFileDialogState state = { 0 };
+
+    // Init window data
+    state.windowBounds = (Rectangle){ GetScreenWidth()/2 - 440/2, GetScreenHeight()/2 - 310/2, 440, 310 };
+    state.windowActive = false;
+    state.supportDrag = true;
+    state.dragMode = false;
+    state.panOffset = (Vector2){ 0, 0 };
+
+    // Init path data
+    state.dirPathEditMode = false;
+    state.filesListActive = -1;
+    state.prevFilesListActive = state.filesListActive;
+    state.filesListScrollIndex = 0;
+
+    state.fileNameEditMode = false;
+
+    state.SelectFilePressed = false;
+    state.CancelFilePressed = false;
+
+    state.fileTypeActive = 0;
+
+    strcpy(state.fileNameText, "\0");
+
+    // Custom variables initialization
+    if (initPath && DirectoryExists(initPath))
+    {
+        strcpy(state.dirPathText, initPath);
+    }
+    else if (initPath && FileExists(initPath))
+    {
+        strcpy(state.dirPathText, GetDirectoryPath(initPath));
+        strcpy(state.fileNameText, GetFileName(initPath));
+    }
+    else strcpy(state.dirPathText, GetWorkingDirectory());
+
+    // TODO: Why we keep a copy?
+    strcpy(state.dirPathTextCopy, state.dirPathText);
+    strcpy(state.fileNameTextCopy, state.fileNameText);
+
+    state.filterExt[0] = '\0';
+    //strcpy(state.filterExt, "all");
+
+    state.dirFiles.count = 0;
+
+    return state;
+}
+
+// Update and draw file dialog
+void GuiWindowFileDialog(GuiWindowFileDialogState *state)
+{
+    if (state->windowActive)
+    {
+        // Update window dragging
+        //----------------------------------------------------------------------------------------
+        if (state->supportDrag)
+        {
+            Vector2 mousePosition = GetMousePosition();
+
+            if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+            {
+                // Window can be dragged from the top window bar
+                if (CheckCollisionPointRec(mousePosition, (Rectangle){ state->windowBounds.x, state->windowBounds.y, (float)state->windowBounds.width, RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT }))
+                {
+                    state->dragMode = true;
+                    state->panOffset.x = mousePosition.x - state->windowBounds.x;
+                    state->panOffset.y = mousePosition.y - state->windowBounds.y;
+                }
+            }
+
+            if (state->dragMode)
+            {
+                state->windowBounds.x = (mousePosition.x - state->panOffset.x);
+                state->windowBounds.y = (mousePosition.y - state->panOffset.y);
+
+                // Check screen limits to avoid moving out of screen
+                if (state->windowBounds.x < 0) state->windowBounds.x = 0;
+                else if (state->windowBounds.x > (GetScreenWidth() - state->windowBounds.width)) state->windowBounds.x = GetScreenWidth() - state->windowBounds.width;
+
+                if (state->windowBounds.y < 0) state->windowBounds.y = 0;
+                else if (state->windowBounds.y > (GetScreenHeight() - state->windowBounds.height)) state->windowBounds.y = GetScreenHeight() - state->windowBounds.height;
+
+                if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) state->dragMode = false;
+            }
+        }
+        //----------------------------------------------------------------------------------------
+
+        // Load dirFilesIcon and state->dirFiles lazily on windows open
+        // NOTE: They are automatically unloaded at fileDialog closing
+        //----------------------------------------------------------------------------------------
+        if (dirFilesIcon == NULL)
+        {
+            dirFilesIcon = (FileInfo *)RL_CALLOC(MAX_DIRECTORY_FILES, sizeof(FileInfo));    // Max files to read
+            for (int i = 0; i < MAX_DIRECTORY_FILES; i++) dirFilesIcon[i] = (char *)RL_CALLOC(MAX_ICON_PATH_LENGTH, 1);    // Max file name length
+        }
+
+        // Load current directory files
+        if (state->dirFiles.paths == NULL) ReloadDirectoryFiles(state);
+        //----------------------------------------------------------------------------------------
+
+        // Draw window and controls
+        //----------------------------------------------------------------------------------------
+        state->windowActive = !GuiWindowBox(state->windowBounds, "#198# Select File Dialog");
+
+        // Draw previous directory button + logic
+        if (GuiButton((Rectangle){ state->windowBounds.x + state->windowBounds.width - 48, state->windowBounds.y + 24 + 12, 40, 24 }, "< .."))
+        {
+            // Move dir path one level up
+            strcpy(state->dirPathText, GetPrevDirectoryPath(state->dirPathText));
+
+            // Reload directory files (frees previous list)
+            ReloadDirectoryFiles(state);
+
+            state->filesListActive = -1;
+            memset(state->fileNameText, 0, 1024);
+            memset(state->fileNameTextCopy, 0, 1024);
+        }
+
+        // Draw current directory text box info + path editing logic
+        if (GuiTextBox((Rectangle){ state->windowBounds.x + 8, state->windowBounds.y + 24 + 12, state->windowBounds.width - 48 - 16, 24 }, state->dirPathText, 1024, state->dirPathEditMode))
+        {
+            if (state->dirPathEditMode)
+            {
+                // Verify if a valid path has been introduced
+                if (DirectoryExists(state->dirPathText))
+                {
+                    // Reload directory files (frees previous list)
+                    ReloadDirectoryFiles(state);
+
+                    strcpy(state->dirPathTextCopy, state->dirPathText);
+                }
+                else strcpy(state->dirPathText, state->dirPathTextCopy);
+            }
+
+            state->dirPathEditMode = !state->dirPathEditMode;
+        }
+
+        // List view elements are aligned left
+        int prevTextAlignment = GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT);
+        int prevElementsHeight = GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
+        GuiSetStyle(LISTVIEW, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
+        GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 24);
+# if defined(USE_CUSTOM_LISTVIEW_FILEINFO)
+        state->filesListActive = GuiListViewFiles((Rectangle){ state->position.x + 8, state->position.y + 48 + 20, state->windowBounds.width - 16, state->windowBounds.height - 60 - 16 - 68 }, fileInfo, state->dirFiles.count, &state->itemFocused, &state->filesListScrollIndex, state->filesListActive);
+# else
+        GuiListViewEx((Rectangle){ state->windowBounds.x + 8, state->windowBounds.y + 48 + 20, state->windowBounds.width - 16, state->windowBounds.height - 60 - 16 - 68 }, 
+                      (const char**)dirFilesIcon, state->dirFiles.count, &state->filesListScrollIndex, &state->filesListActive, &state->itemFocused);
+# endif
+        GuiSetStyle(LISTVIEW, TEXT_ALIGNMENT, prevTextAlignment);
+        GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, prevElementsHeight);
+
+        // Check if a path has been selected, if it is a directory, move to that directory (and reload paths)
+        if ((state->filesListActive >= 0) && (state->filesListActive != state->prevFilesListActive))
+            //&& (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_DPAD_A)))
+        {
+            strcpy(state->fileNameText, GetFileName(state->dirFiles.paths[state->filesListActive]));
+
+            if (DirectoryExists(TextFormat("%s/%s", state->dirPathText, state->fileNameText)))
+            {
+                if (TextIsEqual(state->fileNameText, "..")) strcpy(state->dirPathText, GetPrevDirectoryPath(state->dirPathText));
+                else strcpy(state->dirPathText, TextFormat("%s/%s", (strcmp(state->dirPathText, "/") == 0)? "" : state->dirPathText, state->fileNameText));
+
+                strcpy(state->dirPathTextCopy, state->dirPathText);
+
+                // Reload directory files (frees previous list)
+                ReloadDirectoryFiles(state);
+
+                strcpy(state->dirPathTextCopy, state->dirPathText);
+
+                state->filesListActive = -1;
+                strcpy(state->fileNameText, "\0");
+                strcpy(state->fileNameTextCopy, state->fileNameText);
+            }
+
+            state->prevFilesListActive = state->filesListActive;
+        }
+
+        // Draw bottom controls
+        //--------------------------------------------------------------------------------------
+        GuiLabel((Rectangle){ state->windowBounds.x + 8, state->windowBounds.y + state->windowBounds.height - 68, 60, 24 }, "File name:");
+        if (GuiTextBox((Rectangle){ state->windowBounds.x + 72, state->windowBounds.y + state->windowBounds.height - 68, state->windowBounds.width - 184, 24 }, state->fileNameText, 128, state->fileNameEditMode))
+        {
+            if (*state->fileNameText)
+            {
+                // Verify if a valid filename has been introduced
+                if (FileExists(TextFormat("%s/%s", state->dirPathText, state->fileNameText)))
+                {
+                    // Select filename from list view
+                    for (int i = 0; i < state->dirFiles.count; i++)
+                    {
+                        if (TextIsEqual(state->fileNameText, state->dirFiles.paths[i]))
+                        {
+                            state->filesListActive = i;
+                            strcpy(state->fileNameTextCopy, state->fileNameText);
+                            break;
+                        }
+                    }
+                }
+                else if (!state->saveFileMode)
+                {
+                    strcpy(state->fileNameText, state->fileNameTextCopy);
+                }
+            }
+
+            state->fileNameEditMode = !state->fileNameEditMode;
+        }
+
+        GuiLabel((Rectangle){ state->windowBounds.x + 8, state->windowBounds.y + state->windowBounds.height - 24 - 12, 68, 24 }, "File filter:");
+        GuiComboBox((Rectangle){ state->windowBounds.x + 72, state->windowBounds.y + state->windowBounds.height - 24 - 12, state->windowBounds.width - 184, 24 }, "All files", &state->fileTypeActive);
+
+        state->SelectFilePressed = GuiButton((Rectangle){ state->windowBounds.x + state->windowBounds.width - 96 - 8, state->windowBounds.y + state->windowBounds.height - 68, 96, 24 }, "Select");
+
+        if (GuiButton((Rectangle){ state->windowBounds.x + state->windowBounds.width - 96 - 8, state->windowBounds.y + state->windowBounds.height - 24 - 12, 96, 24 }, "Cancel")) state->windowActive = false;
+        //--------------------------------------------------------------------------------------
+
+        // Exit on file selected
+        if (state->SelectFilePressed) state->windowActive = false;
+
+        // File dialog has been closed, free all memory before exit
+        if (!state->windowActive)
+        {
+            // Free dirFilesIcon memory
+            for (int i = 0; i < MAX_DIRECTORY_FILES; i++) RL_FREE(dirFilesIcon[i]);
+
+            RL_FREE(dirFilesIcon);
+            dirFilesIcon = NULL;
+
+            // Unload directory file paths
+            UnloadDirectoryFiles(state->dirFiles);
+
+            // Reset state variables
+            state->dirFiles.count = 0;
+            state->dirFiles.capacity = 0;
+            state->dirFiles.paths = NULL;
+        }
+    }
+}
+
+// Compare two files from a directory
+static inline int FileCompare(const char *d1, const char *d2, const char *dir)
+{
+    const bool b1 = DirectoryExists(TextFormat("%s/%s", dir, d1));
+    const bool b2 = DirectoryExists(TextFormat("%s/%s", dir, d2));
+
+    if (b1 && !b2) return -1;
+    if (!b1 && b2) return 1;
+
+    if (!FileExists(TextFormat("%s/%s", dir, d1))) return 1;
+    if (!FileExists(TextFormat("%s/%s", dir, d2))) return -1;
+
+    return strcmp(d1, d2);
+}
+
+// Read files in new path
+static void ReloadDirectoryFiles(GuiWindowFileDialogState *state)
+{
+    UnloadDirectoryFiles(state->dirFiles);
+
+    state->dirFiles = LoadDirectoryFilesEx(state->dirPathText, (state->filterExt[0] == '\0')? NULL : state->filterExt, false);
+    state->itemFocused = 0;
+
+    // Reset dirFilesIcon memory
+    for (int i = 0; i < MAX_DIRECTORY_FILES; i++) memset(dirFilesIcon[i], 0, MAX_ICON_PATH_LENGTH);
+
+    // Copy paths as icon + fileNames into dirFilesIcon
+    for (int i = 0; i < state->dirFiles.count; i++)
+    {
+        if (IsPathFile(state->dirFiles.paths[i]))
+        {
+            // Path is a file, a file icon for convenience (for some recognized extensions)
+            if (IsFileExtension(state->dirFiles.paths[i], ".png;.bmp;.tga;.gif;.jpg;.jpeg;.psd;.hdr;.qoi;.dds;.pkm;.ktx;.pvr;.astc"))
+            {
+                strcpy(dirFilesIcon[i], TextFormat("#12#%s", GetFileName(state->dirFiles.paths[i])));
+            }
+            else if (IsFileExtension(state->dirFiles.paths[i], ".wav;.mp3;.ogg;.flac;.xm;.mod;.it;.wma;.aiff"))
+            {
+                strcpy(dirFilesIcon[i], TextFormat("#11#%s", GetFileName(state->dirFiles.paths[i])));
+            }
+            else if (IsFileExtension(state->dirFiles.paths[i], ".txt;.info;.md;.nfo;.xml;.json;.c;.cpp;.cs;.lua;.py;.glsl;.vs;.fs"))
+            {
+                strcpy(dirFilesIcon[i], TextFormat("#10#%s", GetFileName(state->dirFiles.paths[i])));
+            }
+            else if (IsFileExtension(state->dirFiles.paths[i], ".exe;.bin;.raw;.msi"))
+            {
+                strcpy(dirFilesIcon[i], TextFormat("#200#%s", GetFileName(state->dirFiles.paths[i])));
+            }
+            else strcpy(dirFilesIcon[i], TextFormat("#218#%s", GetFileName(state->dirFiles.paths[i])));
+        }
+        else
+        {
+            // Path is a directory, add a directory icon
+            strcpy(dirFilesIcon[i], TextFormat("#1#%s", GetFileName(state->dirFiles.paths[i])));
+        }
+    }
+}
+
+#if defined(USE_CUSTOM_LISTVIEW_FILEINFO)
+// List View control for files info with extended parameters
+static int GuiListViewFiles(Rectangle bounds, FileInfo *files, int count, int *focus, int *scrollIndex, int *active)
+{
+    int result = 0;
+    GuiState state = guiState;
+    int itemFocused = (focus == NULL)? -1 : *focus;
+    int itemSelected = *active;
+
+    // Check if we need a scroll bar
+    bool useScrollBar = false;
+    if ((GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING))*count > bounds.height) useScrollBar = true;
+
+    // Define base item rectangle [0]
+    Rectangle itemBounds = { 0 };
+    itemBounds.x = bounds.x + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING);
+    itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH);
+    itemBounds.width = bounds.width - 2*GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) - GuiGetStyle(DEFAULT, BORDER_WIDTH);
+    itemBounds.height = GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
+    if (useScrollBar) itemBounds.width -= GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH);
+
+    // Get items on the list
+    int visibleItems = bounds.height/(GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING));
+    if (visibleItems > count) visibleItems = count;
+
+    int startIndex = (scrollIndex == NULL)? 0 : *scrollIndex;
+    if ((startIndex < 0) || (startIndex > (count - visibleItems))) startIndex = 0;
+    int endIndex = startIndex + visibleItems;
+
+    // Update control
+    //--------------------------------------------------------------------
+    if ((state != GUI_STATE_DISABLED) && !guiLocked)
+    {
+        Vector2 mousePoint = GetMousePosition();
+
+        // Check mouse inside list view
+        if (CheckCollisionPointRec(mousePoint, bounds))
+        {
+            state = GUI_STATE_FOCUSED;
+
+            // Check focused and selected item
+            for (int i = 0; i < visibleItems; i++)
+            {
+                if (CheckCollisionPointRec(mousePoint, itemBounds))
+                {
+                    itemFocused = startIndex + i;
+                    if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) itemSelected = startIndex + i;
+                    break;
+                }
+
+                // Update item rectangle y position for next item
+                itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING));
+            }
+
+            if (useScrollBar)
+            {
+                int wheelMove = GetMouseWheelMove();
+                startIndex -= wheelMove;
+
+                if (startIndex < 0) startIndex = 0;
+                else if (startIndex > (count - visibleItems)) startIndex = count - visibleItems;
+
+                endIndex = startIndex + visibleItems;
+                if (endIndex > count) endIndex = count;
+            }
+        }
+        else itemFocused = -1;
+
+        // Reset item rectangle y to [0]
+        itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH);
+    }
+    //--------------------------------------------------------------------
+
+    // Draw control
+    //--------------------------------------------------------------------
+    DrawRectangleRec(bounds, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));     // Draw background
+    DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), guiAlpha));
+
+    // TODO: Draw list view header with file sections: icon+name | size | type | modTime
+
+    // Draw visible items
+    for (int i = 0; i < visibleItems; i++)
+    {
+        if (state == GUI_STATE_DISABLED)
+        {
+            if ((startIndex + i) == itemSelected)
+            {
+                DrawRectangleRec(itemBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)), guiAlpha));
+                DrawRectangleLinesEx(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), guiAlpha));
+            }
+
+            // TODO: Draw full file info line: icon+name | size | type | modTime
+
+            GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED)), guiAlpha));
+        }
+        else
+        {
+            if ((startIndex + i) == itemSelected)
+            {
+                // Draw item selected
+                DrawRectangleRec(itemBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)), guiAlpha));
+                DrawRectangleLinesEx(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), guiAlpha));
+
+                GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)), guiAlpha));
+            }
+            else if ((startIndex + i) == itemFocused)
+            {
+                // Draw item focused
+                DrawRectangleRec(itemBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)), guiAlpha));
+                DrawRectangleLinesEx(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), guiAlpha));
+
+                GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)), guiAlpha));
+            }
+            else
+            {
+                // Draw item normal
+                GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL)), guiAlpha));
+            }
+        }
+
+        // Update item rectangle y position for next item
+        itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING));
+    }
+
+    if (useScrollBar)
+    {
+        Rectangle scrollBarBounds = {
+            bounds.x + bounds.width - GuiGetStyle(LISTVIEW, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH),
+            bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH), (float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH),
+            bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH)
+        };
+
+        // Calculate percentage of visible items and apply same percentage to scrollbar
+        float percentVisible = (float)(endIndex - startIndex)/count;
+        float sliderSize = bounds.height*percentVisible;
+
+        int prevSliderSize = GuiGetStyle(SCROLLBAR, SLIDER_WIDTH);  // Save default slider size
+        int prevScrollSpeed = GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed
+        GuiSetStyle(SCROLLBAR, SLIDER_WIDTH, sliderSize);           // Change slider size
+        GuiSetStyle(SCROLLBAR, SCROLL_SPEED, count - visibleItems); // Change scroll speed
+
+        startIndex = GuiScrollBar(scrollBarBounds, startIndex, 0, count - visibleItems);
+
+        GuiSetStyle(SCROLLBAR, SCROLL_SPEED, prevScrollSpeed); // Reset scroll speed to default
+        GuiSetStyle(SCROLLBAR, SLIDER_WIDTH, prevSliderSize);  // Reset slider size to default
+    }
+    //--------------------------------------------------------------------
+
+    if (focus != NULL) *focus = itemFocused;
+    if (scrollIndex != NULL) *scrollIndex = startIndex;
+
+    *active = itemSelected;
+    return result;
+}
+#endif // USE_CUSTOM_LISTVIEW_FILEINFO
+
+#endif // GUI_FILE_DIALOG_IMPLEMENTATION

+ 223 - 0
gui.mod/raygui/examples/custom_input_box/custom_input_box.c

@@ -0,0 +1,223 @@
+/*******************************************************************************************
+*
+*   raygui - basic calculator app with custom input box for float values
+*
+*   DEPENDENCIES:
+*       raylib 4.5  - Windowing/input management and drawing.
+*       raygui 3.5  - Immediate-mode GUI controls.
+*
+*   COMPILATION (Windows - MinGW):
+*       gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
+*
+**********************************************************************************************/
+
+#include "raylib.h"
+
+#define RAYGUI_IMPLEMENTATION
+#include "../../src/raygui.h"
+
+int guiFloatingPointIndex = 0;      // Global variable shared by all GuiFloatBox()
+
+int GuiFloatBox(Rectangle bounds, const char* text, float* value, int minValue, int maxValue, bool editMode); // Custom input box that works with float values. Basicly GuiValueBox(), but with some changes
+
+int main()
+{
+	InitWindow(250, 100, "Basic calculator");
+
+	// General variables
+	SetTargetFPS(60);
+
+	float variableA = 0.0f;
+	float variableB = 0.0f;
+	float result = 0.0f;
+	char operation[2];
+	operation[0] = '+';
+	operation[1] = '\0';
+
+	bool variableAMode = false;
+	bool variableBMode = false;
+	//--------------------------------------------------------------------------------------
+
+	// Main game loop
+	while (!WindowShouldClose())
+	{
+		// Draw 
+		//----------------------------------------------------------------------------------
+		BeginDrawing();
+
+		ClearBackground(RAYWHITE);
+
+		if (GuiFloatBox((Rectangle){ 10, 10, 100, 20 }, NULL, &variableA, -1000000.0, 1000000.0, variableAMode)) variableAMode = !variableAMode;
+		if (GuiFloatBox((Rectangle){ 140, 10, 100, 20 }, NULL, &variableB, -1000000.0, 1000000.0, variableBMode)) variableBMode = !variableBMode;
+		
+		if (GuiButton((Rectangle){ 10, 70, 50, 20 }, "+"))
+		{
+			result = variableA + variableB;
+			operation[0] = '+';
+		}
+		if (GuiButton((Rectangle){ 70, 70, 50, 20 }, "-")) 
+		{
+			result = variableA - variableB;
+			operation[0] = '-';
+		}
+		if (GuiButton((Rectangle){ 130, 70, 50, 20 }, "*")) 
+		{
+			result = variableA * variableB;
+			operation[0] = '*';
+		}
+		if (GuiButton((Rectangle){ 190, 70, 50, 20 }, "/")) 
+		{
+			result = variableA / variableB;
+			operation[0] = '/';
+		}
+
+		DrawText(operation, 123, 15, 10, DARKGRAY);
+		
+		GuiFloatBox((Rectangle){ 55, 40, 135, 20 }, "= ", &result, -2000000.0, 2000000.0, false);
+		
+		EndDrawing();
+        //----------------------------------------------------------------------------------
+	}
+
+	CloseWindow();
+}
+
+// Float Box control, updates input text with numbers
+int GuiFloatBox(Rectangle bounds, const char* text, float* value, int minValue, int maxValue, bool editMode)
+{
+#if !defined(RAYGUI_VALUEBOX_MAX_CHARS)
+#define RAYGUI_VALUEBOX_MAX_CHARS  32
+#endif
+
+    int result = 0;
+    GuiState state = guiState;
+
+    char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0";
+
+    Rectangle textBounds = { 0 };
+    if (text != NULL)
+    {
+        textBounds.width = (float)GetTextWidth(text) + 2;
+        textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+        textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING);
+        textBounds.y = bounds.y + bounds.height / 2.0f - GuiGetStyle(DEFAULT, TEXT_SIZE) / 2.0f;
+        if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING);
+    }
+
+    // Update control
+    //--------------------------------------------------------------------
+    if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+    {
+        Vector2 mousePoint = GetMousePosition();
+
+        if (*value >= 0) sprintf(textValue, "+%.3f", *value);
+        else sprintf(textValue, "%.3f", *value);
+
+        bool valueHasChanged = false;
+
+        int keyCount = (int)strlen(textValue) - guiFloatingPointIndex;
+
+        if (editMode)
+        {
+            state = STATE_PRESSED;
+
+            // Only allow keys in range [48..57]
+            if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS)
+            {
+                if (GetTextWidth(textValue) < bounds.width)
+                {
+                    int key = GetCharPressed();
+                    if ((key >= 48) && (key <= 57) && guiFloatingPointIndex)
+                    {
+                        if (guiFloatingPointIndex && guiFloatingPointIndex != 4) guiFloatingPointIndex--;
+
+                        textValue[keyCount] = (char)key;
+                        textValue[++keyCount] = '\0';
+                        valueHasChanged = true;
+                    }
+                }
+            }
+
+            // Delete text
+            if (keyCount > 0)
+            {
+                if (IsKeyPressed(KEY_BACKSPACE))
+                {
+                    if (guiFloatingPointIndex < 4) guiFloatingPointIndex++;
+
+                    keyCount--;
+                    textValue[keyCount] = '\0';
+                    valueHasChanged = true;
+                }
+            }
+
+            // Change sign
+            if (IsKeyPressed(KEY_MINUS))
+            {
+                if (textValue[0] == '+') textValue[0] = '-';
+                else if (textValue[0] == '-') textValue[0] = '+';
+                valueHasChanged = true;
+            }
+
+            // Add decimal separator
+            if ((IsKeyPressed(KEY_COMMA) || IsKeyPressed(KEY_PERIOD)) && guiFloatingPointIndex == 4)
+            {
+                guiFloatingPointIndex--;
+                valueHasChanged = true;
+            }
+
+            if (valueHasChanged)
+            {
+                *value = atof(textValue);
+            }
+
+            if (IsKeyPressed(KEY_ENTER) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
+            {
+                guiFloatingPointIndex = 0;
+                result = 1;
+            }
+        }
+        else
+        {
+            if (*value > maxValue) *value = maxValue;
+            else if (*value < minValue) *value = minValue;
+
+            if (CheckCollisionPointRec(mousePoint, bounds))
+            {
+                state = STATE_FOCUSED;
+                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
+            }
+        }
+    }
+    //--------------------------------------------------------------------
+
+    // Draw control
+    //--------------------------------------------------------------------
+    Color baseColor = BLANK;
+    sprintf(textValue, "%.3f", *value);
+
+    if (state == STATE_PRESSED)
+    {
+        baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED));
+        textValue[(int)strlen(textValue) - guiFloatingPointIndex] = '\0';
+    }
+    else if (state == STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED));
+
+    // WARNING: BLANK color does not work properly with Fade()
+    GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER + (state * 3))), guiAlpha), baseColor);
+    GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(VALUEBOX, TEXT + (state * 3))), guiAlpha));
+
+    // Draw cursor
+    if (editMode)
+    {
+        // NOTE: ValueBox internal text is always centered
+        Rectangle cursor = { bounds.x + GetTextWidth(textValue) / 2.0f + bounds.width / 2.0f + 1, bounds.y + 2.0f * GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4, bounds.height - 4 * GuiGetStyle(VALUEBOX, BORDER_WIDTH) };
+        GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)), guiAlpha));
+    }
+
+    // Draw text label if provided
+    GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT) ? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state * 3))), guiAlpha));
+    //--------------------------------------------------------------------
+
+    return result;
+}

+ 470 - 0
gui.mod/raygui/examples/custom_sliders/custom_sliders.c

@@ -0,0 +1,470 @@
+/*******************************************************************************************
+*
+*   raygui - custom sliders
+*
+*   DEPENDENCIES:
+*       raylib 4.0  - Windowing/input management and drawing.
+*       raygui 3.0  - Immediate-mode GUI controls.
+*
+*   COMPILATION (Windows - MinGW):
+*       gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
+*
+*   LICENSE: zlib/libpng
+*
+*   Copyright (c) 2016-2024 Ramon Santamaria (@raysan5)
+*
+**********************************************************************************************/
+
+#include "raylib.h"
+
+#define RAYGUI_IMPLEMENTATION
+#include "../../src/raygui.h"
+
+//----------------------------------------------------------------------------------
+// Controls Functions Declaration
+//----------------------------------------------------------------------------------
+float GuiVerticalSlider(Rectangle bounds, const char *textTop, const char *textBottom, float value, float minValue, float maxValue);
+float GuiVerticalSliderBar(Rectangle bounds, const char *textTop, const char *textBottom, float value, float minValue, float maxValue);
+float GuiVerticalSliderPro(Rectangle bounds, const char *textTop, const char *textBottom, float value, float minValue, float maxValue, int sliderHeight);
+
+bool GuiSliderOwning(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue, bool editMode);
+bool GuiSliderBarOwning(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue, bool editMode);
+bool GuiSliderProOwning(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue, int sliderWidth, bool editMode);
+
+bool GuiVerticalSliderOwning(Rectangle bounds, const char *textTop, const char *textBottom, float *value, float minValue, float maxValue, bool editMode);
+bool GuiVerticalSliderBarOwning(Rectangle bounds, const char *textTop, const char *textBottom, float *value, float minValue, float maxValue, bool editMode);
+bool GuiVerticalSliderProOwning(Rectangle bounds, const char *textTop, const char *textBottom, float *value, float minValue, float maxValue, int sliderHeight, bool editMode);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main()
+{
+    // Initialization
+    //---------------------------------------------------------------------------------------
+    int screenWidth = 800;
+    int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raygui - custom sliders");
+
+    float value = 0.5f;
+    bool sliderEditMode = false;
+    bool vSliderEditMode = false;
+    bool vSliderBarEditMode = false;
+
+    SetTargetFPS(60);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        // TODO: Implement required update logic
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));
+
+            if (vSliderEditMode || vSliderBarEditMode) GuiLock();
+            else GuiUnlock();
+
+            // raygui: controls drawing
+            //----------------------------------------------------------------------------------
+            GuiGroupBox((Rectangle){ 66, 24, 276, 312 }, "STANDARD");
+            GuiSlider((Rectangle){ 96, 48, 216, 16 }, TextFormat("%0.2f", value), NULL, &value, 0.0f, 1.0f);
+            value = GuiVerticalSlider((Rectangle){ 120, 120, 24, 192 }, TextFormat("%0.2f", value), NULL, value, 0.0f, 1.0f);
+            value = GuiVerticalSliderBar((Rectangle){ 264, 120, 24, 192 }, TextFormat("%0.2f", value), NULL, value, 0.0f, 1.0f);
+
+            GuiGroupBox((Rectangle){ 378, 24, 276, 312 }, "OWNING");
+            if (GuiSliderOwning((Rectangle){ 408, 48, 216, 16 }, NULL, TextFormat("%0.2f", value), &value, 0.0f, 1.0f, sliderEditMode)) sliderEditMode = !sliderEditMode;
+            if (GuiVerticalSliderOwning((Rectangle){ 432, 120, 24, 192 }, NULL, TextFormat("%0.2f", value), &value, 0.0f, 1.0f, vSliderEditMode)) vSliderEditMode = !vSliderEditMode;
+            if (GuiVerticalSliderBarOwning((Rectangle){ 576, 120, 24, 192 }, NULL, TextFormat("%0.2f", value), &value, 0.0f, 1.0f, vSliderBarEditMode)) vSliderBarEditMode = !vSliderBarEditMode;
+            //----------------------------------------------------------------------------------
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseWindow();        // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
+
+//------------------------------------------------------------------------------------
+// Controls Functions Definitions (local)
+//------------------------------------------------------------------------------------
+float GuiVerticalSliderPro(Rectangle bounds, const char *textTop, const char *textBottom, float value, float minValue, float maxValue, int sliderHeight)
+{
+    GuiState state = (GuiState)GuiGetState();
+
+    int sliderValue = (int)(((value - minValue)/(maxValue - minValue)) * (bounds.height - 2 * GuiGetStyle(SLIDER, BORDER_WIDTH)));
+
+    Rectangle slider = {
+        bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING),
+        bounds.y + bounds.height - sliderValue,
+        bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING),
+        0.0f,
+    };
+
+    if (sliderHeight > 0)        // Slider
+    {
+        slider.y -= sliderHeight/2;
+        slider.height = (float)sliderHeight;
+    }
+    else if (sliderHeight == 0)  // SliderBar
+    {
+        slider.y -= GuiGetStyle(SLIDER, BORDER_WIDTH);
+        slider.height = (float)sliderValue;
+    }
+    // Update control
+    //--------------------------------------------------------------------
+    if ((state != STATE_DISABLED) && !guiLocked)
+    {
+        Vector2 mousePoint = GetMousePosition();
+
+        if (CheckCollisionPointRec(mousePoint, bounds))
+        {
+            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+            {
+                state = STATE_PRESSED;
+
+                // Get equivalent value and slider position from mousePoint.x
+                float normalizedValue = (bounds.y + bounds.height - mousePoint.y - (float)(sliderHeight / 2)) / (bounds.height - (float)sliderHeight);
+                value = (maxValue - minValue) * normalizedValue + minValue;
+
+                if (sliderHeight > 0) slider.y = mousePoint.y - slider.height / 2;  // Slider
+                else if (sliderHeight == 0)                                          // SliderBar
+                {
+                    slider.y = mousePoint.y;
+                    slider.height = bounds.y + bounds.height - slider.y - GuiGetStyle(SLIDER, BORDER_WIDTH);
+                }
+            }
+            else state = STATE_FOCUSED;
+        }
+
+        if (value > maxValue) value = maxValue;
+        else if (value < minValue) value = minValue;
+    }
+
+
+    // Bar limits check
+    if (sliderHeight > 0)        // Slider
+    {
+        if (slider.y < (bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.y = bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH);
+        else if ((slider.y + slider.height) >= (bounds.y + bounds.height)) slider.y = bounds.y + bounds.height - slider.height - GuiGetStyle(SLIDER, BORDER_WIDTH);
+    }
+    else if (sliderHeight == 0)  // SliderBar
+    {
+        if (slider.y < (bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH)))
+        {
+            slider.y = bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH);
+            slider.height = bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH);
+        }
+    }
+
+    //--------------------------------------------------------------------
+    // Draw control
+    //--------------------------------------------------------------------
+    GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(SLIDER, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(SLIDER, (state != STATE_DISABLED)?  BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)), guiAlpha));
+
+    // Draw slider internal bar (depends on state)
+    if ((state == STATE_NORMAL) || (state == STATE_PRESSED)) GuiDrawRectangle(slider, 0, BLANK, Fade(GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)), guiAlpha));
+    else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, Fade(GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED)), guiAlpha));
+
+    // Draw top/bottom text if provided
+    if (textTop != NULL)
+    {
+        Rectangle textBounds = { 0 };
+        textBounds.width = (float)GetTextWidth(textTop);
+        textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+        textBounds.x = bounds.x + bounds.width/2 - textBounds.width/2;
+        textBounds.y = bounds.y - textBounds.height - GuiGetStyle(SLIDER, TEXT_PADDING);
+
+        GuiDrawText(textTop, textBounds, TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))), guiAlpha));
+    }
+
+    if (textBottom != NULL)
+    {
+        Rectangle textBounds = { 0 };
+        textBounds.width = (float)GetTextWidth(textBottom);
+        textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+        textBounds.x = bounds.x + bounds.width/2 - textBounds.width/2;
+        textBounds.y = bounds.y + bounds.height + GuiGetStyle(SLIDER, TEXT_PADDING);
+
+        GuiDrawText(textBottom, textBounds, TEXT_ALIGN_LEFT, Fade(GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))), guiAlpha));
+    }
+    //--------------------------------------------------------------------
+
+    return value;
+}
+
+float GuiVerticalSlider(Rectangle bounds, const char *textTop, const char *textBottom, float value, float minValue, float maxValue)
+{
+    return GuiVerticalSliderPro(bounds, textTop, textBottom, value, minValue, maxValue, GuiGetStyle(SLIDER, SLIDER_WIDTH));
+}
+
+float GuiVerticalSliderBar(Rectangle bounds, const char *textTop, const char *textBottom, float value, float minValue, float maxValue)
+{
+    return GuiVerticalSliderPro(bounds, textTop, textBottom, value, minValue, maxValue, 0);
+}
+
+bool GuiSliderProOwning(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue, int sliderWidth, bool editMode)
+{
+    GuiState state = (GuiState)GuiGetState();
+
+    float tempValue = *value;
+    bool pressed = false;
+
+    int sliderValue = (int)(((tempValue - minValue)/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH)));
+
+    Rectangle slider = {
+        bounds.x,
+        bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING),
+        0,
+        bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING)
+    };
+
+    if (sliderWidth > 0)        // Slider
+    {
+        slider.x += (sliderValue - sliderWidth/2);
+        slider.width = (float)sliderWidth;
+    }
+    else if (sliderWidth == 0)  // SliderBar
+    {
+        slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH);
+        slider.width = (float)sliderValue;
+    }
+
+    // Update control
+    //--------------------------------------------------------------------
+    if ((state != STATE_DISABLED) && (editMode || !guiLocked))
+    {
+        Vector2 mousePoint = GetMousePosition();
+
+        if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+        {
+            if (CheckCollisionPointRec(mousePoint, bounds))
+            {
+                pressed = true;
+            }
+        }
+        else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON) && editMode)
+        {
+            pressed = true;
+        }
+        if (editMode)
+        {
+            state = STATE_PRESSED;
+            tempValue = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue;
+
+            if (sliderWidth > 0) slider.x = mousePoint.x - slider.width/2;  // Slider
+            else if (sliderWidth == 0) slider.width = (float)sliderValue;          // SliderBar
+
+        }
+        else if (CheckCollisionPointRec(mousePoint, bounds))
+        {
+            state = STATE_FOCUSED;
+        }
+
+        if (tempValue > maxValue) tempValue = maxValue;
+        else if (tempValue < minValue) tempValue = minValue;
+    }
+
+
+    // Bar limits check
+    if (sliderWidth > 0)        // Slider
+    {
+        if (slider.x <= (bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH);
+        else if ((slider.x + slider.width) >= (bounds.x + bounds.width)) slider.x = bounds.x + bounds.width - slider.width - GuiGetStyle(SLIDER, BORDER_WIDTH);
+    }
+    else if (sliderWidth == 0)  // SliderBar
+    {
+        if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH);
+    }
+
+    //--------------------------------------------------------------------
+    // Draw control
+    //--------------------------------------------------------------------
+    GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(SLIDER, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(SLIDER, (state != STATE_DISABLED)?  BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)), guiAlpha));
+
+    // Draw slider internal bar (depends on state)
+    if ((state == STATE_NORMAL) || (state == STATE_PRESSED))
+        GuiDrawRectangle(slider, 0, BLANK, Fade(GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)), guiAlpha));
+    else if (state == STATE_FOCUSED)
+        GuiDrawRectangle(slider, 0, BLANK, Fade(GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED)), guiAlpha));
+
+    // Draw left/right text if provided
+    if (textLeft != NULL)
+    {
+        Rectangle textBounds = { 0 };
+        textBounds.width = (float)GetTextWidth(textLeft);
+        textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+        textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SLIDER, TEXT_PADDING);
+        textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+
+        GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))), guiAlpha));
+    }
+
+    if (textRight != NULL)
+    {
+        Rectangle textBounds = { 0 };
+        textBounds.width = (float)GetTextWidth(textRight);
+        textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+        textBounds.x = bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING);
+        textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+
+        GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, Fade(GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))), guiAlpha));
+    }
+    //--------------------------------------------------------------------
+
+    *value = tempValue;
+    return pressed;
+}
+
+bool GuiSliderOwning(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue, bool editMode)
+{
+    return GuiSliderProOwning(bounds, textLeft, textRight, value, minValue, maxValue, GuiGetStyle(SLIDER, SLIDER_WIDTH), editMode);
+}
+
+bool GuiSliderBarOwning(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue, bool editMode)
+{
+    return GuiSliderProOwning(bounds, textLeft, textRight, value, minValue, maxValue, 0, editMode);
+}
+
+bool GuiVerticalSliderProOwning(Rectangle bounds, const char *textTop, const char *textBottom, float *value, float minValue, float maxValue, int sliderHeight, bool editMode)
+{
+    GuiState state = (GuiState)GuiGetState();
+
+    float tempValue = *value;
+    bool pressed = false;
+
+    int sliderValue = (int)(((tempValue - minValue)/(maxValue - minValue)) * (bounds.height - 2 * GuiGetStyle(SLIDER, BORDER_WIDTH)));
+
+    Rectangle slider = {
+        bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING),
+        bounds.y + bounds.height - sliderValue,
+        bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING),
+        0.0f,
+    };
+
+    if (sliderHeight > 0)        // Slider
+    {
+        slider.y -= sliderHeight/2;
+        slider.height = (float)sliderHeight;
+    }
+    else if (sliderHeight == 0)  // SliderBar
+    {
+        slider.y -= GuiGetStyle(SLIDER, BORDER_WIDTH);
+        slider.height = (float)sliderValue;
+    }
+    // Update control
+    //--------------------------------------------------------------------
+    if ((state != STATE_DISABLED) && (editMode || !guiLocked))
+    {
+        Vector2 mousePoint = GetMousePosition();
+
+        if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+        {
+            if (CheckCollisionPointRec(mousePoint, bounds))
+            {
+                pressed = true;
+            }
+        }
+        else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON) && editMode)
+        {
+            pressed = true;
+        }
+        if (editMode)
+        {
+            state = STATE_PRESSED;
+
+            float normalizedValue = (bounds.y + bounds.height - mousePoint.y - (float)(sliderHeight / 2)) / (bounds.height - (float)sliderHeight);
+            tempValue = (maxValue - minValue) * normalizedValue + minValue;
+
+            if (sliderHeight > 0) slider.y = mousePoint.y - slider.height / 2;  // Slider
+            else if (sliderHeight == 0)                                          // SliderBar
+            {
+                slider.y = mousePoint.y;
+                slider.height = bounds.y + bounds.height - slider.y - GuiGetStyle(SLIDER, BORDER_WIDTH);
+            }
+        }
+        else if (CheckCollisionPointRec(mousePoint, bounds))
+        {
+            state = STATE_FOCUSED;
+        }
+
+        if (tempValue > maxValue) tempValue = maxValue;
+        else if (tempValue < minValue) tempValue = minValue;
+    }
+
+
+    // Bar limits check
+    if (sliderHeight > 0)        // Slider
+    {
+        if (slider.y < (bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.y = bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH);
+        else if ((slider.y + slider.height) >= (bounds.y + bounds.height)) slider.y = bounds.y + bounds.height - slider.height - GuiGetStyle(SLIDER, BORDER_WIDTH);
+    }
+    else if (sliderHeight == 0)  // SliderBar
+    {
+        if (slider.y < (bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH)))
+        {
+            slider.y = bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH);
+            slider.height = bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH);
+        }
+    }
+
+    //--------------------------------------------------------------------
+    // Draw control
+    //--------------------------------------------------------------------
+    GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(SLIDER, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(SLIDER, (state != STATE_DISABLED)?  BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)), guiAlpha));
+
+    // Draw slider internal bar (depends on state)
+    if ((state == STATE_NORMAL) || (state == STATE_PRESSED))
+        GuiDrawRectangle(slider, 0, BLANK, Fade(GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)), guiAlpha));
+    else if (state == STATE_FOCUSED)
+        GuiDrawRectangle(slider, 0, BLANK, Fade(GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED)), guiAlpha));
+
+    // Draw top/bottom text if provided
+    if (textTop != NULL)
+    {
+        Rectangle textBounds = { 0 };
+        textBounds.width = (float)GetTextWidth(textTop);
+        textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+        textBounds.x = bounds.x + bounds.width/2 - textBounds.width/2;
+        textBounds.y = bounds.y - textBounds.height - GuiGetStyle(SLIDER, TEXT_PADDING);
+
+        GuiDrawText(textTop, textBounds, TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))), guiAlpha));
+    }
+
+    if (textBottom != NULL)
+    {
+        Rectangle textBounds = { 0 };
+        textBounds.width = (float)GetTextWidth(textBottom);
+        textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+        textBounds.x = bounds.x + bounds.width/2 - textBounds.width/2;
+        textBounds.y = bounds.y + bounds.height + GuiGetStyle(SLIDER, TEXT_PADDING);
+
+        GuiDrawText(textBottom, textBounds, TEXT_ALIGN_LEFT, Fade(GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))), guiAlpha));
+    }
+    //--------------------------------------------------------------------
+
+    *value = tempValue;
+    return pressed;
+}
+
+bool GuiVerticalSliderOwning(Rectangle bounds, const char *textTop, const char *textBottom, float *value, float minValue, float maxValue, bool editMode)
+{
+    return GuiVerticalSliderProOwning(bounds, textTop, textBottom, value, minValue, maxValue, GuiGetStyle(SLIDER, SLIDER_WIDTH), editMode);
+}
+
+bool GuiVerticalSliderBarOwning(Rectangle bounds, const char *textTop, const char *textBottom, float *value, float minValue, float maxValue, bool editMode)
+{
+    return GuiVerticalSliderProOwning(bounds, textTop, textBottom, value, minValue, maxValue, 0, editMode);
+}

+ 148 - 0
gui.mod/raygui/examples/floating_window/floating_window.c

@@ -0,0 +1,148 @@
+#include "raylib.h"
+
+#define RAYGUI_IMPLEMENTATION
+#include "../../src/raygui.h"
+
+#include "../../styles/dark/style_dark.h"
+
+static Vector2 window_position = { 10, 10 };
+static Vector2 window_size = { 200, 400 };
+static bool minimized = false;
+static bool moving = false;
+static bool resizing = false;
+static Vector2 scroll;
+
+static Vector2 window2_position = { 250, 10 };
+static Vector2 window2_size = { 200, 400 };
+static bool minimized2 = false;
+static bool moving2 = false;
+static bool resizing2 = false;
+static Vector2 scroll2;
+
+void GuiWindowFloating(Vector2 *position, Vector2 *size, bool *minimized, bool *moving, bool *resizing, void (*draw_content)(Vector2, Vector2), Vector2 content_size, Vector2 *scroll, const char* title) {
+    #if !defined(RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT)
+        #define RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT 24
+    #endif
+
+    #if !defined(RAYGUI_WINDOW_CLOSEBUTTON_SIZE)
+        #define RAYGUI_WINDOW_CLOSEBUTTON_SIZE 18
+    #endif
+
+    int close_title_size_delta_half = (RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - RAYGUI_WINDOW_CLOSEBUTTON_SIZE) / 2;
+
+    // window movement and resize input and collision check
+    if(IsMouseButtonPressed(MOUSE_LEFT_BUTTON) && !*moving && !*resizing) {
+        Vector2 mouse_position = GetMousePosition();
+
+        Rectangle title_collision_rect = { position->x, position->y, size->x - (RAYGUI_WINDOW_CLOSEBUTTON_SIZE + close_title_size_delta_half), RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT };
+        Rectangle resize_collision_rect = { position->x + size->x - 20, position->y + size->y - 20, 20, 20 };
+
+        if(CheckCollisionPointRec(mouse_position, title_collision_rect)) {
+            *moving = true;
+        } else if(!*minimized && CheckCollisionPointRec(mouse_position, resize_collision_rect)) {
+            *resizing = true;
+        }
+    }
+
+    // window movement and resize update
+    if(*moving) {
+        Vector2 mouse_delta = GetMouseDelta();
+        position->x += mouse_delta.x;
+        position->y += mouse_delta.y;
+
+        if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) {
+            *moving = false;
+
+            // clamp window position keep it inside the application area
+            if(position->x < 0) position->x = 0;
+            else if(position->x > GetScreenWidth() - size->x) position->x = GetScreenWidth() - size->x;
+            if(position->y < 0) position->y = 0;
+            else if(position->y > GetScreenHeight()) position->y = GetScreenHeight() - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT;
+        }
+
+    } else if(*resizing) {
+        Vector2 mouse = GetMousePosition();
+        if (mouse.x > position->x)
+            size->x = mouse.x - position->x;
+        if (mouse.y > position->y)
+            size->y = mouse.y - position->y;
+
+        // clamp window size to an arbitrary minimum value and the window size as the maximum
+        if(size->x < 100) size->x = 100;
+        else if(size->x > GetScreenWidth()) size->x = GetScreenWidth();
+        if(size->y < 100) size->y = 100;
+        else if(size->y > GetScreenHeight()) size->y = GetScreenHeight();
+
+        if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) {
+            *resizing = false;
+        }
+    }
+
+    // window and content drawing with scissor and scroll area
+    if(*minimized) {
+        GuiStatusBar((Rectangle){ position->x, position->y, size->x, RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT }, title);
+
+        if (GuiButton((Rectangle){ position->x + size->x - RAYGUI_WINDOW_CLOSEBUTTON_SIZE - close_title_size_delta_half,
+                                   position->y + close_title_size_delta_half,
+                                   RAYGUI_WINDOW_CLOSEBUTTON_SIZE,
+                                   RAYGUI_WINDOW_CLOSEBUTTON_SIZE },
+                                   "#120#")) {
+            *minimized = false;
+        }
+
+    } else {
+        *minimized = GuiWindowBox((Rectangle) { position->x, position->y, size->x, size->y }, title);
+
+        // scissor and draw content within a scroll panel
+        if(draw_content != NULL) {
+            Rectangle scissor = { 0 };
+            GuiScrollPanel((Rectangle) { position->x, position->y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT, size->x, size->y - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT },
+                                         NULL,
+                                         (Rectangle) { position->x, position->y, content_size.x, content_size.y },
+                                         scroll,
+                                         &scissor);
+
+            bool require_scissor = size->x < content_size.x || size->y < content_size.y;
+
+            if(require_scissor) {
+                BeginScissorMode(scissor.x, scissor.y, scissor.width, scissor.height);
+            }
+
+            draw_content(*position, *scroll);
+
+            if(require_scissor) {
+                EndScissorMode();
+            }
+        }
+
+        // draw the resize button/icon
+        GuiDrawIcon(71, position->x + size->x - 20, position->y + size->y - 20, 1, WHITE);
+    }
+}
+
+static void DrawContent(Vector2 position, Vector2 scroll) {
+    GuiButton((Rectangle) { position.x + 20 + scroll.x, position.y + 50  + scroll.y, 100, 25 }, "Button 1");
+    GuiButton((Rectangle) { position.x + 20 + scroll.x, position.y + 100 + scroll.y, 100, 25 }, "Button 2");
+    GuiButton((Rectangle) { position.x + 20 + scroll.x, position.y + 150 + scroll.y, 100, 25 }, "Button 3");
+    GuiLabel((Rectangle) { position.x + 20 + scroll.x, position.y + 200 + scroll.y, 250, 25 }, "A Label");
+    GuiLabel((Rectangle) { position.x + 20 + scroll.x, position.y + 250 + scroll.y, 250, 25 }, "Another Label");
+    GuiLabel((Rectangle) { position.x + 20 + scroll.x, position.y + 300 + scroll.y, 250, 25 }, "Yet Another Label");
+}
+
+int main(void) {
+    InitWindow(960, 560, "raygui - floating window example");
+    SetTargetFPS(60);
+    GuiLoadStyleDark();
+
+    while(!WindowShouldClose()) {
+        BeginDrawing();
+            ClearBackground(DARKGREEN);
+            GuiWindowFloating(&window_position, &window_size, &minimized, &moving, &resizing, &DrawContent, (Vector2) { 140, 320 }, &scroll, "Movable & Scalable Window");
+            GuiWindowFloating(&window2_position, &window2_size, &minimized2, &moving2, &resizing2, &DrawContent, (Vector2) { 140, 320 }, &scroll2, "Another window");
+        EndDrawing();
+    }
+
+    CloseWindow();
+
+    return 0;
+}

+ 21 - 24
gui.mod/raygui/examples/image_exporter/image_exporter.c

@@ -3,29 +3,27 @@
 *   raygui - image exporter
 *
 *   DEPENDENCIES:
-*       raylib 2.1  - Windowing/input management and drawing.
-*       raygui 2.0  - Immediate-mode GUI controls.
+*       raylib 4.0  - Windowing/input management and drawing.
+*       raygui 3.0  - Immediate-mode GUI controls.
 *
 *   COMPILATION (Windows - MinGW):
 *       gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
 *
 *   LICENSE: zlib/libpng
 *
-*   Copyright (c) 2019 raylib technologies (@raylibtech)
+*   Copyright (c) 2015-2024 Ramon Santamaria (@raysan5)
 *
 ********************************************************************************************/
 
 #include "raylib.h"
 
 #define RAYGUI_IMPLEMENTATION
-#define RAYGUI_SUPPORT_RICONS
 #include "../../src/raygui.h"
 
-
 //------------------------------------------------------------------------------------
 // Program main entry point
 //------------------------------------------------------------------------------------
-int main(int argc, char *argv[0])
+int main(int argc, char *argv[])
 {
     // Initialization
     //--------------------------------------------------------------------------------------
@@ -46,7 +44,7 @@ int main(int argc, char *argv[0])
     const char *pixelFormatTextList[7] = { "GRAYSCALE", "GRAY ALPHA", "R5G6B5", "R8G8B8", "R5G5B5A1", "R4G4B4A4", "R8G8B8A8" };
 
     bool textBoxEditMode = false;
-    char fileName[32] = "untitled";
+    char fileName[64] = "untitled";
     //--------------------------------------------------------------------------------------
     
     Image image = { 0 };
@@ -54,9 +52,9 @@ int main(int argc, char *argv[0])
     
     bool imageLoaded = false;
     float imageScale = 1.0f;
-    Rectangle imageRec = { 0.0f };
+    Rectangle imageRec = { 0 };
     
-    bool btnExport = false;
+    bool btnExportPressed = false;
 
     SetTargetFPS(60);
     //--------------------------------------------------------------------------------------
@@ -68,12 +66,11 @@ int main(int argc, char *argv[0])
         //----------------------------------------------------------------------------------
         if (IsFileDropped())
         {
-            int fileCount = 0;
-            char **droppedFiles = GetDroppedFiles(&fileCount);
+            FilePathList droppedFiles = LoadDroppedFiles();
 
-            if (fileCount == 1)
+            if (droppedFiles.count == 1)
             {
-                Image imTemp = LoadImage(droppedFiles[0]);
+                Image imTemp = LoadImage(droppedFiles.paths[0]);
                 
                 if (imTemp.data != NULL)
                 {
@@ -91,10 +88,10 @@ int main(int argc, char *argv[0])
                 }
             }
 
-            ClearDroppedFiles();
+            UnloadDroppedFiles(droppedFiles);
         }
     
-        if (btnExport)
+        if (btnExportPressed)
         {
             if (imageLoaded)
             {
@@ -102,17 +99,17 @@ int main(int argc, char *argv[0])
                 
                 if (fileFormatActive == 0)        // PNG
                 {
-                    if ((GetExtension(fileName) == NULL) || (!IsFileExtension(fileName, ".png"))) strcat(fileName, ".png\0");     // No extension provided
+                    if ((GetFileExtension(fileName) == NULL) || (!IsFileExtension(fileName, ".png"))) strcat(fileName, ".png\0");     // No extension provided
                     ExportImage(image, fileName);
                 }
                 else if (fileFormatActive == 1)   // RAW
                 {
-                    if ((GetExtension(fileName) == NULL) || (!IsFileExtension(fileName, ".raw"))) strcat(fileName, ".raw\0");     // No extension provided
+                    if ((GetFileExtension(fileName) == NULL) || (!IsFileExtension(fileName, ".raw"))) strcat(fileName, ".raw\0");     // No extension provided
                     
                     int dataSize = GetPixelDataSize(image.width, image.height, image.format);
                     
                     FILE *rawFile = fopen(fileName, "wb");  
-                    fwrite(image.data, dataSize, 1, rawFile);
+                    fwrite(image.data, 1, dataSize, rawFile);
                     fclose(rawFile);
                 }
                 else if (fileFormatActive == 2)   // CODE
@@ -147,7 +144,7 @@ int main(int argc, char *argv[0])
                 DrawTextureEx(texture, (Vector2){ screenWidth/2 - (float)texture.width*imageScale/2, screenHeight/2 - (float)texture.height*imageScale/2 }, 0.0f, imageScale, WHITE);
                 
                 DrawRectangleLinesEx(imageRec, 1, CheckCollisionPointRec(GetMousePosition(), imageRec) ? RED : DARKGRAY); 
-                DrawText(FormatText("SCALE: %.2f%%", imageScale*100.0f), 20, screenHeight - 40, 20, GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)));
+                DrawText(TextFormat("SCALE: %.2f%%", imageScale*100.0f), 20, screenHeight - 40, 20, GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)));
             }
             else
             {
@@ -166,17 +163,17 @@ int main(int argc, char *argv[0])
                 windowBoxActive = !GuiWindowBox((Rectangle){ windowBoxRec.x, windowBoxRec.y, 220, 190 }, "Image Export Options");
             
                 GuiLabel((Rectangle){ windowBoxRec.x + 10, windowBoxRec.y + 35, 60, 25 }, "File format:");
-                fileFormatActive = GuiComboBox((Rectangle){ windowBoxRec.x + 80, windowBoxRec.y + 35, 130, 25 }, TextJoin(fileFormatTextList, 3, ";"), fileFormatActive); 
+                GuiComboBox((Rectangle){ windowBoxRec.x + 80, windowBoxRec.y + 35, 130, 25 }, TextJoin(fileFormatTextList, 3, ";"), &fileFormatActive); 
                 GuiLabel((Rectangle){ windowBoxRec.x + 10, windowBoxRec.y + 70, 63, 25 }, "Pixel format:");
-                pixelFormatActive = GuiComboBox((Rectangle){ windowBoxRec.x + 80, windowBoxRec.y + 70, 130, 25 }, TextJoin(pixelFormatTextList, 7, ";"), pixelFormatActive); 
+                GuiComboBox((Rectangle){ windowBoxRec.x + 80, windowBoxRec.y + 70, 130, 25 }, TextJoin(pixelFormatTextList, 7, ";"), &pixelFormatActive); 
                 GuiLabel((Rectangle){ windowBoxRec.x + 10, windowBoxRec.y + 105, 50, 25 }, "File name:");
                 if (GuiTextBox((Rectangle){ windowBoxRec.x + 80, windowBoxRec.y + 105, 130, 25 }, fileName, 64, textBoxEditMode)) textBoxEditMode = !textBoxEditMode;
 
-                btnExport = GuiButton((Rectangle){ windowBoxRec.x + 10, windowBoxRec.y + 145, 200, 30 }, "Export Image");
+                btnExportPressed = GuiButton((Rectangle){ windowBoxRec.x + 10, windowBoxRec.y + 145, 200, 30 }, "Export Image");
             }
-            else btnExport = false;
+            else btnExportPressed = false;
             
-            if (btnExport) DrawText("Image exported!", 20, screenHeight - 20, 20, RED);
+            if (btnExportPressed) DrawText("Image exported!", 20, screenHeight - 20, 20, RED);
             //-----------------------------------------------------------------------------
 
         EndDrawing();

+ 0 - 0
gui.mod/raygui/examples/image_raw_importer/design/raw_importer_REF.png → gui.mod/raygui/examples/image_importer_raw/design/raw_importer_REF.png


+ 0 - 0
gui.mod/raygui/examples/image_raw_importer/design/raw_importer_REV0.png → gui.mod/raygui/examples/image_importer_raw/design/raw_importer_REV0.png


+ 0 - 0
gui.mod/raygui/examples/image_raw_importer/design/raw_importer_REV1.png → gui.mod/raygui/examples/image_importer_raw/design/raw_importer_REV1.png


+ 0 - 0
gui.mod/raygui/examples/image_raw_importer/design/raw_importer_REV2.png → gui.mod/raygui/examples/image_importer_raw/design/raw_importer_REV2.png


+ 0 - 0
gui.mod/raygui/examples/image_raw_importer/design/raw_importer_REV3.png → gui.mod/raygui/examples/image_importer_raw/design/raw_importer_REV3.png


+ 0 - 0
gui.mod/raygui/examples/image_raw_importer/design/raw_importer_REV4.png → gui.mod/raygui/examples/image_importer_raw/design/raw_importer_REV4.png


+ 0 - 0
gui.mod/raygui/examples/image_raw_importer/design/raw_importer_REV5.png → gui.mod/raygui/examples/image_importer_raw/design/raw_importer_REV5.png


+ 0 - 0
gui.mod/raygui/examples/image_raw_importer/image_2x2_RGBA.raw → gui.mod/raygui/examples/image_importer_raw/image_2x2_RGBA.raw


+ 21 - 23
gui.mod/raygui/examples/image_raw_importer/image_raw_importer.c → gui.mod/raygui/examples/image_importer_raw/image_importer_raw.c

@@ -3,22 +3,21 @@
 *   raygui - image raw importer
 *
 *   DEPENDENCIES:
-*       raylib 2.1  - Windowing/input management and drawing.
-*       raygui 2.0  - Immediate-mode GUI controls.
+*       raylib 4.0  - Windowing/input management and drawing.
+*       raygui 3.0  - Immediate-mode GUI controls.
 *
 *   COMPILATION (Windows - MinGW):
 *       gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
 *
 *   LICENSE: zlib/libpng
 *
-*   Copyright (c) 2019 raylib technologies (@raylibtech)
+*   Copyright (c) 2015-2024 Ramon Santamaria (@raysan5)
 *
 **********************************************************************************************/
 
 #include "raylib.h"
 
 #define RAYGUI_IMPLEMENTATION
-#define RAYGUI_SUPPORT_RICONS
 #include "../../src/raygui.h"
 
 #include <string.h>             // Required for: strcpy()
@@ -83,21 +82,20 @@ int main()
         // Check if a file is dropped
         if (IsFileDropped())
         {
-            int fileCount = 0;
-            char **droppedFiles = GetDroppedFiles(&fileCount);
+            FilePathList droppedFiles = LoadDroppedFiles();
 
             // Check file extensions for drag-and-drop
-            if ((fileCount == 1) && IsFileExtension(droppedFiles[0], ".raw"))
+            if ((droppedFiles.count == 1) && IsFileExtension(droppedFiles.paths[0], ".raw"))
             {
-                FILE *imageFile = fopen(droppedFiles[0], "rb");
+                FILE *imageFile = fopen(droppedFiles.paths[0], "rb");
                 fseek(imageFile, 0L, SEEK_END);
                 dataSize = ftell(imageFile);
                 fclose(imageFile);
                 
                 // NOTE: Returned string is just a pointer to droppedFiles[0],
                 // we need to make a copy of that data somewhere else: fileName
-                strcpy(fileNamePath, droppedFiles[0]);
-                strcpy(fileName, GetFileName(droppedFiles[0]));
+                strcpy(fileNamePath, droppedFiles.paths[0]);
+                strcpy(fileName, GetFileName(droppedFiles.paths[0]));
                 
                 // Try to guess possible raw values
                 // Let's assume image is square, RGBA, 8 bit per channel
@@ -109,7 +107,7 @@ int main()
                 importWindowActive = true;
             }
 
-            ClearDroppedFiles();
+            UnloadDroppedFiles(droppedFiles);
         }
         
         // Check if load button has been pressed
@@ -128,17 +126,17 @@ int main()
                     // Select correct format depending on channels and bpp
                     if (bpp == 8)
                     {
-                        if (channels == 1) format = UNCOMPRESSED_GRAYSCALE;
-                        else if (channels == 2) format = UNCOMPRESSED_GRAY_ALPHA;
-                        else if (channels == 3) format = UNCOMPRESSED_R8G8B8;
-                        else if (channels == 4) format = UNCOMPRESSED_R8G8B8A8;
+                        if (channels == 1) format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
+                        else if (channels == 2) format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA;
+                        else if (channels == 3) format = PIXELFORMAT_UNCOMPRESSED_R8G8B8;
+                        else if (channels == 4) format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
                     }
                     else if (bpp == 32)
                     {
-                        if (channels == 1) format = UNCOMPRESSED_R32;
+                        if (channels == 1) format = PIXELFORMAT_UNCOMPRESSED_R32;
                         else if (channels == 2) TraceLog(LOG_WARNING, "Channel bit-depth not supported!");
-                        else if (channels == 3) format = UNCOMPRESSED_R32G32B32;
-                        else if (channels == 4) format = UNCOMPRESSED_R32G32B32A32;
+                        else if (channels == 3) format = PIXELFORMAT_UNCOMPRESSED_R32G32B32;
+                        else if (channels == 4) format = PIXELFORMAT_UNCOMPRESSED_R32G32B32A32;
                     }
                     else if (bpp == 16) TraceLog(LOG_WARNING, "Channel bit-depth not supported!");
                 }
@@ -174,7 +172,7 @@ int main()
             if (texture.id != 0) 
             {
                 DrawTextureEx(texture, (Vector2){ screenWidth/2 - texture.width*imageScale/2, screenHeight/2 - texture.height*imageScale/2 }, 0, imageScale, WHITE);
-                DrawText(FormatText("SCALE x%.0f", imageScale), 20, screenHeight - 40, 20, GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)));
+                DrawText(TextFormat("SCALE x%.0f", imageScale), 20, screenHeight - 40, 20, GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)));
             }
             else DrawText("drag & drop RAW image file", 320, 180, 10, GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)));
 
@@ -187,7 +185,7 @@ int main()
                 GuiLabel((Rectangle){ windowOffset.x + 10, windowOffset.y + 30, 65, 20 }, "Import file:");
                 GuiLabel((Rectangle){ windowOffset.x + 85, windowOffset.y + 30, 75, 20 }, fileName);
                 GuiLabel((Rectangle){ windowOffset.x + 10, windowOffset.y + 50, 65, 20 }, "File size:");
-                GuiLabel((Rectangle){ windowOffset.x + 85, windowOffset.y + 50, 75, 20 }, FormatText("%i bytes", dataSize));
+                GuiLabel((Rectangle){ windowOffset.x + 85, windowOffset.y + 50, 75, 20 }, TextFormat("%i bytes", dataSize));
                 GuiGroupBox((Rectangle){ windowOffset.x + 10, windowOffset.y + 85, 180, 80 }, "Resolution");
                 GuiLabel((Rectangle){ windowOffset.x + 20, windowOffset.y + 100, 33, 25 }, "Width:");
                 if (GuiValueBox((Rectangle){ windowOffset.x + 60, windowOffset.y + 100, 80, 25 }, NULL, &widthValue, 0, 8192, widthEditMode)) widthEditMode = !widthEditMode; 
@@ -196,14 +194,14 @@ int main()
                 if (GuiValueBox((Rectangle){ windowOffset.x + 60, windowOffset.y + 130, 80, 25 }, NULL, &heightValue, 0, 8192, heightEditMode)) heightEditMode = !heightEditMode; 
                 GuiLabel((Rectangle){ windowOffset.x + 145, windowOffset.y + 130, 30, 25 }, "pixels");
                 GuiGroupBox((Rectangle){ windowOffset.x + 10, windowOffset.y + 180, 180, 160 }, "Pixel Format");
-                pixelFormatActive = GuiComboBox((Rectangle){ windowOffset.x + 20, windowOffset.y + 195, 160, 25 }, TextJoin(pixelFormatTextList, 8, ";"), pixelFormatActive);
+                GuiComboBox((Rectangle){ windowOffset.x + 20, windowOffset.y + 195, 160, 25 }, TextJoin(pixelFormatTextList, 8, ";"), &pixelFormatActive);
                 GuiLine((Rectangle){ windowOffset.x + 20, windowOffset.y + 220, 160, 20 }, NULL);
                 
                 if (pixelFormatActive != 0) GuiDisable();
                 GuiLabel((Rectangle){ windowOffset.x + 20, windowOffset.y + 235, 50, 20 }, "Channels:");
-                channelsActive = GuiToggleGroup((Rectangle){ windowOffset.x + 20, windowOffset.y + 255, 156/4, 25 }, TextJoin(channelsTextList, 4, ";"), channelsActive);
+                GuiToggleGroup((Rectangle){ windowOffset.x + 20, windowOffset.y + 255, 156/4, 25 }, TextJoin(channelsTextList, 4, ";"), &channelsActive);
                 GuiLabel((Rectangle){ windowOffset.x + 20, windowOffset.y + 285, 50, 20 }, "Bit Depth:");
-                bitDepthActive = GuiToggleGroup((Rectangle){ windowOffset.x + 20, windowOffset.y + 305, 160/3, 25 }, TextJoin(bitDepthTextList, 3, ";"), bitDepthActive);
+                GuiToggleGroup((Rectangle){ windowOffset.x + 20, windowOffset.y + 305, 160/3, 25 }, TextJoin(bitDepthTextList, 3, ";"), &bitDepthActive);
                 GuiEnable();
                 
                 GuiGroupBox((Rectangle){ windowOffset.x + 10, windowOffset.y + 355, 180, 50 }, "Header");

+ 11 - 10
gui.mod/raygui/examples/portable_window/portable_window.c

@@ -3,15 +3,15 @@
 *   raygui - portable window
 *
 *   DEPENDENCIES:
-*       raylib 2.1  - Windowing/input management and drawing.
-*       raygui 2.0  - Immediate-mode GUI controls.
+*       raylib 4.0  - Windowing/input management and drawing.
+*       raygui 3.0  - Immediate-mode GUI controls.
 *
 *   COMPILATION (Windows - MinGW):
 *       gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
 *
 *   LICENSE: zlib/libpng
 *
-*   Copyright (c) 2019 raylib technologies (@raylibtech)
+*   Copyright (c) 2016-2024 Ramon Santamaria (@raysan5)
 *
 **********************************************************************************************/
 
@@ -27,8 +27,8 @@ int main()
 {
     // Initialization
     //---------------------------------------------------------------------------------------
-    int screenWidth = 800;
-    int screenHeight = 600;
+    const int screenWidth = 800;
+    const int screenHeight = 600;
     
     SetConfigFlags(FLAG_WINDOW_UNDECORATED);
     InitWindow(screenWidth, screenHeight, "raygui - portable window");
@@ -53,7 +53,7 @@ int main()
         //----------------------------------------------------------------------------------
         mousePosition = GetMousePosition();
         
-        if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+        if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) && !dragWindow)
         {
             if (CheckCollisionPointRec(mousePosition, (Rectangle){ 0, 0, screenWidth, 20 }))
             {
@@ -66,10 +66,10 @@ int main()
         {            
             windowPosition.x += (mousePosition.x - panOffset.x);
             windowPosition.y += (mousePosition.y - panOffset.y);
+
+            SetWindowPosition((int)windowPosition.x, (int)windowPosition.y);
             
             if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) dragWindow = false;
-
-            SetWindowPosition(windowPosition.x, windowPosition.y);
         }
         //----------------------------------------------------------------------------------
 
@@ -79,9 +79,10 @@ int main()
 
             ClearBackground(RAYWHITE);
 
-            exitWindow = GuiWindowBox((Rectangle){ 0, 0, screenWidth, screenHeight }, "PORTABLE WINDOW");
+            exitWindow = GuiWindowBox((Rectangle){ 0, 0, screenWidth, screenHeight }, "#198# PORTABLE WINDOW");
             
-            DrawText(FormatText("Mouse Position: [ %.0f, %.0f ]", mousePosition.x, mousePosition.y), 10, 40, 10, DARKGRAY);
+            DrawText(TextFormat("Mouse Position: [ %.0f, %.0f ]", mousePosition.x, mousePosition.y), 10, 40, 10, DARKGRAY);
+            DrawText(TextFormat("Window Position: [ %.0f, %.0f ]", windowPosition.x, windowPosition.y), 10, 60, 10, DARKGRAY);
 
         EndDrawing();
         //----------------------------------------------------------------------------------

+ 87 - 87
gui.mod/raygui/examples/property_list/dm_property_list.h

@@ -198,7 +198,7 @@ double GuiDMValueBox(Rectangle bounds, double value, double minValue, double max
     
     enum {cursorTimer = 6, maxChars = 31, textPadding = 2};
     
-    GuiControlState state = GuiGetState();
+    GuiState state = GuiGetState();
     
     // Make sure value is in range
     if(maxValue != minValue){
@@ -214,7 +214,7 @@ double GuiDMValueBox(Rectangle bounds, double value, double minValue, double max
     
     // Update control
     //--------------------------------------------------------------------
-    if ((state != GUI_STATE_DISABLED) && !guiLocked)
+    if ((state != STATE_DISABLED) && !guiLocked)
     {
         if (editMode)
         {
@@ -222,7 +222,7 @@ double GuiDMValueBox(Rectangle bounds, double value, double minValue, double max
             if(cursor > len) cursor = len;
             if(cursor < 0) cursor = 0;
             
-            state = GUI_STATE_PRESSED;
+            state = STATE_PRESSED;
             framesCounter++;
             
             if(IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && (framesCounter%cursorTimer == 0))) {
@@ -309,7 +309,7 @@ double GuiDMValueBox(Rectangle bounds, double value, double minValue, double max
         {
             if (CheckCollisionPointRec(GetMousePosition(), bounds))
             {
-                state = GUI_STATE_FOCUSED;
+                state = STATE_FOCUSED;
                 if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) framesCounter = 0;
             }
         }
@@ -326,7 +326,7 @@ double GuiDMValueBox(Rectangle bounds, double value, double minValue, double max
     int textWidth = GetTextWidth(textValue);
     if(textWidth > textBounds.width) textBounds.width = textWidth;
     
-    if (state == GUI_STATE_PRESSED)
+    if (state == STATE_PRESSED)
     {
         DrawRectangle(bounds.x + GuiGetStyle(VALUEBOX, BORDER_WIDTH), bounds.y + GuiGetStyle(VALUEBOX, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED)), guiAlpha));
 
@@ -345,12 +345,12 @@ double GuiDMValueBox(Rectangle bounds, double value, double minValue, double max
             DrawRectangle(bounds.x + textWidthCursor + (int)((bounds.width - textWidth - textPadding)/2.0f) + 2, bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 1, bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)), guiAlpha));
         }
     }
-    else if (state == GUI_STATE_DISABLED)
+    else if (state == STATE_DISABLED)
     {
         DrawRectangle(bounds.x + GuiGetStyle(VALUEBOX, BORDER_WIDTH), bounds.y + GuiGetStyle(VALUEBOX, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED)), guiAlpha));
     }
 
-    GuiDrawText(textValue, textBounds, GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3))), guiAlpha));
+    GuiDrawText(textValue, textBounds, TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3))), guiAlpha));
     
     value = valueHasChanged ? strtod(textValue, NULL) : value;
     
@@ -366,24 +366,24 @@ double GuiDMValueBox(Rectangle bounds, double value, double minValue, double max
 
 
 double GuiDMSpinner(Rectangle bounds, double value, double minValue, double maxValue, double step, int precision, bool editMode) {
-    GuiControlState state = GuiGetState();
+    GuiState state = GuiGetState();
 
-    Rectangle spinner = { bounds.x + GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_PADDING), bounds.y,
-                          bounds.width - 2*(GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_PADDING)), bounds.height };
+    Rectangle spinner = { bounds.x + GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_SPACING), bounds.y,
+                          bounds.width - 2*(GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_SPACING)), bounds.height };
     Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height };
     Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height };
     
     // Update control
     //--------------------------------------------------------------------
-    if ((state != GUI_STATE_DISABLED) && !guiLocked)
+    if ((state != STATE_DISABLED) && !guiLocked)
     {
         Vector2 mousePoint = GetMousePosition();
 
         // Check spinner state
         if (CheckCollisionPointRec(mousePoint, bounds))
         {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
-            else state = GUI_STATE_FOCUSED;
+            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+            else state = STATE_FOCUSED;
         }
     }
     //--------------------------------------------------------------------
@@ -396,9 +396,9 @@ double GuiDMSpinner(Rectangle bounds, double value, double minValue, double maxV
     int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
     int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
     GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(SPINNER, BORDER_WIDTH));
-    GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
+    GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
 
-#if defined(RAYGUI_SUPPORT_ICONS)
+#if defined(RAYGUI_SUPPORT_RICONS)
     if (GuiButton(leftButtonBound, GuiIconText(RICON_ARROW_LEFT_FILL, NULL))) value -= step;
     if (GuiButton(rightButtonBound, GuiIconText(RICON_ARROW_RIGHT_FILL, NULL))) value += step;
 #else
@@ -417,7 +417,7 @@ double GuiDMSpinner(Rectangle bounds, double value, double minValue, double maxV
 
 
 void GuiDMPropertyList(Rectangle bounds, GuiDMProperty* props, int count, int* focus, int* scrollIndex) {
-    #ifdef RAYGUI_SUPPORT_ICONS
+    #ifdef RAYGUI_SUPPORT_RICONS
     #define PROPERTY_COLLAPSED_ICON "#120#"
     #define PROPERTY_EXPANDED_ICON "#121#"
     #else
@@ -430,7 +430,7 @@ void GuiDMPropertyList(Rectangle bounds, GuiDMProperty* props, int count, int* f
     #define PROPERTY_DECIMAL_DIGITS 3  //how many digits to show (used only for the vector properties)
     
     // NOTE: Using ListView style for everything !!
-    GuiControlState state = GuiGetState();
+    GuiState state = GuiGetState();
     int propFocused = (focus == NULL)? -1 : *focus;
     int scroll = *scrollIndex > 0 ? 0 : *scrollIndex; // NOTE: scroll should always be negative or 0
     
@@ -457,9 +457,9 @@ void GuiDMPropertyList(Rectangle bounds, GuiDMProperty* props, int count, int* f
     Rectangle scrollBarBounds = {bounds.x + GuiGetStyle(LISTVIEW, BORDER_WIDTH), bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH),
                 GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH),  bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH)};
                 
-    absoluteBounds.x = bounds.x + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH);
-    absoluteBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + scroll;
-    absoluteBounds.width = bounds.width - 2*(GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH));
+    absoluteBounds.x = bounds.x + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH);
+    absoluteBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + scroll;
+    absoluteBounds.width = bounds.width - 2*(GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH));
     
     if(useScrollBar) {
         if(GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)
@@ -469,13 +469,13 @@ void GuiDMPropertyList(Rectangle bounds, GuiDMProperty* props, int count, int* f
         absoluteBounds.width -= GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH); // adjust width to fit the scrollbar
     }
     
-    int maxScroll = absoluteBounds.height + 2*(GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH))-bounds.height;
+    int maxScroll = absoluteBounds.height + 2*(GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH))-bounds.height;
     
     // Update control
     //--------------------------------------------------------------------
     Vector2 mousePos = GetMousePosition();
     // NOTE: most of the update code is actually done in the draw control section
-    if ((state != GUI_STATE_DISABLED) && !guiLocked) {
+    if ((state != STATE_DISABLED) && !guiLocked) {
         if(!CheckCollisionPointRec(mousePos, bounds)) {
             propFocused = -1;
         }
@@ -508,11 +508,11 @@ void GuiDMPropertyList(Rectangle bounds, GuiDMProperty* props, int count, int* f
             {
                 Rectangle propBounds = {absoluteBounds.x, absoluteBounds.y + currentHeight, absoluteBounds.width, height};
                 Color textColor = Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL)), guiAlpha);
-                int propState = GUI_STATE_NORMAL;
+                int propState = STATE_NORMAL;
                 
                 // Get the state of this property and do some initial drawing
                 if(PROP_CHECK_FLAG(&props[p], GUI_PFLAG_DISABLED)) { 
-                    propState = GUI_STATE_DISABLED;
+                    propState = STATE_DISABLED;
                     propBounds.height += 1; 
                     DrawRectangleRec(propBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)), guiAlpha));
                     propBounds.height -= 1;
@@ -520,78 +520,78 @@ void GuiDMPropertyList(Rectangle bounds, GuiDMProperty* props, int count, int* f
                 } else {
                     if(CheckCollisionPointRec(mousePos, propBounds) && !guiLocked) {
                         if(IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
-                            propState = GUI_STATE_PRESSED;
+                            propState = STATE_PRESSED;
                             //DrawRectangleRec(propRect, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)), guiAlpha));
                             textColor = Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)), guiAlpha);
                         } else { 
-                            propState = GUI_STATE_FOCUSED;
+                            propState = STATE_FOCUSED;
                             propFocused = p;
                             //DrawRectangleRec(propRect, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)), guiAlpha));
                             textColor = Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)), guiAlpha);
                         }
-                    } else propState = GUI_STATE_NORMAL; 
+                    } else propState = STATE_NORMAL; 
                 }
                 
-                if(propState == GUI_STATE_DISABLED) GuiSetState(propState);
+                if(propState == STATE_DISABLED) GuiSetState(propState);
                 switch(props[p].type) 
                 {
                     case GUI_PROP_BOOL: {
                         // draw property name
-                        GuiDrawText(props[p].name, (Rectangle){propBounds.x + PROPERTY_PADDING, propBounds.y, propBounds.width/2-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, GUI_TEXT_ALIGN_LEFT, textColor);
-                        if(propState == GUI_STATE_PRESSED) props[p].value.vbool = !props[p].value.vbool; // toggle the property value when clicked
+                        GuiDrawText(props[p].name, (Rectangle){propBounds.x + PROPERTY_PADDING, propBounds.y, propBounds.width/2-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, TEXT_ALIGN_LEFT, textColor);
+                        if(propState == STATE_PRESSED) props[p].value.vbool = !props[p].value.vbool; // toggle the property value when clicked
                         
                         // draw property value
                         const bool locked = guiLocked;
                         GuiLock(); // lock the checkbox since we changed the value manually
-                        GuiCheckBox((Rectangle){propBounds.x+propBounds.width/2, propBounds.y + height/4, height/2, height/2}, props[p].value.vbool ? "Yes" : "No", props[p].value.vbool);
+                        GuiCheckBox((Rectangle){propBounds.x+propBounds.width/2, propBounds.y + height/4, height/2, height/2}, props[p].value.vbool? "Yes" : "No", &props[p].value.vbool);
                         if(!locked) GuiUnlock(); // only unlock when needed
                     } break;
                     
                     case GUI_PROP_INT:
                         // draw property name
-                        GuiDrawText(props[p].name, (Rectangle){propBounds.x + PROPERTY_PADDING, propBounds.y, propBounds.width/2-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, GUI_TEXT_ALIGN_LEFT, textColor);
+                        GuiDrawText(props[p].name, (Rectangle){propBounds.x + PROPERTY_PADDING, propBounds.y, propBounds.width/2-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, TEXT_ALIGN_LEFT, textColor);
                         // draw property value
                         props[p].value.vint.val = GuiDMSpinner((Rectangle){propBounds.x+propBounds.width/2, propBounds.y + 1, propBounds.width/2, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) - 2}, 
-                                    props[p].value.vint.val, props[p].value.vint.min, props[p].value.vint.max, props[p].value.vint.step, 0, (propState == GUI_STATE_FOCUSED) );
+                                    props[p].value.vint.val, props[p].value.vint.min, props[p].value.vint.max, props[p].value.vint.step, 0, (propState == STATE_FOCUSED) );
                     break;
                     
                     case GUI_PROP_FLOAT:
                         // draw property name
-                        GuiDrawText(props[p].name, (Rectangle){propBounds.x + PROPERTY_PADDING, propBounds.y, propBounds.width/2-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, GUI_TEXT_ALIGN_LEFT, textColor);
+                        GuiDrawText(props[p].name, (Rectangle){propBounds.x + PROPERTY_PADDING, propBounds.y, propBounds.width/2-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, TEXT_ALIGN_LEFT, textColor);
                         // draw property value
                         props[p].value.vfloat.val = GuiDMSpinner((Rectangle){propBounds.x+propBounds.width/2, propBounds.y + 1, propBounds.width/2, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) - 2},
-                                    props[p].value.vfloat.val, props[p].value.vfloat.min, props[p].value.vfloat.max, props[p].value.vfloat.step, props[p].value.vfloat.precision, (propState == GUI_STATE_FOCUSED) );
+                                    props[p].value.vfloat.val, props[p].value.vfloat.min, props[p].value.vfloat.max, props[p].value.vfloat.step, props[p].value.vfloat.precision, (propState == STATE_FOCUSED) );
                     break;
                     
                     case GUI_PROP_TEXT: {
                         Rectangle titleBounds = { propBounds.x, propBounds.y, propBounds.width, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) };
                         // Collapse/Expand property on click
-                        if((propState == GUI_STATE_PRESSED) && CheckCollisionPointRec(mousePos, titleBounds))
+                        if((propState == STATE_PRESSED) && CheckCollisionPointRec(mousePos, titleBounds))
                             PROP_TOGGLE_FLAG(&props[p], GUI_PFLAG_COLLAPSED);
                         
                         // draw property name
-                        GuiDrawText(PROP_CHECK_FLAG(&props[p], GUI_PFLAG_COLLAPSED) ? PROPERTY_COLLAPSED_ICON : PROPERTY_EXPANDED_ICON, titleBounds, GUI_TEXT_ALIGN_LEFT, textColor);
-                        GuiDrawText(props[p].name, (Rectangle){propBounds.x+PROPERTY_ICON_SIZE+PROPERTY_PADDING, propBounds.y, propBounds.width-PROPERTY_ICON_SIZE-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, GUI_TEXT_ALIGN_LEFT, textColor);
-                        GuiDrawText(TextFormat("%i/%i", strlen(props[p].value.vtext.val), props[p].value.vtext.size), (Rectangle){propBounds.x+propBounds.width/2, propBounds.y + 1, propBounds.width/2, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) - 2}, GUI_TEXT_ALIGN_LEFT, textColor);
+                        GuiDrawText(PROP_CHECK_FLAG(&props[p], GUI_PFLAG_COLLAPSED) ? PROPERTY_COLLAPSED_ICON : PROPERTY_EXPANDED_ICON, titleBounds, TEXT_ALIGN_LEFT, textColor);
+                        GuiDrawText(props[p].name, (Rectangle){propBounds.x+PROPERTY_ICON_SIZE+PROPERTY_PADDING, propBounds.y, propBounds.width-PROPERTY_ICON_SIZE-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, TEXT_ALIGN_LEFT, textColor);
+                        GuiDrawText(TextFormat("%i/%i", strlen(props[p].value.vtext.val), props[p].value.vtext.size), (Rectangle){propBounds.x+propBounds.width/2, propBounds.y + 1, propBounds.width/2, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) - 2}, TEXT_ALIGN_LEFT, textColor);
                         
                         // draw property value
                         if(!PROP_CHECK_FLAG(&props[p], GUI_PFLAG_COLLAPSED))
-                            GuiTextBox((Rectangle){propBounds.x, propBounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)+1, propBounds.width, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)-2}, props[p].value.vtext.val, props[p].value.vtext.size, (propState == GUI_STATE_FOCUSED));
+                            GuiTextBox((Rectangle){propBounds.x, propBounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)+1, propBounds.width, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)-2}, props[p].value.vtext.val, props[p].value.vtext.size, (propState == STATE_FOCUSED));
                     } break;
                     
                     case GUI_PROP_SELECT: {
                         // TODO: Create a custom dropdownbox control instead of using the raygui combobox
                         // draw property name
-                        GuiDrawText(props[p].name, (Rectangle){propBounds.x + PROPERTY_PADDING, propBounds.y, propBounds.width/2-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, GUI_TEXT_ALIGN_LEFT, textColor);
+                        GuiDrawText(props[p].name, (Rectangle){propBounds.x + PROPERTY_PADDING, propBounds.y, propBounds.width/2-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, TEXT_ALIGN_LEFT, textColor);
                         // draw property value
-                        props[p].value.vselect.active = GuiComboBox((Rectangle){propBounds.x+propBounds.width/2, propBounds.y + 1, propBounds.width/2, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) - 2}, 
-                                props[p].value.vselect.val, props[p].value.vselect.active);
+                        GuiComboBox((Rectangle){propBounds.x+propBounds.width/2, propBounds.y + 1, propBounds.width/2, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) - 2}, 
+                                props[p].value.vselect.val, &props[p].value.vselect.active);
                     } break;
                     
                     case GUI_PROP_VECTOR2: case GUI_PROP_VECTOR3: case GUI_PROP_VECTOR4: {
                         Rectangle titleBounds = { propBounds.x, propBounds.y, propBounds.width, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) };
                         // Collapse/Expand property on click
-                        if((propState == GUI_STATE_PRESSED) && CheckCollisionPointRec(mousePos, titleBounds))
+                        if((propState == STATE_PRESSED) && CheckCollisionPointRec(mousePos, titleBounds))
                             PROP_TOGGLE_FLAG(&props[p], GUI_PFLAG_COLLAPSED);
                         
                         const char* fmt = "";
@@ -600,33 +600,33 @@ void GuiDMPropertyList(Rectangle bounds, GuiDMProperty* props, int count, int* f
                         else fmt = TextFormat("[%.0f, %.0f, %.0f, %.0f]", props[p].value.v4.x, props[p].value.v4.y, props[p].value.v4.z, props[p].value.v4.w);
                         
                         // draw property name
-                        GuiDrawText(PROP_CHECK_FLAG(&props[p], GUI_PFLAG_COLLAPSED) ? PROPERTY_COLLAPSED_ICON : PROPERTY_EXPANDED_ICON, titleBounds, GUI_TEXT_ALIGN_LEFT, textColor);
-                        GuiDrawText(props[p].name, (Rectangle){propBounds.x+PROPERTY_ICON_SIZE+PROPERTY_PADDING, propBounds.y, propBounds.width-PROPERTY_ICON_SIZE-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, GUI_TEXT_ALIGN_LEFT, textColor);
-                        GuiDrawText(fmt, (Rectangle){propBounds.x+propBounds.width/2, propBounds.y + 1, propBounds.width/2, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) - 2}, GUI_TEXT_ALIGN_LEFT, textColor);
+                        GuiDrawText(PROP_CHECK_FLAG(&props[p], GUI_PFLAG_COLLAPSED) ? PROPERTY_COLLAPSED_ICON : PROPERTY_EXPANDED_ICON, titleBounds, TEXT_ALIGN_LEFT, textColor);
+                        GuiDrawText(props[p].name, (Rectangle){propBounds.x+PROPERTY_ICON_SIZE+PROPERTY_PADDING, propBounds.y, propBounds.width-PROPERTY_ICON_SIZE-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, TEXT_ALIGN_LEFT, textColor);
+                        GuiDrawText(fmt, (Rectangle){propBounds.x+propBounds.width/2, propBounds.y + 1, propBounds.width/2, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) - 2}, TEXT_ALIGN_LEFT, textColor);
                         
                         // draw X, Y, Z, W values (only when expanded)
                         if(!PROP_CHECK_FLAG(&props[p], GUI_PFLAG_COLLAPSED)) {
                             Rectangle slotBounds = { propBounds.x, propBounds.y+GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)+1, propBounds.width, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)-2};
                             Rectangle lblBounds = { propBounds.x+PROPERTY_PADDING, slotBounds.y, GetTextWidth("A"), slotBounds.height};
                             Rectangle valBounds = { lblBounds.x+lblBounds.width+PROPERTY_PADDING, slotBounds.y, propBounds.width-lblBounds.width-2*PROPERTY_PADDING, slotBounds.height};
-                            GuiDrawText("X", lblBounds, GUI_TEXT_ALIGN_LEFT, textColor);
-                            props[p].value.v2.x = GuiDMSpinner(valBounds, props[p].value.v2.x, 0.0, 0.0, 1.0, PROPERTY_DECIMAL_DIGITS, (propState == GUI_STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
+                            GuiDrawText("X", lblBounds, TEXT_ALIGN_LEFT, textColor);
+                            props[p].value.v2.x = GuiDMSpinner(valBounds, props[p].value.v2.x, 0.0, 0.0, 1.0, PROPERTY_DECIMAL_DIGITS, (propState == STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
                             slotBounds.y += GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
                             lblBounds.y = valBounds.y = slotBounds.y;
-                            GuiDrawText("Y", lblBounds, GUI_TEXT_ALIGN_LEFT, textColor);
-                            props[p].value.v2.y = GuiDMSpinner(valBounds, props[p].value.v2.y, 0.0, 0.0, 1.0, PROPERTY_DECIMAL_DIGITS, (propState == GUI_STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
+                            GuiDrawText("Y", lblBounds, TEXT_ALIGN_LEFT, textColor);
+                            props[p].value.v2.y = GuiDMSpinner(valBounds, props[p].value.v2.y, 0.0, 0.0, 1.0, PROPERTY_DECIMAL_DIGITS, (propState == STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
                             slotBounds.y += GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
                             lblBounds.y = valBounds.y = slotBounds.y;
                             if(props[p].type >= GUI_PROP_VECTOR3) {
-                                GuiDrawText("Z", lblBounds, GUI_TEXT_ALIGN_LEFT, textColor);
-                                props[p].value.v3.z = GuiDMSpinner(valBounds, props[p].value.v3.z, 0.0, 0.0, 1.0, PROPERTY_DECIMAL_DIGITS, (propState == GUI_STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
+                                GuiDrawText("Z", lblBounds, TEXT_ALIGN_LEFT, textColor);
+                                props[p].value.v3.z = GuiDMSpinner(valBounds, props[p].value.v3.z, 0.0, 0.0, 1.0, PROPERTY_DECIMAL_DIGITS, (propState == STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
                                 slotBounds.y += GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
                                 lblBounds.y = valBounds.y = slotBounds.y;
                             }
                             
                             if(props[p].type >= GUI_PROP_VECTOR4) {
-                                GuiDrawText("W", lblBounds, GUI_TEXT_ALIGN_LEFT, textColor);
-                                props[p].value.v4.w = GuiDMSpinner(valBounds, props[p].value.v4.w, 0.0, 0.0, 1.0, PROPERTY_DECIMAL_DIGITS, (propState == GUI_STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
+                                GuiDrawText("W", lblBounds, TEXT_ALIGN_LEFT, textColor);
+                                props[p].value.v4.w = GuiDMSpinner(valBounds, props[p].value.v4.w, 0.0, 0.0, 1.0, PROPERTY_DECIMAL_DIGITS, (propState == STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
                             }
                         }
                     } break;
@@ -634,34 +634,34 @@ void GuiDMPropertyList(Rectangle bounds, GuiDMProperty* props, int count, int* f
                     case GUI_PROP_RECT:{
                         Rectangle titleBounds = { propBounds.x, propBounds.y, propBounds.width, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) };
                         // Collapse/Expand property on click
-                        if((propState == GUI_STATE_PRESSED) && CheckCollisionPointRec(mousePos, titleBounds))
+                        if((propState == STATE_PRESSED) && CheckCollisionPointRec(mousePos, titleBounds))
                             PROP_TOGGLE_FLAG(&props[p], GUI_PFLAG_COLLAPSED);
                         
                         // draw property name
-                        GuiDrawText(PROP_CHECK_FLAG(&props[p], GUI_PFLAG_COLLAPSED) ? PROPERTY_COLLAPSED_ICON : PROPERTY_EXPANDED_ICON, titleBounds, GUI_TEXT_ALIGN_LEFT, textColor);
-                        GuiDrawText(props[p].name, (Rectangle){propBounds.x+PROPERTY_ICON_SIZE+PROPERTY_PADDING, propBounds.y, propBounds.width-PROPERTY_ICON_SIZE-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, GUI_TEXT_ALIGN_LEFT, textColor);
+                        GuiDrawText(PROP_CHECK_FLAG(&props[p], GUI_PFLAG_COLLAPSED) ? PROPERTY_COLLAPSED_ICON : PROPERTY_EXPANDED_ICON, titleBounds, TEXT_ALIGN_LEFT, textColor);
+                        GuiDrawText(props[p].name, (Rectangle){propBounds.x+PROPERTY_ICON_SIZE+PROPERTY_PADDING, propBounds.y, propBounds.width-PROPERTY_ICON_SIZE-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, TEXT_ALIGN_LEFT, textColor);
                         GuiDrawText(TextFormat("[%.0f, %.0f, %.0f, %.0f]", props[p].value.vrect.x, props[p].value.vrect.y, props[p].value.vrect.width, props[p].value.vrect.height), 
-                                (Rectangle){propBounds.x+propBounds.width/2, propBounds.y + 1, propBounds.width/2, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) - 2}, GUI_TEXT_ALIGN_LEFT, textColor);
+                                (Rectangle){propBounds.x+propBounds.width/2, propBounds.y + 1, propBounds.width/2, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) - 2}, TEXT_ALIGN_LEFT, textColor);
                         
                         // draw X, Y, Width, Height values (only when expanded)
                         if(!PROP_CHECK_FLAG(&props[p], GUI_PFLAG_COLLAPSED)) {
                             Rectangle slotBounds = { propBounds.x, propBounds.y+GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)+1, propBounds.width, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)-2};
                             Rectangle lblBounds = { propBounds.x+PROPERTY_PADDING, slotBounds.y, GetTextWidth("Height"), slotBounds.height};
                             Rectangle valBounds = { lblBounds.x+lblBounds.width+PROPERTY_PADDING, slotBounds.y, propBounds.width-lblBounds.width-2*PROPERTY_PADDING, slotBounds.height};
-                            GuiDrawText("X", lblBounds, GUI_TEXT_ALIGN_LEFT, textColor);
-                            props[p].value.vrect.x = GuiDMSpinner(valBounds, props[p].value.vrect.x, 0.0, 0.0, 1.0, 0, (propState == GUI_STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
+                            GuiDrawText("X", lblBounds, TEXT_ALIGN_LEFT, textColor);
+                            props[p].value.vrect.x = GuiDMSpinner(valBounds, props[p].value.vrect.x, 0.0, 0.0, 1.0, 0, (propState == STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
                             slotBounds.y += GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
                             lblBounds.y = valBounds.y = slotBounds.y;
-                            GuiDrawText("Y", lblBounds, GUI_TEXT_ALIGN_LEFT, textColor);
-                            props[p].value.vrect.y = GuiDMSpinner(valBounds, props[p].value.vrect.y, 0.0, 0.0, 1.0, 0, (propState == GUI_STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
+                            GuiDrawText("Y", lblBounds, TEXT_ALIGN_LEFT, textColor);
+                            props[p].value.vrect.y = GuiDMSpinner(valBounds, props[p].value.vrect.y, 0.0, 0.0, 1.0, 0, (propState == STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
                             slotBounds.y += GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
                             lblBounds.y = valBounds.y = slotBounds.y;
-                            GuiDrawText("Width", lblBounds, GUI_TEXT_ALIGN_LEFT, textColor);
-                            props[p].value.vrect.width = GuiDMSpinner(valBounds, props[p].value.vrect.width, 0.0, 0.0, 1.0, 0, (propState == GUI_STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
+                            GuiDrawText("Width", lblBounds, TEXT_ALIGN_LEFT, textColor);
+                            props[p].value.vrect.width = GuiDMSpinner(valBounds, props[p].value.vrect.width, 0.0, 0.0, 1.0, 0, (propState == STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
                             slotBounds.y += GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
                             lblBounds.y = valBounds.y = slotBounds.y;
-                            GuiDrawText("Height", lblBounds, GUI_TEXT_ALIGN_LEFT, textColor);
-                            props[p].value.vrect.height = GuiDMSpinner(valBounds, props[p].value.vrect.height, 0.0, 0.0, 1.0, 0, (propState == GUI_STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
+                            GuiDrawText("Height", lblBounds, TEXT_ALIGN_LEFT, textColor);
+                            props[p].value.vrect.height = GuiDMSpinner(valBounds, props[p].value.vrect.height, 0.0, 0.0, 1.0, 0, (propState == STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
                         }
                     } break;
                     
@@ -669,17 +669,17 @@ void GuiDMPropertyList(Rectangle bounds, GuiDMProperty* props, int count, int* f
                     case GUI_PROP_COLOR: {
                         Rectangle titleBounds = { propBounds.x, propBounds.y, propBounds.width, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) };
                         // Collapse/Expand property on click
-                        if((propState == GUI_STATE_PRESSED) && CheckCollisionPointRec(mousePos, titleBounds))
+                        if((propState == STATE_PRESSED) && CheckCollisionPointRec(mousePos, titleBounds))
                             PROP_TOGGLE_FLAG(&props[p], GUI_PFLAG_COLLAPSED);
                         
                         // draw property name
-                        GuiDrawText(PROP_CHECK_FLAG(&props[p], GUI_PFLAG_COLLAPSED) ? PROPERTY_COLLAPSED_ICON : PROPERTY_EXPANDED_ICON, titleBounds, GUI_TEXT_ALIGN_LEFT, textColor);
-                        GuiDrawText(props[p].name, (Rectangle){propBounds.x+PROPERTY_ICON_SIZE+PROPERTY_PADDING, propBounds.y+1, propBounds.width-PROPERTY_ICON_SIZE-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)-2}, GUI_TEXT_ALIGN_LEFT, textColor);
+                        GuiDrawText(PROP_CHECK_FLAG(&props[p], GUI_PFLAG_COLLAPSED) ? PROPERTY_COLLAPSED_ICON : PROPERTY_EXPANDED_ICON, titleBounds, TEXT_ALIGN_LEFT, textColor);
+                        GuiDrawText(props[p].name, (Rectangle){propBounds.x+PROPERTY_ICON_SIZE+PROPERTY_PADDING, propBounds.y+1, propBounds.width-PROPERTY_ICON_SIZE-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)-2}, TEXT_ALIGN_LEFT, textColor);
                         DrawLineEx( (Vector2){propBounds.x+propBounds.width/2, propBounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) - 5}, (Vector2){propBounds.x+propBounds.width, propBounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) - 5}, 6.0f, props[p].value.vcolor);
                         const char* fmt = TextFormat("#%02X%02X%02X%02X", props[p].value.vcolor.r, props[p].value.vcolor.g, props[p].value.vcolor.b, props[p].value.vcolor.a);
                         char clip[10] = "\0";
                         memcpy(clip, fmt, 10*sizeof(char)); // copy to temporary buffer since we can't be sure when TextFormat() will be called again and our text will be overwritten
-                        GuiDrawText(fmt, (Rectangle){propBounds.x+propBounds.width/2, propBounds.y + 1, propBounds.width/2, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) - 2}, GUI_TEXT_ALIGN_LEFT, textColor);
+                        GuiDrawText(fmt, (Rectangle){propBounds.x+propBounds.width/2, propBounds.y + 1, propBounds.width/2, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) - 2}, TEXT_ALIGN_LEFT, textColor);
                                 
                         // draw R, G, B, A values (only when expanded)
                         if(!PROP_CHECK_FLAG(&props[p], GUI_PFLAG_COLLAPSED)) {
@@ -704,29 +704,29 @@ void GuiDMPropertyList(Rectangle bounds, GuiDMProperty* props, int count, int* f
                             GuiSetStyle(SCROLLBAR, ARROWS_VISIBLE, 0);
                             GuiSetStyle(DEFAULT, BORDER_COLOR_DISABLED, GuiGetStyle(DEFAULT, BACKGROUND_COLOR)); // disable scrollbar background
                             
-                            GuiDrawText("R", lblBounds, GUI_TEXT_ALIGN_LEFT, textColor);
-                            props[p].value.vcolor.r = GuiDMValueBox(valBounds, props[p].value.vcolor.r, 0.0, 255.0, 0, (propState == GUI_STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
+                            GuiDrawText("R", lblBounds, TEXT_ALIGN_LEFT, textColor);
+                            props[p].value.vcolor.r = GuiDMValueBox(valBounds, props[p].value.vcolor.r, 0.0, 255.0, 0, (propState == STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
                             if(sbarBounds.width > GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)-2) 
                                 props[p].value.vcolor.r = GuiScrollBar(sbarBounds, props[p].value.vcolor.r, 0, 255);
                             slotBounds.y += GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
                             lblBounds.y = valBounds.y = sbarBounds.y = slotBounds.y;
                             
-                            GuiDrawText("G", lblBounds, GUI_TEXT_ALIGN_LEFT, textColor);
-                            props[p].value.vcolor.g = GuiDMValueBox(valBounds, props[p].value.vcolor.g, 0.0, 255.0, 0, (propState == GUI_STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
+                            GuiDrawText("G", lblBounds, TEXT_ALIGN_LEFT, textColor);
+                            props[p].value.vcolor.g = GuiDMValueBox(valBounds, props[p].value.vcolor.g, 0.0, 255.0, 0, (propState == STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
                             if(sbarBounds.width > GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)-2) 
                                 props[p].value.vcolor.g = GuiScrollBar(sbarBounds, props[p].value.vcolor.g, 0, 255);
                             slotBounds.y += GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
                             lblBounds.y = valBounds.y = sbarBounds.y = slotBounds.y;
                             
-                            GuiDrawText("B", lblBounds, GUI_TEXT_ALIGN_LEFT, textColor);
-                            props[p].value.vcolor.b = GuiDMValueBox(valBounds, props[p].value.vcolor.b, 0.0, 255.0, 0, (propState == GUI_STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
+                            GuiDrawText("B", lblBounds, TEXT_ALIGN_LEFT, textColor);
+                            props[p].value.vcolor.b = GuiDMValueBox(valBounds, props[p].value.vcolor.b, 0.0, 255.0, 0, (propState == STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
                             if(sbarBounds.width > GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)-2) 
                                 props[p].value.vcolor.b = GuiScrollBar(sbarBounds, props[p].value.vcolor.b, 0, 255);
                             slotBounds.y += GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
                             lblBounds.y = valBounds.y = sbarBounds.y = slotBounds.y;
                             
-                            GuiDrawText("A", lblBounds, GUI_TEXT_ALIGN_LEFT, textColor);
-                            props[p].value.vcolor.a = GuiDMValueBox(valBounds, props[p].value.vcolor.a, 0.0, 255.0, 0, (propState == GUI_STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
+                            GuiDrawText("A", lblBounds, TEXT_ALIGN_LEFT, textColor);
+                            props[p].value.vcolor.a = GuiDMValueBox(valBounds, props[p].value.vcolor.a, 0.0, 255.0, 0, (propState == STATE_FOCUSED) && CheckCollisionPointRec(mousePos, slotBounds) );
                             if(sbarBounds.width > GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)-2) 
                                 props[p].value.vcolor.a = GuiScrollBar(sbarBounds, props[p].value.vcolor.a, 0, 255);
                             
@@ -740,7 +740,7 @@ void GuiDMPropertyList(Rectangle bounds, GuiDMProperty* props, int count, int* f
                         }
                         
                         // support COPY/PASTE (need to do this here since GuiDMValueBox() also has COPY/PASTE so we need to overwrite it)
-                        if((propState == GUI_STATE_FOCUSED)) { 
+                        if((propState == STATE_FOCUSED)) { 
                             if(IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_C)) 
                                 SetClipboardText(clip);
                             else if(IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_V)){
@@ -754,15 +754,15 @@ void GuiDMPropertyList(Rectangle bounds, GuiDMProperty* props, int count, int* f
                     case GUI_PROP_SECTION: {
                         Rectangle titleBounds = { propBounds.x, propBounds.y, propBounds.width, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) };
                         // Collapse/Expand section on click
-                        if( (propState == GUI_STATE_PRESSED) && CheckCollisionPointRec(mousePos, titleBounds) )
+                        if( (propState == STATE_PRESSED) && CheckCollisionPointRec(mousePos, titleBounds) )
                             PROP_TOGGLE_FLAG(&props[p], GUI_PFLAG_COLLAPSED);
                         
                         if(!PROP_CHECK_FLAG(&props[p], GUI_PFLAG_COLLAPSED)) {
-                            GuiDrawText(PROPERTY_EXPANDED_ICON, titleBounds, GUI_TEXT_ALIGN_LEFT, textColor);
-                            GuiDrawText(props[p].name, (Rectangle){propBounds.x+PROPERTY_ICON_SIZE+PROPERTY_PADDING, propBounds.y, propBounds.width-PROPERTY_ICON_SIZE-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, GUI_TEXT_ALIGN_CENTER, textColor);
+                            GuiDrawText(PROPERTY_EXPANDED_ICON, titleBounds, TEXT_ALIGN_LEFT, textColor);
+                            GuiDrawText(props[p].name, (Rectangle){propBounds.x+PROPERTY_ICON_SIZE+PROPERTY_PADDING, propBounds.y, propBounds.width-PROPERTY_ICON_SIZE-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, TEXT_ALIGN_CENTER, textColor);
                         } else {
-                            GuiDrawText(PROPERTY_COLLAPSED_ICON, titleBounds, GUI_TEXT_ALIGN_LEFT, textColor);
-                            GuiDrawText(TextFormat("%s [%i]", props[p].name, props[p].value.vsection), (Rectangle){propBounds.x+PROPERTY_ICON_SIZE+PROPERTY_PADDING, propBounds.y, propBounds.width-PROPERTY_ICON_SIZE-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, GUI_TEXT_ALIGN_CENTER, textColor);
+                            GuiDrawText(PROPERTY_COLLAPSED_ICON, titleBounds, TEXT_ALIGN_LEFT, textColor);
+                            GuiDrawText(TextFormat("%s [%i]", props[p].name, props[p].value.vsection), (Rectangle){propBounds.x+PROPERTY_ICON_SIZE+PROPERTY_PADDING, propBounds.y, propBounds.width-PROPERTY_ICON_SIZE-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, TEXT_ALIGN_CENTER, textColor);
                         }
                     } break;
                     
@@ -770,9 +770,9 @@ void GuiDMPropertyList(Rectangle bounds, GuiDMProperty* props, int count, int* f
                     // NOTE: Add your custom property here !!
                     default: {
                         // draw property name
-                        GuiDrawText(props[p].name, (Rectangle){propBounds.x + PROPERTY_PADDING, propBounds.y, propBounds.width/2-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, GUI_TEXT_ALIGN_LEFT, textColor); 
+                        GuiDrawText(props[p].name, (Rectangle){propBounds.x + PROPERTY_PADDING, propBounds.y, propBounds.width/2-PROPERTY_PADDING, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT)}, TEXT_ALIGN_LEFT, textColor); 
                         // draw property type
-                        GuiDrawText(TextFormat("TYPE %i", props[p].type), (Rectangle){propBounds.x+propBounds.width/2, propBounds.y + 1, propBounds.width/2, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) - 2}, GUI_TEXT_ALIGN_LEFT, textColor);
+                        GuiDrawText(TextFormat("TYPE %i", props[p].type), (Rectangle){propBounds.x+propBounds.width/2, propBounds.y + 1, propBounds.width/2, GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) - 2}, TEXT_ALIGN_LEFT, textColor);
                     } break;
                     
                 } // end of switch()

+ 32 - 21
gui.mod/raygui/examples/property_list/property_list.c

@@ -1,24 +1,23 @@
 /*******************************************************************************************
 *
-*   raygui - a custom property list control
+*   raygui - custom property list control
 *
 *   DEPENDENCIES:
-*       raylib 3.0
-*       raygui 2.7
+*       raylib 4.0  - Windowing/input management and drawing.
+*       raygui 3.0  - Immediate-mode GUI controls.
 *
 *   COMPILATION (Windows - MinGW):
 *       gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
 *
 *   LICENSE: zlib/libpng
 *
-*   Copyright (c) 2020 Vlad Adrian (@Demizdor - https://github.com/Demizdor)
+*   Copyright (c) 2020-2024 Vlad Adrian (@Demizdor) and Ramon Santamaria (@raysan5)
 *
 **********************************************************************************************/
 
 #include "raylib.h"
 
 #define RAYGUI_IMPLEMENTATION
-#define RAYGUI_SUPPORT_ICONS
 #include "../../src/raygui.h"
 
 #undef RAYGUI_IMPLEMENTATION            // Avoid including raygui implementation again
@@ -26,8 +25,6 @@
 #define GUI_PROPERTY_LIST_IMPLEMENTATION
 #include "dm_property_list.h"
 
-#define SCREEN_WIDTH 800
-#define SCREEN_HEIGHT 450
 #define SIZEOF(A) (sizeof(A)/sizeof(A[0]))
 
 //------------------------------------------------------------------------------------
@@ -37,7 +34,11 @@ int main()
 {
     // Initialization
     //---------------------------------------------------------------------------------------
-
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+    
+    InitWindow(screenWidth, screenHeight, "raygui - property list");
+    
     GuiDMProperty prop[] = {
         PBOOL("Bool", 0, true),
         PSECTION("#102#SECTION", 0, 2),
@@ -52,17 +53,19 @@ int main()
         PVEC4("Vec4", 0, 12, 13, 14, 15),
         PCOLOR("Color", 0, 0, 255, 0, 255),
     };
-    int focus = 0, scroll = 0; // needed by GuiDMPropertyList()
-    
-    InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "raygui - property list");
-    SetTargetFPS(60);
     
+    int focus = 0, scroll = 0; // Needed by GuiDMPropertyList()
+
     GuiLoadStyleDefault();
-    // adjust the default raygui style a bit
+    
+    // Tweak the default raygui style a bit
     GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 24);
     GuiSetStyle(LISTVIEW, SCROLLBAR_WIDTH, 12);
-    //--------------------------------------------------------------------------------------
+
+    Vector2 gridMouseCell = { 0 };
     
+    SetTargetFPS(60);
+    //--------------------------------------------------------------------------------------
     
     // Main game loop
     while (!WindowShouldClose())    // Detect window close button or ESC key
@@ -70,20 +73,28 @@ int main()
         // Draw
         //----------------------------------------------------------------------------------
         BeginDrawing();
+        
             ClearBackground(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));
         
-            GuiGrid((Rectangle){0,0,SCREEN_WIDTH,SCREEN_HEIGHT},20.0f, 2); // draw a fancy grid
+            GuiGrid((Rectangle){0, 0, screenWidth, screenHeight}, "Property List", 20.0f, 2, &gridMouseCell); // Draw a fancy grid
             
-            GuiDMPropertyList((Rectangle){(SCREEN_WIDTH - 180)/2, (SCREEN_HEIGHT - 280)/2, 180, 280}, prop, SIZEOF(prop), &focus, &scroll);
+            GuiDMPropertyList((Rectangle){(screenWidth - 180)/2, (screenHeight - 280)/2, 180, 280}, prop, SIZEOF(prop), &focus, &scroll);
         
-            if(prop[0].value.vbool)
+            if (prop[0].value.vbool >= 1)
+            {
                 DrawText(TextFormat("FOCUS:%i | SCROLL:%i | FPS:%i", focus, scroll, GetFPS()), prop[8].value.v2.x, prop[8].value.v2.y, 20, prop[11].value.vcolor);
-		EndDrawing();
-		//----------------------------------------------------------------------------------
+            }
+            
+        EndDrawing();
+        //----------------------------------------------------------------------------------
     }
-    
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
     GuiDMSaveProperties("test.props", prop, SIZEOF(prop));  // Save properties to `test.props` file at exit
-    CloseWindow();              // Close window and OpenGL context
+    
+    CloseWindow();        // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
     
     return 0;
 }

+ 27 - 0
gui.mod/raygui/examples/property_list/test.props

@@ -0,0 +1,27 @@
+#
+# Property types:
+#   b  <name> <flags> <value>                                    // Bool
+#   i  <name> <flags> <value> <min> <max> <step>                 // Int
+#   f  <name> <flags> <value> <min> <max> <step> <precision>     // Float
+#   t  <name> <flags> <value> <edit_length>                      // Text
+#   l  <name> <flags> <value> <active>                           // Select
+#   g  <name> <flags> <value>                                    // Section (Group)
+#   v2 <name> <flags> <x> <y>                                    // Vector 2D
+#   v3 <name> <flags> <x> <y> <z>                                // Vector 3D
+#   v4 <name> <flags> <x> <y> <z> <w>                            // Vector 4D
+#   r  <name> <flags> <x> <y> <width> <height>                   // Rectangle
+#   c  <name> <flags> <r> <g> <b> <a>                            // Color
+#
+
+b  Bool 0 1
+g  #102#SECTION 0 2
+i  Int 0 123 0 0 1
+f  Float 0 0.990000 0.000000 0.000000 1.000000 3
+t  Text 1 Hello! 30
+l  Select 0 ONE;TWO;THREE;FOUR 3
+i  Int Range 0 32 0 100 1
+r  Rect 1 0 0 100 200
+v2 Vec2 1 20.000000 20.000000
+v3 Vec3 1 12.000000 13.000000 14.000000
+v4 Vec4 1 12.000000 13.000000 14.000000 15.000000
+c  Color 1 94 68 197 160

部分文件因文件數量過多而無法顯示