Merge remote-tracking branch 'origin/master'

This commit is contained in:
TSnake41 2020-05-26 21:29:12 +02:00
commit 4f569813d2
28 changed files with 20598 additions and 4303 deletions

16
.gitignore vendored
View File

@ -34,13 +34,10 @@ Thumbs.db
[Bb]in
[Dd]ebug/
[Dd]ebug.win32/
[Dd]ebug.DLL/
*.sbr
*.sdf
obj/
[R]elease/
[Rr]elease.win32/
_ReSharper*/
[Tt]est[Rr]esult*
ipch/
@ -62,7 +59,6 @@ examples/*
!examples/*/
# Unignore all examples files with extension
!examples/*.c
!examples/*.lua
!examples/*.png
# Unignore examples Makefile
!examples/Makefile
@ -70,17 +66,6 @@ examples/*
!examples/raylib_compile_execute.bat
!examples/raylib_makefile_example.bat
# Ignore all games files
games/*
# Unignore all games dirs
!games/*/
# Unignore all games files with extension
!games/*.c
!games/*.png
# Unignore games makefile
!games/Makefile
!games/Makefile.Android
# Ignore files build by xcode
*.mode*v*
*.pbxuser
@ -112,7 +97,6 @@ build
# Unignore These makefiles...
!examples/CMakeLists.txt
!games/CMakeLists.txt
# Ignore GNU global tags
GPATH

View File

@ -28,7 +28,6 @@ Here it is a list with the ones I'm aware of:
| raylib-haskell | [Haskell](https://www.haskell.org/) | https://github.com/DevJac/raylib-haskell |
| raylib-cr | Crystal | https://github.com/AregevDev/raylib-cr |
| cray | Crystal | https://gitlab.com/Zatherz/cray |
| cray | Crystal | https://github.com/tapgg/cray |
| raylib.cr | Crystal | https://github.com/sam0x17/raylib.cr |
| raylib-pascal | Pascal | https://github.com/drezgames/raylib-pascal |
| raylib-pas | Pascal | https://github.com/tazdij/raylib-pas |
@ -59,7 +58,7 @@ Here it is a list with the ones I'm aware of:
| Euraylib | [Euphoria](https://openeuphoria.org/) | https://github.com/gAndy50/Euraylib |
| raylib-wren | [Wren](http://wren.io/) | https://github.com/TSnake41/raylib-wren |
| raylib-odin | [Odin](https://odin-lang.org/) | https://github.com/kevinw/raylib-odin |
| raylib-zig | [Zig](https://ziglang.org/) | https://github.com/G3bE/raylib-zig |
| raylib-zig | [Zig](https://ziglang.org/) | https://github.com/Not-Nik/raylib-zig |
| ray.zig | [Zig](https://ziglang.org/) | https://github.com/BitPuffin/zig-raylib-experiments |
| raylib-Ada | [Ada](https://www.adacore.com/about-ada) | https://github.com/mimo/raylib-Ada |
| jaylib | [Janet](https://janet-lang.org/) | https://github.com/janet-lang/jaylib |

View File

@ -8,6 +8,7 @@ The following people has contributed with a generous donation to the raylib proj
- Jonathan Johnson ([@ecton](https://github.com/ecton))
- Eric J. ([@ProfJski](https://github.com/ProfJski))
- Rudy Faile ([@rfaile313](https://github.com/rfaile313))
## 🥉 Bronze Contributors

View File

@ -411,7 +411,8 @@ TEXTURES = \
textures/textures_background_scrolling \
textures/textures_sprite_button \
textures/textures_sprite_explosion \
textures/textures_bunnymark
textures/textures_bunnymark \
textures/textures_blend_modes
TEXT = \
text/text_raylib_fonts \

View File

@ -73,7 +73,7 @@ Examples using raylib text functionality, including sprite fonts loading/generat
Examples using raylib textures functionality, including image/textures loading/generation and drawing, provided by raylib [textures](../src/textures.c) module.
| ## | example | image | developer | new |
|----|----------|--------|:----------:|:---:|
|----|---------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------|:------------------------------------------------:|:---:|
| 48 | [textures_logo_raylib](textures/textures_logo_raylib.c) | <img src="textures/textures_logo_raylib.png" alt="textures_logo_raylib" width="200"> | ray | |
| 49 | [textures_rectangle](textures/textures_rectangle.c) | <img src="textures/textures_rectangle.png" alt="textures_rectangle" width="200"> | ray | |
| 50 | [textures_srcrec_dstrec](textures/textures_srcrec_dstrec.c) | <img src="textures/textures_srcrec_dstrec.png" alt="textures_srcrec_dstrec" width="200"> | ray | |
@ -91,6 +91,7 @@ Examples using raylib textures functionality, including image/textures loading/g
| 62 | [textures_sprite_explosion](textures/textures_sprite_explosion.c) | <img src="textures/textures_sprite_explosion.png" alt="textures_sprite_explosion" width="200"> | ray | ⭐️ |
| 63 | [textures_bunnymark](textures/textures_bunnymark.c) | <img src="textures/textures_bunnymark.png" alt="textures_bunnymark" width="200"> | ray | ⭐️ |
| 64 | [textures_mouse_painting](textures/textures_mouse_painting.c) | <img src="textures/textures_mouse_painting.png" alt="textures_mouse_painting" width="200"> | [Chris Dill](https://github.com/MysteriousSpace) | ⭐️ |
| 65 | [textures_blend_modes](textures/textures_blend_modes.c) | <img src="textures/textures_blend_modes.png" alt="textures_blend_modes" width="200"> | [Karlo Licudine](https://github.com/accidentalrebel) | ⭐️ |
### category: models
@ -98,24 +99,24 @@ Examples using raylib models functionality, including models loading/generation
| ## | example | image | developer | new |
|----|----------|--------|:----------:|:---:|
| 65 | [models_animation](models/models_animation.c) | <img src="models/models_animation.png" alt="models_animation" width="200"> | [culacant](https://github.com/culacant) | ⭐️ |
| 66 | [models_billboard](models/models_billboard.c) | <img src="models/models_billboard.png" alt="models_billboard" width="200"> | ray | |
| 67 | [models_box_collisions](models/models_box_collisions.c) | <img src="models/models_box_collisions.png" alt="models_box_collisions" width="200"> | ray | |
| 68 | [models_cubicmap](models/models_cubicmap.c) | <img src="models/models_cubicmap.png" alt="models_cubicmap" width="200"> | ray | |
| 69 | [models_first_person_maze](models/models_first_person_maze.c) | <img src="models/models_first_person_maze.png" alt="models_first_person_maze" width="200"> | ray | ⭐️ |
| 70 | [models_geometric_shapes](models/models_geometric_shapes.c) | <img src="models/models_geometric_shapes.png" alt="models_geometric_shapes" width="200"> | ray | |
| 71 | [models_material_pbr](models/models_material_pbr.c) | <img src="models/models_material_pbr.png" alt="models_material_pbr" width="200"> | ray | |
| 72 | [models_mesh_generation](models/models_mesh_generation.c) | <img src="models/models_mesh_generation.png" alt="models_mesh_generation" width="200"> | ray | |
| 73 | [models_mesh_picking](models/models_mesh_picking.c) | <img src="models/models_mesh_picking.png" alt="models_mesh_picking" width="200"> | [Joel Davis](https://github.com/joeld42) | |
| 74 | [models_loading](models/models_loading.c) | <img src="models/models_loading.png" alt="models_loading" width="200"> | ray | |
| 75 | [models_orthographic_projection](models/models_orthographic_projection.c) | <img src="models/models_orthographic_projection.png" alt="models_orthographic_projection" width="200"> | [Max Danielsson](https://github.com/autious) | |
| 76 | *TODO* | *TODO* | *TODO* | |
| 66 | [models_animation](models/models_animation.c) | <img src="models/models_animation.png" alt="models_animation" width="200"> | [culacant](https://github.com/culacant) | ⭐️ |
| 67 | [models_billboard](models/models_billboard.c) | <img src="models/models_billboard.png" alt="models_billboard" width="200"> | ray | |
| 68 | [models_box_collisions](models/models_box_collisions.c) | <img src="models/models_box_collisions.png" alt="models_box_collisions" width="200"> | ray | |
| 69 | [models_cubicmap](models/models_cubicmap.c) | <img src="models/models_cubicmap.png" alt="models_cubicmap" width="200"> | ray | |
| 70 | [models_first_person_maze](models/models_first_person_maze.c) | <img src="models/models_first_person_maze.png" alt="models_first_person_maze" width="200"> | ray | ⭐️ |
| 71 | [models_geometric_shapes](models/models_geometric_shapes.c) | <img src="models/models_geometric_shapes.png" alt="models_geometric_shapes" width="200"> | ray | |
| 72 | [models_material_pbr](models/models_material_pbr.c) | <img src="models/models_material_pbr.png" alt="models_material_pbr" width="200"> | ray | |
| 73 | [models_mesh_generation](models/models_mesh_generation.c) | <img src="models/models_mesh_generation.png" alt="models_mesh_generation" width="200"> | ray | |
| 74 | [models_mesh_picking](models/models_mesh_picking.c) | <img src="models/models_mesh_picking.png" alt="models_mesh_picking" width="200"> | [Joel Davis](https://github.com/joeld42) | |
| 75 | [models_loading](models/models_loading.c) | <img src="models/models_loading.png" alt="models_loading" width="200"> | ray | |
| 76 | [models_orthographic_projection](models/models_orthographic_projection.c) | <img src="models/models_orthographic_projection.png" alt="models_orthographic_projection" width="200"> | [Max Danielsson](https://github.com/autious) | |
| 77 | *TODO* | *TODO* | *TODO* | |
| 78 | [models_solar_system_rlgl](models/models_rlgl_solar_system.c) | <img src="models/models_rlgl_solar_system.png" alt="models_rlgl_solar_system" width="200"> | ray | ⭐️ |
| 79 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) | <img src="models/models_yaw_pitch_roll.png" alt="models_yaw_pitch_roll" width="200"> | [Berni](https://github.com/Berni8k) | |
| 80 | [models_waving_cubes](models/models_waving_cubes.c) | <img src="models/models_waving_cubes.png" alt="models_waving_cubes" width="200"> | [codecat](https://github.com/codecat) | ⭐️ |
| 81 | [models_heightmap](models/models_heightmap.c) | <img src="models/models_heightmap.png" alt="models_heightmap" width="200"> | ray | |
| 82 | [models_skybox](models/models_skybox.c) | <img src="models/models_skybox.png" alt="models_skybox" width="200"> | ray | |
| 78 | *TODO* | *TODO* | *TODO* | |
| 79 | [models_solar_system_rlgl](models/models_rlgl_solar_system.c) | <img src="models/models_rlgl_solar_system.png" alt="models_rlgl_solar_system" width="200"> | ray | ⭐️ |
| 80 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) | <img src="models/models_yaw_pitch_roll.png" alt="models_yaw_pitch_roll" width="200"> | [Berni](https://github.com/Berni8k) | |
| 81 | [models_waving_cubes](models/models_waving_cubes.c) | <img src="models/models_waving_cubes.png" alt="models_waving_cubes" width="200"> | [codecat](https://github.com/codecat) | ⭐️ |
| 82 | [models_heightmap](models/models_heightmap.c) | <img src="models/models_heightmap.png" alt="models_heightmap" width="200"> | ray | |
| 83 | [models_skybox](models/models_skybox.c) | <img src="models/models_skybox.png" alt="models_skybox" width="200"> | ray | |
### category: shaders
@ -123,19 +124,19 @@ Examples using raylib shaders functionality, including shaders loading, paramete
| ## | example | image | developer | new |
|----|----------|--------|:----------:|:---:|
| 83 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) | <img src="shaders/shaders_basic_lighting.png" alt="shaders_basic_lighting" width="200"> | [Chris Camacho](https://github.com/codifies) | ⭐️ |
| 84 | [shaders_model_shader](shaders/shaders_model_shader.c) | <img src="shaders/shaders_model_shader.png" alt="shaders_model_shader" width="200"> | ray | |
| 85 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) | <img src="shaders/shaders_shapes_textures.png" alt="shaders_shapes_textures" width="200"> | ray | |
| 86 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) | <img src="shaders/shaders_custom_uniform.png" alt="shaders_custom_uniform" width="200"> | ray | |
| 87 | [shaders_postprocessing](shaders/shaders_postprocessing.c) | <img src="shaders/shaders_postprocessing.png" alt="shaders_postprocessing" width="200"> | ray | |
| 88 | [shaders_palette_switch](shaders/shaders_palette_switch.c) | <img src="shaders/shaders_palette_switch.png" alt="shaders_palette_switch" width="200"> | [Marco Lizza](https://github.com/MarcoLizza) | |
| 89 | [shaders_raymarching](shaders/shaders_raymarching.c) | <img src="shaders/shaders_raymarching.png" alt="shaders_raymarching" width="200"> | Shader by Iñigo Quilez | ⭐️ |
| 90 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) | <img src="shaders/shaders_texture_drawing.png" alt="shaders_texture_drawing" width="200"> | Michał Ciesielski | ⭐️ |
| 91 | [shaders_texture_waves](shaders/shaders_texture_waves.c) | <img src="shaders/shaders_texture_waves.png" alt="shaders_texture_waves" width="200"> | [Anata](https://github.com/anatagawa) | ⭐️ |
| 92 | [shaders_julia_set](shaders/shaders_julia_set.c) | <img src="shaders/shaders_julia_set.png" alt="shaders_julia_set" width="200"> | [eggmund](https://github.com/eggmund) | ⭐️ |
| 93 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) | <img src="shaders/shaders_eratosthenes.png" alt="shaders_eratosthenes" width="200"> | [ProfJski](https://github.com/ProfJski) | ⭐️ |
| 94 | [shaders_fog](shaders/shaders_fog.c) | <img src="shaders/shaders_fog.png" alt="shaders_fog" width="200"> | [Chris Camacho](https://github.com/codifies) | ⭐️ |
| 95 | [shaders_simple_mask](shaders/shaders_simple_mask.c) | <img src="shaders/shaders_simple_mask.png" alt="shaders_simple_mask" width="200"> | [Chris Camacho](https://github.com/codifies) | ⭐️ |
| 84 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) | <img src="shaders/shaders_basic_lighting.png" alt="shaders_basic_lighting" width="200"> | [Chris Camacho](https://github.com/codifies) | ⭐️ |
| 85 | [shaders_model_shader](shaders/shaders_model_shader.c) | <img src="shaders/shaders_model_shader.png" alt="shaders_model_shader" width="200"> | ray | |
| 86 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) | <img src="shaders/shaders_shapes_textures.png" alt="shaders_shapes_textures" width="200"> | ray | |
| 87 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) | <img src="shaders/shaders_custom_uniform.png" alt="shaders_custom_uniform" width="200"> | ray | |
| 88 | [shaders_postprocessing](shaders/shaders_postprocessing.c) | <img src="shaders/shaders_postprocessing.png" alt="shaders_postprocessing" width="200"> | ray | |
| 89 | [shaders_palette_switch](shaders/shaders_palette_switch.c) | <img src="shaders/shaders_palette_switch.png" alt="shaders_palette_switch" width="200"> | [Marco Lizza](https://github.com/MarcoLizza) | |
| 90 | [shaders_raymarching](shaders/shaders_raymarching.c) | <img src="shaders/shaders_raymarching.png" alt="shaders_raymarching" width="200"> | Shader by Iñigo Quilez | ⭐️ |
| 91 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) | <img src="shaders/shaders_texture_drawing.png" alt="shaders_texture_drawing" width="200"> | Michał Ciesielski | ⭐️ |
| 92 | [shaders_texture_waves](shaders/shaders_texture_waves.c) | <img src="shaders/shaders_texture_waves.png" alt="shaders_texture_waves" width="200"> | [Anata](https://github.com/anatagawa) | ⭐️ |
| 93 | [shaders_julia_set](shaders/shaders_julia_set.c) | <img src="shaders/shaders_julia_set.png" alt="shaders_julia_set" width="200"> | [eggmund](https://github.com/eggmund) | ⭐️ |
| 94 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) | <img src="shaders/shaders_eratosthenes.png" alt="shaders_eratosthenes" width="200"> | [ProfJski](https://github.com/ProfJski) | ⭐️ |
| 95 | [shaders_fog](shaders/shaders_fog.c) | <img src="shaders/shaders_fog.png" alt="shaders_fog" width="200"> | [Chris Camacho](https://github.com/codifies) | ⭐️ |
| 96 | [shaders_simple_mask](shaders/shaders_simple_mask.c) | <img src="shaders/shaders_simple_mask.png" alt="shaders_simple_mask" width="200"> | [Chris Camacho](https://github.com/codifies) | ⭐️ |
### category: audio
@ -143,11 +144,11 @@ Examples using raylib audio functionality, including sound/music loading and pla
| ## | example | image | developer | new |
|----|----------|--------|:----------:|:---:|
| 96 | [audio_module_playing](audio/audio_module_playing.c) | <img src="audio/audio_module_playing.png" alt="audio_module_playing" width="200"> | ray | |
| 97 | [audio_music_stream](audio/audio_music_stream.c) | <img src="audio/audio_music_stream.png" alt="audio_music_stream" width="200"> | ray | |
| 98 | [audio_raw_stream](audio/audio_raw_stream.c) | <img src="audio/audio_raw_stream.png" alt="audio_raw_stream" width="200"> | ray | |
| 99 | [audio_sound_loading](audio/audio_sound_loading.c) | <img src="audio/audio_sound_loading.png" alt="audio_sound_loading" width="200"> | ray | |
| 100 | [audio_multichannel_sound](audio/audio_multichannel_sound.c) | <img src="audio/audio_multichannel_sound.png" alt="audio_multichannel_sound" width="200"> | [Chris Camacho](https://github.com/codifies) | ⭐️ |
| 97 | [audio_module_playing](audio/audio_module_playing.c) | <img src="audio/audio_module_playing.png" alt="audio_module_playing" width="200"> | ray | |
| 98 | [audio_music_stream](audio/audio_music_stream.c) | <img src="audio/audio_music_stream.png" alt="audio_music_stream" width="200"> | ray | |
| 99 | [audio_raw_stream](audio/audio_raw_stream.c) | <img src="audio/audio_raw_stream.png" alt="audio_raw_stream" width="200"> | ray | |
| 10 | [audio_sound_loading](audio/audio_sound_loading.c) | <img src="audio/audio_sound_loading.png" alt="audio_sound_loading" width="200"> | ray | |
| 101 | [audio_multichannel_sound](audio/audio_multichannel_sound.c) | <img src="audio/audio_multichannel_sound.png" alt="audio_multichannel_sound" width="200"> | [Chris Camacho](https://github.com/codifies) | ⭐️ |
### category: physics
@ -155,11 +156,11 @@ Examples showing physics functionality with raylib. This functionality is provid
| ## | example | image | developer | new |
|----|----------|--------|:----------:|:---:|
| 101 | [physics_demo](physics/physics_demo.c) | <img src="physics/physics_demo.png" alt="physics_demo" width="200"> | [Victor Fisac](https://github.com/victorfisac) | |
| 102 | [physics_friction](physics/physics_friction.c) | <img src="physics/physics_friction.png" alt="physics_friction" width="200"> | [Victor Fisac](https://github.com/victorfisac) | |
| 103 | [physics_movement](physics/physics_movement.c) | <img src="physics/physics_movement.png" alt="physics_movement" width="200"> | [Victor Fisac](https://github.com/victorfisac) | |
| 104 | [physics_restitution](physics/physics_restitution.c) | <img src="physics/physics_restitution.png" alt="physics_restitution" width="200"> | [Victor Fisac](https://github.com/victorfisac) | |
| 105 | [physics_shatter](physics/physics_shatter.c) | <img src="physics/physics_shatter.png" alt="physics_shatter" width="200"> | [Victor Fisac](https://github.com/victorfisac) | |
| 102 | [physics_demo](physics/physics_demo.c) | <img src="physics/physics_demo.png" alt="physics_demo" width="200"> | [Victor Fisac](https://github.com/victorfisac) | |
| 103 | [physics_friction](physics/physics_friction.c) | <img src="physics/physics_friction.png" alt="physics_friction" width="200"> | [Victor Fisac](https://github.com/victorfisac) | |
| 104 | [physics_movement](physics/physics_movement.c) | <img src="physics/physics_movement.png" alt="physics_movement" width="200"> | [Victor Fisac](https://github.com/victorfisac) | |
| 105 | [physics_restitution](physics/physics_restitution.c) | <img src="physics/physics_restitution.png" alt="physics_restitution" width="200"> | [Victor Fisac](https://github.com/victorfisac) | |
| 106 | [physics_shatter](physics/physics_shatter.c) | <img src="physics/physics_shatter.png" alt="physics_shatter" width="200"> | [Victor Fisac](https://github.com/victorfisac) | |
### category: network
@ -169,13 +170,13 @@ Examples showing raylib network functionality. This functionality is provided by
| ## | example | image | developer | new |
|----|----------|--------|:----------:|:---:|
| 106 | [network_ping_pong](network/network_ping_pong.c) | | [Jak Barnes](https://github.com/syphonx) | |
| 107 | [network_resolve_host](network/network_resolve_host.c) | | [Jak Barnes](https://github.com/syphonx) | |
| 108 | [network_tcp_client](network/network_tcp_client.c) | | [Jak Barnes](https://github.com/syphonx) | |
| 109 | [network_tcp_server](network/network_tcp_server.c) | | [Jak Barnes](https://github.com/syphonx) | |
| 110 | [network_test](network/network_test.c) | | [Jak Barnes](https://github.com/syphonx) | |
| 111 | [network_udp_client](network/network_udp_client.c) | | [Jak Barnes](https://github.com/syphonx) | |
| 112 | [network_udp_server](network/network_udp_server.c) | | [Jak Barnes](https://github.com/syphonx) | |
| 107 | [network_ping_pong](network/network_ping_pong.c) | | [Jak Barnes](https://github.com/syphonx) | |
| 108 | [network_resolve_host](network/network_resolve_host.c) | | [Jak Barnes](https://github.com/syphonx) | |
| 109 | [network_tcp_client](network/network_tcp_client.c) | | [Jak Barnes](https://github.com/syphonx) | |
| 110 | [network_tcp_server](network/network_tcp_server.c) | | [Jak Barnes](https://github.com/syphonx) | |
| 111 | [network_test](network/network_test.c) | | [Jak Barnes](https://github.com/syphonx) | |
| 112 | [network_udp_client](network/network_udp_client.c) | | [Jak Barnes](https://github.com/syphonx) | |
| 113 | [network_udp_server](network/network_udp_server.c) | | [Jak Barnes](https://github.com/syphonx) | |
### category: others
@ -183,9 +184,9 @@ Examples showing raylib misc functionality that does not fit in other categories
| ## | example | image | developer | new |
|----|----------|--------|:----------:|:---:|
| 113 | [raudio_standalone](others/raudio_standalone.c) | | ray | |
| 114 | [rlgl_standalone](others/rlgl_standalone.c) | | ray | |
| 115 | [easings_testbed](others/easings_testbed.c) | | [Juan Miguel López](https://github.com/flashback-fx) | |
| 114 | [raudio_standalone](others/raudio_standalone.c) | | ray | |
| 115 | [rlgl_standalone](others/rlgl_standalone.c) | | ray | |
| 116 | [easings_testbed](others/easings_testbed.c) | | [Juan Miguel López](https://github.com/flashback-fx) | |
As always contributions are welcome, feel free to send new examples! Here it is an [examples template](examples_template.c) to start with!

View File

@ -51,6 +51,7 @@ int main(void)
}
Music music = LoadMusicStream("resources/mini1111.xm");
music.looping = false;
PlayMusicStream(music);

View File

@ -92,13 +92,13 @@ int main(void)
DrawCircle(259, 152, 39, BLACK);
DrawCircle(259, 152, 34, LIGHTGRAY);
DrawCircle(259 + (GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_AXIS_LEFT_X)*20),
152 - (GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_AXIS_LEFT_Y)*20), 25, BLACK);
152 + (GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_AXIS_LEFT_Y)*20), 25, BLACK);
// Draw axis: right joystick
DrawCircle(461, 237, 38, BLACK);
DrawCircle(461, 237, 33, LIGHTGRAY);
DrawCircle(461 + (GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_AXIS_RIGHT_X)*20),
237 - (GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_AXIS_RIGHT_Y)*20), 25, BLACK);
237 + (GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_AXIS_RIGHT_Y)*20), 25, BLACK);
// Draw axis: left-right triggers
DrawRectangle(170, 30, 15, 70, GRAY);

View File

@ -0,0 +1,103 @@
/*******************************************************************************************
*
* raylib [others] example - Embedded files loading (Wave and Image)
*
* This example has been created using raylib 3.0 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
*
* Example contributed by Kristian Holmgren (@defutura) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2020 Kristian Holmgren (@defutura) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
#include "raylib.h"
#include "resources/audio_data.h" // Wave file exported with ExportWaveAsCode()
#include "resources/image_data.h" // Image file exported with ExportImageAsCode()
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [others] example - embedded files loading");
InitAudioDevice(); // Initialize audio device
// Loaded in CPU memory (RAM) from header file (audio_data.h)
// Same as: Wave wave = LoadWave("sound.wav");
Wave wave = {
.data = AUDIO_DATA,
.sampleCount = AUDIO_SAMPLE_COUNT,
.sampleRate = AUDIO_SAMPLE_RATE,
.sampleSize = AUDIO_SAMPLE_SIZE,
.channels = AUDIO_CHANNELS
};
// Wave converted to Sound to be played
Sound sound = LoadSoundFromWave(wave);
// With a Wave loaded from file, after Sound is loaded, we can unload Wave
// but in our case, Wave is embedded in executable, in program .data segment
// we can not (and should not) try to free that private memory region
//UnloadWave(wave); // Do not unload wave data!
// Loaded in CPU memory (RAM) from header file (image_data.h)
// Same as: Image image = LoadImage("raylib_logo.png");
Image image = {
.data = IMAGE_DATA,
.width = IMAGE_WIDTH,
.height = IMAGE_HEIGHT,
.format = IMAGE_FORMAT,
.mipmaps = 1
};
// Image converted to Texture (VRAM) to be drawn
Texture2D texture = LoadTextureFromImage(image);
// With an Image loaded from file, after Texture is loaded, we can unload Image
// but in our case, Image is embedded in executable, in program .data segment
// we can not (and should not) try to free that private memory region
//UnloadImage(image); // Do not unload image data!
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KEY_SPACE)) PlaySound(sound); // Play sound
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
DrawTexture(texture, screenWidth/2 - texture.width/2, 40, WHITE);
DrawText("raylib logo and sound loaded from header files", 65, 320, 20, LIGHTGRAY);
DrawText("Press SPACE to PLAY the sound!", 200, 360, 20, LIGHTGRAY);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadSound(sound); // Unload sound from VRAM
UnloadTexture(texture); // Unload texture from VRAM
CloseAudioDevice(); // Close audio device
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,100 @@
/*******************************************************************************************
*
* raylib [textures] example - blend modes
*
* NOTE: Images are loaded in CPU memory (RAM); textures are loaded in GPU memory (VRAM)
*
* This example has been created using raylib 3.0 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
*
* Copyright (c) 2020 Karlo Licudine (@accidentalrebel)
*
********************************************************************************************/
#include "raylib.h"
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [textures] example - blend modes");
// NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
Image bgImage = LoadImage("resources/cyberpunk_street_background.png"); // Loaded in CPU memory (RAM)
Texture2D bgTexture = LoadTextureFromImage(bgImage); // Image converted to texture, GPU memory (VRAM)
Image fgImage = LoadImage("resources/cyberpunk_street_foreground.png"); // Loaded in CPU memory (RAM)
Texture2D fgTexture = 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 int blendCountMax = 4;
BlendMode blendMode = 0;
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
int key = GetKeyPressed();
if ((key >= 32) && (key <= 126))
{
if ( blendMode >= blendCountMax - 1 )
blendMode = 0;
else
blendMode++;
}
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
BeginBlendMode(BLEND_ALPHA);
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 any key to change blend modes.", 310, 350, 10, GRAY);
switch ( blendMode )
{
case BLEND_ALPHA:
DrawText("Current: BLEND_ALPHA", (screenWidth / 2) - 60, 370, 10, GRAY);
break;
case BLEND_ADDITIVE:
DrawText("Current: BLEND_ADDITIVE", (screenWidth / 2) - 60, 370, 10, GRAY);
break;
case BLEND_MULTIPLIED:
DrawText("Current: BLEND_MULTIPLIED", (screenWidth / 2) - 60, 370, 10, GRAY);
break;
case BLEND_ADD_COLORS:
DrawText("Current: BLEND_ADD_COLORS", (screenWidth / 2) - 60, 370, 10, GRAY);
break;
}
DrawText("(c) Cyberpunk Street Environment by Luis Zuno (@ansimuz)", screenWidth - 330, screenHeight - 20, 10, GRAY);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadTexture(fgTexture); // Unload foreground texture
UnloadTexture(bgTexture); // Unload background texture
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

