Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
4f569813d2
16
.gitignore
vendored
16
.gitignore
vendored
|
|
@ -34,13 +34,10 @@ Thumbs.db
|
||||||
|
|
||||||
[Bb]in
|
[Bb]in
|
||||||
[Dd]ebug/
|
[Dd]ebug/
|
||||||
[Dd]ebug.win32/
|
|
||||||
[Dd]ebug.DLL/
|
|
||||||
*.sbr
|
*.sbr
|
||||||
*.sdf
|
*.sdf
|
||||||
obj/
|
obj/
|
||||||
[R]elease/
|
[R]elease/
|
||||||
[Rr]elease.win32/
|
|
||||||
_ReSharper*/
|
_ReSharper*/
|
||||||
[Tt]est[Rr]esult*
|
[Tt]est[Rr]esult*
|
||||||
ipch/
|
ipch/
|
||||||
|
|
@ -62,7 +59,6 @@ examples/*
|
||||||
!examples/*/
|
!examples/*/
|
||||||
# Unignore all examples files with extension
|
# Unignore all examples files with extension
|
||||||
!examples/*.c
|
!examples/*.c
|
||||||
!examples/*.lua
|
|
||||||
!examples/*.png
|
!examples/*.png
|
||||||
# Unignore examples Makefile
|
# Unignore examples Makefile
|
||||||
!examples/Makefile
|
!examples/Makefile
|
||||||
|
|
@ -70,17 +66,6 @@ examples/*
|
||||||
!examples/raylib_compile_execute.bat
|
!examples/raylib_compile_execute.bat
|
||||||
!examples/raylib_makefile_example.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
|
# Ignore files build by xcode
|
||||||
*.mode*v*
|
*.mode*v*
|
||||||
*.pbxuser
|
*.pbxuser
|
||||||
|
|
@ -112,7 +97,6 @@ build
|
||||||
|
|
||||||
# Unignore These makefiles...
|
# Unignore These makefiles...
|
||||||
!examples/CMakeLists.txt
|
!examples/CMakeLists.txt
|
||||||
!games/CMakeLists.txt
|
|
||||||
|
|
||||||
# Ignore GNU global tags
|
# Ignore GNU global tags
|
||||||
GPATH
|
GPATH
|
||||||
|
|
|
||||||
|
|
@ -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-haskell | [Haskell](https://www.haskell.org/) | https://github.com/DevJac/raylib-haskell |
|
||||||
| raylib-cr | Crystal | https://github.com/AregevDev/raylib-cr |
|
| raylib-cr | Crystal | https://github.com/AregevDev/raylib-cr |
|
||||||
| cray | Crystal | https://gitlab.com/Zatherz/cray |
|
| cray | Crystal | https://gitlab.com/Zatherz/cray |
|
||||||
| cray | Crystal | https://github.com/tapgg/cray |
|
|
||||||
| raylib.cr | Crystal | https://github.com/sam0x17/raylib.cr |
|
| raylib.cr | Crystal | https://github.com/sam0x17/raylib.cr |
|
||||||
| raylib-pascal | Pascal | https://github.com/drezgames/raylib-pascal |
|
| raylib-pascal | Pascal | https://github.com/drezgames/raylib-pascal |
|
||||||
| raylib-pas | Pascal | https://github.com/tazdij/raylib-pas |
|
| 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 |
|
| Euraylib | [Euphoria](https://openeuphoria.org/) | https://github.com/gAndy50/Euraylib |
|
||||||
| raylib-wren | [Wren](http://wren.io/) | https://github.com/TSnake41/raylib-wren |
|
| 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-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 |
|
| 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 |
|
| 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 |
|
| jaylib | [Janet](https://janet-lang.org/) | https://github.com/janet-lang/jaylib |
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ The following people has contributed with a generous donation to the raylib proj
|
||||||
|
|
||||||
- Jonathan Johnson ([@ecton](https://github.com/ecton))
|
- Jonathan Johnson ([@ecton](https://github.com/ecton))
|
||||||
- Eric J. ([@ProfJski](https://github.com/ProfJski))
|
- Eric J. ([@ProfJski](https://github.com/ProfJski))
|
||||||
|
- Rudy Faile ([@rfaile313](https://github.com/rfaile313))
|
||||||
|
|
||||||
## 🥉 Bronze Contributors
|
## 🥉 Bronze Contributors
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -411,7 +411,8 @@ TEXTURES = \
|
||||||
textures/textures_background_scrolling \
|
textures/textures_background_scrolling \
|
||||||
textures/textures_sprite_button \
|
textures/textures_sprite_button \
|
||||||
textures/textures_sprite_explosion \
|
textures/textures_sprite_explosion \
|
||||||
textures/textures_bunnymark
|
textures/textures_bunnymark \
|
||||||
|
textures/textures_blend_modes
|
||||||
|
|
||||||
TEXT = \
|
TEXT = \
|
||||||
text/text_raylib_fonts \
|
text/text_raylib_fonts \
|
||||||
|
|
|
||||||
|
|
@ -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.
|
Examples using raylib textures functionality, including image/textures loading/generation and drawing, provided by raylib [textures](../src/textures.c) module.
|
||||||
|
|
||||||
| ## | example | image | developer | new |
|
| ## | 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 | |
|
| 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 | |
|
| 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 | |
|
| 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 | ⭐️ |
|
| 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 | ⭐️ |
|
| 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) | ⭐️ |
|
| 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
|
### category: models
|
||||||
|
|
||||||
|
|
@ -98,24 +99,24 @@ Examples using raylib models functionality, including models loading/generation
|
||||||
|
|
||||||
| ## | example | image | developer | new |
|
| ## | 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_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_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_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_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_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_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_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_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_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_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 | [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* | |
|
|
||||||
| 77 | *TODO* | *TODO* | *TODO* | |
|
| 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 | ⭐️ |
|
| 78 | *TODO* | *TODO* | *TODO* | |
|
||||||
| 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) | |
|
| 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_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) | ⭐️ |
|
| 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_heightmap](models/models_heightmap.c) | <img src="models/models_heightmap.png" alt="models_heightmap" width="200"> | ray | |
|
| 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_skybox](models/models_skybox.c) | <img src="models/models_skybox.png" alt="models_skybox" width="200"> | ray | |
|
| 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
|
### category: shaders
|
||||||
|
|
||||||
|
|
@ -123,19 +124,19 @@ Examples using raylib shaders functionality, including shaders loading, paramete
|
||||||
|
|
||||||
| ## | example | image | developer | new |
|
| ## | 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_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_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_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_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_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_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_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_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_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_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_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_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) | ⭐️ |
|
| 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
|
### category: audio
|
||||||
|
|
||||||
|
|
@ -143,11 +144,11 @@ Examples using raylib audio functionality, including sound/music loading and pla
|
||||||
|
|
||||||
| ## | example | image | developer | new |
|
| ## | 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_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_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_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 | |
|
| 10 | [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) | ⭐️ |
|
| 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
|
### category: physics
|
||||||
|
|
||||||
|
|
@ -155,11 +156,11 @@ Examples showing physics functionality with raylib. This functionality is provid
|
||||||
|
|
||||||
| ## | example | image | developer | new |
|
| ## | 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_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_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_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_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) | |
|
| 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
|
### category: network
|
||||||
|
|
||||||
|
|
@ -169,13 +170,13 @@ Examples showing raylib network functionality. This functionality is provided by
|
||||||
|
|
||||||
| ## | example | image | developer | new |
|
| ## | example | image | developer | new |
|
||||||
|----|----------|--------|:----------:|:---:|
|
|----|----------|--------|:----------:|:---:|
|
||||||
| 106 | [network_ping_pong](network/network_ping_pong.c) | | [Jak Barnes](https://github.com/syphonx) | |
|
| 107 | [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_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_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_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_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_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) | |
|
| 113 | [network_udp_server](network/network_udp_server.c) | | [Jak Barnes](https://github.com/syphonx) | |
|
||||||
|
|
||||||
### category: others
|
### category: others
|
||||||
|
|
||||||
|
|
@ -183,9 +184,9 @@ Examples showing raylib misc functionality that does not fit in other categories
|
||||||
|
|
||||||
| ## | example | image | developer | new |
|
| ## | example | image | developer | new |
|
||||||
|----|----------|--------|:----------:|:---:|
|
|----|----------|--------|:----------:|:---:|
|
||||||
| 113 | [raudio_standalone](others/raudio_standalone.c) | | ray | |
|
| 114 | [raudio_standalone](others/raudio_standalone.c) | | ray | |
|
||||||
| 114 | [rlgl_standalone](others/rlgl_standalone.c) | | ray | |
|
| 115 | [rlgl_standalone](others/rlgl_standalone.c) | | ray | |
|
||||||
| 115 | [easings_testbed](others/easings_testbed.c) | | [Juan Miguel López](https://github.com/flashback-fx) | |
|
| 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!
|
As always contributions are welcome, feel free to send new examples! Here it is an [examples template](examples_template.c) to start with!
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ int main(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
Music music = LoadMusicStream("resources/mini1111.xm");
|
Music music = LoadMusicStream("resources/mini1111.xm");
|
||||||
|
music.looping = false;
|
||||||
|
|
||||||
PlayMusicStream(music);
|
PlayMusicStream(music);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,13 +92,13 @@ int main(void)
|
||||||
DrawCircle(259, 152, 39, BLACK);
|
DrawCircle(259, 152, 39, BLACK);
|
||||||
DrawCircle(259, 152, 34, LIGHTGRAY);
|
DrawCircle(259, 152, 34, LIGHTGRAY);
|
||||||
DrawCircle(259 + (GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_AXIS_LEFT_X)*20),
|
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
|
// Draw axis: right joystick
|
||||||
DrawCircle(461, 237, 38, BLACK);
|
DrawCircle(461, 237, 38, BLACK);
|
||||||
DrawCircle(461, 237, 33, LIGHTGRAY);
|
DrawCircle(461, 237, 33, LIGHTGRAY);
|
||||||
DrawCircle(461 + (GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_AXIS_RIGHT_X)*20),
|
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
|
// Draw axis: left-right triggers
|
||||||
DrawRectangle(170, 30, 15, 70, GRAY);
|
DrawRectangle(170, 30, 15, 70, GRAY);
|
||||||
|
|
|
||||||
103
examples/others/embedded_files_loading.c
Normal file
103
examples/others/embedded_files_loading.c
Normal 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;
|
||||||
|
}
|
||||||
4893
examples/others/resources/audio_data.h
Normal file
4893
examples/others/resources/audio_data.h
Normal file
File diff suppressed because it is too large
Load Diff
9848
examples/others/resources/image_data.h
Normal file
9848
examples/others/resources/image_data.h
Normal file
File diff suppressed because it is too large
Load Diff
100
examples/textures/textures_blend_modes.c
Normal file
100
examples/textures/textures_blend_modes.c
Normal 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;
|
||||||
|
}
|
||||||
BIN
examples/textures/textures_blend_modes.png
Normal file
BIN
examples/textures/textures_blend_modes.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 152 KiB |
|
|
@ -117,6 +117,15 @@ elseif(${PLATFORM} MATCHES "Raspberry Pi")
|
||||||
set(PLATFORM_CPP "PLATFORM_RPI")
|
set(PLATFORM_CPP "PLATFORM_RPI")
|
||||||
set(GRAPHICS "GRAPHICS_API_OPENGL_ES2")
|
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()
|
endif()
|
||||||
|
|
||||||
if (${OPENGL_VERSION})
|
if (${OPENGL_VERSION})
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ option(SUPPORT_FILEFORMAT_PVR "Support loading PVR as textures" ${OFF})
|
||||||
# text.c
|
# text.c
|
||||||
option(SUPPORT_FILEFORMAT_FNT "Support loading fonts in FNT format" ON)
|
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_FILEFORMAT_TTF "Support loading font in TTF/OTF format" ON)
|
||||||
|
option(SUPPORT_TEXT_MANIPULATION "Support text manipulation functions" ON)
|
||||||
|
|
||||||
# models.c
|
# 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)
|
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)
|
||||||
|
|
|
||||||
11
src/config.h
11
src/config.h
|
|
@ -98,11 +98,12 @@
|
||||||
|
|
||||||
// Support image export functionality (.png, .bmp, .tga, .jpg)
|
// Support image export functionality (.png, .bmp, .tga, .jpg)
|
||||||
#define SUPPORT_IMAGE_EXPORT 1
|
#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)
|
// Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)
|
||||||
#define SUPPORT_IMAGE_GENERATION 1
|
#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
|
// Module: text - Configuration Flags
|
||||||
|
|
@ -114,6 +115,10 @@
|
||||||
#define SUPPORT_FILEFORMAT_FNT 1
|
#define SUPPORT_FILEFORMAT_FNT 1
|
||||||
#define SUPPORT_FILEFORMAT_TTF 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
|
// Module: models - Configuration Flags
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,9 @@
|
||||||
// Selected desired fileformats to be supported for loading.
|
// Selected desired fileformats to be supported for loading.
|
||||||
#cmakedefine SUPPORT_FILEFORMAT_FNT 1
|
#cmakedefine SUPPORT_FILEFORMAT_FNT 1
|
||||||
#cmakedefine SUPPORT_FILEFORMAT_TTF 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
|
// models.c
|
||||||
// Selected desired fileformats to be supported for loading.
|
// Selected desired fileformats to be supported for loading.
|
||||||
|
|
|
||||||
141
src/core.c
141
src/core.c
|
|
@ -496,7 +496,6 @@ static void InitTimer(void); // Initialize timer
|
||||||
static void Wait(float ms); // Wait for some milliseconds (stop program execution)
|
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 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
|
static void PollInputEvents(void); // Register user events
|
||||||
|
|
||||||
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
|
#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)
|
#if defined(PLATFORM_WEB)
|
||||||
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData);
|
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 EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData);
|
||||||
static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
|
static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
|
||||||
static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, 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);
|
emscripten_set_fullscreenchange_callback("#canvas", NULL, 1, EmscriptenFullscreenChangeCallback);
|
||||||
|
|
||||||
// Support keyboard events
|
// 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
|
// Support mouse events
|
||||||
emscripten_set_click_callback("#canvas", NULL, 1, EmscriptenMouseCallback);
|
emscripten_set_click_callback("#canvas", NULL, 1, EmscriptenMouseCallback);
|
||||||
|
|
@ -917,11 +918,9 @@ bool IsWindowFullscreen(void)
|
||||||
// Toggle fullscreen mode (only PLATFORM_DESKTOP)
|
// Toggle fullscreen mode (only PLATFORM_DESKTOP)
|
||||||
void ToggleFullscreen(void)
|
void ToggleFullscreen(void)
|
||||||
{
|
{
|
||||||
CORE.Window.fullscreen = !CORE.Window.fullscreen; // Toggle fullscreen flag
|
|
||||||
|
|
||||||
#if defined(PLATFORM_DESKTOP)
|
#if defined(PLATFORM_DESKTOP)
|
||||||
// NOTE: glfwSetWindowMonitor() doesn't work properly (bugs)
|
// NOTE: glfwSetWindowMonitor() doesn't work properly (bugs)
|
||||||
if (CORE.Window.fullscreen)
|
if (!CORE.Window.fullscreen)
|
||||||
{
|
{
|
||||||
// Store previous window position (in case we exit fullscreen)
|
// Store previous window position (in case we exit fullscreen)
|
||||||
glfwGetWindowPos(CORE.Window.handle, &CORE.Window.position.x, &CORE.Window.position.y);
|
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);
|
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);
|
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
|
#endif
|
||||||
#if defined(PLATFORM_WEB)
|
#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
|
#endif
|
||||||
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
|
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
|
||||||
TRACELOG(LOG_WARNING, "SYSTEM: Failed to toggle to windowed mode");
|
TRACELOG(LOG_WARNING, "SYSTEM: Failed to toggle to windowed mode");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
CORE.Window.fullscreen = !CORE.Window.fullscreen; // Toggle fullscreen flag
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set icon for window (only PLATFORM_DESKTOP)
|
// Set icon for window (only PLATFORM_DESKTOP)
|
||||||
|
|
@ -1285,6 +1318,12 @@ void DisableCursor(void)
|
||||||
CORE.Input.Mouse.cursorHidden = true;
|
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)
|
// Set background color (framebuffer clear color)
|
||||||
void ClearBackground(Color color)
|
void ClearBackground(Color color)
|
||||||
{
|
{
|
||||||
|
|
@ -1950,6 +1989,7 @@ bool IsFileExtension(const char *fileName, const char *ext)
|
||||||
|
|
||||||
if (fileExt != NULL)
|
if (fileExt != NULL)
|
||||||
{
|
{
|
||||||
|
#if defined(SUPPORT_TEXT_MANIPULATION)
|
||||||
int extCount = 0;
|
int extCount = 0;
|
||||||
const char **checkExts = TextSplit(ext, ';', &extCount);
|
const char **checkExts = TextSplit(ext, ';', &extCount);
|
||||||
|
|
||||||
|
|
@ -1964,6 +2004,9 @@ bool IsFileExtension(const char *fileName, const char *ext)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (strcmp(fileExt, ext) == 0) result = true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -2084,11 +2127,13 @@ const char *GetPrevDirectoryPath(const char *dirPath)
|
||||||
|
|
||||||
if (pathLen <= 3) strcpy(prevDirPath, 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 ((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);
|
strncpy(prevDirPath, dirPath, i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -2509,7 +2554,9 @@ float GetGamepadAxisMovement(int gamepad, int axis)
|
||||||
float value = 0;
|
float value = 0;
|
||||||
|
|
||||||
#if !defined(PLATFORM_ANDROID)
|
#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
|
#endif
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
|
|
@ -3485,8 +3532,11 @@ static void InitTimer(void)
|
||||||
static void Wait(float ms)
|
static void Wait(float ms)
|
||||||
{
|
{
|
||||||
#if defined(PLATFORM_UWP)
|
#if defined(PLATFORM_UWP)
|
||||||
UWPGetSleepFunc()(ms / 1000);
|
UWPGetSleepFunc()(ms/1000);
|
||||||
#elif defined(SUPPORT_BUSY_WAIT_LOOP)
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(SUPPORT_BUSY_WAIT_LOOP)
|
||||||
double prevTime = GetTime();
|
double prevTime = GetTime();
|
||||||
double nextTime = 0.0;
|
double nextTime = 0.0;
|
||||||
|
|
||||||
|
|
@ -3514,7 +3564,7 @@ static void Wait(float ms)
|
||||||
usleep(ms*1000.0f);
|
usleep(ms*1000.0f);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(SUPPORT_HALFBUSY_WAIT_LOOP)// && !defined(PLATFORM_UWP)
|
#if defined(SUPPORT_HALFBUSY_WAIT_LOOP)
|
||||||
while (GetTime() < destTime) { }
|
while (GetTime() < destTime) { }
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -3579,40 +3629,6 @@ static int GetGamepadButton(int button)
|
||||||
return btn;
|
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
|
// Poll (store) all input events
|
||||||
static void PollInputEvents(void)
|
static void PollInputEvents(void)
|
||||||
{
|
{
|
||||||
|
|
@ -3710,8 +3726,9 @@ static void PollInputEvents(void)
|
||||||
// Get current gamepad state
|
// Get current gamepad state
|
||||||
// NOTE: There is no callback available, so we get it manually
|
// NOTE: There is no callback available, so we get it manually
|
||||||
// Get remapped buttons
|
// 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
|
glfwGetGamepadState(i, &state); // This remapps all gamepads so they have their buttons mapped like an xbox controller
|
||||||
|
|
||||||
const unsigned char *buttons = state.buttons;
|
const unsigned char *buttons = state.buttons;
|
||||||
|
|
||||||
for (int k = 0; (buttons != NULL) && (k < GLFW_GAMEPAD_BUTTON_DPAD_LEFT + 1) && (k < MAX_GAMEPAD_BUTTONS); k++)
|
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++)
|
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][k] = axes[k];
|
||||||
CORE.Input.Gamepad.axisState[i][axis] = axes[k];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register buttons for 2nd triggers (because GLFW doesn't count these as buttons but rather axis)
|
// 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
|
// Register axis data for every connected gamepad
|
||||||
for (int j = 0; (j < gamepadState.numAxes) && (j < MAX_GAMEPAD_AXIS); j++)
|
for (int j = 0; (j < gamepadState.numAxes) && (j < MAX_GAMEPAD_AXIS); j++)
|
||||||
{
|
{
|
||||||
const int axis = GetGamepadAxis(j);
|
CORE.Input.Gamepad.axisState[i][j] = gamepadState.axis[j];
|
||||||
CORE.Input.Gamepad.axisState[i][axis] = gamepadState.axis[j];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CORE.Input.Gamepad.axisCount = gamepadState.numAxes;
|
CORE.Input.Gamepad.axisCount = gamepadState.numAxes;
|
||||||
|
|
@ -4309,7 +4324,7 @@ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const Emscripte
|
||||||
//fs element id: (char *) event->id
|
//fs element id: (char *) event->id
|
||||||
//Current element size: (int) event->elementWidth, (int) event->elementHeight
|
//Current element size: (int) event->elementWidth, (int) event->elementHeight
|
||||||
//Screen size:(int) event->screenWidth, (int) event->screenHeight
|
//Screen size:(int) event->screenWidth, (int) event->screenHeight
|
||||||
|
/*
|
||||||
if (event->isFullscreen)
|
if (event->isFullscreen)
|
||||||
{
|
{
|
||||||
CORE.Window.fullscreen = true;
|
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
|
// TODO: Depending on scaling factor (screen vs element), calculate factor to scale mouse/touch input
|
||||||
|
*/
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register keyboard input events
|
// Register keyboard input events
|
||||||
static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
|
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();
|
emscripten_exit_pointerlock();
|
||||||
|
CORE.Window.fullscreen = false;
|
||||||
|
TraceLog(LOG_INFO, "CORE.Window.fullscreen = %s", CORE.Window.fullscreen? "true" : "false");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -4445,6 +4464,16 @@ static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadE
|
||||||
|
|
||||||
return 0;
|
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
|
#endif
|
||||||
|
|
||||||
#if defined(PLATFORM_RPI)
|
#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
|
// Identifies a input device and spawns a thread to handle it if needed
|
||||||
static void EventThreadSpawn(char *device)
|
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 NBITS(x) ((((x) - 1)/BITS_PER_LONG) + 1)
|
||||||
#define OFF(x) ((x)%BITS_PER_LONG)
|
#define OFF(x) ((x)%BITS_PER_LONG)
|
||||||
#define BIT(x) (1UL<<OFF(x))
|
#define BIT(x) (1UL<<OFF(x))
|
||||||
|
|
|
||||||
4877
src/external/dr_wav.h
vendored
4877
src/external/dr_wav.h
vendored
File diff suppressed because it is too large
Load Diff
353
src/models.c
353
src/models.c
|
|
@ -43,11 +43,10 @@
|
||||||
#include "config.h" // Defines module configuration flags
|
#include "config.h" // Defines module configuration flags
|
||||||
#endif
|
#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 <stdlib.h> // Required for: malloc(), free()
|
||||||
#include <stdio.h> // Required for: FILE, fopen(), fclose()
|
#include <string.h> // Required for: memcmp(), strlen()
|
||||||
#include <string.h> // Required for: strncmp() [Used in LoadModelAnimations()], strlen() [Used in LoadTextureFromCgltfImage()]
|
|
||||||
#include <math.h> // Required for: sinf(), cosf(), sqrtf(), fabsf()
|
#include <math.h> // Required for: sinf(), cosf(), sqrtf(), fabsf()
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
@ -825,57 +824,64 @@ void UnloadMesh(Mesh mesh)
|
||||||
// Export mesh data to file
|
// Export mesh data to file
|
||||||
void ExportMesh(Mesh mesh, const char *fileName)
|
void ExportMesh(Mesh mesh, const char *fileName)
|
||||||
{
|
{
|
||||||
bool success = false;
|
|
||||||
|
|
||||||
if (IsFileExtension(fileName, ".obj"))
|
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");
|
// NOTE: Text data buffer size is estimated considering mesh data size
|
||||||
fprintf(objFile, "# // //\n");
|
char *txtData = (char *)RL_CALLOC(dataSize + 2000, sizeof(char));
|
||||||
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);
|
|
||||||
|
|
||||||
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)
|
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)
|
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)
|
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)
|
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
|
// Load materials from model file
|
||||||
|
|
@ -959,11 +965,15 @@ void SetModelMeshMaterial(Model *model, int meshId, int materialId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load model animations from file
|
// 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_MAGIC "INTERQUAKEMODEL" // IQM file magic number
|
||||||
#define IQM_VERSION 2 // only IQM version 2 supported
|
#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 {
|
typedef struct IQMHeader {
|
||||||
char magic[16];
|
char magic[16];
|
||||||
unsigned int version;
|
unsigned int version;
|
||||||
|
|
@ -995,72 +1005,66 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount)
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
} IQMAnim;
|
} IQMAnim;
|
||||||
|
|
||||||
FILE *iqmFile = NULL;
|
// In case file can not be read, return an empty model
|
||||||
IQMHeader iqm;
|
if (fileDataPtr == NULL) return NULL;
|
||||||
|
|
||||||
iqmFile = fopen(filename,"rb");
|
|
||||||
|
|
||||||
if (!iqmFile)
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", filename);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read IQM header
|
// 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);
|
TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName);
|
||||||
fclose(iqmFile);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iqm.version != IQM_VERSION)
|
if (iqmHeader->version != IQM_VERSION)
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version incorrect", filename);
|
TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version);
|
||||||
fclose(iqmFile);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get bones data
|
// Get bones data
|
||||||
IQMPose *poses = RL_MALLOC(iqm.num_poses*sizeof(IQMPose));
|
IQMPose *poses = RL_MALLOC(iqmHeader->num_poses*sizeof(IQMPose));
|
||||||
fseek(iqmFile, iqm.ofs_poses, SEEK_SET);
|
//fseek(iqmFile, iqmHeader->ofs_poses, SEEK_SET);
|
||||||
fread(poses, iqm.num_poses*sizeof(IQMPose), 1, iqmFile);
|
//fread(poses, iqmHeader->num_poses*sizeof(IQMPose), 1, iqmFile);
|
||||||
|
memcpy(poses, fileDataPtr + iqmHeader->ofs_poses, iqmHeader->num_poses*sizeof(IQMPose));
|
||||||
|
|
||||||
// Get animations data
|
// Get animations data
|
||||||
*animCount = iqm.num_anims;
|
*animCount = iqmHeader->num_anims;
|
||||||
IQMAnim *anim = RL_MALLOC(iqm.num_anims*sizeof(IQMAnim));
|
IQMAnim *anim = RL_MALLOC(iqmHeader->num_anims*sizeof(IQMAnim));
|
||||||
fseek(iqmFile, iqm.ofs_anims, SEEK_SET);
|
//fseek(iqmFile, iqmHeader->ofs_anims, SEEK_SET);
|
||||||
fread(anim, iqm.num_anims*sizeof(IQMAnim), 1, iqmFile);
|
//fread(anim, iqmHeader->num_anims*sizeof(IQMAnim), 1, iqmFile);
|
||||||
ModelAnimation *animations = RL_MALLOC(iqm.num_anims*sizeof(ModelAnimation));
|
memcpy(anim, fileDataPtr + iqmHeader->ofs_anims, iqmHeader->num_anims*sizeof(IQMAnim));
|
||||||
|
|
||||||
|
ModelAnimation *animations = RL_MALLOC(iqmHeader->num_anims*sizeof(ModelAnimation));
|
||||||
|
|
||||||
// frameposes
|
// frameposes
|
||||||
unsigned short *framedata = RL_MALLOC(iqm.num_frames*iqm.num_framechannels*sizeof(unsigned short));
|
unsigned short *framedata = RL_MALLOC(iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
|
||||||
fseek(iqmFile, iqm.ofs_frames, SEEK_SET);
|
//fseek(iqmFile, iqmHeader->ofs_frames, SEEK_SET);
|
||||||
fread(framedata, iqm.num_frames*iqm.num_framechannels*sizeof(unsigned short), 1, iqmFile);
|
//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].frameCount = anim[a].num_frames;
|
||||||
animations[a].boneCount = iqm.num_poses;
|
animations[a].boneCount = iqmHeader->num_poses;
|
||||||
animations[a].bones = RL_MALLOC(iqm.num_poses*sizeof(BoneInfo));
|
animations[a].bones = RL_MALLOC(iqmHeader->num_poses*sizeof(BoneInfo));
|
||||||
animations[a].framePoses = RL_MALLOC(anim[a].num_frames*sizeof(Transform *));
|
animations[a].framePoses = RL_MALLOC(anim[a].num_frames*sizeof(Transform *));
|
||||||
//animations[a].framerate = anim.framerate; // TODO: Use framerate?
|
//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");
|
strcpy(animations[a].bones[j].name, "ANIMJOINTNAME");
|
||||||
animations[a].bones[j].parent = poses[j].parent;
|
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 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];
|
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(framedata);
|
||||||
RL_FREE(poses);
|
RL_FREE(poses);
|
||||||
RL_FREE(anim);
|
RL_FREE(anim);
|
||||||
|
|
||||||
fclose(iqmFile);
|
|
||||||
|
|
||||||
return animations;
|
return animations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1990,6 +1994,8 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
|
||||||
// NOTE: Vertex data is uploaded to GPU
|
// NOTE: Vertex data is uploaded to GPU
|
||||||
Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
|
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 mesh = { 0 };
|
||||||
mesh.vboId = (unsigned int *)RL_CALLOC(DEFAULT_MESH_VERTEX_BUFFERS, sizeof(unsigned int));
|
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 n2 = { -1.0f, 0.0f, 0.0f };
|
||||||
Vector3 n3 = { 0.0f, 1.0f, 0.0f };
|
Vector3 n3 = { 0.0f, 1.0f, 0.0f };
|
||||||
Vector3 n4 = { 0.0f, -1.0f, 0.0f };
|
Vector3 n4 = { 0.0f, -1.0f, 0.0f };
|
||||||
Vector3 n5 = { 0.0f, 0.0f, 1.0f };
|
Vector3 n5 = { 0.0f, 0.0f, -1.0f };
|
||||||
Vector3 n6 = { 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)
|
// NOTE: We use texture rectangles to define different textures for top-bottom-front-back-right-left (6)
|
||||||
typedef struct RectangleF {
|
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 v7 = { w*(x - 0.5f), 0, h*(z + 0.5f) };
|
||||||
Vector3 v8 = { 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
|
// We check pixel color to be WHITE -> draw full cube
|
||||||
if ((cubicmapPixels[z*cubicmap.width + x].r == 255) &&
|
if (COLOR_EQUAL(cubicmapPixels[z*cubicmap.width + x], WHITE))
|
||||||
(cubicmapPixels[z*cubicmap.width + x].g == 255) &&
|
|
||||||
(cubicmapPixels[z*cubicmap.width + x].b == 255))
|
|
||||||
{
|
{
|
||||||
// Define triangles (Checking Collateral Cubes!)
|
// Define triangles and checking collateral cubes
|
||||||
//----------------------------------------------
|
//------------------------------------------------
|
||||||
|
|
||||||
// Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
|
// 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] = v1;
|
||||||
mapVertices[vCounter + 1] = v2;
|
mapVertices[vCounter + 1] = v2;
|
||||||
mapVertices[vCounter + 2] = v3;
|
mapVertices[vCounter + 2] = v3;
|
||||||
|
|
@ -2108,10 +2113,8 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
|
||||||
mapTexcoords[tcCounter + 5] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
|
mapTexcoords[tcCounter + 5] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
|
||||||
tcCounter += 6;
|
tcCounter += 6;
|
||||||
|
|
||||||
if (((z < cubicmap.height - 1) &&
|
// Checking cube on bottom of current cube
|
||||||
(cubicmapPixels[(z + 1)*cubicmap.width + x].r == 0) &&
|
if (((z < cubicmap.height - 1) && COLOR_EQUAL(cubicmapPixels[(z + 1)*cubicmap.width + x], BLACK)) || (z == cubicmap.height - 1))
|
||||||
(cubicmapPixels[(z + 1)*cubicmap.width + x].g == 0) &&
|
|
||||||
(cubicmapPixels[(z + 1)*cubicmap.width + x].b == 0)) || (z == cubicmap.height - 1))
|
|
||||||
{
|
{
|
||||||
// Define front triangles (2 tris, 6 vertex) --> v2 v7 v3, v3 v7 v8
|
// Define front triangles (2 tris, 6 vertex) --> v2 v7 v3, v3 v7 v8
|
||||||
// NOTE: Collateral occluded faces are not generated
|
// NOTE: Collateral occluded faces are not generated
|
||||||
|
|
@ -2140,10 +2143,8 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
|
||||||
tcCounter += 6;
|
tcCounter += 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((z > 0) &&
|
// Checking cube on top of current cube
|
||||||
(cubicmapPixels[(z - 1)*cubicmap.width + x].r == 0) &&
|
if (((z > 0) && COLOR_EQUAL(cubicmapPixels[(z - 1)*cubicmap.width + x], BLACK)) || (z == 0))
|
||||||
(cubicmapPixels[(z - 1)*cubicmap.width + x].g == 0) &&
|
|
||||||
(cubicmapPixels[(z - 1)*cubicmap.width + x].b == 0)) || (z == 0))
|
|
||||||
{
|
{
|
||||||
// Define back triangles (2 tris, 6 vertex) --> v1 v5 v6, v1 v4 v5
|
// Define back triangles (2 tris, 6 vertex) --> v1 v5 v6, v1 v4 v5
|
||||||
// NOTE: Collateral occluded faces are not generated
|
// NOTE: Collateral occluded faces are not generated
|
||||||
|
|
@ -2172,10 +2173,8 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
|
||||||
tcCounter += 6;
|
tcCounter += 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((x < cubicmap.width - 1) &&
|
// Checking cube on right of current cube
|
||||||
(cubicmapPixels[z*cubicmap.width + (x + 1)].r == 0) &&
|
if (((x < cubicmap.width - 1) && COLOR_EQUAL(cubicmapPixels[z*cubicmap.width + (x + 1)], BLACK)) || (x == cubicmap.width - 1))
|
||||||
(cubicmapPixels[z*cubicmap.width + (x + 1)].g == 0) &&
|
|
||||||
(cubicmapPixels[z*cubicmap.width + (x + 1)].b == 0)) || (x == cubicmap.width - 1))
|
|
||||||
{
|
{
|
||||||
// Define right triangles (2 tris, 6 vertex) --> v3 v8 v4, v4 v8 v5
|
// Define right triangles (2 tris, 6 vertex) --> v3 v8 v4, v4 v8 v5
|
||||||
// NOTE: Collateral occluded faces are not generated
|
// NOTE: Collateral occluded faces are not generated
|
||||||
|
|
@ -2204,10 +2203,8 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
|
||||||
tcCounter += 6;
|
tcCounter += 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((x > 0) &&
|
// Checking cube on left of current cube
|
||||||
(cubicmapPixels[z*cubicmap.width + (x - 1)].r == 0) &&
|
if (((x > 0) && COLOR_EQUAL(cubicmapPixels[z*cubicmap.width + (x - 1)], BLACK)) || (x == 0))
|
||||||
(cubicmapPixels[z*cubicmap.width + (x - 1)].g == 0) &&
|
|
||||||
(cubicmapPixels[z*cubicmap.width + (x - 1)].b == 0)) || (x == 0))
|
|
||||||
{
|
{
|
||||||
// Define left triangles (2 tris, 6 vertex) --> v1 v7 v2, v1 v6 v7
|
// Define left triangles (2 tris, 6 vertex) --> v1 v7 v2, v1 v6 v7
|
||||||
// NOTE: Collateral occluded faces are not generated
|
// 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
|
// We check pixel color to be BLACK, we will only draw floor and roof
|
||||||
else if ((cubicmapPixels[z*cubicmap.width + x].r == 0) &&
|
else if (COLOR_EQUAL(cubicmapPixels[z*cubicmap.width + x], BLACK))
|
||||||
(cubicmapPixels[z*cubicmap.width + x].g == 0) &&
|
|
||||||
(cubicmapPixels[z*cubicmap.width + x].b == 0))
|
|
||||||
{
|
{
|
||||||
// Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
|
// Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
|
||||||
mapVertices[vCounter] = v1;
|
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[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;
|
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
|
// Fill texcoords buffer (float) using vertex index of the face
|
||||||
// NOTE: Y-coordinate must be flipped upside-down
|
// NOTE: Y-coordinate must be flipped upside-down
|
||||||
mesh.texcoords[vtCount + 0] = attrib.texcoords[idx0.vt_idx*2 + 0];
|
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 + 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 + 0] = attrib.texcoords[idx2.vt_idx*2 + 0];
|
||||||
mesh.texcoords[vtCount + 1] = 1.0f - attrib.texcoords[idx2.vt_idx*2 + 1]; vtCount += 2;
|
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
|
// 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[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[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;
|
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
|
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 BONE_NAME_LENGTH 32 // BoneInfo name string length
|
||||||
#define MESH_NAME_LENGTH 32 // Mesh 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
|
// IQM file structs
|
||||||
//-----------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------
|
||||||
|
|
@ -3136,13 +3142,10 @@ static Model LoadIQM(const char *fileName)
|
||||||
|
|
||||||
Model model = { 0 };
|
Model model = { 0 };
|
||||||
|
|
||||||
FILE *iqmFile = NULL;
|
IQMMesh *imesh = NULL;
|
||||||
IQMHeader iqm;
|
IQMTriangle *tri = NULL;
|
||||||
|
IQMVertexArray *va = NULL;
|
||||||
IQMMesh *imesh;
|
IQMJoint *ijoint = NULL;
|
||||||
IQMTriangle *tri;
|
|
||||||
IQMVertexArray *va;
|
|
||||||
IQMJoint *ijoint;
|
|
||||||
|
|
||||||
float *vertex = NULL;
|
float *vertex = NULL;
|
||||||
float *normal = NULL;
|
float *normal = NULL;
|
||||||
|
|
@ -3150,44 +3153,56 @@ static Model LoadIQM(const char *fileName)
|
||||||
char *blendi = NULL;
|
char *blendi = NULL;
|
||||||
unsigned char *blendw = 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)
|
// Read IQM header
|
||||||
{
|
IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr;
|
||||||
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open IQM file", fileName);
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
|
|
||||||
fread(&iqm, sizeof(IQMHeader), 1, iqmFile); // Read IQM header
|
if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0)
|
||||||
|
|
||||||
if (strncmp(iqm.magic, IQM_MAGIC, sizeof(IQM_MAGIC)))
|
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName);
|
TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName);
|
||||||
fclose(iqmFile);
|
|
||||||
return model;
|
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);
|
TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version);
|
||||||
fclose(iqmFile);
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//fileDataPtr += sizeof(IQMHeader); // Move file data pointer
|
||||||
|
|
||||||
// Meshes data processing
|
// Meshes data processing
|
||||||
imesh = RL_MALLOC(sizeof(IQMMesh)*iqm.num_meshes);
|
imesh = RL_MALLOC(sizeof(IQMMesh)*iqmHeader->num_meshes);
|
||||||
fseek(iqmFile, iqm.ofs_meshes, SEEK_SET);
|
//fseek(iqmFile, iqmHeader->ofs_meshes, SEEK_SET);
|
||||||
fread(imesh, sizeof(IQMMesh)*iqm.num_meshes, 1, iqmFile);
|
//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.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 name[MESH_NAME_LENGTH] = { 0 };
|
||||||
|
char material[MATERIAL_NAME_LENGTH] = { 0 };
|
||||||
|
|
||||||
for (int i = 0; i < model.meshCount; i++)
|
for (int i = 0; i < model.meshCount; i++)
|
||||||
{
|
{
|
||||||
fseek(iqmFile, iqm.ofs_text + imesh[i].name, SEEK_SET);
|
//fseek(iqmFile, iqmHeader->ofs_text + imesh[i].name, SEEK_SET);
|
||||||
fread(name, sizeof(char)*MESH_NAME_LENGTH, 1, iqmFile); // Mesh name not used...
|
//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].vertexCount = imesh[i].num_vertexes;
|
||||||
|
|
||||||
model.meshes[i].vertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex positions
|
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
|
// Triangles data processing
|
||||||
tri = RL_MALLOC(iqm.num_triangles*sizeof(IQMTriangle));
|
tri = RL_MALLOC(iqmHeader->num_triangles*sizeof(IQMTriangle));
|
||||||
fseek(iqmFile, iqm.ofs_triangles, SEEK_SET);
|
//fseek(iqmFile, iqmHeader->ofs_triangles, SEEK_SET);
|
||||||
fread(tri, iqm.num_triangles*sizeof(IQMTriangle), 1, iqmFile);
|
//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++)
|
for (int m = 0; m < model.meshCount; m++)
|
||||||
{
|
{
|
||||||
|
|
@ -3228,21 +3244,23 @@ static Model LoadIQM(const char *fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vertex arrays data processing
|
// Vertex arrays data processing
|
||||||
va = RL_MALLOC(iqm.num_vertexarrays*sizeof(IQMVertexArray));
|
va = RL_MALLOC(iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
|
||||||
fseek(iqmFile, iqm.ofs_vertexarrays, SEEK_SET);
|
//fseek(iqmFile, iqmHeader->ofs_vertexarrays, SEEK_SET);
|
||||||
fread(va, iqm.num_vertexarrays*sizeof(IQMVertexArray), 1, iqmFile);
|
//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)
|
switch (va[i].type)
|
||||||
{
|
{
|
||||||
case IQM_POSITION:
|
case IQM_POSITION:
|
||||||
{
|
{
|
||||||
vertex = RL_MALLOC(iqm.num_vertexes*3*sizeof(float));
|
vertex = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
|
||||||
fseek(iqmFile, va[i].offset, SEEK_SET);
|
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||||
fread(vertex, iqm.num_vertexes*3*sizeof(float), 1, iqmFile);
|
//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;
|
int vCounter = 0;
|
||||||
for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++)
|
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;
|
} break;
|
||||||
case IQM_NORMAL:
|
case IQM_NORMAL:
|
||||||
{
|
{
|
||||||
normal = RL_MALLOC(iqm.num_vertexes*3*sizeof(float));
|
normal = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
|
||||||
fseek(iqmFile, va[i].offset, SEEK_SET);
|
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||||
fread(normal, iqm.num_vertexes*3*sizeof(float), 1, iqmFile);
|
//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;
|
int vCounter = 0;
|
||||||
for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++)
|
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;
|
} break;
|
||||||
case IQM_TEXCOORD:
|
case IQM_TEXCOORD:
|
||||||
{
|
{
|
||||||
text = RL_MALLOC(iqm.num_vertexes*2*sizeof(float));
|
text = RL_MALLOC(iqmHeader->num_vertexes*2*sizeof(float));
|
||||||
fseek(iqmFile, va[i].offset, SEEK_SET);
|
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||||
fread(text, iqm.num_vertexes*2*sizeof(float), 1, iqmFile);
|
//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;
|
int vCounter = 0;
|
||||||
for (unsigned int i = imesh[m].first_vertex*2; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*2; i++)
|
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;
|
} break;
|
||||||
case IQM_BLENDINDEXES:
|
case IQM_BLENDINDEXES:
|
||||||
{
|
{
|
||||||
blendi = RL_MALLOC(iqm.num_vertexes*4*sizeof(char));
|
blendi = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(char));
|
||||||
fseek(iqmFile, va[i].offset, SEEK_SET);
|
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||||
fread(blendi, iqm.num_vertexes*4*sizeof(char), 1, iqmFile);
|
//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;
|
int boneCounter = 0;
|
||||||
for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
|
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;
|
} break;
|
||||||
case IQM_BLENDWEIGHTS:
|
case IQM_BLENDWEIGHTS:
|
||||||
{
|
{
|
||||||
blendw = RL_MALLOC(iqm.num_vertexes*4*sizeof(unsigned char));
|
blendw = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||||
fseek(iqmFile, va[i].offset, SEEK_SET);
|
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||||
fread(blendw, iqm.num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
|
//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;
|
int boneCounter = 0;
|
||||||
for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
|
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
|
// Bones (joints) data processing
|
||||||
ijoint = RL_MALLOC(iqm.num_joints*sizeof(IQMJoint));
|
ijoint = RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
|
||||||
fseek(iqmFile, iqm.ofs_joints, SEEK_SET);
|
//fseek(iqmFile, iqmHeader->ofs_joints, SEEK_SET);
|
||||||
fread(ijoint, iqm.num_joints*sizeof(IQMJoint), 1, iqmFile);
|
//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.boneCount = iqmHeader->num_joints;
|
||||||
model.bones = RL_MALLOC(iqm.num_joints*sizeof(BoneInfo));
|
model.bones = RL_MALLOC(iqmHeader->num_joints*sizeof(BoneInfo));
|
||||||
model.bindPose = RL_MALLOC(iqm.num_joints*sizeof(Transform));
|
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
|
// Bones
|
||||||
model.bones[i].parent = ijoint[i].parent;
|
model.bones[i].parent = ijoint[i].parent;
|
||||||
fseek(iqmFile, iqm.ofs_text + ijoint[i].name, SEEK_SET);
|
//fseek(iqmFile, iqmHeader->ofs_text + ijoint[i].name, SEEK_SET);
|
||||||
fread(model.bones[i].name, BONE_NAME_LENGTH*sizeof(char), 1, iqmFile);
|
//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)
|
// Bind pose (base pose)
|
||||||
model.bindPose[i].translation.x = ijoint[i].translate[0];
|
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(imesh);
|
||||||
RL_FREE(tri);
|
RL_FREE(tri);
|
||||||
RL_FREE(va);
|
RL_FREE(va);
|
||||||
|
|
@ -3479,7 +3504,7 @@ static Image LoadImageFromCgltfImage(cgltf_image *image, const char *texPath, Co
|
||||||
|
|
||||||
int width, height;
|
int width, height;
|
||||||
unsigned char *raw = stbi_load_from_memory(data, size, &width, &height, NULL, 4);
|
unsigned char *raw = stbi_load_from_memory(data, size, &width, &height, NULL, 4);
|
||||||
free(data);
|
RL_FREE(data);
|
||||||
|
|
||||||
rimage.data = raw;
|
rimage.data = raw;
|
||||||
rimage.width = width;
|
rimage.width = width;
|
||||||
|
|
@ -3513,7 +3538,7 @@ static Image LoadImageFromCgltfImage(cgltf_image *image, const char *texPath, Co
|
||||||
|
|
||||||
int width, height;
|
int width, height;
|
||||||
unsigned char *raw = stbi_load_from_memory(data, (int)image->buffer_view->size, &width, &height, NULL, 4);
|
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.data = raw;
|
||||||
rimage.width = width;
|
rimage.width = width;
|
||||||
|
|
@ -3677,14 +3702,14 @@ static Model LoadGLTF(const char *fileName)
|
||||||
{
|
{
|
||||||
cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data;
|
cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data;
|
||||||
model.meshes[primitiveIndex].vertexCount = (int)acc->count;
|
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)
|
LOAD_ACCESSOR(float, 3, acc, model.meshes[primitiveIndex].vertices)
|
||||||
}
|
}
|
||||||
else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_normal)
|
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;
|
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)
|
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)
|
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)
|
LOAD_ACCESSOR(float, 2, acc, model.meshes[primitiveIndex].texcoords)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -3712,7 +3737,7 @@ static Model LoadGLTF(const char *fileName)
|
||||||
if (acc->component_type == cgltf_component_type_r_16u)
|
if (acc->component_type == cgltf_component_type_r_16u)
|
||||||
{
|
{
|
||||||
model.meshes[primitiveIndex].triangleCount = (int)acc->count/3;
|
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)
|
LOAD_ACCESSOR(unsigned short, 1, acc, model.meshes[primitiveIndex].indices)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
408
src/raudio.c
408
src/raudio.c
|
|
@ -197,14 +197,13 @@ typedef struct tagBITMAPINFOHEADER {
|
||||||
#include "external/jar_mod.h" // MOD loading functions
|
#include "external/jar_mod.h" // MOD loading functions
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(SUPPORT_FILEFORMAT_FLAC)
|
#if defined(SUPPORT_FILEFORMAT_WAV)
|
||||||
#define DRFLAC_MALLOC RL_MALLOC
|
#define DRWAV_MALLOC RL_MALLOC
|
||||||
#define DRFLAC_REALLOC RL_REALLOC
|
#define DRWAV_REALLOC RL_REALLOC
|
||||||
#define DRFLAC_FREE RL_FREE
|
#define DRWAV_FREE RL_FREE
|
||||||
|
|
||||||
#define DR_FLAC_IMPLEMENTATION
|
#define DR_WAV_IMPLEMENTATION
|
||||||
#define DR_FLAC_NO_WIN32_IO
|
#include "external/dr_wav.h" // WAV loading functions
|
||||||
#include "external/dr_flac.h" // FLAC loading functions
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(SUPPORT_FILEFORMAT_MP3)
|
#if defined(SUPPORT_FILEFORMAT_MP3)
|
||||||
|
|
@ -216,6 +215,16 @@ typedef struct tagBITMAPINFOHEADER {
|
||||||
#include "external/dr_mp3.h" // MP3 loading functions
|
#include "external/dr_mp3.h" // MP3 loading functions
|
||||||
#endif
|
#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)
|
#if defined(_MSC_VER)
|
||||||
#undef bool
|
#undef bool
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -354,8 +363,8 @@ static Wave LoadMP3(const char *fileName); // Load MP3 file
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(RAUDIO_STANDALONE)
|
#if defined(RAUDIO_STANDALONE)
|
||||||
bool IsFileExtension(const char *fileName, const char *ext);// Check file extension
|
static 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 void SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -491,7 +500,7 @@ AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam
|
||||||
return NULL;
|
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
|
// 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);
|
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)
|
// Export wave sample data to code (.h)
|
||||||
void ExportWaveAsCode(Wave wave, const char *fileName)
|
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 };
|
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)
|
#if !defined(RAUDIO_STANDALONE)
|
||||||
// Get file name from path and convert variable name to uppercase
|
// Get file name from path and convert variable name to uppercase
|
||||||
strcpy(varFileName, GetFileNameWithoutExt(fileName));
|
strcpy(varFileName, GetFileNameWithoutExt(fileName));
|
||||||
|
|
@ -808,19 +820,21 @@ void ExportWaveAsCode(Wave wave, const char *fileName)
|
||||||
strcpy(varFileName, fileName);
|
strcpy(varFileName, fileName);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fprintf(txtFile, "// Wave data information\n");
|
bytesCount += sprintf(txtData + bytesCount, "// Wave data information\n");
|
||||||
fprintf(txtFile, "#define %s_SAMPLE_COUNT %u\n", varFileName, wave.sampleCount);
|
bytesCount += sprintf(txtData + bytesCount, "#define %s_SAMPLE_COUNT %u\n", varFileName, wave.sampleCount);
|
||||||
fprintf(txtFile, "#define %s_SAMPLE_RATE %u\n", varFileName, wave.sampleRate);
|
bytesCount += sprintf(txtData + bytesCount, "#define %s_SAMPLE_RATE %u\n", varFileName, wave.sampleRate);
|
||||||
fprintf(txtFile, "#define %s_SAMPLE_SIZE %u\n", varFileName, wave.sampleSize);
|
bytesCount += sprintf(txtData + bytesCount, "#define %s_SAMPLE_SIZE %u\n", varFileName, wave.sampleSize);
|
||||||
fprintf(txtFile, "#define %s_CHANNELS %u\n\n", varFileName, wave.channels);
|
bytesCount += sprintf(txtData + bytesCount, "#define %s_CHANNELS %u\n\n", varFileName, wave.channels);
|
||||||
|
|
||||||
// Write byte data as hexadecimal text
|
// Write byte data as hexadecimal text
|
||||||
fprintf(txtFile, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize);
|
bytesCount += sprintf(txtData + bytesCount, "static unsigned char %s_DATA[%i] = { ", varFileName, waveDataSize);
|
||||||
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]);
|
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]);
|
||||||
fprintf(txtFile, "0x%x };\n", ((unsigned char *)wave.data)[dataSize - 1]);
|
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
|
// Play a sound
|
||||||
|
|
@ -1046,6 +1060,24 @@ Music LoadMusicStream(const char *fileName)
|
||||||
bool musicLoaded = false;
|
bool musicLoaded = false;
|
||||||
|
|
||||||
if (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)
|
#if defined(SUPPORT_FILEFORMAT_OGG)
|
||||||
else if (IsFileExtension(fileName, ".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
|
// OGG bit rate defaults to 16 bit, it's enough for compressed format
|
||||||
music.stream = InitAudioStream(info.sample_rate, 16, info.channels);
|
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.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;
|
musicLoaded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1077,7 +1109,7 @@ Music LoadMusicStream(const char *fileName)
|
||||||
|
|
||||||
music.stream = InitAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels);
|
music.stream = InitAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels);
|
||||||
music.sampleCount = (unsigned int)ctxFlac->totalSampleCount;
|
music.sampleCount = (unsigned int)ctxFlac->totalSampleCount;
|
||||||
music.loopCount = 0; // Infinite loop by default
|
music.looping = true; // Looping enabled by default
|
||||||
musicLoaded = true;
|
musicLoaded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1096,7 +1128,7 @@ Music LoadMusicStream(const char *fileName)
|
||||||
|
|
||||||
music.stream = InitAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels);
|
music.stream = InitAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels);
|
||||||
music.sampleCount = (unsigned int)drmp3_get_pcm_frame_count(ctxMp3)*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;
|
musicLoaded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1116,7 +1148,7 @@ Music LoadMusicStream(const char *fileName)
|
||||||
// NOTE: Only stereo is supported for XM
|
// NOTE: Only stereo is supported for XM
|
||||||
music.stream = InitAudioStream(48000, 16, 2);
|
music.stream = InitAudioStream(48000, 16, 2);
|
||||||
music.sampleCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm)*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
|
jar_xm_reset(ctxXm); // make sure we start at the beginning of the song
|
||||||
musicLoaded = true;
|
musicLoaded = true;
|
||||||
|
|
||||||
|
|
@ -1139,7 +1171,7 @@ Music LoadMusicStream(const char *fileName)
|
||||||
// NOTE: Only stereo is supported for MOD
|
// NOTE: Only stereo is supported for MOD
|
||||||
music.stream = InitAudioStream(48000, 16, 2);
|
music.stream = InitAudioStream(48000, 16, 2);
|
||||||
music.sampleCount = (unsigned int)jar_mod_max_samples(ctxMod)*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;
|
musicLoaded = true;
|
||||||
|
|
||||||
music.ctxData = ctxMod;
|
music.ctxData = ctxMod;
|
||||||
|
|
@ -1151,6 +1183,9 @@ Music LoadMusicStream(const char *fileName)
|
||||||
if (!musicLoaded)
|
if (!musicLoaded)
|
||||||
{
|
{
|
||||||
if (false) { }
|
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)
|
#if defined(SUPPORT_FILEFORMAT_OGG)
|
||||||
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
|
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1188,6 +1223,9 @@ void UnloadMusicStream(Music music)
|
||||||
CloseAudioStream(music.stream);
|
CloseAudioStream(music.stream);
|
||||||
|
|
||||||
if (false) { }
|
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)
|
#if defined(SUPPORT_FILEFORMAT_OGG)
|
||||||
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
|
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1239,6 +1277,9 @@ void StopMusicStream(Music music)
|
||||||
|
|
||||||
switch (music.ctxType)
|
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)
|
#if defined(SUPPORT_FILEFORMAT_OGG)
|
||||||
case MUSIC_AUDIO_OGG: stb_vorbis_seek_start((stb_vorbis *)music.ctxData); break;
|
case MUSIC_AUDIO_OGG: stb_vorbis_seek_start((stb_vorbis *)music.ctxData); break;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1283,6 +1324,14 @@ void UpdateMusicStream(Music music)
|
||||||
|
|
||||||
switch (music.ctxType)
|
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)
|
#if defined(SUPPORT_FILEFORMAT_OGG)
|
||||||
case MUSIC_AUDIO_OGG:
|
case MUSIC_AUDIO_OGG:
|
||||||
{
|
{
|
||||||
|
|
@ -1347,14 +1396,7 @@ void UpdateMusicStream(Music music)
|
||||||
if (streamEnding)
|
if (streamEnding)
|
||||||
{
|
{
|
||||||
StopMusicStream(music); // Stop music (and reset)
|
StopMusicStream(music); // Stop music (and reset)
|
||||||
|
if (music.looping) PlayMusicStream(music); // Play again
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -1382,13 +1424,6 @@ void SetMusicPitch(Music music, float pitch)
|
||||||
SetAudioStreamPitch(music.stream, 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)
|
// Get music time length (in seconds)
|
||||||
float GetMusicTimeLength(Music music)
|
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
|
// 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().
|
// frames. This can be achieved with ma_data_converter_get_required_input_frame_count().
|
||||||
ma_uint8 inputBuffer[4096];
|
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;
|
ma_uint32 totalOutputFramesProcessed = 0;
|
||||||
while (totalOutputFramesProcessed < frameCount)
|
while (totalOutputFramesProcessed < frameCount)
|
||||||
|
|
@ -1812,6 +1847,7 @@ static void InitAudioBufferPool(void)
|
||||||
// Dummy buffers
|
// Dummy buffers
|
||||||
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
|
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);
|
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
|
// Close the audio buffers pool
|
||||||
static void CloseAudioBufferPool(void)
|
static void CloseAudioBufferPool(void)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
|
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) RL_FREE(AUDIO.MultiChannel.pool[i]);
|
||||||
{
|
|
||||||
RL_FREE(AUDIO.MultiChannel.pool[i]->data);
|
|
||||||
RL_FREE(AUDIO.MultiChannel.pool[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(SUPPORT_FILEFORMAT_WAV)
|
#if defined(SUPPORT_FILEFORMAT_WAV)
|
||||||
// Load WAV file into Wave structure
|
// Load WAV file into Wave structure
|
||||||
static Wave LoadWAV(const char *fileName)
|
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 };
|
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)
|
if (wave.data == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load WAV data", fileName);
|
||||||
{
|
|
||||||
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open WAV file", fileName);
|
|
||||||
wave.data = NULL;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Read in the first chunk into the struct
|
wave.sampleCount = (unsigned int)totalPCMFrameCount*wave.channels;
|
||||||
fread(&wavRiffHeader, sizeof(WAVRiffHeader), 1, wavFile);
|
wave.sampleSize = 16;
|
||||||
|
|
||||||
// Check for RIFF and WAVE tags
|
TRACELOG(LOG_INFO, "WAVE: [%s] WAV file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
|
||||||
if ((wavRiffHeader.chunkID[0] != 'R') ||
|
}
|
||||||
(wavRiffHeader.chunkID[1] != 'I') ||
|
|
||||||
(wavRiffHeader.chunkID[2] != 'F') ||
|
/*
|
||||||
(wavRiffHeader.chunkID[3] != 'F') ||
|
// Loading WAV from memory to avoid FILE accesses
|
||||||
(wavRiffHeader.format[0] != 'W') ||
|
unsigned int fileSize = 0;
|
||||||
(wavRiffHeader.format[1] != 'A') ||
|
unsigned char *fileData = LoadFileData(fileName, &fileSize);
|
||||||
(wavRiffHeader.format[2] != 'V') ||
|
|
||||||
(wavRiffHeader.format[3] != 'E'))
|
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);
|
wave.sampleCount = wav.totalPCMFrameCount*wav.channels;
|
||||||
}
|
wave.sampleRate = wav.sampleRate;
|
||||||
else
|
wave.sampleSize = 16; // NOTE: We are forcing conversion to 16bit
|
||||||
{
|
wave.channels = wav.channels;
|
||||||
// Read in the 2nd chunk for the wave info
|
wave.data = (short *)RL_MALLOC(wave.sampleCount*sizeof(short));
|
||||||
fread(&wavFormat, sizeof(WAVFormat), 1, wavFile);
|
drwav_read_pcm_frames_s16(&wav, wav.totalPCMFrameCount, wave.data);
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load WAV data", fileName);
|
||||||
|
|
||||||
|
drwav_uninit(&wav);
|
||||||
|
RL_FREE(fileData);
|
||||||
|
*/
|
||||||
return wave;
|
return wave;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save wave data as WAV file
|
// Save wave data as WAV file
|
||||||
static int SaveWAV(Wave wave, const char *fileName)
|
static int SaveWAV(Wave wave, const char *fileName)
|
||||||
{
|
{
|
||||||
int success = 0;
|
drwav wav = { 0 };
|
||||||
int dataSize = wave.sampleCount*wave.channels*wave.sampleSize/8;
|
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
|
drwav_init_file_write(&wav, fileName, &format, NULL);
|
||||||
typedef struct {
|
//drwav_init_memory_write(&wav, &fileData, &fileDataSize, &format, NULL); // Memory version
|
||||||
char chunkID[4];
|
drwav_write_pcm_frames(&wav, wave.sampleCount/wave.channels, wave.data);
|
||||||
int chunkSize;
|
|
||||||
char format[4];
|
|
||||||
} RiffHeader;
|
|
||||||
|
|
||||||
typedef struct {
|
drwav_uninit(&wav);
|
||||||
char subChunkID[4];
|
|
||||||
int subChunkSize;
|
|
||||||
short audioFormat;
|
|
||||||
short numChannels;
|
|
||||||
int sampleRate;
|
|
||||||
int byteRate;
|
|
||||||
short blockAlign;
|
|
||||||
short bitsPerSample;
|
|
||||||
} WaveFormat;
|
|
||||||
|
|
||||||
typedef struct {
|
// SaveFileData(fileName, fileData, fileDataSize);
|
||||||
char subChunkID[4];
|
//drwav_free(fileData, NULL);
|
||||||
int subChunkSize;
|
|
||||||
} WaveData;
|
|
||||||
|
|
||||||
FILE *wavFile = fopen(fileName, "wb");
|
return true;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -2086,9 +1982,6 @@ static Wave LoadFLAC(const char *fileName)
|
||||||
wave.sampleCount = (unsigned int)totalSampleCount;
|
wave.sampleCount = (unsigned int)totalSampleCount;
|
||||||
wave.sampleSize = 16;
|
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");
|
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
|
// Some required functions for audio standalone module version
|
||||||
#if defined(RAUDIO_STANDALONE)
|
#if defined(RAUDIO_STANDALONE)
|
||||||
// Check file extension
|
// Check file extension
|
||||||
bool IsFileExtension(const char *fileName, const char *ext)
|
static bool IsFileExtension(const char *fileName, const char *ext)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
const char *fileExt;
|
const char *fileExt;
|
||||||
|
|
@ -2141,6 +2034,27 @@ bool IsFileExtension(const char *fileName, const char *ext)
|
||||||
|
|
||||||
return result;
|
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
|
#endif
|
||||||
|
|
||||||
#undef AudioBuffer
|
#undef AudioBuffer
|
||||||
|
|
|
||||||
|
|
@ -111,8 +111,8 @@ typedef struct Music {
|
||||||
int ctxType; // Type of music context (audio filetype)
|
int ctxType; // Type of music context (audio filetype)
|
||||||
void *ctxData; // Audio context data, depends on type
|
void *ctxData; // Audio context data, depends on type
|
||||||
|
|
||||||
|
bool looping; // Music looping enable
|
||||||
unsigned int sampleCount; // Total number of samples
|
unsigned int sampleCount; // Total number of samples
|
||||||
unsigned int loopCount; // Loops count (times music will play), 0 means infinite loop
|
|
||||||
|
|
||||||
AudioStream stream; // Audio stream
|
AudioStream stream; // Audio stream
|
||||||
} Music;
|
} Music;
|
||||||
|
|
@ -173,7 +173,6 @@ void ResumeMusicStream(Music music); // Resume playin
|
||||||
bool IsMusicPlaying(Music music); // Check if music is playing
|
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 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 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 GetMusicTimeLength(Music music); // Get music time length (in seconds)
|
||||||
float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
|
float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
|
||||||
|
|
||||||
|
|
|
||||||
39
src/raylib.h
39
src/raylib.h
|
|
@ -440,8 +440,8 @@ typedef struct Music {
|
||||||
int ctxType; // Type of music context (audio filetype)
|
int ctxType; // Type of music context (audio filetype)
|
||||||
void *ctxData; // Audio context data, depends on type
|
void *ctxData; // Audio context data, depends on type
|
||||||
|
|
||||||
|
bool looping; // Music looping enable
|
||||||
unsigned int sampleCount; // Total number of samples
|
unsigned int sampleCount; // Total number of samples
|
||||||
unsigned int loopCount; // Loops count (times music will play), 0 means infinite loop
|
|
||||||
|
|
||||||
AudioStream stream; // Audio stream
|
AudioStream stream; // Audio stream
|
||||||
} Music;
|
} Music;
|
||||||
|
|
@ -663,20 +663,17 @@ typedef enum {
|
||||||
} GamepadButton;
|
} GamepadButton;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
// This is here just for error checking
|
|
||||||
GAMEPAD_AXIS_UNKNOWN = 0,
|
|
||||||
|
|
||||||
// Left stick
|
// Left stick
|
||||||
GAMEPAD_AXIS_LEFT_X,
|
GAMEPAD_AXIS_LEFT_X = 0,
|
||||||
GAMEPAD_AXIS_LEFT_Y,
|
GAMEPAD_AXIS_LEFT_Y = 1,
|
||||||
|
|
||||||
// Right stick
|
// Right stick
|
||||||
GAMEPAD_AXIS_RIGHT_X,
|
GAMEPAD_AXIS_RIGHT_X = 2,
|
||||||
GAMEPAD_AXIS_RIGHT_Y,
|
GAMEPAD_AXIS_RIGHT_Y = 3,
|
||||||
|
|
||||||
// Pressure levels for the back triggers
|
// Pressure levels for the back triggers
|
||||||
GAMEPAD_AXIS_LEFT_TRIGGER, // [1..-1] (pressure-level)
|
GAMEPAD_AXIS_LEFT_TRIGGER = 4, // [1..-1] (pressure-level)
|
||||||
GAMEPAD_AXIS_RIGHT_TRIGGER // [1..-1] (pressure-level)
|
GAMEPAD_AXIS_RIGHT_TRIGGER = 5 // [1..-1] (pressure-level)
|
||||||
} GamepadAxis;
|
} GamepadAxis;
|
||||||
|
|
||||||
// Shader location point type
|
// Shader location point type
|
||||||
|
|
@ -809,7 +806,8 @@ typedef enum {
|
||||||
typedef enum {
|
typedef enum {
|
||||||
BLEND_ALPHA = 0, // Blend textures considering alpha (default)
|
BLEND_ALPHA = 0, // Blend textures considering alpha (default)
|
||||||
BLEND_ADDITIVE, // Blend textures adding colors
|
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;
|
} BlendMode;
|
||||||
|
|
||||||
// Gestures type
|
// Gestures type
|
||||||
|
|
@ -913,6 +911,7 @@ RLAPI void HideCursor(void); // Hides curso
|
||||||
RLAPI bool IsCursorHidden(void); // Check if cursor is not visible
|
RLAPI bool IsCursorHidden(void); // Check if cursor is not visible
|
||||||
RLAPI void EnableCursor(void); // Enables cursor (unlock cursor)
|
RLAPI void EnableCursor(void); // Enables cursor (unlock cursor)
|
||||||
RLAPI void DisableCursor(void); // Disables cursor (lock cursor)
|
RLAPI void DisableCursor(void); // Disables cursor (lock cursor)
|
||||||
|
RLAPI bool IsCursorOnScreen(void); // Check if cursor is on the current screen.
|
||||||
|
|
||||||
// Drawing-related functions
|
// Drawing-related functions
|
||||||
RLAPI void ClearBackground(Color color); // Set background color (framebuffer clear color)
|
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 UnloadImage(Image image); // Unload image from CPU memory (RAM)
|
||||||
RLAPI void ExportImage(Image image, const char *fileName); // Export image data to file
|
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 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
|
// Image generation functions
|
||||||
RLAPI Image GenImageColor(int width, int height, Color color); // Generate image: plain color
|
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 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 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 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 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 ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two)
|
||||||
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 ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle
|
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 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 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
|
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 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 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 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
|
RLAPI Rectangle GetImageAlphaBorder(Image image, float threshold); // Get image alpha border rectangle
|
||||||
|
|
||||||
// Image drawing functions
|
// Image drawing functions
|
||||||
|
|
@ -1446,7 +1446,6 @@ RLAPI void ResumeMusicStream(Music music); // Resume
|
||||||
RLAPI bool IsMusicPlaying(Music music); // Check if music is playing
|
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 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 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 GetMusicTimeLength(Music music); // Get music time length (in seconds)
|
||||||
RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
|
RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,18 @@ RMDEF float Lerp(float start, float end, float amount)
|
||||||
return start + amount*(end - start);
|
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
|
// Module Functions Definition - Vector2 math
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -207,6 +219,13 @@ RMDEF float Vector2Length(Vector2 v)
|
||||||
return result;
|
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
|
// Calculate two vectors dot product
|
||||||
RMDEF float Vector2DotProduct(Vector2 v1, Vector2 v2)
|
RMDEF float Vector2DotProduct(Vector2 v1, Vector2 v2)
|
||||||
{
|
{
|
||||||
|
|
@ -401,6 +420,13 @@ RMDEF float Vector3Length(const Vector3 v)
|
||||||
return result;
|
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
|
// Calculate two vectors dot product
|
||||||
RMDEF float Vector3DotProduct(Vector3 v1, Vector3 v2)
|
RMDEF float Vector3DotProduct(Vector3 v1, Vector3 v2)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
132
src/rlgl.h
132
src/rlgl.h
|
|
@ -382,7 +382,8 @@ typedef unsigned char byte;
|
||||||
typedef enum {
|
typedef enum {
|
||||||
BLEND_ALPHA = 0,
|
BLEND_ALPHA = 0,
|
||||||
BLEND_ADDITIVE,
|
BLEND_ADDITIVE,
|
||||||
BLEND_MULTIPLIED
|
BLEND_MULTIPLIED,
|
||||||
|
BLEND_ADD_COLORS
|
||||||
} BlendMode;
|
} BlendMode;
|
||||||
|
|
||||||
// Shader location point type
|
// Shader location point type
|
||||||
|
|
@ -542,8 +543,8 @@ RLAPI bool rlRenderTextureComplete(RenderTexture target); // Ver
|
||||||
|
|
||||||
// Vertex data management
|
// Vertex data management
|
||||||
RLAPI void rlLoadMesh(Mesh *mesh, bool dynamic); // Upload vertex data into GPU and provided VAO/VBO ids
|
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 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 num, int index); // Update vertex or index data on GPU, at index
|
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 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
|
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
|
// Get supported extensions list
|
||||||
GLint numExt = 0;
|
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
|
// NOTE: On OpenGL 3.3 VAO and NPOT are supported by default
|
||||||
RLGL.ExtSupported.vao = true;
|
RLGL.ExtSupported.vao = true;
|
||||||
|
|
||||||
|
|
@ -1582,9 +1583,10 @@ void rlglInit(int width, int height)
|
||||||
// Get extensions strings
|
// Get extensions strings
|
||||||
for (int i = 0; i < numExt; i++) extList[i] = (char *)glGetStringi(GL_EXTENSIONS, i);
|
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)
|
// 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
|
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
|
// Free extensions pointers
|
||||||
RL_FREE(extList);
|
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
|
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");
|
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");
|
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 mipHeight = height;
|
||||||
int mipOffset = 0; // Mipmap data offset
|
int mipOffset = 0; // Mipmap data offset
|
||||||
|
|
||||||
TRACELOGD("TEXTURE: Load texture from data memory address: 0x%x", data);
|
|
||||||
|
|
||||||
// Load the different mipmap levels
|
// Load the different mipmap levels
|
||||||
for (int i = 0; i < mipmapCount; i++)
|
for (int i = 0; i < mipmapCount; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -2424,14 +2426,14 @@ void rlLoadMesh(Mesh *mesh, bool dynamic)
|
||||||
// Enable vertex attributes: position (shader-location = 0)
|
// Enable vertex attributes: position (shader-location = 0)
|
||||||
glGenBuffers(1, &mesh->vboId[0]);
|
glGenBuffers(1, &mesh->vboId[0]);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 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);
|
glVertexAttribPointer(0, 3, GL_FLOAT, 0, 0, 0);
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
// Enable vertex attributes: texcoords (shader-location = 1)
|
// Enable vertex attributes: texcoords (shader-location = 1)
|
||||||
glGenBuffers(1, &mesh->vboId[1]);
|
glGenBuffers(1, &mesh->vboId[1]);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 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);
|
glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, 0);
|
||||||
glEnableVertexAttribArray(1);
|
glEnableVertexAttribArray(1);
|
||||||
|
|
||||||
|
|
@ -2440,7 +2442,7 @@ void rlLoadMesh(Mesh *mesh, bool dynamic)
|
||||||
{
|
{
|
||||||
glGenBuffers(1, &mesh->vboId[2]);
|
glGenBuffers(1, &mesh->vboId[2]);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 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);
|
glVertexAttribPointer(2, 3, GL_FLOAT, 0, 0, 0);
|
||||||
glEnableVertexAttribArray(2);
|
glEnableVertexAttribArray(2);
|
||||||
}
|
}
|
||||||
|
|
@ -2456,7 +2458,7 @@ void rlLoadMesh(Mesh *mesh, bool dynamic)
|
||||||
{
|
{
|
||||||
glGenBuffers(1, &mesh->vboId[3]);
|
glGenBuffers(1, &mesh->vboId[3]);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 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);
|
glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
|
||||||
glEnableVertexAttribArray(3);
|
glEnableVertexAttribArray(3);
|
||||||
}
|
}
|
||||||
|
|
@ -2472,7 +2474,7 @@ void rlLoadMesh(Mesh *mesh, bool dynamic)
|
||||||
{
|
{
|
||||||
glGenBuffers(1, &mesh->vboId[4]);
|
glGenBuffers(1, &mesh->vboId[4]);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 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);
|
glVertexAttribPointer(4, 4, GL_FLOAT, 0, 0, 0);
|
||||||
glEnableVertexAttribArray(4);
|
glEnableVertexAttribArray(4);
|
||||||
}
|
}
|
||||||
|
|
@ -2488,7 +2490,7 @@ void rlLoadMesh(Mesh *mesh, bool dynamic)
|
||||||
{
|
{
|
||||||
glGenBuffers(1, &mesh->vboId[5]);
|
glGenBuffers(1, &mesh->vboId[5]);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 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);
|
glVertexAttribPointer(5, 2, GL_FLOAT, 0, 0, 0);
|
||||||
glEnableVertexAttribArray(5);
|
glEnableVertexAttribArray(5);
|
||||||
}
|
}
|
||||||
|
|
@ -2503,7 +2505,7 @@ void rlLoadMesh(Mesh *mesh, bool dynamic)
|
||||||
{
|
{
|
||||||
glGenBuffers(1, &mesh->vboId[6]);
|
glGenBuffers(1, &mesh->vboId[6]);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 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)
|
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)
|
// 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
|
// Update vertex or index data on GPU, at index
|
||||||
// WARNING: error checking is in place that will cause the data to not be
|
// WARNING: error checking is in place that will cause the data to not be
|
||||||
// updated if offset + size exceeds what the buffer can hold
|
// 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)
|
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||||
// Activate mesh VAO
|
// Activate mesh VAO
|
||||||
|
|
@ -2561,60 +2563,61 @@ void rlUpdateMeshAt(Mesh mesh, int buffer, int num, int index)
|
||||||
case 0: // Update vertices (vertex position)
|
case 0: // Update vertices (vertex position)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
|
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);
|
if (index == 0 && count >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, count*3*sizeof(float), mesh.vertices, GL_DYNAMIC_DRAW);
|
||||||
else if (index + num >= mesh.vertexCount) break;
|
else if (index + count >= mesh.vertexCount) break;
|
||||||
else glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*3*index, sizeof(float)*3*num, mesh.vertices);
|
else glBufferSubData(GL_ARRAY_BUFFER, index*3*sizeof(float), count*3*sizeof(float), mesh.vertices);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case 1: // Update texcoords (vertex texture coordinates)
|
case 1: // Update texcoords (vertex texture coordinates)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]);
|
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);
|
if (index == 0 && count >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, count*2*sizeof(float), mesh.texcoords, GL_DYNAMIC_DRAW);
|
||||||
else if (index + num >= mesh.vertexCount) break;
|
else if (index + count >= mesh.vertexCount) break;
|
||||||
else glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*2*index, sizeof(float)*2*num, mesh.texcoords);
|
else glBufferSubData(GL_ARRAY_BUFFER, index*2*sizeof(float), count*2*sizeof(float), mesh.texcoords);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case 2: // Update normals (vertex normals)
|
case 2: // Update normals (vertex normals)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[2]);
|
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);
|
if (index == 0 && count >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, count*3*sizeof(float), mesh.normals, GL_DYNAMIC_DRAW);
|
||||||
else if (index + num >= mesh.vertexCount) break;
|
else if (index + count >= mesh.vertexCount) break;
|
||||||
else glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*3*index, sizeof(float)*3*num, mesh.normals);
|
else glBufferSubData(GL_ARRAY_BUFFER, index*3*sizeof(float), count*3*sizeof(float), mesh.normals);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case 3: // Update colors (vertex colors)
|
case 3: // Update colors (vertex colors)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[3]);
|
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);
|
if (index == 0 && count >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, count*4*sizeof(float), mesh.colors, GL_DYNAMIC_DRAW);
|
||||||
else if (index + num >= mesh.vertexCount) break;
|
else if (index + count >= mesh.vertexCount) break;
|
||||||
else glBufferSubData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*index, sizeof(unsigned char)*4*num, mesh.colors);
|
else glBufferSubData(GL_ARRAY_BUFFER, index*4*sizeof(unsigned char), count*4*sizeof(unsigned char), mesh.colors);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case 4: // Update tangents (vertex tangents)
|
case 4: // Update tangents (vertex tangents)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[4]);
|
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);
|
if (index == 0 && count >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, count*4*sizeof(float), mesh.tangents, GL_DYNAMIC_DRAW);
|
||||||
else if (index + num >= mesh.vertexCount) break;
|
else if (index + count >= mesh.vertexCount) break;
|
||||||
else glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*4*index, sizeof(float)*4*num, mesh.tangents);
|
else glBufferSubData(GL_ARRAY_BUFFER, index*4*sizeof(float), count*4*sizeof(float), mesh.tangents);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case 5: // Update texcoords2 (vertex second texture coordinates)
|
case 5: // Update texcoords2 (vertex second texture coordinates)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[5]);
|
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);
|
if (index == 0 && count >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, count*2*sizeof(float), mesh.texcoords2, GL_DYNAMIC_DRAW);
|
||||||
else if (index + num >= mesh.vertexCount) break;
|
else if (index + count >= mesh.vertexCount) break;
|
||||||
else glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*2*index, sizeof(float)*2*num, mesh.texcoords2);
|
else glBufferSubData(GL_ARRAY_BUFFER, index*2*sizeof(float), count*2*sizeof(float), mesh.texcoords2);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case 6: // Update indices (triangle index buffer)
|
case 6: // Update indices (triangle index buffer)
|
||||||
{
|
{
|
||||||
// the * 3 is because each triangle has 3 indices
|
// the * 3 is because each triangle has 3 indices
|
||||||
unsigned short *indices = mesh.indices;
|
unsigned short *indices = mesh.indices;
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.vboId[6]);
|
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);
|
if (index == 0 && count >= mesh.triangleCount) glBufferData(GL_ELEMENT_ARRAY_BUFFER, count*3*sizeof(*indices), indices, GL_DYNAMIC_DRAW);
|
||||||
else if (index + num >= mesh.triangleCount)
|
else if (index + count >= mesh.triangleCount) break;
|
||||||
break;
|
else glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, index*3*sizeof(*indices), count*3*sizeof(*indices), indices);
|
||||||
else
|
|
||||||
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, sizeof(*indices)*index*3, sizeof(*indices)*num*3, indices);
|
|
||||||
} break;
|
} break;
|
||||||
default: 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);
|
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, screenData);
|
||||||
|
|
||||||
// Flip image vertically!
|
// 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--)
|
for (int y = height - 1; y >= 0; y--)
|
||||||
{
|
{
|
||||||
|
|
@ -3069,7 +3072,7 @@ Shader LoadShaderCode(const char *vsCode, const char *fsCode)
|
||||||
GLenum type = GL_ZERO;
|
GLenum type = GL_ZERO;
|
||||||
|
|
||||||
// Get the name of the uniforms
|
// 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;
|
name[namelen] = 0;
|
||||||
|
|
||||||
|
|
@ -3558,15 +3561,16 @@ void BeginBlendMode(int mode)
|
||||||
{
|
{
|
||||||
static int blendMode = 0; // Track current blending mode
|
static int blendMode = 0; // Track current blending mode
|
||||||
|
|
||||||
if ((blendMode != mode) && (mode < 3))
|
if ((blendMode != mode) && (mode < 4))
|
||||||
{
|
{
|
||||||
rlglDraw();
|
rlglDraw();
|
||||||
|
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case BLEND_ALPHA: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break;
|
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_MULTIPLIED: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break;
|
||||||
|
case BLEND_ADD_COLORS: glBlendFunc(GL_ONE, GL_ONE); break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4067,13 +4071,13 @@ static RenderBatch LoadRenderBatch(int numBuffers, int bufferElements)
|
||||||
{
|
{
|
||||||
batch.vertexBuffer[i].elementsCount = 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].vertices = (float *)RL_MALLOC(bufferElements*3*4*sizeof(float)); // 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].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(sizeof(unsigned char)*4*4*bufferElements); // 4 float by color, 4 colors 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)
|
#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)
|
#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
|
#endif
|
||||||
|
|
||||||
for (int j = 0; j < (3*4*bufferElements); j++) batch.vertexBuffer[i].vertices[j] = 0.0f;
|
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)
|
// Vertex position buffer (shader-location = 0)
|
||||||
glGenBuffers(1, &batch.vertexBuffer[i].vboId[0]);
|
glGenBuffers(1, &batch.vertexBuffer[i].vboId[0]);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 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]);
|
glEnableVertexAttribArray(RLGL.State.currentShader.locs[LOC_VERTEX_POSITION]);
|
||||||
glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0);
|
glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0);
|
||||||
|
|
||||||
// Vertex texcoord buffer (shader-location = 1)
|
// Vertex texcoord buffer (shader-location = 1)
|
||||||
glGenBuffers(1, &batch.vertexBuffer[i].vboId[1]);
|
glGenBuffers(1, &batch.vertexBuffer[i].vboId[1]);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 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]);
|
glEnableVertexAttribArray(RLGL.State.currentShader.locs[LOC_VERTEX_TEXCOORD01]);
|
||||||
glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0);
|
glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0);
|
||||||
|
|
||||||
// Vertex color buffer (shader-location = 3)
|
// Vertex color buffer (shader-location = 3)
|
||||||
glGenBuffers(1, &batch.vertexBuffer[i].vboId[2]);
|
glGenBuffers(1, &batch.vertexBuffer[i].vboId[2]);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 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]);
|
glEnableVertexAttribArray(RLGL.State.currentShader.locs[LOC_VERTEX_COLOR]);
|
||||||
glVertexAttribPointer(RLGL.State.currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
|
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]);
|
glGenBuffers(1, &batch.vertexBuffer[i].vboId[3]);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[3]);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[3]);
|
||||||
#if defined(GRAPHICS_API_OPENGL_33)
|
#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)
|
#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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4154,7 +4158,7 @@ static RenderBatch LoadRenderBatch(int numBuffers, int bufferElements)
|
||||||
|
|
||||||
// Init draw calls tracking system
|
// 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++)
|
for (int i = 0; i < DEFAULT_BATCH_DRAWCALLS; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -4190,17 +4194,17 @@ static void DrawRenderBatch(RenderBatch *batch)
|
||||||
|
|
||||||
// Vertex positions buffer
|
// Vertex positions buffer
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[0]);
|
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
|
//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
|
// Texture coordinates buffer
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[1]);
|
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
|
//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
|
// Colors buffer
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[2]);
|
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
|
//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.
|
// 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
|
// 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
|
// 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
|
// 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)
|
#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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4686,7 +4690,7 @@ char *LoadFileText(const char *fileName)
|
||||||
|
|
||||||
if (size > 0)
|
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);
|
int count = fread(text, sizeof(char), size, textFile);
|
||||||
|
|
||||||
// WARNING: \r\n is converted to \n on reading, so,
|
// WARNING: \r\n is converted to \n on reading, so,
|
||||||
|
|
|
||||||
|
|
@ -618,6 +618,8 @@ void DrawRectangleRec(Rectangle rec, Color color)
|
||||||
// Draw a color-filled rectangle with pro parameters
|
// Draw a color-filled rectangle with pro parameters
|
||||||
void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color)
|
void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color)
|
||||||
{
|
{
|
||||||
|
if (rlCheckBufferLimit(4)) rlglDraw();
|
||||||
|
|
||||||
rlEnableTexture(GetShapesTexture().id);
|
rlEnableTexture(GetShapesTexture().id);
|
||||||
|
|
||||||
rlPushMatrix();
|
rlPushMatrix();
|
||||||
|
|
|
||||||
355
src/text.c
355
src/text.c
|
|
@ -54,12 +54,12 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h> // Required for: malloc(), free()
|
#include <stdlib.h> // Required for: malloc(), free()
|
||||||
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fgets()
|
#include <stdio.h> // Required for: vsprintf()
|
||||||
#include <string.h> // Required for: strcmp(), strstr(), strcpy(), strncpy(), strcat(), strncat(), sscanf()
|
#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 <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 <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)
|
#if defined(SUPPORT_FILEFORMAT_TTF)
|
||||||
#define STB_RECT_PACK_IMPLEMENTATION
|
#define STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
|
@ -191,33 +191,31 @@ extern void LoadFontDefault(void)
|
||||||
|
|
||||||
// Re-construct image from defaultFontData and generate OpenGL texture
|
// Re-construct image from defaultFontData and generate OpenGL texture
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
int imWidth = 128;
|
Image imFont = {
|
||||||
int imHeight = 128;
|
.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));
|
// 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 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)
|
|
||||||
{
|
{
|
||||||
for (int j = 31; j >= 0; j--)
|
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++;
|
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);
|
defaultFont.texture = LoadTextureFromImage(imFont);
|
||||||
|
|
||||||
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, charsCount
|
// 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;
|
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)
|
// Create a new image with the processed color data (key color replaced by BLANK)
|
||||||
Image fontClear = LoadImageEx(pixels, image.width, image.height);
|
Image fontClear = {
|
||||||
|
.data = pixels,
|
||||||
RL_FREE(pixels); // Free pixels array memory
|
.width = image.width,
|
||||||
|
.height = image.height,
|
||||||
|
.format = UNCOMPRESSED_R8G8B8A8,
|
||||||
|
.mipmaps = 1
|
||||||
|
};
|
||||||
|
|
||||||
// Create spritefont with all data parsed from image
|
// Create spritefont with all data parsed from image
|
||||||
Font font = { 0 };
|
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
|
// NOTE: We create an empty image for space character, it could be further required for atlas packing
|
||||||
if (ch == 32)
|
if (ch == 32)
|
||||||
{
|
{
|
||||||
chars[i].image = GenImageColor(chars[i].advanceX, fontSize, BLANK);
|
Image imSpace = {
|
||||||
ImageFormat(&chars[i].image, UNCOMPRESSED_GRAYSCALE);
|
.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)
|
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
|
// TODO: Crop image if required for smaller size
|
||||||
|
|
||||||
// Convert image data from GRAYSCALE to GRAY_ALPHA
|
// 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
|
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)
|
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
|
// 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
|
// Get text length in bytes, check for \0 character
|
||||||
unsigned int TextLength(const char *text)
|
unsigned int TextLength(const char *text)
|
||||||
{
|
{
|
||||||
|
|
@ -1166,6 +1140,58 @@ const char *TextFormat(const char *text, ...)
|
||||||
return currentBuffer;
|
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
|
// Get a piece of a text string
|
||||||
const char *TextSubtext(const char *text, int position, int length)
|
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
|
// Join text strings with delimiter
|
||||||
// REQUIRES: strcat()
|
// REQUIRES: memset(), memcpy()
|
||||||
const char *TextJoin(const char **textList, int count, const char *delimiter)
|
const char *TextJoin(const char **textList, int count, const char *delimiter)
|
||||||
{
|
{
|
||||||
static char text[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
static char text[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||||
memset(text, 0, MAX_TEXT_BUFFER_LENGTH);
|
memset(text, 0, MAX_TEXT_BUFFER_LENGTH);
|
||||||
|
char *textPtr = text;
|
||||||
|
|
||||||
int totalLength = 0;
|
int totalLength = 0;
|
||||||
int delimiterLen = TextLength(delimiter);
|
int delimiterLen = TextLength(delimiter);
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
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
|
// 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]);
|
memcpy(textPtr, textList[i], textLength);
|
||||||
totalLength += textListLength;
|
totalLength += textLength;
|
||||||
|
textPtr += textLength;
|
||||||
|
|
||||||
if ((delimiterLen > 0) && (i < (count - 1)))
|
if ((delimiterLen > 0) && (i < (count - 1)))
|
||||||
{
|
{
|
||||||
strcat(text, delimiter);
|
memcpy(textPtr, delimiter, delimiterLen);
|
||||||
totalLength += delimiterLen;
|
totalLength += delimiterLen;
|
||||||
|
textPtr += textLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1415,24 +1444,6 @@ const char *TextToPascal(const char *text)
|
||||||
return buffer;
|
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!)
|
// Encode text codepoint into utf8 text (memory must be freed!)
|
||||||
char *TextToUtf8(int *codepoints, int length)
|
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++)
|
for (int i = 0, bytes = 0; i < length; i++)
|
||||||
{
|
{
|
||||||
utf8 = CodepointToUtf8(codepoints[i], &bytes);
|
utf8 = CodepointToUtf8(codepoints[i], &bytes);
|
||||||
strncpy(text + size, utf8, bytes);
|
memcpy(text + size, utf8, bytes);
|
||||||
size += bytes;
|
size += bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1457,6 +1468,44 @@ char *TextToUtf8(int *codepoints, int length)
|
||||||
return text;
|
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
|
// Get all codepoints in a string, codepoints count returned by parameters
|
||||||
int *GetCodepoints(const char *text, int *count)
|
int *GetCodepoints(const char *text, int *count)
|
||||||
{
|
{
|
||||||
|
|
@ -1498,7 +1547,7 @@ int GetCodepointsCount(const char *text)
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
#endif // SUPPORT_TEXT_MANIPULATION
|
||||||
|
|
||||||
// Returns next codepoint in a UTF8 encoded text, scanning until '\0' is found
|
// 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
|
// 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;
|
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
|
// Module specific Functions Definition
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
#if defined(SUPPORT_FILEFORMAT_FNT)
|
#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)
|
// Load a BMFont file (AngelCode font file)
|
||||||
|
// REQUIRES: strstr(), sscanf(), strrchr(), memcpy()
|
||||||
static Font LoadBMFont(const char *fileName)
|
static Font LoadBMFont(const char *fileName)
|
||||||
{
|
{
|
||||||
#define MAX_BUFFER_SIZE 256
|
#define MAX_BUFFER_SIZE 256
|
||||||
|
|
@ -1666,65 +1688,56 @@ static Font LoadBMFont(const char *fileName)
|
||||||
char *searchPoint = NULL;
|
char *searchPoint = NULL;
|
||||||
|
|
||||||
int fontSize = 0;
|
int fontSize = 0;
|
||||||
int texWidth = 0;
|
|
||||||
int texHeight = 0;
|
|
||||||
char texFileName[129];
|
|
||||||
int charsCount = 0;
|
int charsCount = 0;
|
||||||
|
|
||||||
|
int imWidth = 0;
|
||||||
|
int imHeight = 0;
|
||||||
|
char imFileName[129];
|
||||||
|
|
||||||
int base = 0; // Useless data
|
int base = 0; // Useless data
|
||||||
|
|
||||||
FILE *fntFile = NULL;
|
char *fileText = LoadFileText(fileName);
|
||||||
|
char *fileTextPtr = fileText;
|
||||||
fntFile = fopen(fileName, "rt");
|
|
||||||
|
|
||||||
if (fntFile == NULL)
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open FNT file", fileName);
|
|
||||||
return font;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: We skip first line, it contains no useful information
|
// NOTE: We skip first line, it contains no useful information
|
||||||
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
|
int lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
|
||||||
//searchPoint = strstr(buffer, "size");
|
fileTextPtr += (lineBytes + 1);
|
||||||
//sscanf(searchPoint, "size=%i", &fontSize);
|
|
||||||
|
|
||||||
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
|
// Read line data
|
||||||
|
lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
|
||||||
searchPoint = strstr(buffer, "lineHeight");
|
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("FONT: [%s] Loaded font info:", fileName);
|
||||||
TRACELOGD(" > Base size: %i", fontSize);
|
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");
|
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");
|
searchPoint = strstr(buffer, "count");
|
||||||
sscanf(searchPoint, "count=%i", &charsCount);
|
sscanf(searchPoint, "count=%i", &charsCount);
|
||||||
|
fileTextPtr += (lineBytes + 1);
|
||||||
|
|
||||||
TRACELOGD(" > Chars count: %i", charsCount);
|
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 *texPath = NULL;
|
||||||
char *lastSlash = NULL;
|
char *lastSlash = NULL;
|
||||||
|
|
||||||
lastSlash = strrchr(fileName, '/');
|
lastSlash = strrchr(fileName, '/');
|
||||||
if (lastSlash == NULL)
|
if (lastSlash == NULL) lastSlash = strrchr(fileName, '\\');
|
||||||
{
|
|
||||||
lastSlash = strrchr(fileName, '\\');
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: We need some extra space to avoid memory corruption on next allocations!
|
// NOTE: We need some extra space to avoid memory corruption on next allocations!
|
||||||
texPath = RL_MALLOC(TextLength(fileName) - TextLength(lastSlash) + TextLength(texFileName) + 4);
|
texPath = RL_CALLOC(TextLength(fileName) - TextLength(lastSlash) + TextLength(imFileName) + 4, 1);
|
||||||
|
memcpy(texPath, fileName, TextLength(fileName) - TextLength(lastSlash) + 1);
|
||||||
// NOTE: strcat() and strncat() required a '\0' terminated string to work!
|
memcpy(texPath + TextLength(fileName) - TextLength(lastSlash) + 1, imFileName, TextLength(imFileName));
|
||||||
*texPath = '\0';
|
|
||||||
strncat(texPath, fileName, TextLength(fileName) - TextLength(lastSlash) + 1);
|
|
||||||
strncat(texPath, texFileName, TextLength(texFileName));
|
|
||||||
|
|
||||||
TRACELOGD(" > Texture loading path: %s", texPath);
|
TRACELOGD(" > Texture loading path: %s", texPath);
|
||||||
|
|
||||||
|
|
@ -1733,8 +1746,22 @@ static Font LoadBMFont(const char *fileName)
|
||||||
if (imFont.format == UNCOMPRESSED_GRAYSCALE)
|
if (imFont.format == UNCOMPRESSED_GRAYSCALE)
|
||||||
{
|
{
|
||||||
// Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel
|
// Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel
|
||||||
ImageAlphaMask(&imFont, imFont);
|
Image imFontAlpha = {
|
||||||
for (int p = 0; p < (imFont.width*imFont.height*2); p += 2) ((unsigned char *)(imFont.data))[p] = 0xff;
|
.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);
|
font.texture = LoadTextureFromImage(imFont);
|
||||||
|
|
@ -1751,9 +1778,10 @@ static Font LoadBMFont(const char *fileName)
|
||||||
|
|
||||||
for (int i = 0; i < charsCount; i++)
|
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",
|
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);
|
&charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX);
|
||||||
|
fileTextPtr += (lineBytes + 1);
|
||||||
|
|
||||||
// Get character rectangle in the font atlas texture
|
// Get character rectangle in the font atlas texture
|
||||||
font.recs[i] = (Rectangle){ (float)charX, (float)charY, (float)charWidth, (float)charHeight };
|
font.recs[i] = (Rectangle){ (float)charX, (float)charY, (float)charWidth, (float)charHeight };
|
||||||
|
|
@ -1769,8 +1797,7 @@ static Font LoadBMFont(const char *fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
UnloadImage(imFont);
|
UnloadImage(imFont);
|
||||||
|
RL_FREE(fileText);
|
||||||
fclose(fntFile);
|
|
||||||
|
|
||||||
if (font.texture.id == 0)
|
if (font.texture.id == 0)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
3192
src/textures.c
3192
src/textures.c
File diff suppressed because it is too large
Load Diff
|
|
@ -199,7 +199,7 @@ unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead)
|
||||||
|
|
||||||
if (size > 0)
|
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]
|
// 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);
|
unsigned int count = (unsigned int)fread(data, sizeof(unsigned char), size, file);
|
||||||
|
|
@ -274,7 +274,7 @@ char *LoadFileText(const char *fileName)
|
||||||
|
|
||||||
if (size > 0)
|
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);
|
unsigned int count = (unsigned int)fread(text, sizeof(char), size, textFile);
|
||||||
|
|
||||||
// WARNING: \r\n is converted to \n on reading, so,
|
// WARNING: \r\n is converted to \n on reading, so,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user