View File

@ -117,6 +117,15 @@ elseif(${PLATFORM} MATCHES "Raspberry Pi")
set(PLATFORM_CPP "PLATFORM_RPI")
set(GRAPHICS "GRAPHICS_API_OPENGL_ES2")
add_definitions(-D_DEFAULT_SOURCE)
find_library(GLESV2 brcmGLESv2 HINTS /opt/vc/lib)
find_library(EGL brcmEGL HINTS /opt/vc/lib)
find_library(BCMHOST bcm_host HINTS /opt/vc/lib)
include_directories(/opt/vc/include /opt/vc/include/interface/vmcs_host/linux /opt/vc/include/interface/vcos/pthreads)
link_directories(/opt/vc/lib)
set(LIBS_PRIVATE ${GLESV2} ${EGL} ${BCMHOST} pthread rt m dl)
endif()
if (${OPENGL_VERSION})

View File

@ -60,6 +60,7 @@ option(SUPPORT_FILEFORMAT_PVR "Support loading PVR as textures" ${OFF})
# text.c
option(SUPPORT_FILEFORMAT_FNT "Support loading fonts in FNT format" ON)
option(SUPPORT_FILEFORMAT_TTF "Support loading font in TTF/OTF format" ON)
option(SUPPORT_TEXT_MANIPULATION "Support text manipulation functions" ON)
# models.c
option(SUPPORT_MESH_GENERATION "Support procedural mesh generation functions, uses external par_shapes.h library. NOTE: Some generated meshes DO NOT include generated texture coordinates" ON)

View File

@ -98,11 +98,12 @@
// Support image export functionality (.png, .bmp, .tga, .jpg)
#define SUPPORT_IMAGE_EXPORT 1
// Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop...
// If not defined only three image editing functions supported: ImageFormat(), ImageAlphaMask(), ImageToPOT()
#define SUPPORT_IMAGE_MANIPULATION 1
// Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)
#define SUPPORT_IMAGE_GENERATION 1
// Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop...
// If not defined, still some functions are supported: ImageFormat(), ImageCrop(), ImageToPOT()
#define SUPPORT_IMAGE_MANIPULATION 1
//------------------------------------------------------------------------------------
// Module: text - Configuration Flags
@ -114,6 +115,10 @@
#define SUPPORT_FILEFORMAT_FNT 1
#define SUPPORT_FILEFORMAT_TTF 1
// Support text management functions
// If not defined, still some functions are supported: TextLength(), TextFormat()
#define SUPPORT_TEXT_MANIPULATION 1
//------------------------------------------------------------------------------------
// Module: models - Configuration Flags
//------------------------------------------------------------------------------------

View File

@ -60,6 +60,9 @@
// Selected desired fileformats to be supported for loading.
#cmakedefine SUPPORT_FILEFORMAT_FNT 1
#cmakedefine SUPPORT_FILEFORMAT_TTF 1
// Support text management functions
// If not defined, still some functions are supported: TextLength(), TextFormat()
#cmakedefine SUPPORT_TEXT_MANIPULATION 1
// models.c
// Selected desired fileformats to be supported for loading.

View File

@ -496,7 +496,6 @@ static void InitTimer(void); // Initialize timer
static void Wait(float ms); // Wait for some milliseconds (stop program execution)
static int GetGamepadButton(int button); // Get gamepad button generic to all platforms
static int GetGamepadAxis(int axis); // Get gamepad axis generic to all platforms
static void PollInputEvents(void); // Register user events
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
@ -520,6 +519,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
#if defined(PLATFORM_WEB)
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData);
static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const void *reserved, void *userData);
static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData);
static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
@ -740,7 +740,8 @@ void InitWindow(int width, int height, const char *title)
emscripten_set_fullscreenchange_callback("#canvas", NULL, 1, EmscriptenFullscreenChangeCallback);
// Support keyboard events
emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
//emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
emscripten_set_keydown_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
// Support mouse events
emscripten_set_click_callback("#canvas", NULL, 1, EmscriptenMouseCallback);
@ -917,11 +918,9 @@ bool IsWindowFullscreen(void)
// Toggle fullscreen mode (only PLATFORM_DESKTOP)
void ToggleFullscreen(void)
{
CORE.Window.fullscreen = !CORE.Window.fullscreen; // Toggle fullscreen flag
#if defined(PLATFORM_DESKTOP)
// NOTE: glfwSetWindowMonitor() doesn't work properly (bugs)
if (CORE.Window.fullscreen)
if (!CORE.Window.fullscreen)
{
// Store previous window position (in case we exit fullscreen)
glfwGetWindowPos(CORE.Window.handle, &CORE.Window.position.x, &CORE.Window.position.y);
@ -942,14 +941,48 @@ void ToggleFullscreen(void)
if (CORE.Window.flags & FLAG_VSYNC_HINT) glfwSwapInterval(1);
}
else glfwSetWindowMonitor(CORE.Window.handle, NULL, CORE.Window.position.x, CORE.Window.position.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
CORE.Window.fullscreen = !CORE.Window.fullscreen; // Toggle fullscreen flag
#endif
#if defined(PLATFORM_WEB)
if (CORE.Window.fullscreen) EM_ASM(Module.requestFullscreen(false, false););
else EM_ASM(document.exitFullscreen(););
/*
EM_ASM(
if (document.fullscreenElement) document.exitFullscreen();
else Module.requestFullscreen(true, true);
);
*/
//EM_ASM(Module.requestFullscreen(false, false););
/*
if (!CORE.Window.fullscreen)
{
//https://github.com/emscripten-core/emscripten/issues/5124
EmscriptenFullscreenStrategy strategy = {
.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH, //EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT,
.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF,
.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT,
.canvasResizedCallback = EmscriptenWindowResizedCallback, //on_canvassize_changed,
.canvasResizedCallbackUserData = NULL
};
emscripten_request_fullscreen("#canvas", false);
//emscripten_request_fullscreen_strategy("#canvas", EM_FALSE, &strategy);
//emscripten_enter_soft_fullscreen("canvas", &strategy);
TraceLog(LOG_INFO, "emscripten_request_fullscreen_strategy");
}
else
{
TraceLog(LOG_INFO, "emscripten_exit_fullscreen");
emscripten_exit_fullscreen();
}
*/
#endif
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
TRACELOG(LOG_WARNING, "SYSTEM: Failed to toggle to windowed mode");
#endif
CORE.Window.fullscreen = !CORE.Window.fullscreen; // Toggle fullscreen flag
}
// Set icon for window (only PLATFORM_DESKTOP)
@ -1285,6 +1318,12 @@ void DisableCursor(void)
CORE.Input.Mouse.cursorHidden = true;
}
// Check if cursor is on the current screen.
bool IsCursorOnScreen(void)
{
return CORE.Input.Mouse.cursorOnScreen;
}
// Set background color (framebuffer clear color)
void ClearBackground(Color color)
{
@ -1950,6 +1989,7 @@ bool IsFileExtension(const char *fileName, const char *ext)
if (fileExt != NULL)
{
#if defined(SUPPORT_TEXT_MANIPULATION)
int extCount = 0;
const char **checkExts = TextSplit(ext, ';', &extCount);
@ -1964,6 +2004,9 @@ bool IsFileExtension(const char *fileName, const char *ext)
break;
}
}
#else
if (strcmp(fileExt, ext) == 0) result = true;
#endif
}
return result;
@ -2084,11 +2127,13 @@ const char *GetPrevDirectoryPath(const char *dirPath)
if (pathLen <= 3) strcpy(prevDirPath, dirPath);
for (int i = (pathLen - 1); (i > 0) && (pathLen > 3); i--)
for (int i = (pathLen - 1); (i >= 0) && (pathLen > 3); i--)
{
if ((dirPath[i] == '\\') || (dirPath[i] == '/'))
{
if (i == 2) i++; // Check for root: "C:\"
// Check for root: "C:\" or "/"
if (((i == 2) && (dirPath[1] ==':')) || (i == 0)) i++;
strncpy(prevDirPath, dirPath, i);
break;
}
@ -2509,7 +2554,9 @@ float GetGamepadAxisMovement(int gamepad, int axis)
float value = 0;
#if !defined(PLATFORM_ANDROID)
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXIS)) value = CORE.Input.Gamepad.axisState[gamepad][axis];
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXIS) &&
((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER) ||
(fabsf(CORE.Input.Gamepad.axisState[gamepad][axis]) >= 0.2f))) value = CORE.Input.Gamepad.axisState[gamepad][axis];
#endif
return value;
@ -3485,8 +3532,11 @@ static void InitTimer(void)
static void Wait(float ms)
{
#if defined(PLATFORM_UWP)
UWPGetSleepFunc()(ms / 1000);
#elif defined(SUPPORT_BUSY_WAIT_LOOP)
UWPGetSleepFunc()(ms/1000);
return;
#endif
#if defined(SUPPORT_BUSY_WAIT_LOOP)
double prevTime = GetTime();
double nextTime = 0.0;
@ -3514,7 +3564,7 @@ static void Wait(float ms)
usleep(ms*1000.0f);
#endif
#if defined(SUPPORT_HALFBUSY_WAIT_LOOP)// && !defined(PLATFORM_UWP)
#if defined(SUPPORT_HALFBUSY_WAIT_LOOP)
while (GetTime() < destTime) { }
#endif
#endif
@ -3579,40 +3629,6 @@ static int GetGamepadButton(int button)
return btn;
}
// Get gamepad axis generic to all platforms
static int GetGamepadAxis(int axis)
{
int axs = GAMEPAD_AXIS_UNKNOWN;
#if defined(PLATFORM_DESKTOP)
switch (axis)
{
case GLFW_GAMEPAD_AXIS_LEFT_X: axs = GAMEPAD_AXIS_LEFT_X; break;
case GLFW_GAMEPAD_AXIS_LEFT_Y: axs = GAMEPAD_AXIS_LEFT_Y; break;
case GLFW_GAMEPAD_AXIS_RIGHT_X: axs = GAMEPAD_AXIS_RIGHT_X; break;
case GLFW_GAMEPAD_AXIS_RIGHT_Y: axs = GAMEPAD_AXIS_RIGHT_Y; break;
case GLFW_GAMEPAD_AXIS_LEFT_TRIGGER: axs = GAMEPAD_AXIS_LEFT_TRIGGER; break;
case GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER: axs = GAMEPAD_AXIS_RIGHT_TRIGGER; break;
}
#endif
#if defined(PLATFORM_UWP)
axs = axis; // UWP will provide the correct axis
#endif
#if defined(PLATFORM_WEB)
// Gamepad axis reference:https://www.w3.org/TR/gamepad/#gamepad-interface
switch (axis)
{
case 0: axs = GAMEPAD_AXIS_LEFT_X;
case 1: axs = GAMEPAD_AXIS_LEFT_Y;
case 2: axs = GAMEPAD_AXIS_RIGHT_X;
case 3: axs = GAMEPAD_AXIS_RIGHT_X;
}
#endif
return axs;
}
// Poll (store) all input events
static void PollInputEvents(void)
{
@ -3710,8 +3726,9 @@ static void PollInputEvents(void)
// Get current gamepad state
// NOTE: There is no callback available, so we get it manually
// Get remapped buttons
GLFWgamepadstate state;
GLFWgamepadstate state = { 0 };
glfwGetGamepadState(i, &state); // This remapps all gamepads so they have their buttons mapped like an xbox controller
const unsigned char *buttons = state.buttons;
for (int k = 0; (buttons != NULL) && (k < GLFW_GAMEPAD_BUTTON_DPAD_LEFT + 1) && (k < MAX_GAMEPAD_BUTTONS); k++)
@ -3731,8 +3748,7 @@ static void PollInputEvents(void)
for (int k = 0; (axes != NULL) && (k < GLFW_GAMEPAD_AXIS_LAST + 1) && (k < MAX_GAMEPAD_AXIS); k++)
{
const int axis = GetGamepadAxis(k);
CORE.Input.Gamepad.axisState[i][axis] = axes[k];
CORE.Input.Gamepad.axisState[i][k] = axes[k];
}
// Register buttons for 2nd triggers (because GLFW doesn't count these as buttons but rather axis)
@ -3787,8 +3803,7 @@ static void PollInputEvents(void)
// Register axis data for every connected gamepad
for (int j = 0; (j < gamepadState.numAxes) && (j < MAX_GAMEPAD_AXIS); j++)
{
const int axis = GetGamepadAxis(j);
CORE.Input.Gamepad.axisState[i][axis] = gamepadState.axis[j];
CORE.Input.Gamepad.axisState[i][j] = gamepadState.axis[j];
}
CORE.Input.Gamepad.axisCount = gamepadState.numAxes;
@ -4309,7 +4324,7 @@ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const Emscripte
//fs element id: (char *) event->id
//Current element size: (int) event->elementWidth, (int) event->elementHeight
//Screen size:(int) event->screenWidth, (int) event->screenHeight
/*
if (event->isFullscreen)
{
CORE.Window.fullscreen = true;
@ -4322,16 +4337,20 @@ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const Emscripte
}
// TODO: Depending on scaling factor (screen vs element), calculate factor to scale mouse/touch input
*/
return 0;
}
// Register keyboard input events
static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
{
if ((eventType == EMSCRIPTEN_EVENT_KEYPRESS) && (keyEvent->key == 27)) // ESCAPE key
if ((eventType == EMSCRIPTEN_EVENT_KEYDOWN) && (keyEvent->keyCode == 27)) // ESCAPE key (strcmp(keyEvent->code, "Escape") == 0)
{
// WARNING: Not executed when pressing Esc to exit fullscreen, it seems document has priority over #canvas
emscripten_exit_pointerlock();
CORE.Window.fullscreen = false;
TraceLog(LOG_INFO, "CORE.Window.fullscreen = %s", CORE.Window.fullscreen? "true" : "false");
}
return 0;
@ -4445,6 +4464,16 @@ static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadE
return 0;
}
static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const void *reserved, void *userData)
{
double width, height;
emscripten_get_element_css_size("canvas", &width, &height);
// TODO.
return true;
}
#endif
#if defined(PLATFORM_RPI)
@ -4664,7 +4693,7 @@ static void InitEvdevInput(void)
// Identifies a input device and spawns a thread to handle it if needed
static void EventThreadSpawn(char *device)
{
#define BITS_PER_LONG (sizeof(long)*8)
#define BITS_PER_LONG (8*sizeof(long))
#define NBITS(x) ((((x) - 1)/BITS_PER_LONG) + 1)
#define OFF(x) ((x)%BITS_PER_LONG)
#define BIT(x) (1UL<<OFF(x))

4877
src/external/dr_wav.h vendored

File diff suppressed because it is too large Load Diff

View File

@ -43,11 +43,10 @@
#include "config.h" // Defines module configuration flags
#endif
#include "utils.h" // Required for: fopen() Android mapping
#include "utils.h" // Required for: LoadFileData(), LoadFileText(), SaveFileText()
#include <stdlib.h> // Required for: malloc(), free()
#include <stdio.h> // Required for: FILE, fopen(), fclose()
#include <string.h> // Required for: strncmp() [Used in LoadModelAnimations()], strlen() [Used in LoadTextureFromCgltfImage()]
#include <string.h> // Required for: memcmp(), strlen()
#include <math.h> // Required for: sinf(), cosf(), sqrtf(), fabsf()
#if defined(_WIN32)
@ -825,57 +824,64 @@ void UnloadMesh(Mesh mesh)
// Export mesh data to file
void ExportMesh(Mesh mesh, const char *fileName)
{
bool success = false;
if (IsFileExtension(fileName, ".obj"))
{
FILE *objFile = fopen(fileName, "wt");
// Estimated data size, it should be enough...
int dataSize = mesh.vertexCount/3*strlen("v 0000.00f 0000.00f 0000.00f") +
mesh.vertexCount/2*strlen("vt 0.000f 0.00f") +
mesh.vertexCount/3*strlen("vn 0.000f 0.00f 0.00f") +
mesh.triangleCount/3*strlen("f 00000/00000/00000 00000/00000/00000 00000/00000/00000");
fprintf(objFile, "# //////////////////////////////////////////////////////////////////////////////////\n");
fprintf(objFile, "# // //\n");
fprintf(objFile, "# // rMeshOBJ exporter v1.0 - Mesh exported as triangle faces and not optimized //\n");
fprintf(objFile, "# // //\n");
fprintf(objFile, "# // more info and bugs-report: github.com/raysan5/raylib //\n");
fprintf(objFile, "# // feedback and support: ray[at]raylib.com //\n");
fprintf(objFile, "# // //\n");
fprintf(objFile, "# // Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n");
fprintf(objFile, "# // //\n");
fprintf(objFile, "# //////////////////////////////////////////////////////////////////////////////////\n\n");
fprintf(objFile, "# Vertex Count: %i\n", mesh.vertexCount);
fprintf(objFile, "# Triangle Count: %i\n\n", mesh.triangleCount);
// NOTE: Text data buffer size is estimated considering mesh data size
char *txtData = (char *)RL_CALLOC(dataSize + 2000, sizeof(char));
fprintf(objFile, "g mesh\n");
int bytesCount = 0;
bytesCount += sprintf(txtData + bytesCount, "# //////////////////////////////////////////////////////////////////////////////////\n");
bytesCount += sprintf(txtData + bytesCount, "# // //\n");
bytesCount += sprintf(txtData + bytesCount, "# // rMeshOBJ exporter v1.0 - Mesh exported as triangle faces and not optimized //\n");
bytesCount += sprintf(txtData + bytesCount, "# // //\n");
bytesCount += sprintf(txtData + bytesCount, "# // more info and bugs-report: github.com/raysan5/raylib //\n");
bytesCount += sprintf(txtData + bytesCount, "# // feedback and support: ray[at]raylib.com //\n");
bytesCount += sprintf(txtData + bytesCount, "# // //\n");
bytesCount += sprintf(txtData + bytesCount, "# // Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n");
bytesCount += sprintf(txtData + bytesCount, "# // //\n");
bytesCount += sprintf(txtData + bytesCount, "# //////////////////////////////////////////////////////////////////////////////////\n\n");
bytesCount += sprintf(txtData + bytesCount, "# Vertex Count: %i\n", mesh.vertexCount);
bytesCount += sprintf(txtData + bytesCount, "# Triangle Count: %i\n\n", mesh.triangleCount);
bytesCount += sprintf(txtData + bytesCount, "g mesh\n");
for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3)
{
fprintf(objFile, "v %.2f %.2f %.2f\n", mesh.vertices[v], mesh.vertices[v + 1], mesh.vertices[v + 2]);
bytesCount += sprintf(txtData + bytesCount, "v %.2f %.2f %.2f\n", mesh.vertices[v], mesh.vertices[v + 1], mesh.vertices[v + 2]);
}
for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 2)
{
fprintf(objFile, "vt %.2f %.2f\n", mesh.texcoords[v], mesh.texcoords[v + 1]);
bytesCount += sprintf(txtData + bytesCount, "vt %.3f %.3f\n", mesh.texcoords[v], mesh.texcoords[v + 1]);
}
for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3)
{
fprintf(objFile, "vn %.2f %.2f %.2f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]);
bytesCount += sprintf(txtData + bytesCount, "vn %.3f %.3f %.3f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]);
}
for (int i = 0; i < mesh.triangleCount; i += 3)
{
fprintf(objFile, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", i, i, i, i + 1, i + 1, i + 1, i + 2, i + 2, i + 2);
bytesCount += sprintf(txtData + bytesCount, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", i, i, i, i + 1, i + 1, i + 1, i + 2, i + 2, i + 2);
}
fprintf(objFile, "\n");
bytesCount += sprintf(txtData + bytesCount, "\n");
fclose(objFile);
// NOTE: Text data length exported is determined by '\0' (NULL) character
SaveFileText(fileName, txtData);
success = true;
RL_FREE(txtData);
}
else if (IsFileExtension(fileName, ".raw"))
{
// TODO: Support additional file formats to export mesh vertex data
}
else if (IsFileExtension(fileName, ".raw")) { } // TODO: Support additional file formats to export mesh vertex data
if (success) TRACELOG(LOG_INFO, "FILEIO: [%s] Mesh exported successfully", fileName);
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export mesh data", fileName);
}
// Load materials from model file
@ -959,11 +965,15 @@ void SetModelMeshMaterial(Model *model, int meshId, int materialId)
}
// Load model animations from file
ModelAnimation *LoadModelAnimations(const char *filename, int *animCount)
ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount)
{
#define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number
#define IQM_VERSION 2 // only IQM version 2 supported
unsigned int fileSize = 0;
unsigned char *fileData = LoadFileData(fileName, &fileSize);
unsigned char *fileDataPtr = fileData;
typedef struct IQMHeader {
char magic[16];
unsigned int version;
@ -995,72 +1005,66 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount)
unsigned int flags;
} IQMAnim;
FILE *iqmFile = NULL;
IQMHeader iqm;
iqmFile = fopen(filename,"rb");
if (!iqmFile)
{
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", filename);
return NULL;
}
// In case file can not be read, return an empty model
if (fileDataPtr == NULL) return NULL;
// Read IQM header
fread(&iqm, sizeof(IQMHeader), 1, iqmFile);
IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr;
if (strncmp(iqm.magic, IQM_MAGIC, sizeof(IQM_MAGIC)))
if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0)
{
TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", filename);
fclose(iqmFile);
TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName);
return NULL;
}
if (iqm.version != IQM_VERSION)
if (iqmHeader->version != IQM_VERSION)
{
TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version incorrect", filename);
fclose(iqmFile);
TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version);
return NULL;
}
// Get bones data
IQMPose *poses = RL_MALLOC(iqm.num_poses*sizeof(IQMPose));
fseek(iqmFile, iqm.ofs_poses, SEEK_SET);
fread(poses, iqm.num_poses*sizeof(IQMPose), 1, iqmFile);
IQMPose *poses = RL_MALLOC(iqmHeader->num_poses*sizeof(IQMPose));
//fseek(iqmFile, iqmHeader->ofs_poses, SEEK_SET);
//fread(poses, iqmHeader->num_poses*sizeof(IQMPose), 1, iqmFile);
memcpy(poses, fileDataPtr + iqmHeader->ofs_poses, iqmHeader->num_poses*sizeof(IQMPose));
// Get animations data
*animCount = iqm.num_anims;
IQMAnim *anim = RL_MALLOC(iqm.num_anims*sizeof(IQMAnim));
fseek(iqmFile, iqm.ofs_anims, SEEK_SET);
fread(anim, iqm.num_anims*sizeof(IQMAnim), 1, iqmFile);
ModelAnimation *animations = RL_MALLOC(iqm.num_anims*sizeof(ModelAnimation));
*animCount = iqmHeader->num_anims;
IQMAnim *anim = RL_MALLOC(iqmHeader->num_anims*sizeof(IQMAnim));
//fseek(iqmFile, iqmHeader->ofs_anims, SEEK_SET);
//fread(anim, iqmHeader->num_anims*sizeof(IQMAnim), 1, iqmFile);
memcpy(anim, fileDataPtr + iqmHeader->ofs_anims, iqmHeader->num_anims*sizeof(IQMAnim));
ModelAnimation *animations = RL_MALLOC(iqmHeader->num_anims*sizeof(ModelAnimation));
// frameposes
unsigned short *framedata = RL_MALLOC(iqm.num_frames*iqm.num_framechannels*sizeof(unsigned short));
fseek(iqmFile, iqm.ofs_frames, SEEK_SET);
fread(framedata, iqm.num_frames*iqm.num_framechannels*sizeof(unsigned short), 1, iqmFile);
unsigned short *framedata = RL_MALLOC(iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
//fseek(iqmFile, iqmHeader->ofs_frames, SEEK_SET);
//fread(framedata, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short), 1, iqmFile);
memcpy(framedata, fileDataPtr + iqmHeader->ofs_frames, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
for (unsigned int a = 0; a < iqm.num_anims; a++)
for (unsigned int a = 0; a < iqmHeader->num_anims; a++)
{
animations[a].frameCount = anim[a].num_frames;
animations[a].boneCount = iqm.num_poses;
animations[a].bones = RL_MALLOC(iqm.num_poses*sizeof(BoneInfo));
animations[a].boneCount = iqmHeader->num_poses;
animations[a].bones = RL_MALLOC(iqmHeader->num_poses*sizeof(BoneInfo));
animations[a].framePoses = RL_MALLOC(anim[a].num_frames*sizeof(Transform *));
//animations[a].framerate = anim.framerate; // TODO: Use framerate?
for (unsigned int j = 0; j < iqm.num_poses; j++)
for (unsigned int j = 0; j < iqmHeader->num_poses; j++)
{
strcpy(animations[a].bones[j].name, "ANIMJOINTNAME");
animations[a].bones[j].parent = poses[j].parent;
}
for (unsigned int j = 0; j < anim[a].num_frames; j++) animations[a].framePoses[j] = RL_MALLOC(iqm.num_poses*sizeof(Transform));
for (unsigned int j = 0; j < anim[a].num_frames; j++) animations[a].framePoses[j] = RL_MALLOC(iqmHeader->num_poses*sizeof(Transform));
int dcounter = anim[a].first_frame*iqm.num_framechannels;
int dcounter = anim[a].first_frame*iqmHeader->num_framechannels;
for (unsigned int frame = 0; frame < anim[a].num_frames; frame++)
{
for (unsigned int i = 0; i < iqm.num_poses; i++)
for (unsigned int i = 0; i < iqmHeader->num_poses; i++)
{
animations[a].framePoses[frame][i].translation.x = poses[i].channeloffset[0];
@ -1162,12 +1166,12 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount)
}
}
RL_FREE(fileData);
RL_FREE(framedata);
RL_FREE(poses);
RL_FREE(anim);
fclose(iqmFile);
return animations;
}
@ -1990,6 +1994,8 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
// NOTE: Vertex data is uploaded to GPU
Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
{
#define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a))
Mesh mesh = { 0 };
mesh.vboId = (unsigned int *)RL_CALLOC(DEFAULT_MESH_VERTEX_BUFFERS, sizeof(unsigned int));
@ -2018,8 +2024,8 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
Vector3 n2 = { -1.0f, 0.0f, 0.0f };
Vector3 n3 = { 0.0f, 1.0f, 0.0f };
Vector3 n4 = { 0.0f, -1.0f, 0.0f };
Vector3 n5 = { 0.0f, 0.0f, 1.0f };
Vector3 n6 = { 0.0f, 0.0f, -1.0f };
Vector3 n5 = { 0.0f, 0.0f, -1.0f };
Vector3 n6 = { 0.0f, 0.0f, 1.0f };
// NOTE: We use texture rectangles to define different textures for top-bottom-front-back-right-left (6)
typedef struct RectangleF {
@ -2050,15 +2056,14 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
Vector3 v7 = { w*(x - 0.5f), 0, h*(z + 0.5f) };
Vector3 v8 = { w*(x + 0.5f), 0, h*(z + 0.5f) };
// We check pixel color to be WHITE, we will full cubes
if ((cubicmapPixels[z*cubicmap.width + x].r == 255) &&
(cubicmapPixels[z*cubicmap.width + x].g == 255) &&
(cubicmapPixels[z*cubicmap.width + x].b == 255))
// We check pixel color to be WHITE -> draw full cube
if (COLOR_EQUAL(cubicmapPixels[z*cubicmap.width + x], WHITE))
{
// Define triangles (Checking Collateral Cubes!)
//----------------------------------------------
// Define triangles and checking collateral cubes
//------------------------------------------------
// Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
// WARNING: Not required for a WHITE cubes, created to allow seeing the map from outside
mapVertices[vCounter] = v1;
mapVertices[vCounter + 1] = v2;
mapVertices[vCounter + 2] = v3;
@ -2108,10 +2113,8 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
mapTexcoords[tcCounter + 5] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
tcCounter += 6;
if (((z < cubicmap.height - 1) &&
(cubicmapPixels[(z + 1)*cubicmap.width + x].r == 0) &&
(cubicmapPixels[(z + 1)*cubicmap.width + x].g == 0) &&
(cubicmapPixels[(z + 1)*cubicmap.width + x].b == 0)) || (z == cubicmap.height - 1))
// Checking cube on bottom of current cube
if (((z < cubicmap.height - 1) && COLOR_EQUAL(cubicmapPixels[(z + 1)*cubicmap.width + x], BLACK)) || (z == cubicmap.height - 1))
{
// Define front triangles (2 tris, 6 vertex) --> v2 v7 v3, v3 v7 v8
// NOTE: Collateral occluded faces are not generated
@ -2140,10 +2143,8 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
tcCounter += 6;
}
if (((z > 0) &&
(cubicmapPixels[(z - 1)*cubicmap.width + x].r == 0) &&
(cubicmapPixels[(z - 1)*cubicmap.width + x].g == 0) &&
(cubicmapPixels[(z - 1)*cubicmap.width + x].b == 0)) || (z == 0))
// Checking cube on top of current cube
if (((z > 0) && COLOR_EQUAL(cubicmapPixels[(z - 1)*cubicmap.width + x], BLACK)) || (z == 0))
{
// Define back triangles (2 tris, 6 vertex) --> v1 v5 v6, v1 v4 v5
// NOTE: Collateral occluded faces are not generated
@ -2172,10 +2173,8 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
tcCounter += 6;
}
if (((x < cubicmap.width - 1) &&
(cubicmapPixels[z*cubicmap.width + (x + 1)].r == 0) &&
(cubicmapPixels[z*cubicmap.width + (x + 1)].g == 0) &&
(cubicmapPixels[z*cubicmap.width + (x + 1)].b == 0)) || (x == cubicmap.width - 1))
// Checking cube on right of current cube
if (((x < cubicmap.width - 1) && COLOR_EQUAL(cubicmapPixels[z*cubicmap.width + (x + 1)], BLACK)) || (x == cubicmap.width - 1))
{
// Define right triangles (2 tris, 6 vertex) --> v3 v8 v4, v4 v8 v5
// NOTE: Collateral occluded faces are not generated
@ -2204,10 +2203,8 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
tcCounter += 6;
}
if (((x > 0) &&
(cubicmapPixels[z*cubicmap.width + (x - 1)].r == 0) &&
(cubicmapPixels[z*cubicmap.width + (x - 1)].g == 0) &&
(cubicmapPixels[z*cubicmap.width + (x - 1)].b == 0)) || (x == 0))
// Checking cube on left of current cube
if (((x > 0) && COLOR_EQUAL(cubicmapPixels[z*cubicmap.width + (x - 1)], BLACK)) || (x == 0))
{
// Define left triangles (2 tris, 6 vertex) --> v1 v7 v2, v1 v6 v7
// NOTE: Collateral occluded faces are not generated
@ -2237,9 +2234,7 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
}
}
// We check pixel color to be BLACK, we will only draw floor and roof
else if ((cubicmapPixels[z*cubicmap.width + x].r == 0) &&
(cubicmapPixels[z*cubicmap.width + x].g == 0) &&
(cubicmapPixels[z*cubicmap.width + x].b == 0))
else if (COLOR_EQUAL(cubicmapPixels[z*cubicmap.width + x], BLACK))
{
// Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
mapVertices[vCounter] = v1;
@ -2951,6 +2946,8 @@ static Model LoadOBJ(const char *fileName)
for (int v = 0; v < 3; v++) { mesh.vertices[vCount + v] = attrib.vertices[idx1.v_idx*3 + v]; } vCount +=3;
for (int v = 0; v < 3; v++) { mesh.vertices[vCount + v] = attrib.vertices[idx2.v_idx*3 + v]; } vCount +=3;
if (attrib.num_texcoords > 0)
{
// Fill texcoords buffer (float) using vertex index of the face
// NOTE: Y-coordinate must be flipped upside-down
mesh.texcoords[vtCount + 0] = attrib.texcoords[idx0.vt_idx*2 + 0];
@ -2959,12 +2956,16 @@ static Model LoadOBJ(const char *fileName)
mesh.texcoords[vtCount + 1] = 1.0f - attrib.texcoords[idx1.vt_idx*2 + 1]; vtCount += 2;
mesh.texcoords[vtCount + 0] = attrib.texcoords[idx2.vt_idx*2 + 0];
mesh.texcoords[vtCount + 1] = 1.0f - attrib.texcoords[idx2.vt_idx*2 + 1]; vtCount += 2;
}
if (attrib.num_normals > 0)
{
// Fill normals buffer (float) using vertex index of the face
for (int v = 0; v < 3; v++) { mesh.normals[vnCount + v] = attrib.normals[idx0.vn_idx*3 + v]; } vnCount +=3;
for (int v = 0; v < 3; v++) { mesh.normals[vnCount + v] = attrib.normals[idx1.vn_idx*3 + v]; } vnCount +=3;
for (int v = 0; v < 3; v++) { mesh.normals[vnCount + v] = attrib.normals[idx2.vn_idx*3 + v]; } vnCount +=3;
}
}
model.meshes[m] = mesh; // Assign mesh data to model
@ -3050,6 +3051,11 @@ static Model LoadIQM(const char *fileName)
#define BONE_NAME_LENGTH 32 // BoneInfo name string length
#define MESH_NAME_LENGTH 32 // Mesh name string length
#define MATERIAL_NAME_LENGTH 32 // Material name string length
unsigned int fileSize = 0;
unsigned char *fileData = LoadFileData(fileName, &fileSize);
unsigned char *fileDataPtr = fileData;
// IQM file structs
//-----------------------------------------------------------------------------------
@ -3136,13 +3142,10 @@ static Model LoadIQM(const char *fileName)
Model model = { 0 };
FILE *iqmFile = NULL;
IQMHeader iqm;
IQMMesh *imesh;
IQMTriangle *tri;
IQMVertexArray *va;
IQMJoint *ijoint;
IQMMesh *imesh = NULL;
IQMTriangle *tri = NULL;
IQMVertexArray *va = NULL;
IQMJoint *ijoint = NULL;
float *vertex = NULL;
float *normal = NULL;
@ -3150,44 +3153,56 @@ static Model LoadIQM(const char *fileName)
char *blendi = NULL;
unsigned char *blendw = NULL;
iqmFile = fopen(fileName, "rb");
// In case file can not be read, return an empty model
if (fileDataPtr == NULL) return model;
if (iqmFile == NULL)
{
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open IQM file", fileName);
return model;
}
// Read IQM header
IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr;
fread(&iqm, sizeof(IQMHeader), 1, iqmFile); // Read IQM header
if (strncmp(iqm.magic, IQM_MAGIC, sizeof(IQM_MAGIC)))
if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0)
{
TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName);
fclose(iqmFile);
return model;
}
if (iqm.version != IQM_VERSION)
if (iqmHeader->version != IQM_VERSION)
{
TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqm.version);
fclose(iqmFile);
TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version);
return model;
}
//fileDataPtr += sizeof(IQMHeader); // Move file data pointer
// Meshes data processing
imesh = RL_MALLOC(sizeof(IQMMesh)*iqm.num_meshes);
fseek(iqmFile, iqm.ofs_meshes, SEEK_SET);
fread(imesh, sizeof(IQMMesh)*iqm.num_meshes, 1, iqmFile);
imesh = RL_MALLOC(sizeof(IQMMesh)*iqmHeader->num_meshes);
//fseek(iqmFile, iqmHeader->ofs_meshes, SEEK_SET);
//fread(imesh, sizeof(IQMMesh)*iqmHeader->num_meshes, 1, iqmFile);
memcpy(imesh, fileDataPtr + iqmHeader->ofs_meshes, iqmHeader->num_meshes*sizeof(IQMMesh));
model.meshCount = iqm.num_meshes;
model.meshCount = iqmHeader->num_meshes;
model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh));
model.materialCount = model.meshCount;
model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
char name[MESH_NAME_LENGTH] = { 0 };
char material[MATERIAL_NAME_LENGTH] = { 0 };
for (int i = 0; i < model.meshCount; i++)
{
fseek(iqmFile, iqm.ofs_text + imesh[i].name, SEEK_SET);
fread(name, sizeof(char)*MESH_NAME_LENGTH, 1, iqmFile); // Mesh name not used...
//fseek(iqmFile, iqmHeader->ofs_text + imesh[i].name, SEEK_SET);
//fread(name, sizeof(char)*MESH_NAME_LENGTH, 1, iqmFile);
memcpy(name, fileDataPtr + iqmHeader->ofs_text + imesh[i].name, MESH_NAME_LENGTH*sizeof(char));
//fseek(iqmFile, iqmHeader->ofs_text + imesh[i].material, SEEK_SET);
//fread(material, sizeof(char)*MATERIAL_NAME_LENGTH, 1, iqmFile);
memcpy(material, fileDataPtr + iqmHeader->ofs_text + imesh[i].material, MATERIAL_NAME_LENGTH*sizeof(char));
model.materials[i] = LoadMaterialDefault();
TRACELOG(LOG_DEBUG, "MODEL: [%s] mesh name (%s), material (%s)", fileName, name, material);
model.meshes[i].vertexCount = imesh[i].num_vertexes;
model.meshes[i].vertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex positions
@ -3209,9 +3224,10 @@ static Model LoadIQM(const char *fileName)
}
// Triangles data processing
tri = RL_MALLOC(iqm.num_triangles*sizeof(IQMTriangle));
fseek(iqmFile, iqm.ofs_triangles, SEEK_SET);
fread(tri, iqm.num_triangles*sizeof(IQMTriangle), 1, iqmFile);
tri = RL_MALLOC(iqmHeader->num_triangles*sizeof(IQMTriangle));
//fseek(iqmFile, iqmHeader->ofs_triangles, SEEK_SET);
//fread(tri, iqmHeader->num_triangles*sizeof(IQMTriangle), 1, iqmFile);
memcpy(tri, fileDataPtr + iqmHeader->ofs_triangles, iqmHeader->num_triangles*sizeof(IQMTriangle));
for (int m = 0; m < model.meshCount; m++)
{
@ -3228,21 +3244,23 @@ static Model LoadIQM(const char *fileName)
}
// Vertex arrays data processing
va = RL_MALLOC(iqm.num_vertexarrays*sizeof(IQMVertexArray));
fseek(iqmFile, iqm.ofs_vertexarrays, SEEK_SET);
fread(va, iqm.num_vertexarrays*sizeof(IQMVertexArray), 1, iqmFile);
va = RL_MALLOC(iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
//fseek(iqmFile, iqmHeader->ofs_vertexarrays, SEEK_SET);
//fread(va, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray), 1, iqmFile);
memcpy(va, fileDataPtr + iqmHeader->ofs_vertexarrays, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
for (unsigned int i = 0; i < iqm.num_vertexarrays; i++)
for (unsigned int i = 0; i < iqmHeader->num_vertexarrays; i++)
{
switch (va[i].type)
{
case IQM_POSITION:
{
vertex = RL_MALLOC(iqm.num_vertexes*3*sizeof(float));
fseek(iqmFile, va[i].offset, SEEK_SET);
fread(vertex, iqm.num_vertexes*3*sizeof(float), 1, iqmFile);
vertex = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
//fseek(iqmFile, va[i].offset, SEEK_SET);
//fread(vertex, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
memcpy(vertex, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
for (unsigned int m = 0; m < iqm.num_meshes; m++)
for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
{
int vCounter = 0;
for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++)
@ -3255,11 +3273,12 @@ static Model LoadIQM(const char *fileName)
} break;
case IQM_NORMAL:
{
normal = RL_MALLOC(iqm.num_vertexes*3*sizeof(float));
fseek(iqmFile, va[i].offset, SEEK_SET);
fread(normal, iqm.num_vertexes*3*sizeof(float), 1, iqmFile);
normal = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
//fseek(iqmFile, va[i].offset, SEEK_SET);
//fread(normal, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
memcpy(normal, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
for (unsigned int m = 0; m < iqm.num_meshes; m++)
for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
{
int vCounter = 0;
for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++)
@ -3272,11 +3291,12 @@ static Model LoadIQM(const char *fileName)
} break;
case IQM_TEXCOORD:
{
text = RL_MALLOC(iqm.num_vertexes*2*sizeof(float));
fseek(iqmFile, va[i].offset, SEEK_SET);
fread(text, iqm.num_vertexes*2*sizeof(float), 1, iqmFile);
text = RL_MALLOC(iqmHeader->num_vertexes*2*sizeof(float));
//fseek(iqmFile, va[i].offset, SEEK_SET);
//fread(text, iqmHeader->num_vertexes*2*sizeof(float), 1, iqmFile);
memcpy(text, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*2*sizeof(float));
for (unsigned int m = 0; m < iqm.num_meshes; m++)
for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
{
int vCounter = 0;
for (unsigned int i = imesh[m].first_vertex*2; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*2; i++)
@ -3288,11 +3308,12 @@ static Model LoadIQM(const char *fileName)
} break;
case IQM_BLENDINDEXES:
{
blendi = RL_MALLOC(iqm.num_vertexes*4*sizeof(char));
fseek(iqmFile, va[i].offset, SEEK_SET);
fread(blendi, iqm.num_vertexes*4*sizeof(char), 1, iqmFile);
blendi = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(char));
//fseek(iqmFile, va[i].offset, SEEK_SET);
//fread(blendi, iqmHeader->num_vertexes*4*sizeof(char), 1, iqmFile);
memcpy(blendi, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(char));
for (unsigned int m = 0; m < iqm.num_meshes; m++)
for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
{
int boneCounter = 0;
for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
@ -3304,11 +3325,12 @@ static Model LoadIQM(const char *fileName)
} break;
case IQM_BLENDWEIGHTS:
{
blendw = RL_MALLOC(iqm.num_vertexes*4*sizeof(unsigned char));
fseek(iqmFile, va[i].offset, SEEK_SET);
fread(blendw, iqm.num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
blendw = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
//fseek(iqmFile, va[i].offset, SEEK_SET);
//fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
memcpy(blendw, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
for (unsigned int m = 0; m < iqm.num_meshes; m++)
for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
{
int boneCounter = 0;
for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
@ -3322,20 +3344,22 @@ static Model LoadIQM(const char *fileName)
}
// Bones (joints) data processing
ijoint = RL_MALLOC(iqm.num_joints*sizeof(IQMJoint));
fseek(iqmFile, iqm.ofs_joints, SEEK_SET);
fread(ijoint, iqm.num_joints*sizeof(IQMJoint), 1, iqmFile);
ijoint = RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
//fseek(iqmFile, iqmHeader->ofs_joints, SEEK_SET);
//fread(ijoint, iqmHeader->num_joints*sizeof(IQMJoint), 1, iqmFile);
memcpy(ijoint, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint));
model.boneCount = iqm.num_joints;
model.bones = RL_MALLOC(iqm.num_joints*sizeof(BoneInfo));
model.bindPose = RL_MALLOC(iqm.num_joints*sizeof(Transform));
model.boneCount = iqmHeader->num_joints;
model.bones = RL_MALLOC(iqmHeader->num_joints*sizeof(BoneInfo));
model.bindPose = RL_MALLOC(iqmHeader->num_joints*sizeof(Transform));
for (unsigned int i = 0; i < iqm.num_joints; i++)
for (unsigned int i = 0; i < iqmHeader->num_joints; i++)
{
// Bones
model.bones[i].parent = ijoint[i].parent;
fseek(iqmFile, iqm.ofs_text + ijoint[i].name, SEEK_SET);
fread(model.bones[i].name, BONE_NAME_LENGTH*sizeof(char), 1, iqmFile);
//fseek(iqmFile, iqmHeader->ofs_text + ijoint[i].name, SEEK_SET);
//fread(model.bones[i].name, BONE_NAME_LENGTH*sizeof(char), 1, iqmFile);
memcpy(model.bones[i].name, fileDataPtr + iqmHeader->ofs_text + ijoint[i].name, BONE_NAME_LENGTH*sizeof(char));
// Bind pose (base pose)
model.bindPose[i].translation.x = ijoint[i].translate[0];
@ -3364,7 +3388,8 @@ static Model LoadIQM(const char *fileName)
}
}
fclose(iqmFile);
RL_FREE(fileData);
RL_FREE(imesh);
RL_FREE(tri);
RL_FREE(va);
@ -3479,7 +3504,7 @@ static Image LoadImageFromCgltfImage(cgltf_image *image, const char *texPath, Co
int width, height;
unsigned char *raw = stbi_load_from_memory(data, size, &width, &height, NULL, 4);
free(data);
RL_FREE(data);
rimage.data = raw;
rimage.width = width;
@ -3513,7 +3538,7 @@ static Image LoadImageFromCgltfImage(cgltf_image *image, const char *texPath, Co
int width, height;
unsigned char *raw = stbi_load_from_memory(data, (int)image->buffer_view->size, &width, &height, NULL, 4);
free(data);
RL_FREE(data);
rimage.data = raw;
rimage.width = width;
@ -3677,14 +3702,14 @@ static Model LoadGLTF(const char *fileName)
{
cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data;
model.meshes[primitiveIndex].vertexCount = (int)acc->count;
model.meshes[primitiveIndex].vertices = RL_MALLOC(sizeof(float)*model.meshes[primitiveIndex].vertexCount*3);
model.meshes[primitiveIndex].vertices = RL_MALLOC(model.meshes[primitiveIndex].vertexCount*3*sizeof(float));
LOAD_ACCESSOR(float, 3, acc, model.meshes[primitiveIndex].vertices)
}
else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_normal)
{
cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data;
model.meshes[primitiveIndex].normals = RL_MALLOC(sizeof(float)*acc->count*3);
model.meshes[primitiveIndex].normals = RL_MALLOC(acc->count*3*sizeof(float));
LOAD_ACCESSOR(float, 3, acc, model.meshes[primitiveIndex].normals)
}
@ -3694,7 +3719,7 @@ static Model LoadGLTF(const char *fileName)
if (acc->component_type == cgltf_component_type_r_32f)
{
model.meshes[primitiveIndex].texcoords = RL_MALLOC(sizeof(float)*acc->count*2);
model.meshes[primitiveIndex].texcoords = RL_MALLOC(acc->count*2*sizeof(float));
LOAD_ACCESSOR(float, 2, acc, model.meshes[primitiveIndex].texcoords)
}
else
@ -3712,7 +3737,7 @@ static Model LoadGLTF(const char *fileName)
if (acc->component_type == cgltf_component_type_r_16u)
{
model.meshes[primitiveIndex].triangleCount = (int)acc->count/3;
model.meshes[primitiveIndex].indices = RL_MALLOC(sizeof(unsigned short)*model.meshes[primitiveIndex].triangleCount*3);
model.meshes[primitiveIndex].indices = RL_MALLOC(model.meshes[primitiveIndex].triangleCount*3*sizeof(unsigned short));
LOAD_ACCESSOR(unsigned short, 1, acc, model.meshes[primitiveIndex].indices)
}
else

View File

@ -197,14 +197,13 @@ typedef struct tagBITMAPINFOHEADER {
#include "external/jar_mod.h" // MOD loading functions
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
#define DRFLAC_MALLOC RL_MALLOC
#define DRFLAC_REALLOC RL_REALLOC
#define DRFLAC_FREE RL_FREE
#if defined(SUPPORT_FILEFORMAT_WAV)
#define DRWAV_MALLOC RL_MALLOC
#define DRWAV_REALLOC RL_REALLOC
#define DRWAV_FREE RL_FREE
#define DR_FLAC_IMPLEMENTATION
#define DR_FLAC_NO_WIN32_IO
#include "external/dr_flac.h" // FLAC loading functions
#define DR_WAV_IMPLEMENTATION
#include "external/dr_wav.h" // WAV loading functions
#endif
#if defined(SUPPORT_FILEFORMAT_MP3)
@ -216,6 +215,16 @@ typedef struct tagBITMAPINFOHEADER {
#include "external/dr_mp3.h" // MP3 loading functions
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
#define DRFLAC_MALLOC RL_MALLOC
#define DRFLAC_REALLOC RL_REALLOC
#define DRFLAC_FREE RL_FREE
#define DR_FLAC_IMPLEMENTATION
#define DR_FLAC_NO_WIN32_IO
#include "external/dr_flac.h" // FLAC loading functions
#endif
#if defined(_MSC_VER)
#undef bool
#endif
@ -354,8 +363,8 @@ static Wave LoadMP3(const char *fileName); // Load MP3 file
#endif
#if defined(RAUDIO_STANDALONE)
bool IsFileExtension(const char *fileName, const char *ext);// Check file extension
void TraceLog(int msgType, const char *text, ...); // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
static bool IsFileExtension(const char *fileName, const char *ext); // Check file extension
static void SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated
#endif
//----------------------------------------------------------------------------------
@ -491,7 +500,7 @@ AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam
return NULL;
}
audioBuffer->data = RL_CALLOC(sizeInFrames*channels*ma_get_bytes_per_sample(format), 1);
if (sizeInFrames > 0) audioBuffer->data = RL_CALLOC(sizeInFrames*channels*ma_get_bytes_per_sample(format), 1);
// Audio data runs through a format converter
ma_data_converter_config converterConfig = ma_data_converter_config_init(format, AUDIO_DEVICE_FORMAT, channels, AUDIO_DEVICE_CHANNELS, sampleRate, AUDIO_DEVICE_SAMPLE_RATE);
@ -780,26 +789,29 @@ void ExportWave(Wave wave, const char *fileName)
// Export wave sample data to code (.h)
void ExportWaveAsCode(Wave wave, const char *fileName)
{
#define BYTES_TEXT_PER_LINE 20
#ifndef TEXT_BYTES_PER_LINE
#define TEXT_BYTES_PER_LINE 20
#endif
int waveDataSize = wave.sampleCount*wave.channels*wave.sampleSize/8;
// NOTE: Text data buffer size is estimated considering wave data size in bytes
// and requiring 6 char bytes for every byte: "0x00, "
char *txtData = (char *)RL_CALLOC(6*waveDataSize + 2000, sizeof(char));
int bytesCount = 0;
bytesCount += sprintf(txtData + bytesCount, "\n//////////////////////////////////////////////////////////////////////////////////\n");
bytesCount += sprintf(txtData + bytesCount, "// //\n");
bytesCount += sprintf(txtData + bytesCount, "// WaveAsCode exporter v1.0 - Wave data exported as an array of bytes //\n");
bytesCount += sprintf(txtData + bytesCount, "// //\n");
bytesCount += sprintf(txtData + bytesCount, "// more info and bugs-report: github.com/raysan5/raylib //\n");
bytesCount += sprintf(txtData + bytesCount, "// feedback and support: ray[at]raylib.com //\n");
bytesCount += sprintf(txtData + bytesCount, "// //\n");
bytesCount += sprintf(txtData + bytesCount, "// Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n");
bytesCount += sprintf(txtData + bytesCount, "// //\n");
bytesCount += sprintf(txtData + bytesCount, "//////////////////////////////////////////////////////////////////////////////////\n\n");
char varFileName[256] = { 0 };
int dataSize = wave.sampleCount*wave.channels*wave.sampleSize/8;
FILE *txtFile = fopen(fileName, "wt");
if (txtFile != NULL)
{
fprintf(txtFile, "\n//////////////////////////////////////////////////////////////////////////////////\n");
fprintf(txtFile, "// //\n");
fprintf(txtFile, "// WaveAsCode exporter v1.0 - Wave data exported as an array of bytes //\n");
fprintf(txtFile, "// //\n");
fprintf(txtFile, "// more info and bugs-report: github.com/raysan5/raylib //\n");
fprintf(txtFile, "// feedback and support: ray[at]raylib.com //\n");
fprintf(txtFile, "// //\n");
fprintf(txtFile, "// Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n");
fprintf(txtFile, "// //\n");
fprintf(txtFile, "//////////////////////////////////////////////////////////////////////////////////\n\n");
#if !defined(RAUDIO_STANDALONE)
// Get file name from path and convert variable name to uppercase
strcpy(varFileName, GetFileNameWithoutExt(fileName));
@ -808,19 +820,21 @@ void ExportWaveAsCode(Wave wave, const char *fileName)
strcpy(varFileName, fileName);
#endif
fprintf(txtFile, "// Wave data information\n");
fprintf(txtFile, "#define %s_SAMPLE_COUNT %u\n", varFileName, wave.sampleCount);
fprintf(txtFile, "#define %s_SAMPLE_RATE %u\n", varFileName, wave.sampleRate);
fprintf(txtFile, "#define %s_SAMPLE_SIZE %u\n", varFileName, wave.sampleSize);
fprintf(txtFile, "#define %s_CHANNELS %u\n\n", varFileName, wave.channels);
bytesCount += sprintf(txtData + bytesCount, "// Wave data information\n");
bytesCount += sprintf(txtData + bytesCount, "#define %s_SAMPLE_COUNT %u\n", varFileName, wave.sampleCount);
bytesCount += sprintf(txtData + bytesCount, "#define %s_SAMPLE_RATE %u\n", varFileName, wave.sampleRate);
bytesCount += sprintf(txtData + bytesCount, "#define %s_SAMPLE_SIZE %u\n", varFileName, wave.sampleSize);
bytesCount += sprintf(txtData + bytesCount, "#define %s_CHANNELS %u\n\n", varFileName, wave.channels);
// Write byte data as hexadecimal text
fprintf(txtFile, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize);
for (int i = 0; i < dataSize - 1; i++) fprintf(txtFile, ((i%BYTES_TEXT_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)wave.data)[i]);
fprintf(txtFile, "0x%x };\n", ((unsigned char *)wave.data)[dataSize - 1]);
bytesCount += sprintf(txtData + bytesCount, "static unsigned char %s_DATA[%i] = { ", varFileName, waveDataSize);
for (int i = 0; i < waveDataSize - 1; i++) bytesCount += sprintf(txtData + bytesCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)wave.data)[i]);
bytesCount += sprintf(txtData + bytesCount, "0x%x };\n", ((unsigned char *)wave.data)[waveDataSize - 1]);
fclose(txtFile);
}
// NOTE: Text data length exported is determined by '\0' (NULL) character
SaveFileText(fileName, txtData);
RL_FREE(txtData);
}
// Play a sound
@ -1046,6 +1060,24 @@ Music LoadMusicStream(const char *fileName)
bool musicLoaded = false;
if (false) { }
#if defined(SUPPORT_FILEFORMAT_WAV)
else if (IsFileExtension(fileName, ".wav"))
{
drwav *ctxWav = RL_MALLOC(sizeof(drwav));
bool success = drwav_init_file(ctxWav, fileName, NULL);
if (success)
{
music.ctxType = MUSIC_AUDIO_WAV;
music.ctxData = ctxWav;
music.stream = InitAudioStream(ctxWav->sampleRate, ctxWav->bitsPerSample, ctxWav->channels);
music.sampleCount = (unsigned int)ctxWav->totalPCMFrameCount*ctxWav->channels;
music.looping = true; // Looping enabled by default
musicLoaded = true;
}
}
#endif
#if defined(SUPPORT_FILEFORMAT_OGG)
else if (IsFileExtension(fileName, ".ogg"))
{
@ -1060,7 +1092,7 @@ Music LoadMusicStream(const char *fileName)
// OGG bit rate defaults to 16 bit, it's enough for compressed format
music.stream = InitAudioStream(info.sample_rate, 16, info.channels);
music.sampleCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData)*info.channels;
music.loopCount = 0; // Infinite loop by default
music.looping = true; // Looping enabled by default
musicLoaded = true;
}
}
@ -1077,7 +1109,7 @@ Music LoadMusicStream(const char *fileName)
music.stream = InitAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels);
music.sampleCount = (unsigned int)ctxFlac->totalSampleCount;
music.loopCount = 0; // Infinite loop by default
music.looping = true; // Looping enabled by default
musicLoaded = true;
}
}
@ -1096,7 +1128,7 @@ Music LoadMusicStream(const char *fileName)
music.stream = InitAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels);
music.sampleCount = (unsigned int)drmp3_get_pcm_frame_count(ctxMp3)*ctxMp3->channels;
music.loopCount = 0; // Infinite loop by default
music.looping = true; // Looping enabled by default
musicLoaded = true;
}
}
@ -1116,7 +1148,7 @@ Music LoadMusicStream(const char *fileName)
// NOTE: Only stereo is supported for XM
music.stream = InitAudioStream(48000, 16, 2);
music.sampleCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm)*2;
music.loopCount = 0; // Infinite loop by default
music.looping = true; // Looping enabled by default
jar_xm_reset(ctxXm); // make sure we start at the beginning of the song
musicLoaded = true;
@ -1139,7 +1171,7 @@ Music LoadMusicStream(const char *fileName)
// NOTE: Only stereo is supported for MOD
music.stream = InitAudioStream(48000, 16, 2);
music.sampleCount = (unsigned int)jar_mod_max_samples(ctxMod)*2;
music.loopCount = 0; // Infinite loop by default
music.looping = true; // Looping enabled by default
musicLoaded = true;
music.ctxData = ctxMod;
@ -1151,6 +1183,9 @@ Music LoadMusicStream(const char *fileName)
if (!musicLoaded)
{
if (false) { }
#if defined(SUPPORT_FILEFORMAT_WAV)
else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData);
#endif
#if defined(SUPPORT_FILEFORMAT_OGG)
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
#endif
@ -1188,6 +1223,9 @@ void UnloadMusicStream(Music music)
CloseAudioStream(music.stream);
if (false) { }
#if defined(SUPPORT_FILEFORMAT_WAV)
else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData);
#endif
#if defined(SUPPORT_FILEFORMAT_OGG)
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
#endif
@ -1239,6 +1277,9 @@ void StopMusicStream(Music music)
switch (music.ctxType)
{
#if defined(SUPPORT_FILEFORMAT_WAV)
case MUSIC_AUDIO_WAV: drwav_seek_to_pcm_frame((drwav *)music.ctxData, 0); break;
#endif
#if defined(SUPPORT_FILEFORMAT_OGG)
case MUSIC_AUDIO_OGG: stb_vorbis_seek_start((stb_vorbis *)music.ctxData); break;
#endif
@ -1283,6 +1324,14 @@ void UpdateMusicStream(Music music)
switch (music.ctxType)
{
#if defined(SUPPORT_FILEFORMAT_WAV)
case MUSIC_AUDIO_WAV:
{
// NOTE: Returns the number of samples to process (not required)
drwav_read_pcm_frames_s16((drwav *)music.ctxData, samplesCount/music.stream.channels, (short *)pcm);
} break;
#endif
#if defined(SUPPORT_FILEFORMAT_OGG)
case MUSIC_AUDIO_OGG:
{
@ -1347,14 +1396,7 @@ void UpdateMusicStream(Music music)
if (streamEnding)
{
StopMusicStream(music); // Stop music (and reset)
// Decrease loopCount to stop when required
if (music.loopCount > 1)
{
music.loopCount--; // Decrease loop count
PlayMusicStream(music); // Play again
}
else if (music.loopCount == 0) PlayMusicStream(music);
if (music.looping) PlayMusicStream(music); // Play again
}
else
{
@ -1382,13 +1424,6 @@ void SetMusicPitch(Music music, float pitch)
SetAudioStreamPitch(music.stream, pitch);
}
// Set music loop count (loop repeats)
// NOTE: If set to 0, means infinite loop
void SetMusicLoopCount(Music music, int count)
{
music.loopCount = count;
}
// Get music time length (in seconds)
float GetMusicTimeLength(Music music)
{
@ -1669,7 +1704,7 @@ static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, f
// detail to remember here is that we never, ever attempt to read more input data than is required for the specified number of output
// frames. This can be achieved with ma_data_converter_get_required_input_frame_count().
ma_uint8 inputBuffer[4096];
ma_uint32 inputBufferFrameCap = sizeof(inputBuffer) / ma_get_bytes_per_frame(audioBuffer->converter.config.formatIn, audioBuffer->converter.config.channelsIn);
ma_uint32 inputBufferFrameCap = sizeof(inputBuffer)/ma_get_bytes_per_frame(audioBuffer->converter.config.formatIn, audioBuffer->converter.config.channelsIn);
ma_uint32 totalOutputFramesProcessed = 0;
while (totalOutputFramesProcessed < frameCount)
@ -1812,6 +1847,7 @@ static void InitAudioBufferPool(void)
// Dummy buffers
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
{
// WARNING: An empty audioBuffer is created (data = 0)
AUDIO.MultiChannel.pool[i] = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO_DEVICE_SAMPLE_RATE, 0, AUDIO_BUFFER_USAGE_STATIC);
}
@ -1822,215 +1858,75 @@ static void InitAudioBufferPool(void)
// Close the audio buffers pool
static void CloseAudioBufferPool(void)
{
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
{
RL_FREE(AUDIO.MultiChannel.pool[i]->data);
RL_FREE(AUDIO.MultiChannel.pool[i]);
}
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) RL_FREE(AUDIO.MultiChannel.pool[i]);
}
#if defined(SUPPORT_FILEFORMAT_WAV)
// Load WAV file into Wave structure
static Wave LoadWAV(const char *fileName)
{
// Basic WAV headers structs
typedef struct {
char chunkID[4];
int chunkSize;
char format[4];
} WAVRiffHeader;
typedef struct {
char subChunkID[4];
int subChunkSize;
short audioFormat;
short numChannels;
int sampleRate;
int byteRate;
short blockAlign;
short bitsPerSample;
} WAVFormat;
typedef struct {
char subChunkID[4];
int subChunkSize;
} WAVData;
WAVRiffHeader wavRiffHeader = { 0 };
WAVFormat wavFormat = { 0 };
WAVData wavData = { 0 };
Wave wave = { 0 };
FILE *wavFile = NULL;
wavFile = fopen(fileName, "rb");
// Decode an entire WAV file in one go
unsigned long long int totalPCMFrameCount = 0;
wave.data = drwav_open_file_and_read_pcm_frames_s16(fileName, &wave.channels, &wave.sampleRate, &totalPCMFrameCount, NULL);
if (wavFile == NULL)
{
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open WAV file", fileName);
wave.data = NULL;
}
if (wave.data == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load WAV data", fileName);
else
{
// Read in the first chunk into the struct
fread(&wavRiffHeader, sizeof(WAVRiffHeader), 1, wavFile);
wave.sampleCount = (unsigned int)totalPCMFrameCount*wave.channels;
wave.sampleSize = 16;
// Check for RIFF and WAVE tags
if ((wavRiffHeader.chunkID[0] != 'R') ||
(wavRiffHeader.chunkID[1] != 'I') ||
(wavRiffHeader.chunkID[2] != 'F') ||
(wavRiffHeader.chunkID[3] != 'F') ||
(wavRiffHeader.format[0] != 'W') ||
(wavRiffHeader.format[1] != 'A') ||
(wavRiffHeader.format[2] != 'V') ||
(wavRiffHeader.format[3] != 'E'))
TRACELOG(LOG_INFO, "WAVE: [%s] WAV file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
}
/*
// Loading WAV from memory to avoid FILE accesses
unsigned int fileSize = 0;
unsigned char *fileData = LoadFileData(fileName, &fileSize);
drwav wav = { 0 };
bool success = drwav_init_memory(&wav, fileData, fileSize, NULL);
if (success)
{
TRACELOG(LOG_WARNING, "WAVE: [%s] RIFF or WAVE header are not valid", fileName);
}
else
{
// Read in the 2nd chunk for the wave info
fread(&wavFormat, sizeof(WAVFormat), 1, wavFile);
// Check for fmt tag
if ((wavFormat.subChunkID[0] != 'f') || (wavFormat.subChunkID[1] != 'm') ||
(wavFormat.subChunkID[2] != 't') || (wavFormat.subChunkID[3] != ' '))
{
TRACELOG(LOG_WARNING, "WAVE: [%s] Wave format header is not valid", fileName);
}
else
{
// Check for extra parameters;
if (wavFormat.subChunkSize > 16) fseek(wavFile, sizeof(short), SEEK_CUR);
// Read in the the last byte of data before the sound file
fread(&wavData, sizeof(WAVData), 1, wavFile);
// Check for data tag
if ((wavData.subChunkID[0] != 'd') || (wavData.subChunkID[1] != 'a') ||
(wavData.subChunkID[2] != 't') || (wavData.subChunkID[3] != 'a'))
{
TRACELOG(LOG_WARNING, "WAVE: [%s] Data header is not valid", fileName);
}
else
{
// Allocate memory for data
wave.data = RL_MALLOC(wavData.subChunkSize);
// Read in the sound data into the soundData variable
fread(wave.data, wavData.subChunkSize, 1, wavFile);
// Store wave parameters
wave.sampleRate = wavFormat.sampleRate;
wave.sampleSize = wavFormat.bitsPerSample;
wave.channels = wavFormat.numChannels;
// NOTE: Only support 8 bit, 16 bit and 32 bit sample sizes
if ((wave.sampleSize != 8) && (wave.sampleSize != 16) && (wave.sampleSize != 32))
{
TRACELOG(LOG_WARNING, "WAVE: [%s] Sample size (%ibit) not supported, converted to 16bit", fileName, wave.sampleSize);
WaveFormat(&wave, wave.sampleRate, 16, wave.channels);
}
// NOTE: Only support up to 2 channels (mono, stereo)
if (wave.channels > 2)
{
WaveFormat(&wave, wave.sampleRate, wave.sampleSize, 2);
TRACELOG(LOG_WARNING, "WAVE: [%s] Channels number (%i) not supported, converted to 2 channels", fileName, wave.channels);
}
// NOTE: subChunkSize comes in bytes, we need to translate it to number of samples
wave.sampleCount = (wavData.subChunkSize/(wave.sampleSize/8))/wave.channels;
TRACELOG(LOG_INFO, "WAVE: [%s] File loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
}
}
}
fclose(wavFile);
wave.sampleCount = wav.totalPCMFrameCount*wav.channels;
wave.sampleRate = wav.sampleRate;
wave.sampleSize = 16; // NOTE: We are forcing conversion to 16bit
wave.channels = wav.channels;
wave.data = (short *)RL_MALLOC(wave.sampleCount*sizeof(short));
drwav_read_pcm_frames_s16(&wav, wav.totalPCMFrameCount, wave.data);
}
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load WAV data", fileName);
drwav_uninit(&wav);
RL_FREE(fileData);
*/
return wave;
}
// Save wave data as WAV file
static int SaveWAV(Wave wave, const char *fileName)
{
int success = 0;
int dataSize = wave.sampleCount*wave.channels*wave.sampleSize/8;
drwav wav = { 0 };
drwav_data_format format = { 0 };
format.container = drwav_container_riff; // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64.
format.format = DR_WAVE_FORMAT_PCM; // <-- Any of the DR_WAVE_FORMAT_* codes.
format.channels = wave.channels;
format.sampleRate = wave.sampleRate;
format.bitsPerSample = wave.sampleSize;
// Basic WAV headers structs
typedef struct {
char chunkID[4];
int chunkSize;
char format[4];
} RiffHeader;
drwav_init_file_write(&wav, fileName, &format, NULL);
//drwav_init_memory_write(&wav, &fileData, &fileDataSize, &format, NULL); // Memory version
drwav_write_pcm_frames(&wav, wave.sampleCount/wave.channels, wave.data);
typedef struct {
char subChunkID[4];
int subChunkSize;
short audioFormat;
short numChannels;
int sampleRate;
int byteRate;
short blockAlign;
short bitsPerSample;
} WaveFormat;
drwav_uninit(&wav);
typedef struct {
char subChunkID[4];
int subChunkSize;
} WaveData;
// SaveFileData(fileName, fileData, fileDataSize);
//drwav_free(fileData, NULL);
FILE *wavFile = fopen(fileName, "wb");
if (wavFile == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open audio file", fileName);
else
{
RiffHeader riffHeader;
WaveFormat waveFormat;
WaveData waveData;
// Fill structs with data
riffHeader.chunkID[0] = 'R';
riffHeader.chunkID[1] = 'I';
riffHeader.chunkID[2] = 'F';
riffHeader.chunkID[3] = 'F';
riffHeader.chunkSize = 44 - 4 + wave.sampleCount*wave.sampleSize/8;
riffHeader.format[0] = 'W';
riffHeader.format[1] = 'A';
riffHeader.format[2] = 'V';
riffHeader.format[3] = 'E';
waveFormat.subChunkID[0] = 'f';
waveFormat.subChunkID[1] = 'm';
waveFormat.subChunkID[2] = 't';
waveFormat.subChunkID[3] = ' ';
waveFormat.subChunkSize = 16;
waveFormat.audioFormat = 1;
waveFormat.numChannels = wave.channels;
waveFormat.sampleRate = wave.sampleRate;
waveFormat.byteRate = wave.sampleRate*wave.sampleSize/8;
waveFormat.blockAlign = wave.sampleSize/8;
waveFormat.bitsPerSample = wave.sampleSize;
waveData.subChunkID[0] = 'd';
waveData.subChunkID[1] = 'a';
waveData.subChunkID[2] = 't';
waveData.subChunkID[3] = 'a';
waveData.subChunkSize = dataSize;
fwrite(&riffHeader, sizeof(RiffHeader), 1, wavFile);
fwrite(&waveFormat, sizeof(WaveFormat), 1, wavFile);
fwrite(&waveData, sizeof(WaveData), 1, wavFile);
success = (int)fwrite(wave.data, dataSize, 1, wavFile);
fclose(wavFile);
}
// If all data has been written correctly to file, success = 1
return success;
return true;
}
#endif
@ -2086,9 +1982,6 @@ static Wave LoadFLAC(const char *fileName)
wave.sampleCount = (unsigned int)totalSampleCount;
wave.sampleSize = 16;
// NOTE: Only support up to 2 channels (mono, stereo)
if (wave.channels > 2) TRACELOG(LOG_WARNING, "WAVE: [%s] FLAC channels number (%i) not supported", fileName, wave.channels);
TRACELOG(LOG_INFO, "WAVE: [%s] FLAC file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
}
@ -2129,7 +2022,7 @@ static Wave LoadMP3(const char *fileName)
// Some required functions for audio standalone module version
#if defined(RAUDIO_STANDALONE)
// Check file extension
bool IsFileExtension(const char *fileName, const char *ext)
static bool IsFileExtension(const char *fileName, const char *ext)
{
bool result = false;
const char *fileExt;
@ -2141,6 +2034,27 @@ bool IsFileExtension(const char *fileName, const char *ext)
return result;
}
// Save text data to file (write), string must be '\0' terminated
static void SaveFileText(const char *fileName, char *text)
{
if (fileName != NULL)
{
FILE *file = fopen(fileName, "wt");
if (file != NULL)
{
int count = fprintf(file, "%s", text);
if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write text file", fileName);
else TRACELOG(LOG_INFO, "FILEIO: [%s] Text file saved successfully", fileName);
fclose(file);
}
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName);
}
else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
}
#endif
#undef AudioBuffer

View File

@ -111,8 +111,8 @@ typedef struct Music {
int ctxType; // Type of music context (audio filetype)
void *ctxData; // Audio context data, depends on type
bool looping; // Music looping enable
unsigned int sampleCount; // Total number of samples
unsigned int loopCount; // Loops count (times music will play), 0 means infinite loop
AudioStream stream; // Audio stream
} Music;
@ -173,7 +173,6 @@ void ResumeMusicStream(Music music); // Resume playin
bool IsMusicPlaying(Music music); // Check if music is playing
void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level)
void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level)
void SetMusicLoopCount(Music music, int count); // Set music loop count (loop repeats)
float GetMusicTimeLength(Music music); // Get music time length (in seconds)
float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)

View File

@ -440,8 +440,8 @@ typedef struct Music {
int ctxType; // Type of music context (audio filetype)
void *ctxData; // Audio context data, depends on type
bool looping; // Music looping enable
unsigned int sampleCount; // Total number of samples
unsigned int loopCount; // Loops count (times music will play), 0 means infinite loop
AudioStream stream; // Audio stream
} Music;
@ -663,20 +663,17 @@ typedef enum {
} GamepadButton;
typedef enum {
// This is here just for error checking
GAMEPAD_AXIS_UNKNOWN = 0,
// Left stick
GAMEPAD_AXIS_LEFT_X,
GAMEPAD_AXIS_LEFT_Y,
GAMEPAD_AXIS_LEFT_X = 0,
GAMEPAD_AXIS_LEFT_Y = 1,
// Right stick
GAMEPAD_AXIS_RIGHT_X,
GAMEPAD_AXIS_RIGHT_Y,
GAMEPAD_AXIS_RIGHT_X = 2,
GAMEPAD_AXIS_RIGHT_Y = 3,
// Pressure levels for the back triggers
GAMEPAD_AXIS_LEFT_TRIGGER, // [1..-1] (pressure-level)
GAMEPAD_AXIS_RIGHT_TRIGGER // [1..-1] (pressure-level)
GAMEPAD_AXIS_LEFT_TRIGGER = 4, // [1..-1] (pressure-level)
GAMEPAD_AXIS_RIGHT_TRIGGER = 5 // [1..-1] (pressure-level)
} GamepadAxis;
// Shader location point type
@ -809,7 +806,8 @@ typedef enum {
typedef enum {
BLEND_ALPHA = 0, // Blend textures considering alpha (default)
BLEND_ADDITIVE, // Blend textures adding colors
BLEND_MULTIPLIED // Blend textures multiplying colors
BLEND_MULTIPLIED, // Blend textures multiplying colors
BLEND_ADD_COLORS // Blend textures adding colors (alternative)
} BlendMode;
// Gestures type
@ -913,6 +911,7 @@ RLAPI void HideCursor(void); // Hides curso
RLAPI bool IsCursorHidden(void); // Check if cursor is not visible
RLAPI void EnableCursor(void); // Enables cursor (unlock cursor)
RLAPI void DisableCursor(void); // Disables cursor (lock cursor)
RLAPI bool IsCursorOnScreen(void); // Check if cursor is on the current screen.
// Drawing-related functions
RLAPI void ClearBackground(Color color); // Set background color (framebuffer clear color)
@ -1119,8 +1118,6 @@ RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format
RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM)
RLAPI void ExportImage(Image image, const char *fileName); // Export image data to file
RLAPI void ExportImageAsCode(Image image, const char *fileName); // Export image as code file defining an array of bytes
RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array
RLAPI Vector4 *GetImageDataNormalized(Image image); // Get pixel data from image as Vector4 array (float normalized)
// Image generation functions
RLAPI Image GenImageColor(int width, int height, Color color); // Generate image: plain color
@ -1137,13 +1134,13 @@ RLAPI Image ImageCopy(Image image);
RLAPI Image ImageFromImage(Image image, Rectangle rec); // Create an image from another image piece
RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font)
RLAPI Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint); // Create an image from text (custom sprite font)
RLAPI void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two)
RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format
RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image
RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); // Clear alpha channel to desired color
RLAPI void ImageAlphaCrop(Image *image, float threshold); // Crop image depending on alpha value
RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel
RLAPI void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two)
RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle
RLAPI void ImageAlphaCrop(Image *image, float threshold); // Crop image depending on alpha value
RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); // Clear alpha channel to desired color
RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image
RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel
RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize image (Bicubic scaling algorithm)
RLAPI void ImageResizeNN(Image *image, int newWidth,int newHeight); // Resize image (Nearest-Neighbor scaling algorithm)
RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color color); // Resize canvas and fill with color
@ -1159,7 +1156,10 @@ RLAPI void ImageColorGrayscale(Image *image);
RLAPI void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100)
RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255)
RLAPI void ImageColorReplace(Image *image, Color color, Color replace); // Modify image color: replace color
RLAPI Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount); // Extract color palette from image to maximum size (memory should be freed)
RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array
RLAPI Color *GetImagePalette(Image image, int maxPaletteSize, int *extractCount); // Get color palette from image to maximum size (memory should be freed)
RLAPI Vector4 *GetImageDataNormalized(Image image); // Get pixel data from image as Vector4 array (float normalized)
RLAPI Rectangle GetImageAlphaBorder(Image image, float threshold); // Get image alpha border rectangle
// Image drawing functions
@ -1446,7 +1446,6 @@ RLAPI void ResumeMusicStream(Music music); // Resume
RLAPI bool IsMusicPlaying(Music music); // Check if music is playing
RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level)
RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level)
RLAPI void SetMusicLoopCount(Music music, int count); // Set music loop count (loop repeats)
RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds)
RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)

View File

@ -154,6 +154,18 @@ RMDEF float Lerp(float start, float end, float amount)
return start + amount*(end - start);
}
// Normalize input value within input range
RMDEF float Normalize(float value, float start, float end)
{
return (value - start) / (end - start);
}
// Remap input value within input range to output range
RMDEF float Remap(float value, float inputStart, float inputEnd, float outputStart, float outputEnd)
{
return (value - inputStart) / (inputEnd - inputStart) * (outputEnd - outputStart) + outputStart;
}
//----------------------------------------------------------------------------------
// Module Functions Definition - Vector2 math
//----------------------------------------------------------------------------------
@ -207,6 +219,13 @@ RMDEF float Vector2Length(Vector2 v)
return result;
}
// Calculate vector square length
RMDEF float Vector2LengthSqr(Vector2 v)
{
float result = (v.x*v.x) + (v.y*v.y);
return result;
}
// Calculate two vectors dot product
RMDEF float Vector2DotProduct(Vector2 v1, Vector2 v2)
{
@ -401,6 +420,13 @@ RMDEF float Vector3Length(const Vector3 v)
return result;
}
// Calculate vector square length
RMDEF float Vector3LengthSqr(const Vector3 v)
{
float result = v.x*v.x + v.y*v.y + v.z*v.z;
return result;
}
// Calculate two vectors dot product
RMDEF float Vector3DotProduct(Vector3 v1, Vector3 v2)
{

View File

@ -382,7 +382,8 @@ typedef unsigned char byte;
typedef enum {
BLEND_ALPHA = 0,
BLEND_ADDITIVE,
BLEND_MULTIPLIED
BLEND_MULTIPLIED,
BLEND_ADD_COLORS
} BlendMode;
// Shader location point type
@ -542,8 +543,8 @@ RLAPI bool rlRenderTextureComplete(RenderTexture target); // Ver
// Vertex data management
RLAPI void rlLoadMesh(Mesh *mesh, bool dynamic); // Upload vertex data into GPU and provided VAO/VBO ids
RLAPI void rlUpdateMesh(Mesh mesh, int buffer, int num); // Update vertex or index data on GPU (upload new data to one buffer)
RLAPI void rlUpdateMeshAt(Mesh mesh, int buffer, int num, int index); // Update vertex or index data on GPU, at index
RLAPI void rlUpdateMesh(Mesh mesh, int buffer, int count); // Update vertex or index data on GPU (upload new data to one buffer)
RLAPI void rlUpdateMeshAt(Mesh mesh, int buffer, int count, int index); // Update vertex or index data on GPU, at index
RLAPI void rlDrawMesh(Mesh mesh, Material material, Matrix transform); // Draw a 3d mesh with material and transform
RLAPI void rlUnloadMesh(Mesh mesh); // Unload mesh data from CPU and GPU
@ -1563,7 +1564,7 @@ void rlglInit(int width, int height)
// Get supported extensions list
GLint numExt = 0;
#if defined(GRAPHICS_API_OPENGL_33)
#if defined(GRAPHICS_API_OPENGL_33) && !defined(GRAPHICS_API_OPENGL_21)
// NOTE: On OpenGL 3.3 VAO and NPOT are supported by default
RLGL.ExtSupported.vao = true;
@ -1582,9 +1583,10 @@ void rlglInit(int width, int height)
// Get extensions strings
for (int i = 0; i < numExt; i++) extList[i] = (char *)glGetStringi(GL_EXTENSIONS, i);
#elif defined(GRAPHICS_API_OPENGL_ES2)
#endif
#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
// Allocate 512 strings pointers (2 KB)
const char **extList = RL_MALLOC(sizeof(const char *)*512);
const char **extList = RL_MALLOC(512*sizeof(const char *));
const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string
@ -1681,9 +1683,11 @@ void rlglInit(int width, int height)
// Free extensions pointers
RL_FREE(extList);
#if defined(GRAPHICS_API_OPENGL_ES2)
#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
RL_FREE(extensionsDup); // Duplicated string must be deallocated
#endif
#if defined(GRAPHICS_API_OPENGL_ES2)
if (RLGL.ExtSupported.vao) TRACELOG(LOG_INFO, "GL: VAO extension detected, VAO functions initialized successfully");
else TRACELOG(LOG_WARNING, "GL: VAO extension not found, VAO usage not supported");
@ -1933,8 +1937,6 @@ unsigned int rlLoadTexture(void *data, int width, int height, int format, int mi
int mipHeight = height;
int mipOffset = 0; // Mipmap data offset
TRACELOGD("TEXTURE: Load texture from data memory address: 0x%x", data);
// Load the different mipmap levels
for (int i = 0; i < mipmapCount; i++)
{
@ -2424,14 +2426,14 @@ void rlLoadMesh(Mesh *mesh, bool dynamic)
// Enable vertex attributes: position (shader-location = 0)
glGenBuffers(1, &mesh->vboId[0]);
glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->vertices, drawHint);
glBufferData(GL_ARRAY_BUFFER, mesh->vertexCount*3*sizeof(float), mesh->vertices, drawHint);
glVertexAttribPointer(0, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(0);
// Enable vertex attributes: texcoords (shader-location = 1)
glGenBuffers(1, &mesh->vboId[1]);
glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords, drawHint);
glBufferData(GL_ARRAY_BUFFER, mesh->vertexCount*2*sizeof(float), mesh->texcoords, drawHint);
glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(1);
@ -2440,7 +2442,7 @@ void rlLoadMesh(Mesh *mesh, bool dynamic)
{
glGenBuffers(1, &mesh->vboId[2]);
glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->normals, drawHint);
glBufferData(GL_ARRAY_BUFFER, mesh->vertexCount*3*sizeof(float), mesh->normals, drawHint);
glVertexAttribPointer(2, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(2);
}
@ -2456,7 +2458,7 @@ void rlLoadMesh(Mesh *mesh, bool dynamic)
{
glGenBuffers(1, &mesh->vboId[3]);
glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[3]);
glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*mesh->vertexCount, mesh->colors, drawHint);
glBufferData(GL_ARRAY_BUFFER, mesh->vertexCount*4*sizeof(unsigned char), mesh->colors, drawHint);
glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
glEnableVertexAttribArray(3);
}
@ -2472,7 +2474,7 @@ void rlLoadMesh(Mesh *mesh, bool dynamic)
{
glGenBuffers(1, &mesh->vboId[4]);
glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[4]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*mesh->vertexCount, mesh->tangents, drawHint);
glBufferData(GL_ARRAY_BUFFER, mesh->vertexCount*4*sizeof(float), mesh->tangents, drawHint);
glVertexAttribPointer(4, 4, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(4);
}
@ -2488,7 +2490,7 @@ void rlLoadMesh(Mesh *mesh, bool dynamic)
{
glGenBuffers(1, &mesh->vboId[5]);
glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[5]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords2, drawHint);
glBufferData(GL_ARRAY_BUFFER, mesh->vertexCount*2*sizeof(float), mesh->texcoords2, drawHint);
glVertexAttribPointer(5, 2, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(5);
}
@ -2503,7 +2505,7 @@ void rlLoadMesh(Mesh *mesh, bool dynamic)
{
glGenBuffers(1, &mesh->vboId[6]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->vboId[6]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short)*mesh->triangleCount*3, mesh->indices, drawHint);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh->triangleCount*3*sizeof(unsigned short), mesh->indices, drawHint);
}
if (RLGL.ExtSupported.vao)
@ -2542,15 +2544,15 @@ unsigned int rlLoadAttribBuffer(unsigned int vaoId, int shaderLoc, void *buffer,
}
// Update vertex or index data on GPU (upload new data to one buffer)
void rlUpdateMesh(Mesh mesh, int buffer, int num)
void rlUpdateMesh(Mesh mesh, int buffer, int count)
{
rlUpdateMeshAt(mesh, buffer, num, 0);
rlUpdateMeshAt(mesh, buffer, count, 0);
}
// Update vertex or index data on GPU, at index
// WARNING: error checking is in place that will cause the data to not be
// updated if offset + size exceeds what the buffer can hold
void rlUpdateMeshAt(Mesh mesh, int buffer, int num, int index)
void rlUpdateMeshAt(Mesh mesh, int buffer, int count, int index)
{
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Activate mesh VAO
@ -2561,60 +2563,61 @@ void rlUpdateMeshAt(Mesh mesh, int buffer, int num, int index)
case 0: // Update vertices (vertex position)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
if (index == 0 && num >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*num, mesh.vertices, GL_DYNAMIC_DRAW);
else if (index + num >= mesh.vertexCount) break;
else glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*3*index, sizeof(float)*3*num, mesh.vertices);
if (index == 0 && count >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, count*3*sizeof(float), mesh.vertices, GL_DYNAMIC_DRAW);
else if (index + count >= mesh.vertexCount) break;
else glBufferSubData(GL_ARRAY_BUFFER, index*3*sizeof(float), count*3*sizeof(float), mesh.vertices);
} break;
case 1: // Update texcoords (vertex texture coordinates)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]);
if (index == 0 && num >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*num, mesh.texcoords, GL_DYNAMIC_DRAW);
else if (index + num >= mesh.vertexCount) break;
else glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*2*index, sizeof(float)*2*num, mesh.texcoords);
if (index == 0 && count >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, count*2*sizeof(float), mesh.texcoords, GL_DYNAMIC_DRAW);
else if (index + count >= mesh.vertexCount) break;
else glBufferSubData(GL_ARRAY_BUFFER, index*2*sizeof(float), count*2*sizeof(float), mesh.texcoords);
} break;
case 2: // Update normals (vertex normals)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[2]);
if (index == 0 && num >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*num, mesh.normals, GL_DYNAMIC_DRAW);
else if (index + num >= mesh.vertexCount) break;
else glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*3*index, sizeof(float)*3*num, mesh.normals);
if (index == 0 && count >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, count*3*sizeof(float), mesh.normals, GL_DYNAMIC_DRAW);
else if (index + count >= mesh.vertexCount) break;
else glBufferSubData(GL_ARRAY_BUFFER, index*3*sizeof(float), count*3*sizeof(float), mesh.normals);
} break;
case 3: // Update colors (vertex colors)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[3]);
if (index == 0 && num >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*num, mesh.colors, GL_DYNAMIC_DRAW);
else if (index + num >= mesh.vertexCount) break;
else glBufferSubData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*index, sizeof(unsigned char)*4*num, mesh.colors);
if (index == 0 && count >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, count*4*sizeof(float), mesh.colors, GL_DYNAMIC_DRAW);
else if (index + count >= mesh.vertexCount) break;
else glBufferSubData(GL_ARRAY_BUFFER, index*4*sizeof(unsigned char), count*4*sizeof(unsigned char), mesh.colors);
} break;
case 4: // Update tangents (vertex tangents)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[4]);
if (index == 0 && num >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*num, mesh.tangents, GL_DYNAMIC_DRAW);
else if (index + num >= mesh.vertexCount) break;
else glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*4*index, sizeof(float)*4*num, mesh.tangents);
if (index == 0 && count >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, count*4*sizeof(float), mesh.tangents, GL_DYNAMIC_DRAW);
else if (index + count >= mesh.vertexCount) break;
else glBufferSubData(GL_ARRAY_BUFFER, index*4*sizeof(float), count*4*sizeof(float), mesh.tangents);
} break;
case 5: // Update texcoords2 (vertex second texture coordinates)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[5]);
if (index == 0 && num >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*num, mesh.texcoords2, GL_DYNAMIC_DRAW);
else if (index + num >= mesh.vertexCount) break;
else glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*2*index, sizeof(float)*2*num, mesh.texcoords2);
if (index == 0 && count >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, count*2*sizeof(float), mesh.texcoords2, GL_DYNAMIC_DRAW);
else if (index + count >= mesh.vertexCount) break;
else glBufferSubData(GL_ARRAY_BUFFER, index*2*sizeof(float), count*2*sizeof(float), mesh.texcoords2);
} break;
case 6: // Update indices (triangle index buffer)
{
// the * 3 is because each triangle has 3 indices
unsigned short *indices = mesh.indices;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.vboId[6]);
if (index == 0 && num >= mesh.triangleCount)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(*indices)*num*3, indices, GL_DYNAMIC_DRAW);
else if (index + num >= mesh.triangleCount)
break;
else
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, sizeof(*indices)*index*3, sizeof(*indices)*num*3, indices);
if (index == 0 && count >= mesh.triangleCount) glBufferData(GL_ELEMENT_ARRAY_BUFFER, count*3*sizeof(*indices), indices, GL_DYNAMIC_DRAW);
else if (index + count >= mesh.triangleCount) break;
else glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, index*3*sizeof(*indices), count*3*sizeof(*indices), indices);
} break;
default: break;
}
@ -2862,7 +2865,7 @@ unsigned char *rlReadScreenPixels(int width, int height)
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, screenData);
// Flip image vertically!
unsigned char *imgData = (unsigned char *)RL_MALLOC(width*height*sizeof(unsigned char)*4);
unsigned char *imgData = (unsigned char *)RL_MALLOC(width*height*4*sizeof(unsigned char));
for (int y = height - 1; y >= 0; y--)
{
@ -3069,7 +3072,7 @@ Shader LoadShaderCode(const char *vsCode, const char *fsCode)
GLenum type = GL_ZERO;
// Get the name of the uniforms
glGetActiveUniform(shader.id, i,sizeof(name) - 1, &namelen, &num, &type, name);
glGetActiveUniform(shader.id, i, sizeof(name) - 1, &namelen, &num, &type, name);
name[namelen] = 0;
@ -3558,15 +3561,16 @@ void BeginBlendMode(int mode)
{
static int blendMode = 0; // Track current blending mode
if ((blendMode != mode) && (mode < 3))
if ((blendMode != mode) && (mode < 4))
{
rlglDraw();
switch (mode)
{
case BLEND_ALPHA: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break;
case BLEND_ADDITIVE: glBlendFunc(GL_SRC_ALPHA, GL_ONE); break; // Alternative: glBlendFunc(GL_ONE, GL_ONE);
case BLEND_ADDITIVE: glBlendFunc(GL_SRC_ALPHA, GL_ONE); break;
case BLEND_MULTIPLIED: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break;
case BLEND_ADD_COLORS: glBlendFunc(GL_ONE, GL_ONE); break;
default: break;
}
@ -4067,13 +4071,13 @@ static RenderBatch LoadRenderBatch(int numBuffers, int bufferElements)
{
batch.vertexBuffer[i].elementsCount = bufferElements;
batch.vertexBuffer[i].vertices = (float *)RL_MALLOC(sizeof(float)*3*4*bufferElements); // 3 float by vertex, 4 vertex by quad
batch.vertexBuffer[i].texcoords = (float *)RL_MALLOC(sizeof(float)*2*4*bufferElements); // 2 float by texcoord, 4 texcoord by quad
batch.vertexBuffer[i].colors = (unsigned char *)RL_MALLOC(sizeof(unsigned char)*4*4*bufferElements); // 4 float by color, 4 colors by quad
batch.vertexBuffer[i].vertices = (float *)RL_MALLOC(bufferElements*3*4*sizeof(float)); // 3 float by vertex, 4 vertex by quad
batch.vertexBuffer[i].texcoords = (float *)RL_MALLOC(bufferElements*2*4*sizeof(float)); // 2 float by texcoord, 4 texcoord by quad
batch.vertexBuffer[i].colors = (unsigned char *)RL_MALLOC(bufferElements*4*4*sizeof(unsigned char)); // 4 float by color, 4 colors by quad
#if defined(GRAPHICS_API_OPENGL_33)
batch.vertexBuffer[i].indices = (unsigned int *)RL_MALLOC(sizeof(unsigned int)*6*bufferElements); // 6 int by quad (indices)
batch.vertexBuffer[i].indices = (unsigned int *)RL_MALLOC(bufferElements*6*sizeof(unsigned int)); // 6 int by quad (indices)
#elif defined(GRAPHICS_API_OPENGL_ES2)
batch.vertexBuffer[i].indices = (unsigned short *)RL_MALLOC(sizeof(unsigned short)*6*bufferElements); // 6 int by quad (indices)
batch.vertexBuffer[i].indices = (unsigned short *)RL_MALLOC(bufferElements*6*sizeof(unsigned short)); // 6 int by quad (indices)
#endif
for (int j = 0; j < (3*4*bufferElements); j++) batch.vertexBuffer[i].vertices[j] = 0.0f;
@ -4118,21 +4122,21 @@ static RenderBatch LoadRenderBatch(int numBuffers, int bufferElements)
// Vertex position buffer (shader-location = 0)
glGenBuffers(1, &batch.vertexBuffer[i].vboId[0]);
glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*bufferElements, batch.vertexBuffer[i].vertices, GL_DYNAMIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, bufferElements*3*4*sizeof(float), batch.vertexBuffer[i].vertices, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(RLGL.State.currentShader.locs[LOC_VERTEX_POSITION]);
glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0);
// Vertex texcoord buffer (shader-location = 1)
glGenBuffers(1, &batch.vertexBuffer[i].vboId[1]);
glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*bufferElements, batch.vertexBuffer[i].texcoords, GL_DYNAMIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, bufferElements*2*4*sizeof(float), batch.vertexBuffer[i].texcoords, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(RLGL.State.currentShader.locs[LOC_VERTEX_TEXCOORD01]);
glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0);
// Vertex color buffer (shader-location = 3)
glGenBuffers(1, &batch.vertexBuffer[i].vboId[2]);
glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*4*bufferElements, batch.vertexBuffer[i].colors, GL_DYNAMIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, bufferElements*4*4*sizeof(unsigned char), batch.vertexBuffer[i].colors, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(RLGL.State.currentShader.locs[LOC_VERTEX_COLOR]);
glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
@ -4140,9 +4144,9 @@ static RenderBatch LoadRenderBatch(int numBuffers, int bufferElements)
glGenBuffers(1, &batch.vertexBuffer[i].vboId[3]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[3]);
#if defined(GRAPHICS_API_OPENGL_33)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*bufferElements, batch.vertexBuffer[i].indices, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferElements*6*sizeof(int), batch.vertexBuffer[i].indices, GL_STATIC_DRAW);
#elif defined(GRAPHICS_API_OPENGL_ES2)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short)*6*bufferElements, batch.vertexBuffer[i].indices, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferElements*6*sizeof(short), batch.vertexBuffer[i].indices, GL_STATIC_DRAW);
#endif
}
@ -4154,7 +4158,7 @@ static RenderBatch LoadRenderBatch(int numBuffers, int bufferElements)
// Init draw calls tracking system
//--------------------------------------------------------------------------------------------
batch.draws = (DrawCall *)RL_MALLOC(sizeof(DrawCall)*DEFAULT_BATCH_DRAWCALLS);
batch.draws = (DrawCall *)RL_MALLOC(DEFAULT_BATCH_DRAWCALLS*sizeof(DrawCall));
for (int i = 0; i < DEFAULT_BATCH_DRAWCALLS; i++)
{
@ -4190,17 +4194,17 @@ static void DrawRenderBatch(RenderBatch *batch)
// Vertex positions buffer
glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[0]);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*batch->vertexBuffer[batch->currentBuffer].vCounter, batch->vertexBuffer[batch->currentBuffer].vertices);
glBufferSubData(GL_ARRAY_BUFFER, 0, batch->vertexBuffer[batch->currentBuffer].vCounter*3*sizeof(float), batch->vertexBuffer[batch->currentBuffer].vertices);
//glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*batch->vertexBuffer[batch->currentBuffer].elementsCount, batch->vertexBuffer[batch->currentBuffer].vertices, GL_DYNAMIC_DRAW); // Update all buffer
// Texture coordinates buffer
glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[1]);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*batch->vertexBuffer[batch->currentBuffer].vCounter, batch->vertexBuffer[batch->currentBuffer].texcoords);
glBufferSubData(GL_ARRAY_BUFFER, 0, batch->vertexBuffer[batch->currentBuffer].vCounter*2*sizeof(float), batch->vertexBuffer[batch->currentBuffer].texcoords);
//glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*batch->vertexBuffer[batch->currentBuffer].elementsCount, batch->vertexBuffer[batch->currentBuffer].texcoords, GL_DYNAMIC_DRAW); // Update all buffer
// Colors buffer
glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[2]);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*batch->vertexBuffer[batch->currentBuffer].vCounter, batch->vertexBuffer[batch->currentBuffer].colors);
glBufferSubData(GL_ARRAY_BUFFER, 0, batch->vertexBuffer[batch->currentBuffer].vCounter*4*sizeof(unsigned char), batch->vertexBuffer[batch->currentBuffer].colors);
//glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*batch->vertexBuffer[batch->currentBuffer].elementsCount, batch->vertexBuffer[batch->currentBuffer].colors, GL_DYNAMIC_DRAW); // Update all buffer
// NOTE: glMapBuffer() causes sync issue.
@ -4298,9 +4302,9 @@ static void DrawRenderBatch(RenderBatch *batch)
// We need to define the number of indices to be processed: quadsCount*6
// NOTE: The final parameter tells the GPU the offset in bytes from the
// start of the index buffer to the location of the first index to process
glDrawElements(GL_TRIANGLES, batch->draws[i].vertexCount/4*6, GL_UNSIGNED_INT, (GLvoid *)(sizeof(GLuint)*vertexOffset/4*6));
glDrawElements(GL_TRIANGLES, batch->draws[i].vertexCount/4*6, GL_UNSIGNED_INT, (GLvoid *)(vertexOffset/4*6*sizeof(GLuint)));
#elif defined(GRAPHICS_API_OPENGL_ES2)
glDrawElements(GL_TRIANGLES, batch->draws[i].vertexCount/4*6, GL_UNSIGNED_SHORT, (GLvoid *)(sizeof(GLushort)*vertexOffset/4*6));
glDrawElements(GL_TRIANGLES, batch->draws[i].vertexCount/4*6, GL_UNSIGNED_SHORT, (GLvoid *)(vertexOffset/4*6*sizeof(GLushort)));
#endif
}
@ -4686,7 +4690,7 @@ char *LoadFileText(const char *fileName)
if (size > 0)
{
text = (char *)RL_MALLOC(sizeof(char)*(size + 1));
text = (char *)RL_MALLOC((size + 1)*sizeof(char));
int count = fread(text, sizeof(char), size, textFile);
// WARNING: \r\n is converted to \n on reading, so,

View File

@ -618,6 +618,8 @@ void DrawRectangleRec(Rectangle rec, Color color)
// Draw a color-filled rectangle with pro parameters
void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color)
{
if (rlCheckBufferLimit(4)) rlglDraw();
rlEnableTexture(GetShapesTexture().id);
rlPushMatrix();

View File

@ -54,12 +54,12 @@
#endif
#include <stdlib.h> // Required for: malloc(), free()
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fgets()
#include <string.h> // Required for: strcmp(), strstr(), strcpy(), strncpy(), strcat(), strncat(), sscanf()
#include <stdio.h> // Required for: vsprintf()
#include <string.h> // Required for: strcmp(), strstr(), strcpy(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()]
#include <stdarg.h> // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()]
#include <ctype.h> // Requried for: toupper(), tolower() [Used in TextToUpper(), TextToLower()]
#include "utils.h" // Required for: fopen() Android mapping
#include "utils.h" // Required for: LoadFileText()
#if defined(SUPPORT_FILEFORMAT_TTF)
#define STB_RECT_PACK_IMPLEMENTATION
@ -191,33 +191,31 @@ extern void LoadFontDefault(void)
// Re-construct image from defaultFontData and generate OpenGL texture
//----------------------------------------------------------------------
int imWidth = 128;
int imHeight = 128;
Image imFont = {
.data = calloc(128*128, 2), // 2 bytes per pixel (gray + alpha)
.width = 128,
.height = 128,
.format = UNCOMPRESSED_GRAY_ALPHA,
.mipmaps = 1
};
Color *imagePixels = (Color *)RL_MALLOC(imWidth*imHeight*sizeof(Color));
for (int i = 0; i < imWidth*imHeight; i++) imagePixels[i] = BLANK; // Initialize array
int counter = 0; // Font data elements counter
// Fill imgData with defaultFontData (convert from bit to pixel!)
for (int i = 0; i < imWidth*imHeight; i += 32)
// Fill image.data with defaultFontData (convert from bit to pixel!)
for (int i = 0, counter = 0; i < imFont.width*imFont.height; i += 32)
{
for (int j = 31; j >= 0; j--)
{
if (BIT_CHECK(defaultFontData[counter], j)) imagePixels[i+j] = WHITE;
if (BIT_CHECK(defaultFontData[counter], j))
{
// NOTE: We are unreferencing data as short, so,
// we must consider data as little-endian order (alpha + gray)
((unsigned short *)imFont.data)[i + j] = 0xffff;
}
else ((unsigned short *)imFont.data)[i + j] = 0x00ff;
}
counter++;
if (counter > 512) counter = 0; // Security check...
}
Image imFont = LoadImageEx(imagePixels, imWidth, imHeight);
ImageFormat(&imFont, UNCOMPRESSED_GRAY_ALPHA);
RL_FREE(imagePixels);
defaultFont.texture = LoadTextureFromImage(imFont);
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, charsCount
@ -445,9 +443,13 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
for (int i = 0; i < image.height*image.width; i++) if (COLOR_EQUAL(pixels[i], key)) pixels[i] = BLANK;
// Create a new image with the processed color data (key color replaced by BLANK)
Image fontClear = LoadImageEx(pixels, image.width, image.height);
RL_FREE(pixels); // Free pixels array memory
Image fontClear = {
.data = pixels,
.width = image.width,
.height = image.height,
.format = UNCOMPRESSED_R8G8B8A8,
.mipmaps = 1
};
// Create spritefont with all data parsed from image
Font font = { 0 };
@ -571,8 +573,15 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
// NOTE: We create an empty image for space character, it could be further required for atlas packing
if (ch == 32)
{
chars[i].image = GenImageColor(chars[i].advanceX, fontSize, BLANK);
ImageFormat(&chars[i].image, UNCOMPRESSED_GRAYSCALE);
Image imSpace = {
.data = calloc(chars[i].advanceX*fontSize, 2),
.width = chars[i].advanceX,
.height = fontSize,
.format = UNCOMPRESSED_GRAYSCALE,
.mipmaps = 1
};
chars[i].image = imSpace;
}
if (type == FONT_BITMAP)
@ -727,7 +736,6 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
// TODO: Crop image if required for smaller size
// Convert image data from GRAYSCALE to GRAY_ALPHA
// WARNING: ImageAlphaMask(&atlas, atlas) does not work in this case, requires manual operation
unsigned char *dataGrayAlpha = (unsigned char *)RL_MALLOC(atlas.width*atlas.height*sizeof(unsigned char)*2); // Two channels
for (int i = 0, k = 0; i < atlas.width*atlas.height; i++, k += 2)
@ -1093,40 +1101,6 @@ int GetGlyphIndex(Font font, int codepoint)
//----------------------------------------------------------------------------------
// Text strings management functions
//----------------------------------------------------------------------------------
// Copy one string to another, returns bytes copied
int TextCopy(char *dst, const char *src)
{
int bytes = 0;
if (dst != NULL)
{
while (*src != '\0')
{
*dst = *src;
dst++;
src++;
bytes++;
}
*dst = '\0';
}
return bytes;
}
// Check if two text string are equal
// REQUIRES: strcmp()
bool TextIsEqual(const char *text1, const char *text2)
{
bool result = false;
if (strcmp(text1, text2) == 0) result = true;
return result;
}
// Get text length in bytes, check for \0 character
unsigned int TextLength(const char *text)
{
@ -1166,6 +1140,58 @@ const char *TextFormat(const char *text, ...)
return currentBuffer;
}
// Get integer value from text
// NOTE: This function replaces atoi() [stdlib.h]
int TextToInteger(const char *text)
{
int value = 0;
int sign = 1;
if ((text[0] == '+') || (text[0] == '-'))
{
if (text[0] == '-') sign = -1;
text++;
}
for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0');
return value*sign;
}
#if defined(SUPPORT_TEXT_MANIPULATION)
// Copy one string to another, returns bytes copied
int TextCopy(char *dst, const char *src)
{
int bytes = 0;
if (dst != NULL)
{
while (*src != '\0')
{
*dst = *src;
dst++;
src++;
bytes++;
}
*dst = '\0';
}
return bytes;
}
// Check if two text string are equal
// REQUIRES: strcmp()
bool TextIsEqual(const char *text1, const char *text2)
{
bool result = false;
if (strcmp(text1, text2) == 0) result = true;
return result;
}
// Get a piece of a text string
const char *TextSubtext(const char *text, int position, int length)
{
@ -1261,29 +1287,32 @@ char *TextInsert(const char *text, const char *insert, int position)
}
// Join text strings with delimiter
// REQUIRES: strcat()
// REQUIRES: memset(), memcpy()
const char *TextJoin(const char **textList, int count, const char *delimiter)
{
static char text[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(text, 0, MAX_TEXT_BUFFER_LENGTH);
char *textPtr = text;
int totalLength = 0;
int delimiterLen = TextLength(delimiter);
for (int i = 0; i < count; i++)
{
int textListLength = TextLength(textList[i]);
int textLength = TextLength(textList[i]);
// Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH
if ((totalLength + textListLength) < MAX_TEXT_BUFFER_LENGTH)
if ((totalLength + textLength) < MAX_TEXT_BUFFER_LENGTH)
{
strcat(text, textList[i]);
totalLength += textListLength;
memcpy(textPtr, textList[i], textLength);
totalLength += textLength;
textPtr += textLength;
if ((delimiterLen > 0) && (i < (count - 1)))
{
strcat(text, delimiter);
memcpy(textPtr, delimiter, delimiterLen);
totalLength += delimiterLen;
textPtr += textLength;
}
}
}
@ -1415,24 +1444,6 @@ const char *TextToPascal(const char *text)
return buffer;
}
// Get integer value from text
// NOTE: This function replaces atoi() [stdlib.h]
int TextToInteger(const char *text)
{
int value = 0;
int sign = 1;
if ((text[0] == '+') || (text[0] == '-'))
{
if (text[0] == '-') sign = -1;
text++;
}
for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0');
return value*sign;
}
// Encode text codepoint into utf8 text (memory must be freed!)
char *TextToUtf8(int *codepoints, int length)
{
@ -1445,7 +1456,7 @@ char *TextToUtf8(int *codepoints, int length)
for (int i = 0, bytes = 0; i < length; i++)
{
utf8 = CodepointToUtf8(codepoints[i], &bytes);
strncpy(text + size, utf8, bytes);
memcpy(text + size, utf8, bytes);
size += bytes;
}
@ -1457,6 +1468,44 @@ char *TextToUtf8(int *codepoints, int length)
return text;
}
// Encode codepoint into utf8 text (char array length returned as parameter)
RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength)
{
static char utf8[6] = { 0 };
int length = 0;
if (codepoint <= 0x7f)
{
utf8[0] = (char)codepoint;
length = 1;
}
else if (codepoint <= 0x7ff)
{
utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0);
utf8[1] = (char)((codepoint & 0x3f) | 0x80);
length = 2;
}
else if (codepoint <= 0xffff)
{
utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0);
utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
utf8[2] = (char)((codepoint & 0x3f) | 0x80);
length = 3;
}
else if (codepoint <= 0x10ffff)
{
utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0);
utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80);
utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
utf8[3] = (char)((codepoint & 0x3f) | 0x80);
length = 4;
}
*byteLength = length;
return utf8;
}
// Get all codepoints in a string, codepoints count returned by parameters
int *GetCodepoints(const char *text, int *count)
{
@ -1498,7 +1547,7 @@ int GetCodepointsCount(const char *text)
return len;
}
#endif // SUPPORT_TEXT_MANIPULATION
// Returns next codepoint in a UTF8 encoded text, scanning until '\0' is found
// When a invalid UTF8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
@ -1612,50 +1661,23 @@ int GetNextCodepoint(const char *text, int *bytesProcessed)
return code;
}
// Encode codepoint into utf8 text (char array length returned as parameter)
RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength)
{
static char utf8[6] = { 0 };
int length = 0;
if (codepoint <= 0x7f)
{
utf8[0] = (char)codepoint;
length = 1;
}
else if (codepoint <= 0x7ff)
{
utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0);
utf8[1] = (char)((codepoint & 0x3f) | 0x80);
length = 2;
}
else if (codepoint <= 0xffff)
{
utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0);
utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
utf8[2] = (char)((codepoint & 0x3f) | 0x80);
length = 3;
}
else if (codepoint <= 0x10ffff)
{
utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0);
utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80);
utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
utf8[3] = (char)((codepoint & 0x3f) | 0x80);
length = 4;
}
*byteLength = length;
return utf8;
}
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
#if defined(SUPPORT_FILEFORMAT_FNT)
// Read a line from memory
// NOTE: Returns the number of bytes read
static int GetLine(const char *origin, char *buffer, int maxLength)
{
int count = 0;
for (; count < maxLength; count++) if (origin[count] == '\n') break;
memcpy(buffer, origin, count);
return count;
}
// Load a BMFont file (AngelCode font file)
// REQUIRES: strstr(), sscanf(), strrchr(), memcpy()
static Font LoadBMFont(const char *fileName)
{
#define MAX_BUFFER_SIZE 256
@ -1666,65 +1688,56 @@ static Font LoadBMFont(const char *fileName)
char *searchPoint = NULL;
int fontSize = 0;
int texWidth = 0;
int texHeight = 0;
char texFileName[129];
int charsCount = 0;
int imWidth = 0;
int imHeight = 0;
char imFileName[129];
int base = 0; // Useless data
FILE *fntFile = NULL;
fntFile = fopen(fileName, "rt");
if (fntFile == NULL)
{
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open FNT file", fileName);
return font;
}
char *fileText = LoadFileText(fileName);
char *fileTextPtr = fileText;
// NOTE: We skip first line, it contains no useful information
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
//searchPoint = strstr(buffer, "size");
//sscanf(searchPoint, "size=%i", &fontSize);
int lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
fileTextPtr += (lineBytes + 1);
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
// Read line data
lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
searchPoint = strstr(buffer, "lineHeight");
sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i", &fontSize, &base, &texWidth, &texHeight);
sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i", &fontSize, &base, &imWidth, &imHeight);
fileTextPtr += (lineBytes + 1);
TRACELOGD("FONT: [%s] Loaded font info:", fileName);
TRACELOGD(" > Base size: %i", fontSize);
TRACELOGD(" > Texture scale: %ix%i", texWidth, texHeight);
TRACELOGD(" > Texture scale: %ix%i", imWidth, imHeight);
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
searchPoint = strstr(buffer, "file");
sscanf(searchPoint, "file=\"%128[^\"]\"", texFileName);
sscanf(searchPoint, "file=\"%128[^\"]\"", imFileName);
fileTextPtr += (lineBytes + 1);
TRACELOGD(" > Texture filename: %s", texFileName);
TRACELOGD(" > Texture filename: %s", imFileName);
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
searchPoint = strstr(buffer, "count");
sscanf(searchPoint, "count=%i", &charsCount);
fileTextPtr += (lineBytes + 1);
TRACELOGD(" > Chars count: %i", charsCount);
// Compose correct path using route of .fnt file (fileName) and texFileName
// Compose correct path using route of .fnt file (fileName) and imFileName
char *texPath = NULL;
char *lastSlash = NULL;
lastSlash = strrchr(fileName, '/');
if (lastSlash == NULL)
{
lastSlash = strrchr(fileName, '\\');
}
if (lastSlash == NULL) lastSlash = strrchr(fileName, '\\');
// NOTE: We need some extra space to avoid memory corruption on next allocations!
texPath = RL_MALLOC(TextLength(fileName) - TextLength(lastSlash) + TextLength(texFileName) + 4);
// NOTE: strcat() and strncat() required a '\0' terminated string to work!
*texPath = '\0';
strncat(texPath, fileName, TextLength(fileName) - TextLength(lastSlash) + 1);
strncat(texPath, texFileName, TextLength(texFileName));
texPath = RL_CALLOC(TextLength(fileName) - TextLength(lastSlash) + TextLength(imFileName) + 4, 1);
memcpy(texPath, fileName, TextLength(fileName) - TextLength(lastSlash) + 1);
memcpy(texPath + TextLength(fileName) - TextLength(lastSlash) + 1, imFileName, TextLength(imFileName));
TRACELOGD(" > Texture loading path: %s", texPath);
@ -1733,8 +1746,22 @@ static Font LoadBMFont(const char *fileName)
if (imFont.format == UNCOMPRESSED_GRAYSCALE)
{
// Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel
ImageAlphaMask(&imFont, imFont);
for (int p = 0; p < (imFont.width*imFont.height*2); p += 2) ((unsigned char *)(imFont.data))[p] = 0xff;
Image imFontAlpha = {
.data = calloc(imFont.width*imFont.height, 2),
.width = imFont.width,
.height = imFont.height,
.format = UNCOMPRESSED_GRAY_ALPHA,
.mipmaps = 1
};
for (int p = 0, i = 0; p < (imFont.width*imFont.height*2); p += 2, i++)
{
((unsigned char *)(imFontAlpha.data))[p] = 0xff;
((unsigned char *)(imFontAlpha.data))[p + 1] = ((unsigned char *)imFont.data)[i];
}
UnloadImage(imFont);
imFont = imFontAlpha;
}
font.texture = LoadTextureFromImage(imFont);
@ -1751,9 +1778,10 @@ static Font LoadBMFont(const char *fileName)
for (int i = 0; i < charsCount; i++)
{
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i",
&charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX);
fileTextPtr += (lineBytes + 1);
// Get character rectangle in the font atlas texture
font.recs[i] = (Rectangle){ (float)charX, (float)charY, (float)charWidth, (float)charHeight };
@ -1769,8 +1797,7 @@ static Font LoadBMFont(const char *fileName)
}
UnloadImage(imFont);
fclose(fntFile);
RL_FREE(fileText);
if (font.texture.id == 0)
{

File diff suppressed because it is too large Load Diff

View File

@ -199,7 +199,7 @@ unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead)
if (size > 0)
{
data = (unsigned char *)RL_MALLOC(sizeof(unsigned char)*size);
data = (unsigned char *)RL_MALLOC(size*sizeof(unsigned char));
// NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements]
unsigned int count = (unsigned int)fread(data, sizeof(unsigned char), size, file);
@ -274,7 +274,7 @@ char *LoadFileText(const char *fileName)
if (size > 0)
{
text = (char *)RL_MALLOC(sizeof(char)*(size + 1));
text = (char *)RL_MALLOC((size + 1)*sizeof(char));
unsigned int count = (unsigned int)fread(text, sizeof(char), size, textFile);
// WARNING: \r\n is converted to \n on reading, so,