Merge branch 'raysan5:master' into master

This commit is contained in:
Dennis E. Hamilton 2021-09-25 12:10:41 -07:00 committed by GitHub
commit 1cc9a9c738
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 3961 additions and 1151 deletions

View File

@ -55,7 +55,7 @@ jobs:
- name: Build Library - name: Build Library
run: | run: |
cd src cd src
make PLATFORM=PLATFORM_DESKTOP CC=gcc RAYLIB_LIBTYPE=STATIC RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" CFLAGS="-m32" make PLATFORM=PLATFORM_DESKTOP CC=gcc RAYLIB_LIBTYPE=STATIC RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" CFLAGS="-m32" -B
# make PLATFORM=PLATFORM_DESKTOP CC=gcc RAYLIB_LIBTYPE=SHARED RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" -B # make PLATFORM=PLATFORM_DESKTOP CC=gcc RAYLIB_LIBTYPE=SHARED RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" -B
cd .. cd ..
if: matrix.bits == 32 if: matrix.bits == 32
@ -63,7 +63,7 @@ jobs:
- name: Build Library - name: Build Library
run: | run: |
cd src cd src
make PLATFORM=PLATFORM_DESKTOP CC=gcc RAYLIB_LIBTYPE=STATIC RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" make PLATFORM=PLATFORM_DESKTOP CC=gcc RAYLIB_LIBTYPE=STATIC RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" -B
make PLATFORM=PLATFORM_DESKTOP CC=gcc RAYLIB_LIBTYPE=SHARED RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" -B make PLATFORM=PLATFORM_DESKTOP CC=gcc RAYLIB_LIBTYPE=SHARED RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" -B
cd .. cd ..
if: matrix.bits == 64 if: matrix.bits == 64

View File

@ -40,12 +40,12 @@ jobs:
run: | run: |
cd src cd src
clang --version clang --version
make PLATFORM=PLATFORM_DESKTOP RAYLIB_LIBTYPE=STATIC RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" CFLAGS="-target x86_64-apple-macos10.12 -DGL_SILENCE_DEPRECATION" make PLATFORM=PLATFORM_DESKTOP RAYLIB_LIBTYPE=STATIC RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" CFLAGS="-target x86_64-apple-macos10.12 -DGL_SILENCE_DEPRECATION" -B
# make PLATFORM=PLATFORM_DESKTOP RAYLIB_LIBTYPE=STATIC RAYLIB_LIB_NAME=raylib_x86_64 CFLAGS="-target x86_64-apple-macos10.12 -DGL_SILENCE_DEPRECATION" # make PLATFORM=PLATFORM_DESKTOP RAYLIB_LIBTYPE=STATIC RAYLIB_LIB_NAME=raylib_x86_64 CFLAGS="-target x86_64-apple-macos10.12 -DGL_SILENCE_DEPRECATION"
# make PLATFORM=PLATFORM_DESKTOP RAYLIB_LIBTYPE=STATIC RAYLIB_LIB_NAME=raylib_arm64 CFLAGS="-target arm64-apple-macos11 -DGL_SILENCE_DEPRECATION" -B # make PLATFORM=PLATFORM_DESKTOP RAYLIB_LIBTYPE=STATIC RAYLIB_LIB_NAME=raylib_arm64 CFLAGS="-target arm64-apple-macos11 -DGL_SILENCE_DEPRECATION" -B
# lipo -create -output ../build/${{ env.RELEASE_NAME }}/lib/libraylib.a libraylib_x86_64.a libraylib_arm64.a # lipo -create -output ../build/${{ env.RELEASE_NAME }}/lib/libraylib.a libraylib_x86_64.a libraylib_arm64.a
make clean make clean
make PLATFORM=PLATFORM_DESKTOP RAYLIB_LIBTYPE=SHARED RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" CFLAGS="-target x86_64-apple-macos10.12 -DGL_SILENCE_DEPRECATION" make PLATFORM=PLATFORM_DESKTOP RAYLIB_LIBTYPE=SHARED RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" CFLAGS="-target x86_64-apple-macos10.12 -DGL_SILENCE_DEPRECATION" -B
# make PLATFORM=PLATFORM_DESKTOP RAYLIB_LIBTYPE=SHARED RAYLIB_LIB_NAME=raylib_x86_64 CFLAGS="-target x86_64-apple-macos10.12 -DGL_SILENCE_DEPRECATION" -B # make PLATFORM=PLATFORM_DESKTOP RAYLIB_LIBTYPE=SHARED RAYLIB_LIB_NAME=raylib_x86_64 CFLAGS="-target x86_64-apple-macos10.12 -DGL_SILENCE_DEPRECATION" -B
# make PLATFORM=PLATFORM_DESKTOP RAYLIB_LIBTYPE=SHARED RAYLIB_LIB_NAME=raylib_arm64 CFLAGS="-target i686-apple-macos -DGL_SILENCE_DEPRECATION" -B # make PLATFORM=PLATFORM_DESKTOP RAYLIB_LIBTYPE=SHARED RAYLIB_LIB_NAME=raylib_arm64 CFLAGS="-target i686-apple-macos -DGL_SILENCE_DEPRECATION" -B
# lipo -create -output ../build/${{ env.RELEASE_NAME }}/lib/libraylib.3.1.0.dylib libraylib_x86_64.3.1.0.dylib libraylib_arm64.3.1.0.dylib # lipo -create -output ../build/${{ env.RELEASE_NAME }}/lib/libraylib.3.1.0.dylib libraylib_x86_64.3.1.0.dylib libraylib_arm64.3.1.0.dylib

View File

@ -43,7 +43,7 @@ jobs:
run: | run: |
cd src cd src
emcc -v emcc -v
make PLATFORM=PLATFORM_WEB EMSDK_PATH="D:/a/raylib/raylib/emsdk-cache/emsdk-master" RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" make PLATFORM=PLATFORM_WEB EMSDK_PATH="D:/a/raylib/raylib/emsdk-cache/emsdk-master" RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" -B
cd .. cd ..
- name: Generate Artifacts - name: Generate Artifacts

7
.gitignore vendored
View File

@ -93,3 +93,10 @@ build
GPATH GPATH
GRTAGS GRTAGS
GTAGS GTAGS
# Zig programming language
zig-cache/
zig-out/
build/
build-*/
docgen_tmp/

View File

@ -45,9 +45,10 @@ Some people ported raylib to other languages in form of bindings or wrappers to
| raylib-ruby-ffi | 2.0 | [Ruby](https://www.ruby-lang.org/en/) | https://github.com/D3nX/raylib-ruby-ffi | | raylib-ruby-ffi | 2.0 | [Ruby](https://www.ruby-lang.org/en/) | https://github.com/D3nX/raylib-ruby-ffi |
| raylib-ruby | 2.6 | [Ruby](https://www.ruby-lang.org/en/) | https://github.com/a0/raylib-ruby | | raylib-ruby | 2.6 | [Ruby](https://www.ruby-lang.org/en/) | https://github.com/a0/raylib-ruby |
| raylib-mruby | 2.5-dev | [mruby](https://github.com/mruby/mruby) | https://github.com/lihaochen910/raylib-mruby | | raylib-mruby | 2.5-dev | [mruby](https://github.com/mruby/mruby) | https://github.com/lihaochen910/raylib-mruby |
| pyraylib | 3.7 | [Python](https://www.python.org/) | https://github.com/Ho011/pyraylib |
| raylib-py | 2.0 | [Python](https://www.python.org/) | https://github.com/overdev/raylib-py | | raylib-py | 2.0 | [Python](https://www.python.org/) | https://github.com/overdev/raylib-py |
| raylib-python-cffi | 3.7 | [Python](https://www.python.org/) | https://github.com/electronstudio/raylib-python-cffi | | raylib-python-cffi | 3.7 | [Python](https://www.python.org/) | https://github.com/electronstudio/raylib-python-cffi |
| raylib-py-ctbg | 2.6 | [Python](https://www.python.org/) | https://github.com/overdev/raylib-py-ctbg | | raylib-py-ctbg | 2.6 | [Python](https://www.python.org/) | https://github.com/overdev/raylib-py-ctbg |
| jaylib | 3.7 | [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) | https://github.com/electronstudio/jaylib/ | | jaylib | 3.7 | [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) | https://github.com/electronstudio/jaylib/ |
| raylib-java | 2.0 | [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) | https://github.com/XoanaIO/raylib-java | | raylib-java | 2.0 | [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) | https://github.com/XoanaIO/raylib-java |
| raylib-j | 3.5 | [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) | https://github.com/CreedVI/Raylib-J | | raylib-j | 3.5 | [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) | https://github.com/CreedVI/Raylib-J |
@ -93,12 +94,13 @@ Some people ported raylib to other languages in form of bindings or wrappers to
| raylib-smallBasic | 3.1-dev | [SmallBASIC](https://github.com/smallbasic/SmallBASIC) | https://github.com/smallbasic/smallbasic.plugins/tree/master/raylib | | raylib-smallBasic | 3.1-dev | [SmallBASIC](https://github.com/smallbasic/SmallBASIC) | https://github.com/smallbasic/smallbasic.plugins/tree/master/raylib |
| raylib-ats2 | 3.0 | [ATS2](http://www.ats-lang.org/) | https://github.com/mephistopheles-8/raylib-ats2 | | raylib-ats2 | 3.0 | [ATS2](http://www.ats-lang.org/) | https://github.com/mephistopheles-8/raylib-ats2 |
| raylib-beef | 3.0 | [Beef](https://www.beeflang.org/) | https://github.com/M0n7y5/raylib-beef | | raylib-beef | 3.0 | [Beef](https://www.beeflang.org/) | https://github.com/M0n7y5/raylib-beef |
| raylib-swift | 3.5 | [Swift](https://swift.org/) | https://github.com/conifer-dev/raylib-swift | | raylib-swift | 3.7 | [Swift](https://swift.org/) | https://github.com/STREGAsGate/Raylib |
| raylib-never | 3.0 | [Never](https://github.com/never-lang/never) | https://github.com/never-lang/raylib-never | | raylib-never | 3.0 | [Never](https://github.com/never-lang/never) | https://github.com/never-lang/raylib-never |
| hb-raylib | 3.5 | [Harbour](https://harbour.github.io) | https://github.com/MarcosLeonardoMendezGerencir/hb-raylib | | hb-raylib | 3.5 | [Harbour](https://harbour.github.io) | https://github.com/MarcosLeonardoMendezGerencir/hb-raylib |
| Relib | 3.5 | [ReCT](https://github.com/RedCubeDev-ByteSpace/ReCT) | https://github.com/RedCubeDev-ByteSpace/Relib | | Relib | 3.5 | [ReCT](https://github.com/RedCubeDev-ByteSpace/ReCT) | https://github.com/RedCubeDev-ByteSpace/Relib |
| rayex | 3.7 | [elixir](https://elixir-lang.org/) | https://github.com/shiryel/rayex | | rayex | 3.7 | [elixir](https://elixir-lang.org/) | https://github.com/shiryel/rayex |
| raylib.cbl | 2.0 | [COBOL](https://en.wikipedia.org/wiki/COBOL) | *[code examples](https://github.com/Martinfx/Cobol/tree/master/OpenCobol/Games/raylib)* | | raylib.cbl | 2.0 | [COBOL](https://en.wikipedia.org/wiki/COBOL) | *[code examples](https://github.com/Martinfx/Cobol/tree/master/OpenCobol/Games/raylib)* |
| kaylib | 3.7 | [Kotlin/native](https://kotlinlang.org) | https://github.com/electronstudio/kaylib |
### Utility Wrapers ### Utility Wrapers

View File

@ -27,9 +27,9 @@ endif()
option(INCLUDE_EVERYTHING "Include everything disabled by default (for CI usage" OFF) option(INCLUDE_EVERYTHING "Include everything disabled by default (for CI usage" OFF)
set(OFF ${INCLUDE_EVERYTHING} CACHE INTERNAL "Replace any OFF by default with \${OFF} to have it covered by this option") set(OFF ${INCLUDE_EVERYTHING} CACHE INTERNAL "Replace any OFF by default with \${OFF} to have it covered by this option")
# core.c # rcore.c
cmake_dependent_option(SUPPORT_CAMERA_SYSTEM "Provide camera module (camera.h) with multiple predefined cameras: free, 1st/3rd person, orbital" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_CAMERA_SYSTEM "Provide camera module (rcamera.h) with multiple predefined cameras: free, 1st/3rd person, orbital" ON CUSTOMIZE_BUILD ON)
cmake_dependent_option(SUPPORT_GESTURES_SYSTEM "Gestures module is included (gestures.h) to support gestures detection: tap, hold, swipe, drag" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_GESTURES_SYSTEM "Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag" ON CUSTOMIZE_BUILD ON)
cmake_dependent_option(SUPPORT_MOUSE_GESTURES "Mouse gestures are directly mapped like touches and processed by gestures system" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_MOUSE_GESTURES "Mouse gestures are directly mapped like touches and processed by gestures system" ON CUSTOMIZE_BUILD ON)
cmake_dependent_option(SUPPORT_SSH_KEYBOARD_RPI "Reconfigure standard input to receive key inputs, works with SSH connection" OFF CUSTOMIZE_BUILD OFF) cmake_dependent_option(SUPPORT_SSH_KEYBOARD_RPI "Reconfigure standard input to receive key inputs, works with SSH connection" OFF CUSTOMIZE_BUILD OFF)
cmake_dependent_option(SUPPORT_DEFAULT_FONT "Default font is loaded on window initialization to be available for the user to render simple text. If enabled, uses external module functions to load default raylib font (module: text)" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_DEFAULT_FONT "Default font is loaded on window initialization to be available for the user to render simple text. If enabled, uses external module functions to load default raylib font (module: text)" ON CUSTOMIZE_BUILD ON)
@ -41,10 +41,10 @@ cmake_dependent_option(SUPPORT_WINMM_HIGHRES_TIMER "Setting a higher resolution
cmake_dependent_option(SUPPORT_DATA_STORAGE "Support for persistent data storage" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_DATA_STORAGE "Support for persistent data storage" ON CUSTOMIZE_BUILD ON)
cmake_dependent_option(SUPPORT_COMPRESSION_API "Support for compression API" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_COMPRESSION_API "Support for compression API" ON CUSTOMIZE_BUILD ON)
# shapes.c # rshapes.c
cmake_dependent_option(SUPPORT_QUADS_DRAW_MODE "Use QUADS instead of TRIANGLES for drawing when possible. Some lines-based shapes could still use lines" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_QUADS_DRAW_MODE "Use QUADS instead of TRIANGLES for drawing when possible. Some lines-based shapes could still use lines" ON CUSTOMIZE_BUILD ON)
# textures.c # rtextures.c
cmake_dependent_option(SUPPORT_IMAGE_EXPORT "Support image exporting to file" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_IMAGE_EXPORT "Support image exporting to file" ON CUSTOMIZE_BUILD ON)
cmake_dependent_option(SUPPORT_IMAGE_GENERATION "Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_IMAGE_GENERATION "Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)" ON CUSTOMIZE_BUILD ON)
cmake_dependent_option(SUPPORT_IMAGE_MANIPULATION "Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop... If not defined only three image editing functions supported: ImageFormat(), ImageAlphaMask(), ImageToPOT()" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_IMAGE_MANIPULATION "Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop... If not defined only three image editing functions supported: ImageFormat(), ImageAlphaMask(), ImageToPOT()" ON CUSTOMIZE_BUILD ON)
@ -61,12 +61,12 @@ cmake_dependent_option(SUPPORT_FILEFORMAT_PSD "Support loading PSD as textures"
cmake_dependent_option(SUPPORT_FILEFORMAT_PKM "Support loading PKM as textures" ${OFF} CUSTOMIZE_BUILD OFF) cmake_dependent_option(SUPPORT_FILEFORMAT_PKM "Support loading PKM as textures" ${OFF} CUSTOMIZE_BUILD OFF)
cmake_dependent_option(SUPPORT_FILEFORMAT_PVR "Support loading PVR as textures" ${OFF} CUSTOMIZE_BUILD OFF) cmake_dependent_option(SUPPORT_FILEFORMAT_PVR "Support loading PVR as textures" ${OFF} CUSTOMIZE_BUILD OFF)
# text.c # rtext.c
cmake_dependent_option(SUPPORT_FILEFORMAT_FNT "Support loading fonts in FNT format" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_FILEFORMAT_FNT "Support loading fonts in FNT format" ON CUSTOMIZE_BUILD ON)
cmake_dependent_option(SUPPORT_FILEFORMAT_TTF "Support loading font in TTF/OTF format" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_FILEFORMAT_TTF "Support loading font in TTF/OTF format" ON CUSTOMIZE_BUILD ON)
cmake_dependent_option(SUPPORT_TEXT_MANIPULATION "Support text manipulation functions" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_TEXT_MANIPULATION "Support text manipulation functions" ON CUSTOMIZE_BUILD ON)
# models.c # rmodels.c
cmake_dependent_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 CUSTOMIZE_BUILD ON) cmake_dependent_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 CUSTOMIZE_BUILD ON)
cmake_dependent_option(SUPPORT_FILEFORMAT_OBJ "Support loading OBJ file format" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_FILEFORMAT_OBJ "Support loading OBJ file format" ON CUSTOMIZE_BUILD ON)
cmake_dependent_option(SUPPORT_FILEFORMAT_MTL "Support loading MTL file format" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_FILEFORMAT_MTL "Support loading MTL file format" ON CUSTOMIZE_BUILD ON)

View File

@ -33,7 +33,7 @@ Lots of code changes and lot of testing have concluded in this amazing new rayli
notes on raylib 1.2 notes on raylib 1.2
------------------- -------------------
On September 2014, after 5 month of raylib 1.1 release, it comes raylib 1.2. Again, this version presents a complete internal redesign of [core](https://github.com/raysan5/raylib/blob/master/src/core.c) module to support two new platforms: [Android](http://www.android.com/) and [Raspberry Pi](http://www.raspberrypi.org/). On September 2014, after 5 month of raylib 1.1 release, it comes raylib 1.2. Again, this version presents a complete internal redesign of [core](https://github.com/raysan5/raylib/blob/master/src/rcore.c) module to support two new platforms: [Android](http://www.android.com/) and [Raspberry Pi](http://www.raspberrypi.org/).
It's been some month of really hard work to accomodate raylib to those new platforms while keeping it easy for the users. On Android, raylib manages internally the activity cicle, as well as the inputs; on Raspberry Pi, a complete raw input system has been written from scratch. It's been some month of really hard work to accomodate raylib to those new platforms while keeping it easy for the users. On Android, raylib manages internally the activity cicle, as well as the inputs; on Raspberry Pi, a complete raw input system has been written from scratch.
@ -54,9 +54,9 @@ On September 2015, after 1 year of raylib 1.2 release, arrives raylib 1.3. This
- Textures module has grown to support most of the internal texture formats available in OpenGL (RGB565, RGB888, RGBA5551, RGBA4444, etc.), including compressed texture formats (DXT, ETC1, ETC2, ASTC, PVRT); raylib 1.3 can load .dds, .pkm, .ktx, .astc and .pvr files. - Textures module has grown to support most of the internal texture formats available in OpenGL (RGB565, RGB888, RGBA5551, RGBA4444, etc.), including compressed texture formats (DXT, ETC1, ETC2, ASTC, PVRT); raylib 1.3 can load .dds, .pkm, .ktx, .astc and .pvr files.
- A brand new [camera](https://github.com/raysan5/raylib/blob/master/src/camera.c) module offers to the user multiple preconfigured ready-to-use camera systems (free camera, 1st person, 3rd person). Camera modes are very easy to use, just check examples: [core_3d_camera_free.c](https://github.com/raysan5/raylib/blob/master/examples/core_3d_camera_free.c) and [core_3d_camera_first_person.c](https://github.com/raysan5/raylib/blob/master/examples/core_3d_camera_first_person.c). - A brand new [camera](https://github.com/raysan5/raylib/blob/master/src/rcamera.c) module offers to the user multiple preconfigured ready-to-use camera systems (free camera, 1st person, 3rd person). Camera modes are very easy to use, just check examples: [core_3d_camera_free.c](https://github.com/raysan5/raylib/blob/master/examples/core_3d_camera_free.c) and [core_3d_camera_first_person.c](https://github.com/raysan5/raylib/blob/master/examples/core_3d_camera_first_person.c).
- New [gestures](https://github.com/raysan5/raylib/blob/master/src/gestures.h) module simplifies gestures detection on Android and HTML5 programs. - New [gestures](https://github.com/raysan5/raylib/blob/master/src/rgestures.h) module simplifies gestures detection on Android and HTML5 programs.
- [raygui](https://github.com/raysan5/raylib/blob/master/src/raygui.h), the new immediate-mode GUI module offers a set of functions to create simple user interfaces, primary intended for tools development. It's still in experimental state but already fully functional. - [raygui](https://github.com/raysan5/raylib/blob/master/src/raygui.h), the new immediate-mode GUI module offers a set of functions to create simple user interfaces, primary intended for tools development. It's still in experimental state but already fully functional.
@ -77,7 +77,7 @@ On February 2016, after 4 months of raylib 1.3 release, it comes raylib 1.4. For
- [raymath](https://github.com/raysan5/raylib/blob/master/src/raymath.h) module has been reviewed; some bugs have been solved and the module has been converted to a header-only file for easier portability, optionally, functions can also be used as inline. - [raymath](https://github.com/raysan5/raylib/blob/master/src/raymath.h) module has been reviewed; some bugs have been solved and the module has been converted to a header-only file for easier portability, optionally, functions can also be used as inline.
- [gestures](https://github.com/raysan5/raylib/blob/master/src/gestures.c) module has redesigned and simplified, now it can process touch events from any source, including mouse. This way, gestures system can be used on any platform providing an unified way to work with inputs and allowing the user to create multiplatform games with only one source code. - [gestures](https://github.com/raysan5/raylib/blob/master/src/rgestures.c) module has redesigned and simplified, now it can process touch events from any source, including mouse. This way, gestures system can be used on any platform providing an unified way to work with inputs and allowing the user to create multiplatform games with only one source code.
- Raspberry Pi input system has been redesigned to better read raw inputs using generic Linux event handlers (keyboard:`stdin`, mouse:`/dev/input/mouse0`, gamepad:`/dev/input/js0`). Gamepad support has also been added (experimental). - Raspberry Pi input system has been redesigned to better read raw inputs using generic Linux event handlers (keyboard:`stdin`, mouse:`/dev/input/mouse0`, gamepad:`/dev/input/js0`). Gamepad support has also been added (experimental).
@ -106,7 +106,7 @@ On July 2016, after 5 months of raylib 1.4 release, arrives raylib 1.5. This new
- Audio chiptunese support and mixing channels: Added support for module audio music (.xm, .mod) loading and playing. Multiple mixing channels are now also supported. All this features thanks to the amazing work of @kd7tck. - Audio chiptunese support and mixing channels: Added support for module audio music (.xm, .mod) loading and playing. Multiple mixing channels are now also supported. All this features thanks to the amazing work of @kd7tck.
Other additions include a [2D camera system](https://github.com/raysan5/raylib/blob/master/examples/core_2d_camera.c), render textures for offline render (and most comprehensive [postprocessing](https://github.com/raysan5/raylib/blob/master/examples/shaders_postprocessing.c)) or support for legacy OpenGL 2.1 on desktop platforms. Other additions include a [2D camera system](https://github.com/raysan5/raylib/blob/master/examples/core_2d_rcamera.c), render textures for offline render (and most comprehensive [postprocessing](https://github.com/raysan5/raylib/blob/master/examples/shaders_postprocessing.c)) or support for legacy OpenGL 2.1 on desktop platforms.
This new version is so massive that is difficult to list all the improvements, most of raylib modules have been reviewed and [rlgl](https://github.com/raysan5/raylib/blob/master/src/rlgl.c) module has been completely redesigned to accomodate to new material-lighting systems and stereo rendering. You can check [CHANGELOG](https://github.com/raysan5/raylib/blob/master/CHANGELOG) file for a more detailed list of changes. This new version is so massive that is difficult to list all the improvements, most of raylib modules have been reviewed and [rlgl](https://github.com/raysan5/raylib/blob/master/src/rlgl.c) module has been completely redesigned to accomodate to new material-lighting systems and stereo rendering. You can check [CHANGELOG](https://github.com/raysan5/raylib/blob/master/CHANGELOG) file for a more detailed list of changes.

View File

@ -14,7 +14,8 @@ if (${PLATFORM} MATCHES "Desktop")
endif () endif ()
elseif (WIN32) elseif (WIN32)
add_definitions(-D_CRT_SECURE_NO_WARNINGS) add_definitions(-D_CRT_SECURE_NO_WARNINGS)
set(LIBS_PRIVATE ${LIBS_PRIVATE} winmm) find_package(OpenGL QUIET)
set(LIBS_PRIVATE ${OPENGL_LIBRARIES} winmm)
else () else ()
find_library(pthread NAMES pthread) find_library(pthread NAMES pthread)
find_package(OpenGL QUIET) find_package(OpenGL QUIET)

View File

@ -86,7 +86,9 @@ if (${PLATFORM} MATCHES "Android")
list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/models/models_obj_viewer.c) list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/models/models_obj_viewer.c)
list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/models/models_animation.c) list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/models/models_animation.c)
list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/models/models_first_person_maze.c) list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/models/models_first_person_maze.c)
list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/models/models_magicavoxel_loading.c)
list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/shaders/shaders_custom_uniform.c) list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/shaders/shaders_custom_uniform.c)
list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/shaders/shaders_model_shader.c) list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/shaders/shaders_model_shader.c)
list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/shaders/shaders_postprocessing.c) list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/shaders/shaders_postprocessing.c)

View File

@ -25,7 +25,7 @@
# Define required raylib variables # Define required raylib variables
PROJECT_NAME ?= raylib_examples PROJECT_NAME ?= raylib_examples
RAYLIB_VERSION ?= 3.8.0 RAYLIB_VERSION ?= 4.0.0
RAYLIB_PATH ?= .. RAYLIB_PATH ?= ..
# Define default options # Define default options
@ -185,6 +185,12 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
MAKE = mingw32-make MAKE = mingw32-make
endif endif
endif endif
ifeq ($(PLATFORM),PLATFORM_ANDROID)
MAKE = mingw32-make
endif
ifeq ($(PLATFORM),PLATFORM_WEB)
MAKE = mingw32-make
endif
# Define compiler flags: # Define compiler flags:
# -O1 defines optimization level # -O1 defines optimization level
@ -229,32 +235,6 @@ endif
ifeq ($(PLATFORM),PLATFORM_DRM) ifeq ($(PLATFORM),PLATFORM_DRM)
CFLAGS += -std=gnu99 -DEGL_NO_X11 CFLAGS += -std=gnu99 -DEGL_NO_X11
endif endif
ifeq ($(PLATFORM),PLATFORM_WEB)
# -Os # size optimization
# -O2 # optimization level 2, if used, also set --memory-init-file 0
# -s USE_GLFW=3 # Use glfw3 library (context/input management)
# -s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing -> WARNING: Audio buffers could FAIL!
# -s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB)
# -s USE_PTHREADS=1 # multithreading support
# -s WASM=0 # disable Web Assembly, emitted by default
# -s ASYNCIFY # lets synchronous C/C++ code interact with asynchronous JS
# -s FORCE_FILESYSTEM=1 # force filesystem to load/save files data
# -s ASSERTIONS=1 # enable runtime checks for common memory allocation errors (-O1 and above turn it off)
# --profiling # include information for code profiling
# --memory-init-file 0 # to avoid an external memory initialization code file (.mem)
# --preload-file resources # specify a resources folder for data compilation
# --source-map-base # allow debugging in browser with source map
CFLAGS += -s USE_GLFW=3 -s ASYNCIFY -s TOTAL_MEMORY=67108864 -s FORCE_FILESYSTEM=1 --preload-file $(dir $<)resources@resources
# NOTE: Simple raylib examples are compiled to be interpreter with asyncify, that way,
# we can compile same code for ALL platforms with no change required, but, working on bigger
# projects, code needs to be refactored to avoid a blocking while() loop, moving Update and Draw
# logic to a self contained function: UpdateDrawFrame(), check core_basic_window_web.c for reference.
# Define a custom shell .html and output extension
CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html
EXT = .html
endif
# Define include paths for required headers # Define include paths for required headers
# NOTE: Some external/extras libraries could be required (stb, physac, easings...) # NOTE: Some external/extras libraries could be required (stb, physac, easings...)
@ -303,7 +283,32 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
LDFLAGS = -L. -L$(RAYLIB_INSTALL_PATH) -L$(RAYLIB_RELEASE_PATH) -L$(RAYLIB_PATH) LDFLAGS = -L. -L$(RAYLIB_INSTALL_PATH) -L$(RAYLIB_RELEASE_PATH) -L$(RAYLIB_PATH)
endif endif
endif endif
ifeq ($(PLATFORM),PLATFORM_WEB)
# -Os # size optimization
# -O2 # optimization level 2, if used, also set --memory-init-file 0
# -s USE_GLFW=3 # Use glfw3 library (context/input management)
# -s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing -> WARNING: Audio buffers could FAIL!
# -s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) (67108864 = 64MB)
# -s USE_PTHREADS=1 # multithreading support
# -s WASM=0 # disable Web Assembly, emitted by default
# -s ASYNCIFY # lets synchronous C/C++ code interact with asynchronous JS
# -s FORCE_FILESYSTEM=1 # force filesystem to load/save files data
# -s ASSERTIONS=1 # enable runtime checks for common memory allocation errors (-O1 and above turn it off)
# --profiling # include information for code profiling
# --memory-init-file 0 # to avoid an external memory initialization code file (.mem)
# --preload-file resources # specify a resources folder for data compilation
# --source-map-base # allow debugging in browser with source map
LDFLAGS += -s USE_GLFW=3 -s ASYNCIFY -s TOTAL_MEMORY=67108864 -s FORCE_FILESYSTEM=1 --preload-file $(dir $<)resources@resources
# NOTE: Simple raylib examples are compiled to be interpreter with asyncify, that way,
# we can compile same code for ALL platforms with no change required, but, working on bigger
# projects, code needs to be refactored to avoid a blocking while() loop, moving Update and Draw
# logic to a self contained function: UpdateDrawFrame(), check core_basic_window_web.c for reference.
# Define a custom shell .html and output extension
LDFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html
EXT = .html
endif
ifeq ($(PLATFORM),PLATFORM_RPI) ifeq ($(PLATFORM),PLATFORM_RPI)
LDFLAGS += -L/opt/vc/lib LDFLAGS += -L/opt/vc/lib
endif endif
@ -466,7 +471,8 @@ MODELS = \
models/models_skybox \ models/models_skybox \
models/models_yaw_pitch_roll \ models/models_yaw_pitch_roll \
models/models_heightmap \ models/models_heightmap \
models/models_waving_cubes models/models_waving_cubes \
models/models_magicavoxel_loading
SHADERS = \ SHADERS = \
shaders/shaders_model_shader \ shaders/shaders_model_shader \

View File

@ -0,0 +1,151 @@
/*******************************************************************************************
*
* raylib [models] example - magicavoxel loader and viewer
*
* This example has been created using raylib 3.8 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
*
* Example contributed by Johann Nadalutti
*
* Copyright (c) 2021 Johann Nadalutti
*
********************************************************************************************/
#include "raylib.h"
#include "raymath.h"
#include <string.h>
// VOX Files to load and view
#define NUM_VOX_FILES 3
const char* szVoxFiles[] = {
"resources/vox/chr_knight.vox",
"resources/vox/chr_sword.vox",
"resources/vox/monu9.vox"
};
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [models] example - magicavoxel loading");
// Load MagicaVoxel files
Model models[NUM_VOX_FILES] = { 0 };
for (int i = 0; i < NUM_VOX_FILES; i++)
{
// Load MagicaVoxel File and build model
double t0, t1;
t0 = GetTime() * 1000.0;
models[i] = LoadModel(szVoxFiles[i]);
t1 = GetTime() * 1000.0;
TraceLog(LOG_INFO, TextFormat("Vox <%s> loaded in %f ms", GetFileName(szVoxFiles[i]), t1 - t0));
//Compute model's center matrix
BoundingBox bb = GetModelBoundingBox(models[i]);
Vector3 center;
center.x = bb.min.x + (((bb.max.x - bb.min.x) / 2));
center.z = bb.min.z + (((bb.max.z - bb.min.z) / 2));
Matrix matP = MatrixTranslate(-center.x, 0, -center.z);
models[i].transform = matP;
}
// Define the camera to look into our 3d world
Camera camera = { { 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 };
// Model drawing position
Vector3 position = { 0.0f, 0.0f, 0.0f };
int currentModel = 0;
SetCameraMode(camera, CAMERA_ORBITAL); // Set a orbital camera mode
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
//----------------------------------------------------------------------------------
UpdateCamera(&camera); // Update internal camera and our camera
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
{
currentModel = (currentModel + 1) % NUM_VOX_FILES; // Cycle between models
}
if (IsKeyPressed(KEY_RIGHT))
{
currentModel++;
if (currentModel >= NUM_VOX_FILES) currentModel = 0;
}
else if (IsKeyPressed(KEY_LEFT))
{
currentModel--;
if (currentModel < 0) currentModel = NUM_VOX_FILES - 1;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
//Display model
BeginMode3D(camera);
Vector3 rotAxis = { 1,0,0 };
Vector3 scale = { 1,1,1 };
DrawModelEx(models[currentModel], position, rotAxis, 0, scale, WHITE);
//DrawModelWiresEx(models[currentModel], position, rotAxis, -90.0f, scale, BLACK);
DrawGrid(10, 1.0);
EndMode3D();
//Display debug infos
DrawRectangle(30, 400, 310, 30, Fade(SKYBLUE, 0.5f));
DrawRectangleLines(30, 400, 310, 30, Fade(DARKBLUE, 0.5f));
DrawText("MOUSE LEFT BUTTON to CYCLE VOX MODELS", 40, 410, 10, BLUE);
DrawText(GetFileName(szVoxFiles[currentModel]), 100, 10, 20, DARKBLUE);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
// Unload models data (GPU VRAM)
for (int i = 0; i < NUM_VOX_FILES; i++) UnloadModel(models[i]);
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -454,16 +454,16 @@ void DrawTextCodepoint3D(Font font, int codepoint, Vector3 position, float fontS
// Character destination rectangle on screen // Character destination rectangle on screen
// NOTE: We consider charsPadding on drawing // NOTE: We consider charsPadding on drawing
position.x += (float)(font.chars[index].offsetX - font.charsPadding)/(float)font.baseSize*scale; position.x += (float)(font.glyphs[index].offsetX - font.glyphPadding)/(float)font.baseSize*scale;
position.z += (float)(font.chars[index].offsetY - font.charsPadding)/(float)font.baseSize*scale; position.z += (float)(font.glyphs[index].offsetY - font.glyphPadding)/(float)font.baseSize*scale;
// Character source rectangle from font texture atlas // Character source rectangle from font texture atlas
// NOTE: We consider chars padding when drawing, it could be required for outline/glow shader effects // NOTE: We consider chars padding when drawing, it could be required for outline/glow shader effects
Rectangle srcRec = { font.recs[index].x - (float)font.charsPadding, font.recs[index].y - (float)font.charsPadding, Rectangle srcRec = { font.recs[index].x - (float)font.glyphPadding, font.recs[index].y - (float)font.glyphPadding,
font.recs[index].width + 2.0f*font.charsPadding, font.recs[index].height + 2.0f*font.charsPadding }; font.recs[index].width + 2.0f*font.glyphPadding, font.recs[index].height + 2.0f*font.glyphPadding };
float width = (float)(font.recs[index].width + 2.0f*font.charsPadding)/(float)font.baseSize*scale; float width = (float)(font.recs[index].width + 2.0f*font.glyphPadding)/(float)font.baseSize*scale;
float height = (float)(font.recs[index].height + 2.0f*font.charsPadding)/(float)font.baseSize*scale; float height = (float)(font.recs[index].height + 2.0f*font.glyphPadding)/(float)font.baseSize*scale;
if (font.texture.id > 0) if (font.texture.id > 0)
{ {
@ -477,16 +477,11 @@ void DrawTextCodepoint3D(Font font, int codepoint, Vector3 position, float fontS
const float tw = (srcRec.x+srcRec.width)/font.texture.width; const float tw = (srcRec.x+srcRec.width)/font.texture.width;
const float th = (srcRec.y+srcRec.height)/font.texture.height; const float th = (srcRec.y+srcRec.height)/font.texture.height;
if (SHOW_LETTER_BOUNDRY) if (SHOW_LETTER_BOUNDRY) DrawCubeWiresV((Vector3){ position.x + width/2, position.y, position.z + height/2}, (Vector3){ width, LETTER_BOUNDRY_SIZE, height }, LETTER_BOUNDRY_COLOR);
DrawCubeWiresV((Vector3){ position.x + width/2, position.y, position.z + height/2}, (Vector3){ width, LETTER_BOUNDRY_SIZE, height }, LETTER_BOUNDRY_COLOR);
#if defined(RAYLIB_NEW_RLGL)
rlCheckRenderBatchLimit(4 + 4*backface); rlCheckRenderBatchLimit(4 + 4*backface);
rlSetTexture(font.texture.id); rlSetTexture(font.texture.id);
#else
if (rlCheckBufferLimit(4 + 4*backface)) rlglDraw();
rlEnableTexture(font.texture.id);
#endif
rlPushMatrix(); rlPushMatrix();
rlTranslatef(position.x, position.y, position.z); rlTranslatef(position.x, position.y, position.z);
@ -512,11 +507,7 @@ void DrawTextCodepoint3D(Font font, int codepoint, Vector3 position, float fontS
rlEnd(); rlEnd();
rlPopMatrix(); rlPopMatrix();
#if defined(RAYLIB_NEW_RLGL)
rlSetTexture(0); rlSetTexture(0);
#else
rlDisableTexture();
#endif
} }
} }
@ -554,8 +545,8 @@ void DrawText3D(Font font, const char *text, Vector3 position, float fontSize, f
DrawTextCodepoint3D(font, codepoint, (Vector3){ position.x + textOffsetX, position.y, position.z + textOffsetY }, fontSize, backface, tint); DrawTextCodepoint3D(font, codepoint, (Vector3){ position.x + textOffsetX, position.y, position.z + textOffsetY }, fontSize, backface, tint);
} }
if (font.chars[index].advanceX == 0) textOffsetX += (float)(font.recs[index].width + fontSpacing)/(float)font.baseSize*scale; if (font.glyphs[index].advanceX == 0) textOffsetX += (float)(font.recs[index].width + fontSpacing)/(float)font.baseSize*scale;
else textOffsetX += (float)(font.chars[index].advanceX + fontSpacing)/(float)font.baseSize*scale; else textOffsetX += (float)(font.glyphs[index].advanceX + fontSpacing)/(float)font.baseSize*scale;
} }
i += codepointByteCount; // Move text bytes counter to next codepoint i += codepointByteCount; // Move text bytes counter to next codepoint
@ -592,8 +583,8 @@ Vector3 MeasureText3D(Font font, const char* text, float fontSize, float fontSpa
if (letter != '\n') if (letter != '\n')
{ {
if (font.chars[index].advanceX != 0) textWidth += (font.chars[index].advanceX+fontSpacing)/(float)font.baseSize*scale; if (font.glyphs[index].advanceX != 0) textWidth += (font.glyphs[index].advanceX+fontSpacing)/(float)font.baseSize*scale;
else textWidth += (font.recs[index].width + font.chars[index].offsetX)/(float)font.baseSize*scale; else textWidth += (font.recs[index].width + font.glyphs[index].offsetX)/(float)font.baseSize*scale;
} }
else else
{ {
@ -670,8 +661,8 @@ void DrawTextWave3D(Font font, const char *text, Vector3 position, float fontSiz
DrawTextCodepoint3D(font, codepoint, (Vector3){ pos.x + textOffsetX, pos.y, pos.z + textOffsetY }, fontSize, backface, tint); DrawTextCodepoint3D(font, codepoint, (Vector3){ pos.x + textOffsetX, pos.y, pos.z + textOffsetY }, fontSize, backface, tint);
} }
if (font.chars[index].advanceX == 0) textOffsetX += (float)(font.recs[index].width + fontSpacing)/(float)font.baseSize*scale; if (font.glyphs[index].advanceX == 0) textOffsetX += (float)(font.recs[index].width + fontSpacing)/(float)font.baseSize*scale;
else textOffsetX += (float)(font.chars[index].advanceX + fontSpacing)/(float)font.baseSize*scale; else textOffsetX += (float)(font.glyphs[index].advanceX + fontSpacing)/(float)font.baseSize*scale;
} }
i += codepointByteCount; // Move text bytes counter to next codepoint i += codepointByteCount; // Move text bytes counter to next codepoint
@ -714,8 +705,8 @@ Vector3 MeasureTextWave3D(Font font, const char* text, float fontSize, float fon
} }
else else
{ {
if (font.chars[index].advanceX != 0) textWidth += (font.chars[index].advanceX+fontSpacing)/(float)font.baseSize*scale; if (font.glyphs[index].advanceX != 0) textWidth += (font.glyphs[index].advanceX+fontSpacing)/(float)font.baseSize*scale;
else textWidth += (font.recs[index].width + font.chars[index].offsetX)/(float)font.baseSize*scale; else textWidth += (font.recs[index].width + font.glyphs[index].offsetX)/(float)font.baseSize*scale;
} }
} }
else else

View File

@ -39,24 +39,24 @@ int main(void)
// Default font generation from TTF font // Default font generation from TTF font
Font fontDefault = { 0 }; Font fontDefault = { 0 };
fontDefault.baseSize = 16; fontDefault.baseSize = 16;
fontDefault.charsCount = 95; fontDefault.glyphCount = 95;
// Loading font data from memory data // Loading font data from memory data
// Parameters > font size: 16, no chars array provided (0), chars count: 95 (autogenerate chars array) // Parameters > font size: 16, no glyphs array provided (0), glyphs count: 95 (autogenerate chars array)
fontDefault.chars = LoadFontData(fileData, fileSize, 16, 0, 95, FONT_DEFAULT); fontDefault.glyphs = LoadFontData(fileData, fileSize, 16, 0, 95, FONT_DEFAULT);
// Parameters > chars count: 95, font size: 16, chars padding in image: 4 px, pack method: 0 (default) // Parameters > glyphs count: 95, font size: 16, glyphs padding in image: 4 px, pack method: 0 (default)
Image atlas = GenImageFontAtlas(fontDefault.chars, &fontDefault.recs, 95, 16, 4, 0); Image atlas = GenImageFontAtlas(fontDefault.glyphs, &fontDefault.recs, 95, 16, 4, 0);
fontDefault.texture = LoadTextureFromImage(atlas); fontDefault.texture = LoadTextureFromImage(atlas);
UnloadImage(atlas); UnloadImage(atlas);
// SDF font generation from TTF font // SDF font generation from TTF font
Font fontSDF = { 0 }; Font fontSDF = { 0 };
fontSDF.baseSize = 16; fontSDF.baseSize = 16;
fontSDF.charsCount = 95; fontSDF.glyphCount = 95;
// Parameters > font size: 16, no chars array provided (0), chars count: 0 (defaults to 95) // Parameters > font size: 16, no glyphs array provided (0), glyphs count: 0 (defaults to 95)
fontSDF.chars = LoadFontData(fileData, fileSize, 16, 0, 0, FONT_SDF); fontSDF.glyphs = LoadFontData(fileData, fileSize, 16, 0, 0, FONT_SDF);
// Parameters > chars count: 95, font size: 16, chars padding in image: 0 px, pack method: 1 (Skyline algorythm) // Parameters > glyphs count: 95, font size: 16, glyphs padding in image: 0 px, pack method: 1 (Skyline algorythm)
atlas = GenImageFontAtlas(fontSDF.chars, &fontSDF.recs, 95, 16, 0, 1); atlas = GenImageFontAtlas(fontSDF.glyphs, &fontSDF.recs, 95, 16, 0, 1);
fontSDF.texture = LoadTextureFromImage(atlas); fontSDF.texture = LoadTextureFromImage(atlas);
UnloadImage(atlas); UnloadImage(atlas);

View File

@ -166,7 +166,7 @@ static void DrawTextBoxedSelectable(Font font, const char *text, Rectangle rec,
float glyphWidth = 0; float glyphWidth = 0;
if (codepoint != '\n') if (codepoint != '\n')
{ {
glyphWidth = (font.chars[index].advanceX == 0) ? font.recs[index].width*scaleFactor : font.chars[index].advanceX*scaleFactor; glyphWidth = (font.glyphs[index].advanceX == 0) ? font.recs[index].width*scaleFactor : font.glyphs[index].advanceX*scaleFactor;
if (i + 1 < length) glyphWidth = glyphWidth + spacing; if (i + 1 < length) glyphWidth = glyphWidth + spacing;
} }

View File

@ -277,8 +277,8 @@ int main(int argc, char **argv)
// Draw the info text below the main message // Draw the info text below the main message
int size = (int)strlen(messages[message].text); int size = (int)strlen(messages[message].text);
int len = GetCodepointsCount(messages[message].text); int length = GetCodepointCount(messages[message].text);
const char *info = TextFormat("%s %u characters %i bytes", messages[message].language, len, size); const char *info = TextFormat("%s %u characters %i bytes", messages[message].language, length, size);
sz = MeasureTextEx(GetFontDefault(), info, 10, 1.0f); sz = MeasureTextEx(GetFontDefault(), info, 10, 1.0f);
Vector2 pos = { textRect.x + textRect.width - sz.x, msgRect.y + msgRect.height - sz.y - 2 }; Vector2 pos = { textRect.x + textRect.width - sz.x, msgRect.y + msgRect.height - sz.y - 2 };
DrawText(info, (int)pos.x, (int)pos.y, 10, RAYWHITE); DrawText(info, (int)pos.x, (int)pos.y, 10, RAYWHITE);
@ -367,7 +367,7 @@ static void DrawTextBoxedSelectable(Font font, const char *text, Rectangle rec,
float glyphWidth = 0; float glyphWidth = 0;
if (codepoint != '\n') if (codepoint != '\n')
{ {
glyphWidth = (font.chars[index].advanceX == 0) ? font.recs[index].width*scaleFactor : font.chars[index].advanceX*scaleFactor; glyphWidth = (font.glyphs[index].advanceX == 0) ? font.recs[index].width*scaleFactor : font.glyphs[index].advanceX*scaleFactor;
if (i + 1 < length) glyphWidth = glyphWidth + spacing; if (i + 1 < length) glyphWidth = glyphWidth + spacing;
} }

View File

@ -26,8 +26,8 @@ int main(void)
Image image = LoadImage("resources/raylib_logo.png"); // Loaded in CPU memory (RAM) Image image = LoadImage("resources/raylib_logo.png"); // Loaded in CPU memory (RAM)
Texture2D texture = LoadTextureFromImage(image); // Image converted to texture, GPU memory (VRAM) Texture2D texture = LoadTextureFromImage(image); // Image converted to texture, GPU memory (VRAM)
UnloadImage(image); // Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM UnloadImage(image); // Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM
SetTargetFPS(60); // Set our game to run at 60 frames-per-second SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------

View File

@ -18,11 +18,11 @@ cmd /c del /F libraylib.a
:: > Compile raylib modules :: > Compile raylib modules
:: ------------------------------ :: ------------------------------
gcc -O2 -c rglfw.c -Wall -I. -Iexternal/glfw/include gcc -O2 -c rglfw.c -Wall -I. -Iexternal/glfw/include
gcc -O2 -c core.c -std=c99 -Wall -Iexternal/glfw/include -DPLATFORM_DESKTOP -D%GRAPHICS_API% gcc -O2 -c rcore.c -std=c99 -Wall -Iexternal/glfw/include -DPLATFORM_DESKTOP -D%GRAPHICS_API%
gcc -O2 -c shapes.c -std=c99 -Wall -DPLATFORM_DESKTOP gcc -O2 -c rshapes.c -std=c99 -Wall -DPLATFORM_DESKTOP
gcc -O2 -c textures.c -std=c99 -Wall -DPLATFORM_DESKTOP gcc -O2 -c rtextures.c -std=c99 -Wall -DPLATFORM_DESKTOP
gcc -O2 -c text.c -std=c99 -Wall -DPLATFORM_DESKTOP gcc -O2 -c rtext.c -std=c99 -Wall -DPLATFORM_DESKTOP
gcc -O2 -c models.c -std=c99 -Wall -DPLATFORM_DESKTOP gcc -O2 -c rmodels.c -std=c99 -Wall -DPLATFORM_DESKTOP
gcc -O2 -c raudio.c -std=c99 -Wall -DPLATFORM_DESKTOP gcc -O2 -c raudio.c -std=c99 -Wall -DPLATFORM_DESKTOP
gcc -O2 -c utils.c -std=c99 -Wall -DPLATFORM_DESKTOP gcc -O2 -c utils.c -std=c99 -Wall -DPLATFORM_DESKTOP

View File

@ -0,0 +1,387 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug.DLL|Win32">
<Configuration>Debug.DLL</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug.DLL|x64">
<Configuration>Debug.DLL</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release.DLL|Win32">
<Configuration>Release.DLL</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release.DLL|x64">
<Configuration>Release.DLL</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{2F1B955B-275E-4D8E-8864-06FEC44D7912}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>models_mesh_magicavoxel_loading</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>models_mesh_magicavoxel_loading</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|Win32'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\models</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|x64'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\models</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\models</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\models</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|Win32'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\models</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\models</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\models</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|x64'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\models</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<CompileAs>CompileAsC</CompileAs>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<CompileAs>CompileAsC</CompileAs>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/FS %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<CompileAs>CompileAsC</CompileAs>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"</Command>
<Message>Copy Debug DLL to output directory</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<CompileAs>CompileAsC</CompileAs>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"</Command>
<Message>Copy Debug DLL to output directory</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<CompileAs>CompileAsC</CompileAs>
<RemoveUnreferencedCodeData>true</RemoveUnreferencedCodeData>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<CompileAs>CompileAsC</CompileAs>
<RemoveUnreferencedCodeData>true</RemoveUnreferencedCodeData>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<CompileAs>CompileAsC</CompileAs>
<RemoveUnreferencedCodeData>true</RemoveUnreferencedCodeData>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy Release DLL to output directory</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<CompileAs>CompileAsC</CompileAs>
<RemoveUnreferencedCodeData>true</RemoveUnreferencedCodeData>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy Release DLL to output directory</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectReference Include="..\raylib\raylib.vcxproj">
<Project>{e89d61ac-55de-4482-afd4-df7242ebc859}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\examples\models\models_magicavoxel_loading.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -275,6 +275,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rlgl_standalone", "examples
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_split_screen", "examples\core_split_screen.vcxproj", "{946A1700-C7AA-46F0-AEF2-67C98B5722AC}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_split_screen", "examples\core_split_screen.vcxproj", "{946A1700-C7AA-46F0-AEF2-67C98B5722AC}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_mesh_magicavoxel_loading", "examples\models_mesh_magicavoxel_loading.vcxproj", "{2F1B955B-275E-4D8E-8864-06FEC44D7912}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug.DLL|x64 = Debug.DLL|x64 Debug.DLL|x64 = Debug.DLL|x64
@ -2283,6 +2285,22 @@ Global
{946A1700-C7AA-46F0-AEF2-67C98B5722AC}.Release|x64.Build.0 = Release|x64 {946A1700-C7AA-46F0-AEF2-67C98B5722AC}.Release|x64.Build.0 = Release|x64
{946A1700-C7AA-46F0-AEF2-67C98B5722AC}.Release|x86.ActiveCfg = Release|Win32 {946A1700-C7AA-46F0-AEF2-67C98B5722AC}.Release|x86.ActiveCfg = Release|Win32
{946A1700-C7AA-46F0-AEF2-67C98B5722AC}.Release|x86.Build.0 = Release|Win32 {946A1700-C7AA-46F0-AEF2-67C98B5722AC}.Release|x86.Build.0 = Release|Win32
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Debug|x64.ActiveCfg = Debug|x64
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Debug|x64.Build.0 = Debug|x64
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Debug|x86.ActiveCfg = Debug|Win32
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Debug|x86.Build.0 = Debug|Win32
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Release.DLL|x64.Build.0 = Release.DLL|x64
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Release.DLL|x86.Build.0 = Release.DLL|Win32
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Release|x64.ActiveCfg = Release|x64
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Release|x64.Build.0 = Release|x64
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Release|x86.ActiveCfg = Release|Win32
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Release|x86.Build.0 = Release|Win32
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -2422,6 +2440,7 @@ Global
{6237BEDE-BAAA-4A06-9C5E-8089BAA14C8B} = {E9D708A5-9C1F-4B84-A795-C5F191801762} {6237BEDE-BAAA-4A06-9C5E-8089BAA14C8B} = {E9D708A5-9C1F-4B84-A795-C5F191801762}
{C8765523-58F8-4C8E-9914-693396F6F0FF} = {E9D708A5-9C1F-4B84-A795-C5F191801762} {C8765523-58F8-4C8E-9914-693396F6F0FF} = {E9D708A5-9C1F-4B84-A795-C5F191801762}
{946A1700-C7AA-46F0-AEF2-67C98B5722AC} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {946A1700-C7AA-46F0-AEF2-67C98B5722AC} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
{2F1B955B-275E-4D8E-8864-06FEC44D7912} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29}

View File

@ -303,16 +303,16 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\..\src\raudio.c" /> <ClCompile Include="..\..\..\src\raudio.c" />
<ClCompile Include="..\..\..\src\core.c" /> <ClCompile Include="..\..\..\src\rcore.c" />
<ClCompile Include="..\..\..\src\models.c" /> <ClCompile Include="..\..\..\src\rmodels.c" />
<ClCompile Include="..\..\..\src\rglfw.c" /> <ClCompile Include="..\..\..\src\rglfw.c" />
<ClCompile Include="..\..\..\src\shapes.c" /> <ClCompile Include="..\..\..\src\rshapes.c" />
<ClCompile Include="..\..\..\src\text.c" /> <ClCompile Include="..\..\..\src\rtext.c" />
<ClCompile Include="..\..\..\src\textures.c" /> <ClCompile Include="..\..\..\src\rtextures.c" />
<ClCompile Include="..\..\..\src\utils.c" /> <ClCompile Include="..\..\..\src\utils.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\..\src\camera.h" /> <ClInclude Include="..\..\..\src\rcamera.h" />
<ClInclude Include="..\..\..\src\config.h" /> <ClInclude Include="..\..\..\src\config.h" />
<ClInclude Include="..\..\..\src\external\glad.h" /> <ClInclude Include="..\..\..\src\external\glad.h" />
<ClInclude Include="..\..\..\src\external\jar_mod.h" /> <ClInclude Include="..\..\..\src\external\jar_mod.h" />
@ -324,7 +324,7 @@
<ClInclude Include="..\..\..\src\external\stb_rect_pack.h" /> <ClInclude Include="..\..\..\src\external\stb_rect_pack.h" />
<ClInclude Include="..\..\..\src\external\stb_truetype.h" /> <ClInclude Include="..\..\..\src\external\stb_truetype.h" />
<ClInclude Include="..\..\..\src\external\stb_vorbis.h" /> <ClInclude Include="..\..\..\src\external\stb_vorbis.h" />
<ClInclude Include="..\..\..\src\gestures.h" /> <ClInclude Include="..\..\..\src\rgestures.h" />
<ClInclude Include="..\..\..\src\raylib.h" /> <ClInclude Include="..\..\..\src\raylib.h" />
<ClInclude Include="..\..\..\src\raymath.h" /> <ClInclude Include="..\..\..\src\raymath.h" />
<ClInclude Include="..\..\..\src\rlgl.h" /> <ClInclude Include="..\..\..\src\rlgl.h" />

View File

@ -120,7 +120,7 @@ if [ ! -d "$TEMP_DIR" ]; then
mkdir -p $TEMP_DIR mkdir -p $TEMP_DIR
cd $TEMP_DIR cd $TEMP_DIR
RAYLIB_DEFINES="-D_DEFAULT_SOURCE -DPLATFORM_DESKTOP -DGRAPHICS_API_OPENGL_33" RAYLIB_DEFINES="-D_DEFAULT_SOURCE -DPLATFORM_DESKTOP -DGRAPHICS_API_OPENGL_33"
RAYLIB_C_FILES="$RAYLIB_SRC/core.c $RAYLIB_SRC/shapes.c $RAYLIB_SRC/textures.c $RAYLIB_SRC/text.c $RAYLIB_SRC/models.c $RAYLIB_SRC/utils.c $RAYLIB_SRC/raudio.c $RAYLIB_SRC/rglfw.c" RAYLIB_C_FILES="$RAYLIB_SRC/rcore.c $RAYLIB_SRC/rshapes.c $RAYLIB_SRC/rtextures.c $RAYLIB_SRC/rtext.c $RAYLIB_SRC/rmodels.c $RAYLIB_SRC/utils.c $RAYLIB_SRC/raudio.c $RAYLIB_SRC/rglfw.c"
RAYLIB_INCLUDE_FLAGS="-I$RAYLIB_SRC -I$RAYLIB_SRC/external/glfw/include" RAYLIB_INCLUDE_FLAGS="-I$RAYLIB_SRC -I$RAYLIB_SRC/external/glfw/include"
if [ -n "$REALLY_QUIET" ]; then if [ -n "$REALLY_QUIET" ]; then

View File

@ -120,7 +120,7 @@ if [ ! -d "$TEMP_DIR" ]; then
mkdir -p $TEMP_DIR mkdir -p $TEMP_DIR
cd $TEMP_DIR cd $TEMP_DIR
RAYLIB_DEFINES="-D_DEFAULT_SOURCE -DPLATFORM_DESKTOP -DGRAPHICS_API_OPENGL_33" RAYLIB_DEFINES="-D_DEFAULT_SOURCE -DPLATFORM_DESKTOP -DGRAPHICS_API_OPENGL_33"
RAYLIB_C_FILES="$RAYLIB_SRC/core.c $RAYLIB_SRC/shapes.c $RAYLIB_SRC/textures.c $RAYLIB_SRC/text.c $RAYLIB_SRC/models.c $RAYLIB_SRC/utils.c $RAYLIB_SRC/raudio.c" RAYLIB_C_FILES="$RAYLIB_SRC/rcore.c $RAYLIB_SRC/rshapes.c $RAYLIB_SRC/rtextures.c $RAYLIB_SRC/rtext.c $RAYLIB_SRC/rmodels.c $RAYLIB_SRC/utils.c $RAYLIB_SRC/raudio.c"
RAYLIB_INCLUDE_FLAGS="-I$RAYLIB_SRC -I$RAYLIB_SRC/external/glfw/include" RAYLIB_INCLUDE_FLAGS="-I$RAYLIB_SRC -I$RAYLIB_SRC/external/glfw/include"
if [ -n "$REALLY_QUIET" ]; then if [ -n "$REALLY_QUIET" ]; then

View File

@ -120,7 +120,7 @@ if [ ! -d "$TEMP_DIR" ]; then
mkdir -p $TEMP_DIR mkdir -p $TEMP_DIR
cd $TEMP_DIR cd $TEMP_DIR
RAYLIB_DEFINES="-D_DEFAULT_SOURCE -DPLATFORM_RPI -DGRAPHICS_API_OPENGL_ES2" RAYLIB_DEFINES="-D_DEFAULT_SOURCE -DPLATFORM_RPI -DGRAPHICS_API_OPENGL_ES2"
RAYLIB_C_FILES="$RAYLIB_SRC/core.c $RAYLIB_SRC/shapes.c $RAYLIB_SRC/textures.c $RAYLIB_SRC/text.c $RAYLIB_SRC/models.c $RAYLIB_SRC/utils.c $RAYLIB_SRC/raudio.c" RAYLIB_C_FILES="$RAYLIB_SRC/rcore.c $RAYLIB_SRC/rshapes.c $RAYLIB_SRC/rtextures.c $RAYLIB_SRC/rtext.c $RAYLIB_SRC/rmodels.c $RAYLIB_SRC/utils.c $RAYLIB_SRC/raudio.c"
RAYLIB_INCLUDE_FLAGS="-I$RAYLIB_SRC -I/opt/vc/include" RAYLIB_INCLUDE_FLAGS="-I$RAYLIB_SRC -I/opt/vc/include"
if [ -n "$REALLY_QUIET" ]; then if [ -n "$REALLY_QUIET" ]; then

View File

@ -167,7 +167,7 @@ IF NOT EXIST !TEMP_DIR!\ (
cd !TEMP_DIR! cd !TEMP_DIR!
REM Raylib's src folder REM Raylib's src folder
set "RAYLIB_DEFINES=/D_DEFAULT_SOURCE /DPLATFORM_DESKTOP /DGRAPHICS_API_OPENGL_33" set "RAYLIB_DEFINES=/D_DEFAULT_SOURCE /DPLATFORM_DESKTOP /DGRAPHICS_API_OPENGL_33"
set RAYLIB_C_FILES="!RAYLIB_SRC!\core.c" "!RAYLIB_SRC!\shapes.c" "!RAYLIB_SRC!\textures.c" "!RAYLIB_SRC!\text.c" "!RAYLIB_SRC!\models.c" "!RAYLIB_SRC!\utils.c" "!RAYLIB_SRC!\raudio.c" "!RAYLIB_SRC!\rglfw.c" set RAYLIB_C_FILES="!RAYLIB_SRC!\rcore.c" "!RAYLIB_SRC!\rshapes.c" "!RAYLIB_SRC!\rtextures.c" "!RAYLIB_SRC!\rtext.c" "!RAYLIB_SRC!\rmodels.c" "!RAYLIB_SRC!\utils.c" "!RAYLIB_SRC!\raudio.c" "!RAYLIB_SRC!\rglfw.c"
set RAYLIB_INCLUDE_FLAGS=/I"!RAYLIB_SRC!" /I"!RAYLIB_SRC!\external\glfw\include" set RAYLIB_INCLUDE_FLAGS=/I"!RAYLIB_SRC!" /I"!RAYLIB_SRC!\external\glfw\include"
IF DEFINED REALLY_QUIET ( IF DEFINED REALLY_QUIET (

View File

@ -30,11 +30,11 @@ set(raylib_public_headers
# Sources to be compiled # Sources to be compiled
set(raylib_sources set(raylib_sources
core.c rcore.c
models.c rmodels.c
shapes.c rshapes.c
text.c rtext.c
textures.c rtextures.c
utils.c utils.c
) )

View File

@ -80,7 +80,6 @@ RAYLIB_MODULE_RAYGUI_PATH ?= $(RAYLIB_SRC_PATH)/../../raygui/src
RAYLIB_MODULE_PHYSAC_PATH ?= $(RAYLIB_SRC_PATH)/extras RAYLIB_MODULE_PHYSAC_PATH ?= $(RAYLIB_SRC_PATH)/extras
# Use external GLFW library instead of rglfw module # Use external GLFW library instead of rglfw module
# TODO: Review usage of examples on Linux.
USE_EXTERNAL_GLFW ?= FALSE USE_EXTERNAL_GLFW ?= FALSE
# Use Wayland display server protocol on Linux desktop # Use Wayland display server protocol on Linux desktop
@ -186,16 +185,16 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID)
ANDROID_SYSROOT ?= $(ANDROID_TOOLCHAIN)/sysroot ANDROID_SYSROOT ?= $(ANDROID_TOOLCHAIN)/sysroot
ifeq ($(ANDROID_ARCH),arm) ifeq ($(ANDROID_ARCH),arm)
ANDROID_ARCH_NAME = armeabi-v7a ANDROID_COMPILER_ARCH = armv7a
endif endif
ifeq ($(ANDROID_ARCH),arm64) ifeq ($(ANDROID_ARCH),arm64)
ANDROID_ARCH_NAME = arm64-v8a ANDROID_COMPILER_ARCH = aarch64
endif endif
ifeq ($(ANDROID_ARCH),x86) ifeq ($(ANDROID_ARCH),x86)
ANDROID_ARCH_NAME = i686 ANDROID_COMPILER_ARCH = i686
endif endif
ifeq ($(ANDROID_ARCH),x86_64) ifeq ($(ANDROID_ARCH),x86_64)
ANDROID_ARCH_NAME = x86_64 ANDROID_COMPILER_ARCH = x86_64
endif endif
endif endif
@ -255,21 +254,13 @@ endif
ifeq ($(PLATFORM),PLATFORM_ANDROID) ifeq ($(PLATFORM),PLATFORM_ANDROID)
# Android toolchain (must be provided for desired architecture and compiler) # Android toolchain (must be provided for desired architecture and compiler)
ifeq ($(ANDROID_ARCH),arm) ifeq ($(ANDROID_ARCH),arm)
CC = $(ANDROID_TOOLCHAIN)/bin/armv7a-linux-androideabi$(ANDROID_API_VERSION)-clang CC = $(ANDROID_TOOLCHAIN)/bin/$(ANDROID_COMPILER_ARCH)-linux-androideabi$(ANDROID_API_VERSION)-clang
AR = $(ANDROID_TOOLCHAIN)/bin/arm-linux-androideabi-ar
endif endif
ifeq ($(ANDROID_ARCH),arm64) ifeq ($(ANDROID_ARCH),arm64)
CC = $(ANDROID_TOOLCHAIN)/bin/aarch64-linux-android$(ANDROID_API_VERSION)-clang CC = $(ANDROID_TOOLCHAIN)/bin/$(ANDROID_COMPILER_ARCH)-linux-android$(ANDROID_API_VERSION)-clang
AR = $(ANDROID_TOOLCHAIN)/bin/aarch64-linux-android-ar
endif
ifeq ($(ANDROID_ARCH),x86)
CC = $(ANDROID_TOOLCHAIN)/bin/i686-linux-android$(ANDROID_API_VERSION)-clang
AR = $(ANDROID_TOOLCHAIN)/bin/i686-linux-android-ar
endif
ifeq ($(ANDROID_ARCH),x86_64)
CC = $(ANDROID_TOOLCHAIN)/bin/x86_64-linux-android$(ANDROID_API_VERSION)-clang
AR = $(ANDROID_TOOLCHAIN)/bin/x86_64-linux-android-ar
endif endif
# It seems from Android NDK r22 onwards we need to use llvm-ar
AR = $(ANDROID_TOOLCHAIN)/bin/llvm-ar
endif endif
# Define compiler flags: # Define compiler flags:
@ -322,7 +313,7 @@ endif
ifeq ($(PLATFORM),PLATFORM_WEB) ifeq ($(PLATFORM),PLATFORM_WEB)
# -Os # size optimization # -Os # size optimization
# -O2 # optimization level 2, if used, also set --memory-init-file 0 # -O2 # optimization level 2, if used, also set --memory-init-file 0
# -s USE_GLFW=3 # Use glfw3 library (context/input management) # -s USE_GLFW=3 # Use glfw3 library (context/input management) -> Only for linker!
# -s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing -> WARNING: Audio buffers could FAIL! # -s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing -> WARNING: Audio buffers could FAIL!
# -s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) # -s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB)
# -s USE_PTHREADS=1 # multithreading support # -s USE_PTHREADS=1 # multithreading support
@ -331,7 +322,6 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
# --profiling # include information for code profiling # --profiling # include information for code profiling
# --memory-init-file 0 # to avoid an external memory initialization code file (.mem) # --memory-init-file 0 # to avoid an external memory initialization code file (.mem)
# --preload-file resources # specify a resources folder for data compilation # --preload-file resources # specify a resources folder for data compilation
CFLAGS += -s USE_GLFW=3
ifeq ($(RAYLIB_BUILD_MODE),DEBUG) ifeq ($(RAYLIB_BUILD_MODE),DEBUG)
CFLAGS += -s ASSERTIONS=1 --profiling CFLAGS += -s ASSERTIONS=1 --profiling
endif endif
@ -344,10 +334,10 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID)
ifeq ($(ANDROID_ARCH),arm64) ifeq ($(ANDROID_ARCH),arm64)
CFLAGS += -target aarch64 -mfix-cortex-a53-835769 CFLAGS += -target aarch64 -mfix-cortex-a53-835769
endif endif
ifeq ($(ANDROID_ARCH), x86) ifeq ($(ANDROID_ARCH),x86)
CFLAGS += -march=i686 CFLAGS += -march=i686
endif endif
ifeq ($(ANDROID_ARCH), x86_64) ifeq ($(ANDROID_ARCH),x86_64)
CFLAGS += -march=x86-64 CFLAGS += -march=x86-64
endif endif
# Compilation functions attributes options # Compilation functions attributes options
@ -452,10 +442,10 @@ endif
# OBJS = $(patsubst %.c, %.o, $(wildcard *.c)) # OBJS = $(patsubst %.c, %.o, $(wildcard *.c))
# Define object required on compilation # Define object required on compilation
OBJS = core.o \ OBJS = rcore.o \
shapes.o \ rshapes.o \
textures.o \ rtextures.o \
text.o \ rtext.o \
utils.o utils.o
ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM),PLATFORM_DESKTOP)
@ -464,7 +454,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
endif endif
endif endif
ifeq ($(RAYLIB_MODULE_MODELS),TRUE) ifeq ($(RAYLIB_MODULE_MODELS),TRUE)
OBJS += models.o OBJS += rmodels.o
endif endif
ifeq ($(RAYLIB_MODULE_AUDIO),TRUE) ifeq ($(RAYLIB_MODULE_AUDIO),TRUE)
OBJS += raudio.o OBJS += raudio.o
@ -509,7 +499,7 @@ else
endif endif
ifeq ($(PLATFORM_OS),OSX) ifeq ($(PLATFORM_OS),OSX)
$(CC) -dynamiclib -o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).dylib $(OBJS) $(LDFLAGS) -compatibility_version $(RAYLIB_API_VERSION) -current_version $(RAYLIB_VERSION) -framework OpenGL -framework Cocoa -framework IOKit -framework CoreAudio -framework CoreVideo $(CC) -dynamiclib -o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).dylib $(OBJS) $(LDFLAGS) -compatibility_version $(RAYLIB_API_VERSION) -current_version $(RAYLIB_VERSION) -framework OpenGL -framework Cocoa -framework IOKit -framework CoreAudio -framework CoreVideo
install_name_tool -id "lib$(RAYLIB_LIB_NAME).$(VERSION).dylib" $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).dylib install_name_tool -id "@rpath/lib$(RAYLIB_LIB_NAME).$(RAYLIB_API_VERSION).dylib" $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).dylib
@echo "raylib shared library generated (lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).dylib)!" @echo "raylib shared library generated (lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).dylib)!"
cd $(RAYLIB_RELEASE_PATH) && ln -fs lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).dylib lib$(RAYLIB_LIB_NAME).$(RAYLIB_API_VERSION).dylib cd $(RAYLIB_RELEASE_PATH) && ln -fs lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).dylib lib$(RAYLIB_LIB_NAME).$(RAYLIB_API_VERSION).dylib
cd $(RAYLIB_RELEASE_PATH) && ln -fs lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).dylib lib$(RAYLIB_LIB_NAME).dylib cd $(RAYLIB_RELEASE_PATH) && ln -fs lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).dylib lib$(RAYLIB_LIB_NAME).dylib
@ -558,7 +548,7 @@ endif
# Compile all modules with their prerequisites # Compile all modules with their prerequisites
# Compile core module # Compile core module
core.o : core.c raylib.h rlgl.h utils.h raymath.h camera.h gestures.h rcore.o : rcore.c raylib.h rlgl.h utils.h raymath.h rcamera.h rgestures.h
$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) -D$(GRAPHICS) $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) -D$(GRAPHICS)
# Compile rglfw module # Compile rglfw module
@ -566,15 +556,15 @@ rglfw.o : rglfw.c
$(CC) $(GLFW_OSX) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) -D$(GRAPHICS) $(CC) $(GLFW_OSX) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) -D$(GRAPHICS)
# Compile shapes module # Compile shapes module
shapes.o : shapes.c raylib.h rlgl.h rshapes.o : rshapes.c raylib.h rlgl.h
$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) -D$(GRAPHICS) $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) -D$(GRAPHICS)
# Compile textures module # Compile textures module
textures.o : textures.c raylib.h rlgl.h utils.h rtextures.o : rtextures.c raylib.h rlgl.h utils.h
$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) -D$(GRAPHICS) $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) -D$(GRAPHICS)
# Compile text module # Compile text module
text.o : text.c raylib.h utils.h rtext.o : rtext.c raylib.h utils.h
$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) -D$(GRAPHICS) $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) -D$(GRAPHICS)
# Compile utils module # Compile utils module
@ -582,7 +572,7 @@ utils.o : utils.c utils.h
$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM)
# Compile models module # Compile models module
models.o : models.c raylib.h rlgl.h raymath.h rmodels.o : rmodels.c raylib.h rlgl.h raymath.h
$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) -D$(GRAPHICS) $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) -D$(GRAPHICS)
# Compile audio module # Compile audio module
@ -617,7 +607,7 @@ android_native_app_glue.o : $(NATIVE_APP_GLUE)/android_native_app_glue.c
# for our -L and -I specification to simplify management of the raylib source package. # for our -L and -I specification to simplify management of the raylib source package.
# Customize these locations if you like but don't forget to pass them to make # Customize these locations if you like but don't forget to pass them to make
# for compilation and enable runtime linking with -rpath, LD_LIBRARY_PATH, or ldconfig. # for compilation and enable runtime linking with -rpath, LD_LIBRARY_PATH, or ldconfig.
# Hint: add -L$(RAYLIB_INSTALL_PATH) -I$(RAYLIB_H_INSTALL_PATH) to your own makefiles. # HINT: Add -L$(RAYLIB_INSTALL_PATH) -I$(RAYLIB_H_INSTALL_PATH) to your own makefiles.
# See below and ../examples/Makefile for more information. # See below and ../examples/Makefile for more information.
# TODO: Add other platforms. Remove sudo requirement, i.e. add USER mode. # TODO: Add other platforms. Remove sudo requirement, i.e. add USER mode.
@ -661,7 +651,7 @@ else
endif endif
# Remove raylib dev files installed on the system # Remove raylib dev files installed on the system
# TODO: see 'install' target. # NOTE: see 'install' target.
uninstall : uninstall :
ifeq ($(ROOT),root) ifeq ($(ROOT),root)
# WARNING: You are root, about to delete items from $(RAYLIB_INSTALL_PATH). # WARNING: You are root, about to delete items from $(RAYLIB_INSTALL_PATH).

58
src/build.zig Normal file
View File

@ -0,0 +1,58 @@
const std = @import("std");
pub fn build(b: *std.build.Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const raylib_flags = &[_][]const u8{
"-std=gnu99",
"-DPLATFORM_DESKTOP",
"-DGL_SILENCE_DEPRECATION",
"-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/1891
};
const raylib = b.addStaticLibrary("raylib", "raylib.h");
raylib.setTarget(target);
raylib.setBuildMode(mode);
raylib.linkLibC();
raylib.addIncludeDir("external/glfw/include");
raylib.addCSourceFile("rcore.c", raylib_flags);
raylib.addCSourceFile("rmodels.c", raylib_flags);
raylib.addCSourceFile("raudio.c", raylib_flags);
raylib.addCSourceFile("rshapes.c", raylib_flags);
raylib.addCSourceFile("rtext.c", raylib_flags);
raylib.addCSourceFile("rtextures.c", raylib_flags);
raylib.addCSourceFile("utils.c", raylib_flags);
raylib.addCSourceFile("rglfw.c", raylib_flags);
switch (raylib.target.toTarget().os.tag) {
.windows => {
raylib.linkSystemLibrary("winmm");
raylib.linkSystemLibrary("gdi32");
raylib.linkSystemLibrary("opengl32");
raylib.addIncludeDir("external/glfw/deps/mingw");
},
.linux => {
raylib.linkSystemLibrary("GL");
raylib.linkSystemLibrary("rt");
raylib.linkSystemLibrary("dl");
raylib.linkSystemLibrary("m");
raylib.linkSystemLibrary("X11");
},
else => {
@panic("Unsupported OS");
},
}
raylib.setOutputDir("./");
raylib.install();
}

View File

@ -28,9 +28,9 @@
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Module: core - Configuration Flags // Module: core - Configuration Flags
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Camera module is included (camera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital // Camera module is included (rcamera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital
#define SUPPORT_CAMERA_SYSTEM 1 #define SUPPORT_CAMERA_SYSTEM 1
// Gestures module is included (gestures.h) to support gestures detection: tap, hold, swipe, drag // Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag
#define SUPPORT_GESTURES_SYSTEM 1 #define SUPPORT_GESTURES_SYSTEM 1
// Mouse gestures are directly mapped like touches and processed by gestures system // Mouse gestures are directly mapped like touches and processed by gestures system
#define SUPPORT_MOUSE_GESTURES 1 #define SUPPORT_MOUSE_GESTURES 1
@ -73,7 +73,7 @@
#define MAX_GAMEPADS 4 // Max number of gamepads supported #define MAX_GAMEPADS 4 // Max number of gamepads supported
#define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad) #define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad)
#define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad) #define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad)
#define MAX_TOUCH_POINTS 10 // Maximum number of touch points supported #define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
#define MAX_KEY_PRESSED_QUEUE 16 // Max number of characters in the key input queue #define MAX_KEY_PRESSED_QUEUE 16 // Max number of characters in the key input queue
#define STORAGE_DATA_FILE "storage.data" // Automatic storage filename #define STORAGE_DATA_FILE "storage.data" // Automatic storage filename
@ -182,6 +182,7 @@
#define SUPPORT_FILEFORMAT_MTL 1 #define SUPPORT_FILEFORMAT_MTL 1
#define SUPPORT_FILEFORMAT_IQM 1 #define SUPPORT_FILEFORMAT_IQM 1
#define SUPPORT_FILEFORMAT_GLTF 1 #define SUPPORT_FILEFORMAT_GLTF 1
#define SUPPORT_FILEFORMAT_VOX 1
// Support procedural mesh generation functions, uses external par_shapes.h library // Support procedural mesh generation functions, uses external par_shapes.h library
// NOTE: Some generated meshes DO NOT include generated texture coordinates // NOTE: Some generated meshes DO NOT include generated texture coordinates
#define SUPPORT_MESH_GENERATION 1 #define SUPPORT_MESH_GENERATION 1

File diff suppressed because it is too large Load Diff

744
src/external/vox_loader.h vendored Normal file
View File

@ -0,0 +1,744 @@
/*
The MIT License (MIT)
Copyright (c) 2021 Johann Nadalutti.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
vox_loader - v1.01
no warranty implied; use at your own risk
Do this:
#define VOX_LOADER_INCLUDE__H
before you include this file in* one* C or C++ file to create the implementation.
// i.e. it should look like this:
#include ...
#include ...
#include ...
#define VOX_LOADER_INCLUDE__H
#include "vox_loader.h"
revision history:
1.00 (2021-09-03) first released version
1.01 (2021-09-07) Support custom memory allocators
Removed Raylib dependencies
Changed Vox_LoadFileName to Vox_LoadFromMemory
1.02 (2021-09-10) @raysan5: Reviewed some formating
*/
#ifndef VOX_LOADER_H
#define VOX_LOADER_H
#include <string.h>
#include <stdlib.h>
// Allow custom memory allocators
#ifndef VOX_MALLOC
#define VOX_MALLOC RL_MALLOC
#endif
#ifndef VOX_CALLOC
#define VOX_CALLOC RL_CALLOC
#endif
#ifndef VOX_REALLOC
#define VOX_REALLOC RL_REALLOC
#endif
#ifndef VOX_FREE
#define VOX_FREE RL_FREE
#endif
#define VOX_SUCCESS (0)
#define VOX_ERROR_FILE_NOT_FOUND (-1)
#define VOX_ERROR_INVALID_FORMAT (-2)
#define VOX_ERROR_FILE_VERSION_TOO_OLD (-3)
// VoxColor, 4 components, R8G8B8A8 (32bit)
typedef struct {
unsigned char r, g, b, a;
} VoxColor;
// VoxVector3, 3 components
typedef struct {
float x, y, z;
} VoxVector3;
typedef struct {
int* array;
int used, size;
} ArrayInt;
typedef struct {
VoxVector3* array;
int used, size;
} ArrayVector3;
typedef struct {
VoxColor* array;
int used, size;
} ArrayColor;
typedef struct {
unsigned short* array;
int used, size;
} ArrayUShort;
// A chunk that contain voxels
typedef struct {
unsigned char* m_array; //If Sparse != null
int arraySize; //Size for m_array in bytes (DEBUG ONLY)
} CubeChunk3D;
// Array for voxels
// Array is divised into chunks of CHUNKSIZE*CHUNKSIZE*CHUNKSIZE voxels size
typedef struct {
// Array size in voxels
int sizeX;
int sizeY;
int sizeZ;
// Chunks size into array (array is divised into chunks)
int chunksSizeX;
int chunksSizeY;
int chunksSizeZ;
// Chunks array
CubeChunk3D* m_arrayChunks;
int arrayChunksSize; // Size for m_arrayChunks in bytes (DEBUG ONLY)
int ChunkFlattenOffset;
int chunksAllocated;
int chunksTotal;
// Arrays for mesh build
ArrayVector3 vertices;
ArrayUShort indices;
ArrayColor colors;
//Palette for voxels
VoxColor palette[256];
} VoxArray3D;
#if defined(__cplusplus)
extern "C" { // Prevents name mangling of functions
#endif
// Functions
int Vox_LoadFromMemory(const unsigned char* pvoxData, unsigned int voxDataSize, VoxArray3D* pvoxarray);
void Vox_FreeArrays(VoxArray3D* voxarray);
#ifdef __cplusplus
}
#endif
#endif // VOX_LOADER_H
//// end header file /////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
// Implementation
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
#ifdef VOX_LOADER_IMPLEMENTATION
/////////////////////////////////////////////////////////////////////////////////////////////
// ArrayInt helper
/////////////////////////////////////////////////////////////////////////////////////////////
static void initArrayInt(ArrayInt* a, int initialSize)
{
a->array = VOX_MALLOC(initialSize * sizeof(int));
a->used = 0;
a->size = initialSize;
}
static void insertArrayInt(ArrayInt* a, int element)
{
if (a->used == a->size)
{
a->size *= 2;
a->array = VOX_REALLOC(a->array, a->size * sizeof(int));
}
a->array[a->used++] = element;
}
static void freeArrayInt(ArrayInt* a)
{
VOX_FREE(a->array);
a->array = NULL;
a->used = a->size = 0;
}
/////////////////////////////////////////////////////////////////////////////////////////////
// ArrayUShort helper
/////////////////////////////////////////////////////////////////////////////////////////////
static void initArrayUShort(ArrayUShort* a, int initialSize)
{
a->array = VOX_MALLOC(initialSize * sizeof(unsigned short));
a->used = 0;
a->size = initialSize;
}
static void insertArrayUShort(ArrayUShort* a, unsigned short element)
{
if (a->used == a->size)
{
a->size *= 2;
a->array = VOX_REALLOC(a->array, a->size * sizeof(unsigned short));
}
a->array[a->used++] = element;
}
static void freeArrayUShort(ArrayUShort* a)
{
VOX_FREE(a->array);
a->array = NULL;
a->used = a->size = 0;
}
/////////////////////////////////////////////////////////////////////////////////////////////
// ArrayVector3 helper
/////////////////////////////////////////////////////////////////////////////////////////////
static void initArrayVector3(ArrayVector3* a, int initialSize)
{
a->array = VOX_MALLOC(initialSize * sizeof(VoxVector3));
a->used = 0;
a->size = initialSize;
}
static void insertArrayVector3(ArrayVector3* a, VoxVector3 element)
{
if (a->used == a->size)
{
a->size *= 2;
a->array = VOX_REALLOC(a->array, a->size * sizeof(VoxVector3));
}
a->array[a->used++] = element;
}
static void freeArrayVector3(ArrayVector3* a)
{
VOX_FREE(a->array);
a->array = NULL;
a->used = a->size = 0;
}
/////////////////////////////////////////////////////////////////////////////////////////////
// ArrayColor helper
/////////////////////////////////////////////////////////////////////////////////////////////
static void initArrayColor(ArrayColor* a, int initialSize)
{
a->array = VOX_MALLOC(initialSize * sizeof(VoxColor));
a->used = 0;
a->size = initialSize;
}
static void insertArrayColor(ArrayColor* a, VoxColor element)
{
if (a->used == a->size)
{
a->size *= 2;
a->array = VOX_REALLOC(a->array, a->size * sizeof(VoxColor));
}
a->array[a->used++] = element;
}
static void freeArrayColor(ArrayColor* a)
{
VOX_FREE(a->array);
a->array = NULL;
a->used = a->size = 0;
}
/////////////////////////////////////////////////////////////////////////////////////////////
// Vox Loader
/////////////////////////////////////////////////////////////////////////////////////////////
#define CHUNKSIZE 16 // chunk size (CHUNKSIZE*CHUNKSIZE*CHUNKSIZE) in voxels
#define CHUNKSIZE_OPSHIFT 4 // 1<<4=16 -> Warning depend of CHUNKSIZE
#define CHUNK_FLATTENOFFSET_OPSHIFT 8 // Warning depend of CHUNKSIZE
//
// used right handed system and CCW face
//
// indexes for voxelcoords, per face orientation
//
//# Y
//# |
//# o----X
//# /
//# Z 2------------3
//# /| /|
//# 6------------7 |
//# | | | |
//# |0 ----------|- 1
//# |/ |/
//# 4------------5
//
// CCW
const int fv[6][4] = {
{0, 2, 6, 4 }, //-X
{5, 7, 3, 1 }, //+X
{0, 4, 5, 1 }, //-y
{6, 2, 3, 7 }, //+y
{1, 3, 2, 0 }, //-Z
{4, 6, 7, 5 } //+Z
};
const VoxVector3 SolidVertex[] = {
{0, 0, 0}, //0
{1, 0, 0}, //1
{0, 1, 0}, //2
{1, 1, 0}, //3
{0, 0, 1}, //4
{1, 0, 1}, //5
{0, 1, 1}, //6
{1, 1, 1} //7
};
// Allocated VoxArray3D size
static void Vox_AllocArray(VoxArray3D* pvoxarray, int _sx, int _sy, int _sz)
{
int sx = _sx + ((CHUNKSIZE - (_sx % CHUNKSIZE)) % CHUNKSIZE);
int sy = _sy + ((CHUNKSIZE - (_sy % CHUNKSIZE)) % CHUNKSIZE);
int sz = _sz + ((CHUNKSIZE - (_sz % CHUNKSIZE)) % CHUNKSIZE);
int chx = sx >> CHUNKSIZE_OPSHIFT; //Chunks Count in X
int chy = sy >> CHUNKSIZE_OPSHIFT; //Chunks Count in Y
int chz = sz >> CHUNKSIZE_OPSHIFT; //Chunks Count in Z
//VoxArray3D* parray = (VoxArray3D*)VOX_MALLOC(sizeof(VoxArray3D));
pvoxarray->sizeX = sx;
pvoxarray->sizeY = sy;
pvoxarray->sizeZ = sz;
pvoxarray->chunksSizeX = chx;
pvoxarray->chunksSizeY = chy;
pvoxarray->chunksSizeZ = chz;
pvoxarray->ChunkFlattenOffset = (chy * chz); //m_arrayChunks[(x * (sy*sz)) + (z * sy) + y]
// Alloc chunks array
int size = sizeof(CubeChunk3D) * chx * chy * chz;
pvoxarray->m_arrayChunks = VOX_MALLOC(size);
pvoxarray->arrayChunksSize = size;
// Init chunks array
size = chx * chy * chz;
pvoxarray->chunksTotal = size;
pvoxarray->chunksAllocated = 0;
for (int i = 0; i < size; i++)
{
pvoxarray->m_arrayChunks[i].m_array = 0;
pvoxarray->m_arrayChunks[i].arraySize = 0;
}
}
// Set voxel ID from its position into VoxArray3D
static void Vox_SetVoxel(VoxArray3D* pvoxarray, int x, int y, int z, unsigned char id)
{
// Get chunk from array pos
int chX = x >> CHUNKSIZE_OPSHIFT; //x / CHUNKSIZE;
int chY = y >> CHUNKSIZE_OPSHIFT; //y / CHUNKSIZE;
int chZ = z >> CHUNKSIZE_OPSHIFT; //z / CHUNKSIZE;
int offset = (chX * pvoxarray->ChunkFlattenOffset) + (chZ * pvoxarray->chunksSizeY) + chY;
//if (offset > voxarray->arrayChunksSize)
//{
// TraceLog(LOG_ERROR, "Out of array");
//}
CubeChunk3D* chunk = &pvoxarray->m_arrayChunks[offset];
// Set Chunk
chX = x - (chX << CHUNKSIZE_OPSHIFT); //x - (bx * CHUNKSIZE);
chY = y - (chY << CHUNKSIZE_OPSHIFT); //y - (by * CHUNKSIZE);
chZ = z - (chZ << CHUNKSIZE_OPSHIFT); //z - (bz * CHUNKSIZE);
if (chunk->m_array == 0)
{
int size = CHUNKSIZE * CHUNKSIZE * CHUNKSIZE;
chunk->m_array = VOX_MALLOC(size);
chunk->arraySize = size;
memset(chunk->m_array, 0, size);
pvoxarray->chunksAllocated++;
}
offset = (chX << CHUNK_FLATTENOFFSET_OPSHIFT) + (chZ << CHUNKSIZE_OPSHIFT) + chY;
//if (offset > chunk->arraySize)
//{
// TraceLog(LOG_ERROR, "Out of array");
//}
chunk->m_array[offset] = id;
}
// Get voxel ID from its position into VoxArray3D
static unsigned char Vox_GetVoxel(VoxArray3D* pvoxarray, int x, int y, int z)
{
if (x < 0 || y < 0 || z < 0) return 0;
if (x >= pvoxarray->sizeX || y >= pvoxarray->sizeY || z >= pvoxarray->sizeZ) return 0;
// Get chunk from array pos
int chX = x >> CHUNKSIZE_OPSHIFT; //x / CHUNKSIZE;
int chY = y >> CHUNKSIZE_OPSHIFT; //y / CHUNKSIZE;
int chZ = z >> CHUNKSIZE_OPSHIFT; //z / CHUNKSIZE;
int offset = (chX * pvoxarray->ChunkFlattenOffset) + (chZ * pvoxarray->chunksSizeY) + chY;
//if (offset > voxarray->arrayChunksSize)
//{
// TraceLog(LOG_ERROR, "Out of array");
//}
CubeChunk3D* chunk = &pvoxarray->m_arrayChunks[offset];
// Set Chunk
chX = x - (chX << CHUNKSIZE_OPSHIFT); //x - (bx * CHUNKSIZE);
chY = y - (chY << CHUNKSIZE_OPSHIFT); //y - (by * CHUNKSIZE);
chZ = z - (chZ << CHUNKSIZE_OPSHIFT); //z - (bz * CHUNKSIZE);
if (chunk->m_array == 0)
{
return 0;
}
offset = (chX << CHUNK_FLATTENOFFSET_OPSHIFT) + (chZ << CHUNKSIZE_OPSHIFT) + chY;
//if (offset > chunk->arraySize)
//{
// TraceLog(LOG_ERROR, "Out of array");
//}
return chunk->m_array[offset];
}
// Calc visibles faces from a voxel position
static unsigned char Vox_CalcFacesVisible(VoxArray3D* pvoxArray, int cx, int cy, int cz)
{
unsigned char idXm1 = Vox_GetVoxel(pvoxArray, cx - 1, cy, cz);
unsigned char idXp1 = Vox_GetVoxel(pvoxArray, cx + 1, cy, cz);
unsigned char idYm1 = Vox_GetVoxel(pvoxArray, cx, cy - 1, cz);
unsigned char idYp1 = Vox_GetVoxel(pvoxArray, cx, cy + 1, cz);
unsigned char idZm1 = Vox_GetVoxel(pvoxArray, cx, cy, cz - 1);
unsigned char idZp1 = Vox_GetVoxel(pvoxArray, cx, cy, cz + 1);
unsigned char byVFMask = 0;
//#-x
if (idXm1 == 0) byVFMask |= (1 << 0);
//#+x
if (idXp1 == 0) byVFMask |= (1 << 1);
//#-y
if (idYm1 == 0) byVFMask |= (1 << 2);
//#+y
if (idYp1 == 0) byVFMask |= (1 << 3);
//#-z
if (idZm1 == 0) byVFMask |= (1 << 4);
//#+z
if (idZp1 == 0) byVFMask |= (1 << 5);
return byVFMask;
}
// Get a vertex position from a voxel's corner
static VoxVector3 Vox_GetVertexPosition(int _wcx, int _wcy, int _wcz, int _nNumVertex)
{
float scale = 0.25;
VoxVector3 vtx = SolidVertex[_nNumVertex];
vtx.x = (vtx.x + _wcx) * scale;
vtx.y = (vtx.y + _wcy) * scale;
vtx.z = (vtx.z + _wcz) * scale;
return vtx;
}
// Build a voxel vertices/colors/indices
static void Vox_Build_Voxel(VoxArray3D* pvoxArray, int x, int y, int z, int matID)
{
unsigned char byVFMask = Vox_CalcFacesVisible(pvoxArray, x, y, z);
if (byVFMask == 0) return;
int i, j;
VoxVector3 vertComputed[8];
int bVertexComputed[8];
memset(vertComputed, 0, sizeof(vertComputed));
memset(bVertexComputed, 0, sizeof(bVertexComputed));
//For each Cube's faces
for (i = 0; i < 6; i++) // 6 faces
{
if ((byVFMask & (1 << i)) != 0) //If face is visible
{
for (j = 0; j < 4; j++) // 4 corners
{
int nNumVertex = fv[i][j]; //Face,Corner
if (bVertexComputed[nNumVertex] == 0) //if never calc
{
bVertexComputed[nNumVertex] = 1;
vertComputed[nNumVertex] = Vox_GetVertexPosition(x, y, z, nNumVertex);
}
}
}
}
//Add face
for (i = 0; i < 6; i++)// 6 faces
{
if ((byVFMask & (1 << i)) == 0)
continue; //Face invisible
int v0 = fv[i][0]; //Face, Corner
int v1 = fv[i][1]; //Face, Corner
int v2 = fv[i][2]; //Face, Corner
int v3 = fv[i][3]; //Face, Corner
//Arrays
int idx = pvoxArray->vertices.used;
insertArrayVector3(&pvoxArray->vertices, vertComputed[v0]);
insertArrayVector3(&pvoxArray->vertices, vertComputed[v1]);
insertArrayVector3(&pvoxArray->vertices, vertComputed[v2]);
insertArrayVector3(&pvoxArray->vertices, vertComputed[v3]);
VoxColor col = pvoxArray->palette[matID];
insertArrayColor(&pvoxArray->colors, col);
insertArrayColor(&pvoxArray->colors, col);
insertArrayColor(&pvoxArray->colors, col);
insertArrayColor(&pvoxArray->colors, col);
//v0 - v1 - v2, v0 - v2 - v3
insertArrayUShort(&pvoxArray->indices, idx + 0);
insertArrayUShort(&pvoxArray->indices, idx + 2);
insertArrayUShort(&pvoxArray->indices, idx + 1);
insertArrayUShort(&pvoxArray->indices, idx + 0);
insertArrayUShort(&pvoxArray->indices, idx + 3);
insertArrayUShort(&pvoxArray->indices, idx + 2);
}
}
// MagicaVoxel *.vox file format Loader
int Vox_LoadFromMemory(const unsigned char* pvoxData, unsigned int voxDataSize, VoxArray3D* pvoxarray)
{
//////////////////////////////////////////////////
//Read VOX file
//4 bytes: magic number ('V' 'O' 'X' 'space' )
//4 bytes: version number (current version is 150 )
unsigned long signature;
unsigned char* fileData = pvoxData;
unsigned char* fileDataPtr = fileData;
unsigned char* endfileDataPtr = fileData + voxDataSize;
signature = *((unsigned long *)fileDataPtr);
fileDataPtr += sizeof(unsigned long);
if (signature != 0x20584F56) //56 4F 58 20
{
return VOX_ERROR_INVALID_FORMAT; //"Not an MagicaVoxel File format"
}
unsigned long version;
version = *((unsigned long*)fileDataPtr);
fileDataPtr += sizeof(unsigned long);
if (version < 150)
{
return VOX_ERROR_FILE_VERSION_TOO_OLD; //"MagicaVoxel version too old"
}
// header
//4 bytes: chunk id
//4 bytes: size of chunk contents (n)
//4 bytes: total size of children chunks(m)
//// chunk content
//n bytes: chunk contents
//// children chunks : m bytes
//{ child chunk 0 }
//{ child chunk 1 }
unsigned long sizeX, sizeY, sizeZ;
sizeX = sizeY = sizeZ = 0;
unsigned long numVoxels = 0;
int offsetX, offsetY, offsetZ;
offsetX = offsetY = offsetZ = 0;
while (fileDataPtr < endfileDataPtr)
{
char szChunkName[5];
memcpy(szChunkName, fileDataPtr, 4);
szChunkName[4] = 0;
fileDataPtr += 4;
unsigned long chunkSize = *((unsigned long*)fileDataPtr);
fileDataPtr += sizeof(unsigned long);
unsigned long chunkTotalChildSize = *((unsigned long*)fileDataPtr);
fileDataPtr += sizeof(unsigned long);
if (strcmp(szChunkName, "SIZE") == 0)
{
//(4 bytes x 3 : x, y, z )
sizeX = *((unsigned long*)fileDataPtr);
fileDataPtr += sizeof(unsigned long);
sizeY = *((unsigned long*)fileDataPtr);
fileDataPtr += sizeof(unsigned long);
sizeZ = *((unsigned long*)fileDataPtr);
fileDataPtr += sizeof(unsigned long);
//Alloc vox array
Vox_AllocArray(pvoxarray, sizeX, sizeZ, sizeY); //Reverse Y<>Z for left to right handed system
}
else if (strcmp(szChunkName, "XYZI") == 0)
{
unsigned char vx, vy, vz, vi;
//(numVoxels : 4 bytes )
//(each voxel: 1 byte x 4 : x, y, z, colorIndex ) x numVoxels
numVoxels = *((unsigned long*)fileDataPtr);
fileDataPtr += sizeof(unsigned long);
while (numVoxels > 0)
{
vx = *((unsigned char*)fileDataPtr++);
vy = *((unsigned char*)fileDataPtr++);
vz = *((unsigned char*)fileDataPtr++);
vi = *((unsigned char*)fileDataPtr++);
Vox_SetVoxel(pvoxarray, vx, vz, pvoxarray->sizeZ-vy-1, vi); //Reverse Y<>Z for left to right handed system
numVoxels--;
}
}
else if (strcmp(szChunkName, "RGBA") == 0)
{
VoxColor col;
//(each pixel: 1 byte x 4 : r, g, b, a ) x 256
for (int i = 0; i < 256 - 1; i++)
{
col.r = *((unsigned char*)fileDataPtr++);
col.g = *((unsigned char*)fileDataPtr++);
col.b = *((unsigned char*)fileDataPtr++);
col.a = *((unsigned char*)fileDataPtr++);
pvoxarray->palette[i + 1] = col;
}
}
else
{
fileDataPtr += chunkSize;
}
}
//////////////////////////////////////////////////////////
// Building Mesh
// TODO compute globals indices array
// Init Arrays
initArrayVector3(&pvoxarray->vertices, 3 * 1024);
initArrayUShort(&pvoxarray->indices, 3 * 1024);
initArrayColor(&pvoxarray->colors, 3 * 1024);
// Create vertices and indices buffers
int x, y, z;
for (x = 0; x <= pvoxarray->sizeX; x++)
{
for (z = 0; z <= pvoxarray->sizeZ; z++)
{
for (y = 0; y <= pvoxarray->sizeY; y++)
{
unsigned char matID = Vox_GetVoxel(pvoxarray, x, y, z);
if (matID != 0)
Vox_Build_Voxel(pvoxarray, x, y, z, matID);
}
}
}
return VOX_SUCCESS;
}
void Vox_FreeArrays(VoxArray3D* voxarray)
{
// Free chunks
if (voxarray->m_arrayChunks != 0)
{
for (int i = 0; i < voxarray->chunksTotal; i++)
{
CubeChunk3D* chunk = &voxarray->m_arrayChunks[i];
if (chunk->m_array != 0)
{
chunk->arraySize = 0;
VOX_FREE(chunk->m_array);
}
}
VOX_FREE(voxarray->m_arrayChunks);
voxarray->m_arrayChunks = 0;
voxarray->arrayChunksSize = 0;
voxarray->chunksSizeX = voxarray->chunksSizeY = voxarray->chunksSizeZ = 0;
voxarray->chunksTotal = 0;
voxarray->chunksAllocated = 0;
voxarray->ChunkFlattenOffset = 0;
voxarray->sizeX = voxarray->sizeY = voxarray->sizeZ = 0;
}
// Free arrays
freeArrayVector3(&voxarray->vertices);
freeArrayUShort(&voxarray->indices);
freeArrayColor(&voxarray->colors);
}
#endif //VOX_LOADER_IMPLEMENTATION

View File

@ -220,14 +220,20 @@
int format; // Data format (PixelFormat type) int format; // Data format (PixelFormat type)
} Texture2D; } Texture2D;
// Font character info // GlyphInfo, font characters glyphs info
typedef struct GlyphInfo GlyphInfo; typedef struct GlyphInfo {
int value; // Character value (Unicode)
int offsetX; // Character offset X when drawing
int offsetY; // Character offset Y when drawing
int advanceX; // Character advance position X
Image image; // Character image data
} GlyphInfo;
// TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle() // TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle()
// It should be redesigned to be provided by user // It should be redesigned to be provided by user
typedef struct Font { typedef struct Font {
int baseSize; // Base size (default chars height) int baseSize; // Base size (default chars height)
int charsCount; // Number of characters int glyphCount; // Number of characters
Texture2D texture; // Characters texture atlas Texture2D texture; // Characters texture atlas
Rectangle *recs; // Characters rectangles in texture Rectangle *recs; // Characters rectangles in texture
GlyphInfo *chars; // Characters info data GlyphInfo *chars; // Characters info data
@ -406,7 +412,7 @@ typedef enum {
extern "C" { // Prevents name mangling of functions extern "C" { // Prevents name mangling of functions
#endif #endif
// State modification functions // Global gui state control functions
RAYGUIDEF void GuiEnable(void); // Enable gui controls (global state) RAYGUIDEF void GuiEnable(void); // Enable gui controls (global state)
RAYGUIDEF void GuiDisable(void); // Disable gui controls (global state) RAYGUIDEF void GuiDisable(void); // Disable gui controls (global state)
RAYGUIDEF void GuiLock(void); // Lock gui controls (global state) RAYGUIDEF void GuiLock(void); // Lock gui controls (global state)
@ -1067,7 +1073,7 @@ static unsigned int guiIcons[RICON_MAX_ICONS*RICON_DATA_ELEMENTS] = {
#endif // RAYGUI_SUPPORT_RICONS #endif // RAYGUI_SUPPORT_RICONS
#ifndef RICON_SIZE #ifndef RICON_SIZE
#define RICON_SIZE 0 #define RICON_SIZE 0
#endif #endif
#define RAYGUI_MAX_CONTROLS 16 // Maximum number of standard controls #define RAYGUI_MAX_CONTROLS 16 // Maximum number of standard controls
@ -1076,7 +1082,7 @@ static unsigned int guiIcons[RICON_MAX_ICONS*RICON_DATA_ELEMENTS] = {
// TODO: Avoid animations and time-based states // TODO: Avoid animations and time-based states
// Functions using it: GuiTextBox(), GuiValueBox(), GuiTextBoxMulti() // Functions using it: GuiTextBox(), GuiValueBox(), GuiTextBoxMulti()
#define TEXTEDIT_CURSOR_BLINK_FRAMES 20 // Text edit controls cursor blink timming //#define TEXTEDIT_CURSOR_BLINK_FRAMES 20 // Text edit controls cursor blink timming
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
@ -1147,14 +1153,14 @@ static Font GetFontDefault(void); // -- GuiLoadStyleDe
static Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // -- GetTextWidth(), GuiTextBoxMulti() static Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // -- GetTextWidth(), GuiTextBoxMulti()
static void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // -- GuiDrawText() static void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // -- GuiDrawText()
static Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCount); // -- GuiLoadStyle() static Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int glyphCount); // -- GuiLoadStyle()
static char *LoadFileText(const char *fileName); // -- GuiLoadStyle() static char *LoadFileText(const char *fileName); // -- GuiLoadStyle()
static const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle() static const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle()
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
// raylib functions already implemented in raygui // raylib functions already implemented in raygui
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
static Color GetColor(unsigned int hexValue); // Returns a Color struct from hexadecimal value static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value
static int ColorToInt(Color color); // Returns hexadecimal value for a Color static int ColorToInt(Color color); // Returns hexadecimal value for a Color
static Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f static Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle
@ -1594,7 +1600,7 @@ bool GuiImageButtonEx(Rectangle bounds, const char *text, Texture2D texture, Rec
//-------------------------------------------------------------------- //--------------------------------------------------------------------
GuiDrawRectangle(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(BUTTON, BASE + (state*3))), guiAlpha)); GuiDrawRectangle(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(BUTTON, BASE + (state*3))), guiAlpha));
if (text != NULL) GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))), guiAlpha)); GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))), guiAlpha));
if (texture.id > 0) DrawTextureRec(texture, texSource, RAYGUI_CLITERAL(Vector2){ bounds.x + bounds.width/2 - texSource.width/2, bounds.y + bounds.height/2 - texSource.height/2 }, Fade(GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))), guiAlpha)); if (texture.id > 0) DrawTextureRec(texture, texSource, RAYGUI_CLITERAL(Vector2){ bounds.x + bounds.width/2 - texSource.width/2, bounds.y + bounds.height/2 - texSource.height/2 }, Fade(GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))), guiAlpha));
//------------------------------------------------------------------ //------------------------------------------------------------------
@ -1654,12 +1660,12 @@ int GuiToggleGroup(Rectangle bounds, const char *text, int active)
// Get substrings items from text (items pointers) // Get substrings items from text (items pointers)
int rows[TOGGLEGROUP_MAX_ELEMENTS] = { 0 }; int rows[TOGGLEGROUP_MAX_ELEMENTS] = { 0 };
int itemsCount = 0; int itemCount = 0;
const char **items = GuiTextSplit(text, &itemsCount, rows); const char **items = GuiTextSplit(text, &itemCount, rows);
int prevRow = rows[0]; int prevRow = rows[0];
for (int i = 0; i < itemsCount; i++) for (int i = 0; i < itemCount; i++)
{ {
if (prevRow != rows[i]) if (prevRow != rows[i])
{ {
@ -1730,7 +1736,7 @@ bool GuiCheckBox(Rectangle bounds, const char *text, bool checked)
GuiDrawRectangle(check, 0, BLANK, Fade(GetColor(GuiGetStyle(CHECKBOX, TEXT + state*3)), guiAlpha)); GuiDrawRectangle(check, 0, BLANK, Fade(GetColor(GuiGetStyle(CHECKBOX, TEXT + state*3)), guiAlpha));
} }
if (text != NULL) GuiDrawText(text, textBounds, (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT)? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha)); GuiDrawText(text, textBounds, (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT)? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha));
//-------------------------------------------------------------------- //--------------------------------------------------------------------
return checked; return checked;
@ -1747,15 +1753,15 @@ int GuiComboBox(Rectangle bounds, const char *text, int active)
(float)bounds.y, (float)GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH), (float)bounds.height }; (float)bounds.y, (float)GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH), (float)bounds.height };
// Get substrings items from text (items pointers, lengths and count) // Get substrings items from text (items pointers, lengths and count)
int itemsCount = 0; int itemCount = 0;
const char **items = GuiTextSplit(text, &itemsCount, NULL); const char **items = GuiTextSplit(text, &itemCount, NULL);
if (active < 0) active = 0; if (active < 0) active = 0;
else if (active > itemsCount - 1) active = itemsCount - 1; else if (active > itemCount - 1) active = itemCount - 1;
// Update control // Update control
//-------------------------------------------------------------------- //--------------------------------------------------------------------
if ((state != GUI_STATE_DISABLED) && !guiLocked && (itemsCount > 1)) if ((state != GUI_STATE_DISABLED) && !guiLocked && (itemCount > 1))
{ {
Vector2 mousePoint = GetMousePosition(); Vector2 mousePoint = GetMousePosition();
@ -1765,7 +1771,7 @@ int GuiComboBox(Rectangle bounds, const char *text, int active)
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
{ {
active += 1; active += 1;
if (active >= itemsCount) active = 0; if (active >= itemCount) active = 0;
} }
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED; if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
@ -1787,7 +1793,7 @@ int GuiComboBox(Rectangle bounds, const char *text, int active)
GuiSetStyle(BUTTON, BORDER_WIDTH, 1); GuiSetStyle(BUTTON, BORDER_WIDTH, 1);
GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
GuiButton(selector, TextFormat("%i/%i", active + 1, itemsCount)); GuiButton(selector, TextFormat("%i/%i", active + 1, itemCount));
GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign); GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign);
GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
@ -1805,11 +1811,11 @@ bool GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMo
int itemFocused = -1; int itemFocused = -1;
// Get substrings items from text (items pointers, lengths and count) // Get substrings items from text (items pointers, lengths and count)
int itemsCount = 0; int itemCount = 0;
const char **items = GuiTextSplit(text, &itemsCount, NULL); const char **items = GuiTextSplit(text, &itemCount, NULL);
Rectangle boundsOpen = bounds; Rectangle boundsOpen = bounds;
boundsOpen.height = (itemsCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_PADDING)); boundsOpen.height = (itemCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_PADDING));
Rectangle itemBounds = bounds; Rectangle itemBounds = bounds;
@ -1817,7 +1823,7 @@ bool GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMo
// Update control // Update control
//-------------------------------------------------------------------- //--------------------------------------------------------------------
if ((state != GUI_STATE_DISABLED) && !guiLocked && (itemsCount > 1)) if ((state != GUI_STATE_DISABLED) && !guiLocked && (itemCount > 1))
{ {
Vector2 mousePoint = GetMousePosition(); Vector2 mousePoint = GetMousePosition();
@ -1835,7 +1841,7 @@ bool GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMo
if (CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true; if (CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
// Check focused and selected item // Check focused and selected item
for (int i = 0; i < itemsCount; i++) for (int i = 0; i < itemCount; i++)
{ {
// Update item rectangle y position for next item // Update item rectangle y position for next item
itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_PADDING)); itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_PADDING));
@ -1879,7 +1885,7 @@ bool GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMo
if (editMode) if (editMode)
{ {
// Draw visible items // Draw visible items
for (int i = 0; i < itemsCount; i++) for (int i = 0; i < itemCount; i++)
{ {
// Update item rectangle y position for next item // Update item rectangle y position for next item
itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_PADDING)); itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_PADDING));
@ -1913,19 +1919,16 @@ bool GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMo
} }
// Text Box control, updates input text // Text Box control, updates input text
// NOTE 1: Requires static variables: framesCounter
// NOTE 2: Returns if KEY_ENTER pressed (useful for data validation) // NOTE 2: Returns if KEY_ENTER pressed (useful for data validation)
bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
{ {
static int framesCounter = 0; // Blinking cursor counter
GuiControlState state = guiState; GuiControlState state = guiState;
bool pressed = false; bool pressed = false;
Rectangle cursor = { Rectangle cursor = {
bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GetTextWidth(text) + 2, bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GetTextWidth(text) + 2,
bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE), bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE),
1, 4,
(float)GuiGetStyle(DEFAULT, TEXT_SIZE)*2 (float)GuiGetStyle(DEFAULT, TEXT_SIZE)*2
}; };
@ -1938,8 +1941,7 @@ bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
if (editMode) if (editMode)
{ {
state = GUI_STATE_PRESSED; state = GUI_STATE_PRESSED;
framesCounter++;
int key = GetCharPressed(); // Returns codepoint as Unicode int key = GetCharPressed(); // Returns codepoint as Unicode
int keyCount = (int)strlen(text); int keyCount = (int)strlen(text);
@ -1950,10 +1952,10 @@ bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
if ((GetTextWidth(text) < (maxWidth - GuiGetStyle(DEFAULT, TEXT_SIZE))) && (key >= 32)) if ((GetTextWidth(text) < (maxWidth - GuiGetStyle(DEFAULT, TEXT_SIZE))) && (key >= 32))
{ {
int byteLength = 0; int byteSize = 0;
const char *textUTF8 = CodepointToUTF8(key, &byteLength); const char *textUTF8 = CodepointToUTF8(key, &byteSize);
for (int i = 0; i < byteLength; i++) for (int i = 0; i < byteSize; i++)
{ {
text[keyCount] = textUTF8[i]; text[keyCount] = textUTF8[i];
keyCount++; keyCount++;
@ -1970,13 +1972,6 @@ bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
{ {
keyCount--; keyCount--;
text[keyCount] = '\0'; text[keyCount] = '\0';
framesCounter = 0;
if (keyCount < 0) keyCount = 0;
}
else if (IsKeyDown(KEY_BACKSPACE))
{
if ((framesCounter > TEXTEDIT_CURSOR_BLINK_FRAMES) && (framesCounter%2) == 0) keyCount--;
text[keyCount] = '\0';
if (keyCount < 0) keyCount = 0; if (keyCount < 0) keyCount = 0;
} }
} }
@ -1996,8 +1991,6 @@ bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true; if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
} }
} }
if (pressed) framesCounter = 0;
} }
//-------------------------------------------------------------------- //--------------------------------------------------------------------
@ -2006,9 +1999,6 @@ bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
if (state == GUI_STATE_PRESSED) if (state == GUI_STATE_PRESSED)
{ {
GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)), guiAlpha)); GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)), guiAlpha));
// Draw blinking cursor
if (editMode && ((framesCounter/20)%2 == 0)) GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha));
} }
else if (state == GUI_STATE_DISABLED) else if (state == GUI_STATE_DISABLED)
{ {
@ -2017,6 +2007,9 @@ bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
else GuiDrawRectangle(bounds, 1, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), BLANK); else GuiDrawRectangle(bounds, 1, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), BLANK);
GuiDrawText(text, GetTextBounds(TEXTBOX, bounds), GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha)); GuiDrawText(text, GetTextBounds(TEXTBOX, bounds), GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha));
// Draw cursor
if (editMode) GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha));
//-------------------------------------------------------------------- //--------------------------------------------------------------------
return pressed; return pressed;
@ -2090,7 +2083,7 @@ bool GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, in
GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
// Draw text label if provided // Draw text label if provided
if (text != NULL) GuiDrawText(text, textBounds, (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT)? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha)); GuiDrawText(text, textBounds, (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT)? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha));
//-------------------------------------------------------------------- //--------------------------------------------------------------------
*value = tempValue; *value = tempValue;
@ -2098,15 +2091,13 @@ bool GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, in
} }
// Value Box control, updates input text with numbers // Value Box control, updates input text with numbers
// NOTE: Requires static variables: framesCounter // NOTE: Requires static variables: frameCounter
bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode)
{ {
#if !defined(VALUEBOX_MAX_CHARS) #if !defined(VALUEBOX_MAX_CHARS)
#define VALUEBOX_MAX_CHARS 32 #define VALUEBOX_MAX_CHARS 32
#endif #endif
static int framesCounter = 0; // Blinking cursor counter
GuiControlState state = guiState; GuiControlState state = guiState;
bool pressed = false; bool pressed = false;
@ -2135,8 +2126,6 @@ bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, i
{ {
state = GUI_STATE_PRESSED; state = GUI_STATE_PRESSED;
framesCounter++;
int keyCount = (int)strlen(textValue); int keyCount = (int)strlen(textValue);
// Only allow keys in range [48..57] // Only allow keys in range [48..57]
@ -2161,14 +2150,6 @@ bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, i
{ {
keyCount--; keyCount--;
textValue[keyCount] = '\0'; textValue[keyCount] = '\0';
framesCounter = 0;
if (keyCount < 0) keyCount = 0;
valueHasChanged = true;
}
else if (IsKeyDown(KEY_BACKSPACE))
{
if ((framesCounter > TEXTEDIT_CURSOR_BLINK_FRAMES) && (framesCounter%2) == 0) keyCount--;
textValue[keyCount] = '\0';
if (keyCount < 0) keyCount = 0; if (keyCount < 0) keyCount = 0;
valueHasChanged = true; valueHasChanged = true;
} }
@ -2189,8 +2170,6 @@ bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, i
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true; if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
} }
} }
if (pressed) framesCounter = 0;
} }
//-------------------------------------------------------------------- //--------------------------------------------------------------------
@ -2204,16 +2183,16 @@ bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, i
GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), guiAlpha), baseColor); GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), guiAlpha), baseColor);
GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3))), guiAlpha)); GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3))), guiAlpha));
// Draw blinking cursor // Draw cursor
if ((state == GUI_STATE_PRESSED) && (editMode && ((framesCounter/20)%2 == 0))) if (editMode)
{ {
// NOTE: ValueBox internal text is always centered // NOTE: ValueBox internal text is always centered
Rectangle cursor = { bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 2, bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 1, bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH) }; Rectangle cursor = { bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 2, bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4, bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH) };
GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)), guiAlpha)); GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)), guiAlpha));
} }
// Draw text label if provided // Draw text label if provided
if (text != NULL) GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT)? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha)); GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT)? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha));
//-------------------------------------------------------------------- //--------------------------------------------------------------------
return pressed; return pressed;
@ -2222,8 +2201,6 @@ bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, i
// Text Box control with multiple lines // Text Box control with multiple lines
bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode) bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
{ {
static int framesCounter = 0; // Blinking cursor counter
GuiControlState state = guiState; GuiControlState state = guiState;
bool pressed = false; bool pressed = false;
@ -2235,10 +2212,9 @@ bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
}; };
// Cursor position, [x, y] values should be updated // Cursor position, [x, y] values should be updated
Rectangle cursor = { 0, 0, 1, (float)GuiGetStyle(DEFAULT, TEXT_SIZE) + 2 }; Rectangle cursor = { 0, -1, 4, (float)GuiGetStyle(DEFAULT, TEXT_SIZE) + 2 };
int textWidth = 0; float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize; // Character rectangle scaling factor
int currentLine = 0;
// Update control // Update control
//-------------------------------------------------------------------- //--------------------------------------------------------------------
@ -2249,77 +2225,52 @@ bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
if (editMode) if (editMode)
{ {
state = GUI_STATE_PRESSED; state = GUI_STATE_PRESSED;
framesCounter++;
int character = GetCharPressed(); // We get an Unicode codepoint
int keyCount = (int)strlen(text); int codepoint = GetCharPressed();
int textLength = (int)strlen(text); // Length in bytes (UTF-8 string)
// Introduce characters // Introduce characters
if (keyCount < (textSize - 1)) if (textLength < (textSize - 1))
{ {
Vector2 textSize = MeasureTextEx(guiFont, text, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); if (IsKeyPressed(KEY_ENTER))
if (textSize.y < (textAreaBounds.height - GuiGetStyle(DEFAULT, TEXT_SIZE)))
{ {
if (IsKeyPressed(KEY_ENTER)) text[textLength] = '\n';
{ textLength++;
text[keyCount] = '\n'; }
keyCount++; else if (codepoint >= 32)
} {
else if (((character >= 32) && (character < 255))) // TODO: Support Unicode inputs // Supports Unicode inputs -> Encoded to UTF-8
{ int charUTF8Length = 0;
text[keyCount] = (char)character; const char *charEncoded = CodepointToUTF8(codepoint, &charUTF8Length);
keyCount++; memcpy(text + textLength, charEncoded, charUTF8Length);
} textLength += charUTF8Length;
} }
} }
// Delete characters // Delete characters
if (keyCount > 0) if (textLength > 0)
{ {
if (IsKeyPressed(KEY_BACKSPACE)) if (IsKeyPressed(KEY_BACKSPACE))
{ {
keyCount--; if ((unsigned char)text[textLength - 1] < 127)
text[keyCount] = '\0'; {
framesCounter = 0; // Remove ASCII equivalent character (1 byte)
textLength--;
if (keyCount < 0) keyCount = 0; text[textLength] = '\0';
} }
else if (IsKeyDown(KEY_BACKSPACE)) else
{ {
if ((framesCounter > TEXTEDIT_CURSOR_BLINK_FRAMES) && (framesCounter%2) == 0) keyCount--; // Remove latest UTF-8 unicode character introduced (n bytes)
text[keyCount] = '\0'; int charUTF8Length = 0;
while (((unsigned char)text[textLength - 1 - charUTF8Length] & 0b01000000) == 0) charUTF8Length++;
if (keyCount < 0) keyCount = 0;
textLength -= (charUTF8Length + 1);
text[textLength] = '\0';
}
} }
} }
// Calculate cursor position considering text
char oneCharText[2] = { 0 };
int lastBreakingPos = -1;
for (int i = 0; i < keyCount && currentLine < keyCount; i++)
{
oneCharText[0] = text[i];
textWidth += (GetTextWidth(oneCharText) + GuiGetStyle(DEFAULT, TEXT_SPACING));
if (text[i] == ' ' || text[i] == '\n') lastBreakingPos = i;
if ( text[i] == '\n' || textWidth >= textAreaBounds.width)
{
currentLine++;
textWidth = 0;
if (lastBreakingPos > 0) i = lastBreakingPos;
else textWidth += (GetTextWidth(oneCharText) + GuiGetStyle(DEFAULT, TEXT_SPACING));
lastBreakingPos = -1;
}
}
cursor.x = bounds.x + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING) + textWidth - GuiGetStyle(DEFAULT, TEXT_SPACING);
cursor.y = bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING)/2 + ((GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING))*currentLine);
// Exit edit mode // Exit edit mode
if (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true; if (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
} }
@ -2331,8 +2282,6 @@ bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true; if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
} }
} }
if (pressed) framesCounter = 0; // Reset blinking cursor
} }
//-------------------------------------------------------------------- //--------------------------------------------------------------------
@ -2341,9 +2290,6 @@ bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
if (state == GUI_STATE_PRESSED) if (state == GUI_STATE_PRESSED)
{ {
GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)), guiAlpha)); GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)), guiAlpha));
// Draw blinking cursor
if (editMode && ((framesCounter/20)%2 == 0)) GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha));
} }
else if (state == GUI_STATE_DISABLED) else if (state == GUI_STATE_DISABLED)
{ {
@ -2351,9 +2297,76 @@ bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
} }
else GuiDrawRectangle(bounds, 1, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), BLANK); else GuiDrawRectangle(bounds, 1, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), BLANK);
// TODO: Review to support boxed text with word-wrap int wrapMode = 1; // 0-No wrap, 1-Char wrap, 2-Word wrap
//DrawTextBoxed(guiFont, text, textAreaBounds, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING), true, Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha)); Vector2 cursorPos = { textAreaBounds.x, textAreaBounds.y };
DrawTextEx(guiFont, text, (Vector2){ textAreaBounds.x, textAreaBounds.y }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha));
//int lastSpacePos = 0;
//int lastSpaceWidth = 0;
//int lastSpaceCursorPos = 0;
for (int i = 0, codepointLength = 0; text[i] != '\0'; i += codepointLength)
{
int codepoint = GetCodepoint(text + i, &codepointLength);
int index = GetGlyphIndex(guiFont, codepoint); // If requested codepoint is not found, we get '?' (0x3f) -> TODO: review that case!
Rectangle atlasRec = guiFont.recs[index];
GlyphInfo glyphInfo = guiFont.glyphs[index]; // Glyph measures
if ((codepointLength == 1) && (codepoint == '\n'))
{
cursorPos.y += (guiFont.baseSize*scaleFactor + GuiGetStyle(TEXTBOX, TEXT_LINES_PADDING)); // Line feed
cursorPos.x = textAreaBounds.x; // Carriage return
}
else
{
if (wrapMode == 1)
{
int glyphWidth = 0;
if (glyphInfo.advanceX != 0) glyphWidth += glyphInfo.advanceX;
else glyphWidth += (atlasRec.width + glyphInfo.offsetX);
// Jump line if the end of the text box area has been reached
if ((cursorPos.x + (glyphWidth*scaleFactor)) > (textAreaBounds.x + textAreaBounds.width))
{
cursorPos.y += (guiFont.baseSize*scaleFactor + GuiGetStyle(TEXTBOX, TEXT_LINES_PADDING)); // Line feed
cursorPos.x = textAreaBounds.x; // Carriage return
}
}
else if (wrapMode == 2)
{
/*
if ((codepointLength == 1) && (codepoint == ' '))
{
lastSpacePos = i;
lastSpaceWidth = 0;
lastSpaceCursorPos = cursorPos.x;
}
// Jump line if last word reaches end of text box area
if ((lastSpaceCursorPos + lastSpaceWidth) > (textAreaBounds.x + textAreaBounds.width))
{
cursorPos.y += 12; // Line feed
cursorPos.x = textAreaBounds.x; // Carriage return
}
*/
}
// Draw current character glyph
DrawTextCodepoint(guiFont, codepoint, cursorPos, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha));
int glyphWidth = 0;
if (glyphInfo.advanceX != 0) glyphWidth += glyphInfo.advanceX;
else glyphWidth += (atlasRec.width + glyphInfo.offsetX);
cursorPos.x += (glyphWidth*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
//if (i > lastSpacePos) lastSpaceWidth += (atlasRec.width + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
}
}
cursor.x = cursorPos.x;
cursor.y = cursorPos.y;
// Draw cursor position considering text glyphs
if (editMode) GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha));
//-------------------------------------------------------------------- //--------------------------------------------------------------------
return pressed; return pressed;
@ -2698,12 +2711,12 @@ int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue)
// List View control // List View control
int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int active) int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int active)
{ {
int itemsCount = 0; int itemCount = 0;
const char **items = NULL; const char **items = NULL;
if (text != NULL) items = GuiTextSplit(text, &itemsCount, NULL); if (text != NULL) items = GuiTextSplit(text, &itemCount, NULL);
return GuiListViewEx(bounds, items, itemsCount, NULL, scrollIndex, active); return GuiListViewEx(bounds, items, itemCount, NULL, scrollIndex, active);
} }
// List View control with extended parameters // List View control with extended parameters
@ -3096,12 +3109,12 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons
int clicked = -1; // Returns clicked button from buttons list, 0 refers to closed window button int clicked = -1; // Returns clicked button from buttons list, 0 refers to closed window button
int buttonsCount = 0; int buttonCount = 0;
const char **buttonsText = GuiTextSplit(buttons, &buttonsCount, NULL); const char **buttonsText = GuiTextSplit(buttons, &buttonCount, NULL);
Rectangle buttonBounds = { 0 }; Rectangle buttonBounds = { 0 };
buttonBounds.x = bounds.x + MESSAGEBOX_BUTTON_PADDING; buttonBounds.x = bounds.x + MESSAGEBOX_BUTTON_PADDING;
buttonBounds.y = bounds.y + bounds.height - MESSAGEBOX_BUTTON_HEIGHT - MESSAGEBOX_BUTTON_PADDING; buttonBounds.y = bounds.y + bounds.height - MESSAGEBOX_BUTTON_HEIGHT - MESSAGEBOX_BUTTON_PADDING;
buttonBounds.width = (bounds.width - MESSAGEBOX_BUTTON_PADDING*(buttonsCount + 1))/buttonsCount; buttonBounds.width = (bounds.width - MESSAGEBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount;
buttonBounds.height = MESSAGEBOX_BUTTON_HEIGHT; buttonBounds.height = MESSAGEBOX_BUTTON_HEIGHT;
Vector2 textSize = MeasureTextEx(guiFont, message, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), 1); Vector2 textSize = MeasureTextEx(guiFont, message, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), 1);
@ -3124,7 +3137,7 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons
prevTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); prevTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
for (int i = 0; i < buttonsCount; i++) for (int i = 0; i < buttonCount; i++)
{ {
if (GuiButton(buttonBounds, buttonsText[i])) clicked = i + 1; if (GuiButton(buttonBounds, buttonsText[i])) clicked = i + 1;
buttonBounds.x += (buttonBounds.width + MESSAGEBOX_BUTTON_PADDING); buttonBounds.x += (buttonBounds.width + MESSAGEBOX_BUTTON_PADDING);
@ -3151,12 +3164,12 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co
int btnIndex = -1; int btnIndex = -1;
int buttonsCount = 0; int buttonCount = 0;
const char **buttonsText = GuiTextSplit(buttons, &buttonsCount, NULL); const char **buttonsText = GuiTextSplit(buttons, &buttonCount, NULL);
Rectangle buttonBounds = { 0 }; Rectangle buttonBounds = { 0 };
buttonBounds.x = bounds.x + TEXTINPUTBOX_BUTTON_PADDING; buttonBounds.x = bounds.x + TEXTINPUTBOX_BUTTON_PADDING;
buttonBounds.y = bounds.y + bounds.height - TEXTINPUTBOX_BUTTON_HEIGHT - TEXTINPUTBOX_BUTTON_PADDING; buttonBounds.y = bounds.y + bounds.height - TEXTINPUTBOX_BUTTON_HEIGHT - TEXTINPUTBOX_BUTTON_PADDING;
buttonBounds.width = (bounds.width - TEXTINPUTBOX_BUTTON_PADDING*(buttonsCount + 1))/buttonsCount; buttonBounds.width = (bounds.width - TEXTINPUTBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount;
buttonBounds.height = TEXTINPUTBOX_BUTTON_HEIGHT; buttonBounds.height = TEXTINPUTBOX_BUTTON_HEIGHT;
int messageInputHeight = (int)bounds.height - WINDOW_STATUSBAR_HEIGHT - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - TEXTINPUTBOX_BUTTON_HEIGHT - 2*TEXTINPUTBOX_BUTTON_PADDING; int messageInputHeight = (int)bounds.height - WINDOW_STATUSBAR_HEIGHT - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - TEXTINPUTBOX_BUTTON_HEIGHT - 2*TEXTINPUTBOX_BUTTON_PADDING;
@ -3198,7 +3211,7 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co
int prevBtnTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); int prevBtnTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
for (int i = 0; i < buttonsCount; i++) for (int i = 0; i < buttonCount; i++)
{ {
if (GuiButton(buttonBounds, buttonsText[i])) btnIndex = i + 1; if (GuiButton(buttonBounds, buttonsText[i])) btnIndex = i + 1;
buttonBounds.x += (buttonBounds.width + MESSAGEBOX_BUTTON_PADDING); buttonBounds.x += (buttonBounds.width + MESSAGEBOX_BUTTON_PADDING);
@ -3322,20 +3335,20 @@ void GuiLoadStyle(const char *fileName)
char *charValues = LoadFileText(charmapFileName); char *charValues = LoadFileText(charmapFileName);
if (charValues != NULL) if (charValues != NULL)
{ {
int charsCount = 0; int glyphCount = 0;
const char **chars = TextSplit(charValues, '\n', &charsCount); const char **chars = TextSplit(charValues, '\n', &glyphCount);
int *values = (int *)RAYGUI_MALLOC(charsCount*sizeof(int)); int *values = (int *)RAYGUI_MALLOC(glyphCount*sizeof(int));
for (int i = 0; i < charsCount; i++) values[i] = TextToInteger(chars[i]); for (int i = 0; i < glyphCount; i++) values[i] = TextToInteger(chars[i]);
font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, values, charsCount); font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, values, glyphCount);
RAYGUI_FREE(values); RAYGUI_FREE(values);
} }
} }
else font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, NULL, 0); else font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, NULL, 0);
if ((font.texture.id > 0) && (font.charsCount > 0)) GuiSetFont(font); if ((font.texture.id > 0) && (font.glyphCount > 0)) GuiSetFont(font);
} break; } break;
default: break; default: break;
@ -3358,12 +3371,12 @@ void GuiLoadStyle(const char *fileName)
char signature[5] = ""; char signature[5] = "";
short version = 0; short version = 0;
short reserved = 0; short reserved = 0;
int propertiesCount = 0; int propertyCount = 0;
fread(signature, 1, 4, rgsFile); fread(signature, 1, 4, rgsFile);
fread(&version, 1, sizeof(short), rgsFile); fread(&version, 1, sizeof(short), rgsFile);
fread(&reserved, 1, sizeof(short), rgsFile); fread(&reserved, 1, sizeof(short), rgsFile);
fread(&propertiesCount, 1, sizeof(int), rgsFile); fread(&propertyCount, 1, sizeof(int), rgsFile);
if ((signature[0] == 'r') && if ((signature[0] == 'r') &&
(signature[1] == 'G') && (signature[1] == 'G') &&
@ -3374,7 +3387,7 @@ void GuiLoadStyle(const char *fileName)
short propertyId = 0; short propertyId = 0;
int propertyValue = 0; int propertyValue = 0;
for (int i = 0; i < propertiesCount; i++) for (int i = 0; i < propertyCount; i++)
{ {
fread(&controlId, 1, sizeof(short), rgsFile); fread(&controlId, 1, sizeof(short), rgsFile);
fread(&propertyId, 1, sizeof(short), rgsFile); fread(&propertyId, 1, sizeof(short), rgsFile);
@ -3405,7 +3418,7 @@ void GuiLoadStyle(const char *fileName)
Rectangle whiteRec = { 0 }; Rectangle whiteRec = { 0 };
fread(&font.baseSize, 1, sizeof(int), rgsFile); fread(&font.baseSize, 1, sizeof(int), rgsFile);
fread(&font.charsCount, 1, sizeof(int), rgsFile); fread(&font.glyphCount, 1, sizeof(int), rgsFile);
fread(&fontType, 1, sizeof(int), rgsFile); fread(&fontType, 1, sizeof(int), rgsFile);
// Load font white rectangle // Load font white rectangle
@ -3432,17 +3445,17 @@ void GuiLoadStyle(const char *fileName)
} }
// Load font recs data // Load font recs data
font.recs = (Rectangle *)RAYGUI_CALLOC(font.charsCount, sizeof(Rectangle)); font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
for (int i = 0; i < font.charsCount; i++) fread(&font.recs[i], 1, sizeof(Rectangle), rgsFile); for (int i = 0; i < font.glyphCount; i++) fread(&font.recs[i], 1, sizeof(Rectangle), rgsFile);
// Load font chars info data // Load font chars info data
font.chars = (GlyphInfo *)RAYGUI_CALLOC(font.charsCount, sizeof(GlyphInfo)); font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
for (int i = 0; i < font.charsCount; i++) for (int i = 0; i < font.glyphCount; i++)
{ {
fread(&font.chars[i].value, 1, sizeof(int), rgsFile); fread(&font.glyphs[i].value, 1, sizeof(int), rgsFile);
fread(&font.chars[i].offsetX, 1, sizeof(int), rgsFile); fread(&font.glyphs[i].offsetX, 1, sizeof(int), rgsFile);
fread(&font.chars[i].offsetY, 1, sizeof(int), rgsFile); fread(&font.glyphs[i].offsetY, 1, sizeof(int), rgsFile);
fread(&font.chars[i].advanceX, 1, sizeof(int), rgsFile); fread(&font.glyphs[i].advanceX, 1, sizeof(int), rgsFile);
} }
GuiSetFont(font); GuiSetFont(font);
@ -3572,7 +3585,7 @@ unsigned int *GuiGetIcons(void) { return guiIcons; }
// Load raygui icons file (.rgi) // Load raygui icons file (.rgi)
// NOTE: In case nameIds are required, they can be requested with loadIconsName, // NOTE: In case nameIds are required, they can be requested with loadIconsName,
// they are returned as a guiIconsName[iconsCount][RICON_MAX_NAME_LENGTH], // they are returned as a guiIconsName[iconCount][RICON_MAX_NAME_LENGTH],
// guiIconsName[]][] memory should be manually freed! // guiIconsName[]][] memory should be manually freed!
char **GuiLoadIcons(const char *fileName, bool loadIconsName) char **GuiLoadIcons(const char *fileName, bool loadIconsName)
{ {
@ -3609,14 +3622,14 @@ char **GuiLoadIcons(const char *fileName, bool loadIconsName)
char signature[5] = ""; char signature[5] = "";
short version = 0; short version = 0;
short reserved = 0; short reserved = 0;
short iconsCount = 0; short iconCount = 0;
short iconsSize = 0; short iconSize = 0;
fread(signature, 1, 4, rgiFile); fread(signature, 1, 4, rgiFile);
fread(&version, 1, sizeof(short), rgiFile); fread(&version, 1, sizeof(short), rgiFile);
fread(&reserved, 1, sizeof(short), rgiFile); fread(&reserved, 1, sizeof(short), rgiFile);
fread(&iconsCount, 1, sizeof(short), rgiFile); fread(&iconCount, 1, sizeof(short), rgiFile);
fread(&iconsSize, 1, sizeof(short), rgiFile); fread(&iconSize, 1, sizeof(short), rgiFile);
if ((signature[0] == 'r') && if ((signature[0] == 'r') &&
(signature[1] == 'G') && (signature[1] == 'G') &&
@ -3625,17 +3638,17 @@ char **GuiLoadIcons(const char *fileName, bool loadIconsName)
{ {
if (loadIconsName) if (loadIconsName)
{ {
guiIconsName = (char **)RAYGUI_MALLOC(iconsCount*sizeof(char **)); guiIconsName = (char **)RAYGUI_MALLOC(iconCount*sizeof(char **));
for (int i = 0; i < iconsCount; i++) for (int i = 0; i < iconCount; i++)
{ {
guiIconsName[i] = (char *)RAYGUI_MALLOC(RICON_MAX_NAME_LENGTH); guiIconsName[i] = (char *)RAYGUI_MALLOC(RICON_MAX_NAME_LENGTH);
fread(guiIconsName[i], RICON_MAX_NAME_LENGTH, 1, rgiFile); fread(guiIconsName[i], RICON_MAX_NAME_LENGTH, 1, rgiFile);
} }
} }
else fseek(rgiFile, iconsCount*RICON_MAX_NAME_LENGTH, SEEK_CUR); else fseek(rgiFile, iconCount*RICON_MAX_NAME_LENGTH, SEEK_CUR);
// Read icons data directly over guiIcons data array // Read icons data directly over guiIcons data array
fread(guiIcons, iconsCount*(iconsSize*iconsSize/32), sizeof(unsigned int), rgiFile); fread(guiIcons, iconCount*(iconSize*iconSize/32), sizeof(unsigned int), rgiFile);
} }
fclose(rgiFile); fclose(rgiFile);
@ -4061,7 +4074,7 @@ static Vector3 ConvertHSVtoRGB(Vector3 hsv)
#if defined(RAYGUI_STANDALONE) #if defined(RAYGUI_STANDALONE)
// Returns a Color struct from hexadecimal value // Returns a Color struct from hexadecimal value
static Color GetColor(unsigned int hexValue) static Color GetColor(int hexValue)
{ {
Color color; Color color;
@ -4186,29 +4199,29 @@ static int TextToInteger(const char *text)
return value*sign; return value*sign;
} }
// Encode codepoint into UTF-8 text (char array length returned as parameter) // Encode codepoint into UTF-8 text (char array size returned as parameter)
static const char *CodepointToUTF8(int codepoint, int *byteLength) static const char *CodepointToUTF8(int codepoint, int *byteSize)
{ {
static char utf8[6] = { 0 }; static char utf8[6] = { 0 };
int length = 0; int size = 0;
if (codepoint <= 0x7f) if (codepoint <= 0x7f)
{ {
utf8[0] = (char)codepoint; utf8[0] = (char)codepoint;
length = 1; size = 1;
} }
else if (codepoint <= 0x7ff) else if (codepoint <= 0x7ff)
{ {
utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0); utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0);
utf8[1] = (char)((codepoint & 0x3f) | 0x80); utf8[1] = (char)((codepoint & 0x3f) | 0x80);
length = 2; size = 2;
} }
else if (codepoint <= 0xffff) else if (codepoint <= 0xffff)
{ {
utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0); utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0);
utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80); utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
utf8[2] = (char)((codepoint & 0x3f) | 0x80); utf8[2] = (char)((codepoint & 0x3f) | 0x80);
length = 3; size = 3;
} }
else if (codepoint <= 0x10ffff) else if (codepoint <= 0x10ffff)
{ {
@ -4216,10 +4229,10 @@ static const char *CodepointToUTF8(int codepoint, int *byteLength)
utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80); utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80);
utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80); utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
utf8[3] = (char)((codepoint & 0x3f) | 0x80); utf8[3] = (char)((codepoint & 0x3f) | 0x80);
length = 4; size = 4;
} }
*byteLength = length; *byteSize = size;
return utf8; return utf8;
} }

View File

@ -276,7 +276,10 @@ static void __InsertMemNode(MemPool *const mempool, AllocList *const list, MemNo
mempool->arena.offs += iter->size; mempool->arena.offs += iter->size;
__RemoveMemNode(list, iter); __RemoveMemNode(list, iter);
iter = list->head; iter = list->head;
if (iter == NULL) return; if (iter == NULL) {
list->head = node;
return;
}
} }
const uintptr_t inode = ( uintptr_t )node; const uintptr_t inode = ( uintptr_t )node;
const uintptr_t iiter = ( uintptr_t )iter; const uintptr_t iiter = ( uintptr_t )iter;
@ -293,6 +296,14 @@ static void __InsertMemNode(MemPool *const mempool, AllocList *const list, MemNo
iter->size += node->size; iter->size += node->size;
return; return;
} }
else if (iter->next == NULL)
{
// we reached the end of the free list -> append the node
iter->next = node;
node->prev = iter;
list->len++;
return;
}
} }
else if (iter > node) else if (iter > node)
{ {
@ -326,7 +337,7 @@ static void __InsertMemNode(MemPool *const mempool, AllocList *const list, MemNo
} }
else else
{ {
__InsertMemNodeBefore(list, iter, node); __InsertMemNodeBefore(list, node, iter);
list->len++; list->len++;
return; return;
} }

View File

@ -155,10 +155,6 @@ typedef int socklen_t;
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif
#ifndef INVALID_SOCKET
#define INVALID_SOCKET ~(0)
#endif
#ifndef __USE_W32_SOCKETS #ifndef __USE_W32_SOCKETS
#define closesocket close #define closesocket close
#define SOCKET int #define SOCKET int
@ -166,6 +162,10 @@ typedef int socklen_t;
#define SOCKET_ERROR -1 #define SOCKET_ERROR -1
#endif #endif
#ifndef INVALID_SOCKET
#define INVALID_SOCKET ~(0)
#endif
#ifdef __USE_W32_SOCKETS #ifdef __USE_W32_SOCKETS
#ifndef EINTR #ifndef EINTR
#define EINTR WSAEINTR #define EINTR WSAEINTR
@ -2253,4 +2253,4 @@ uint64_t PacketRead64(Packet *packet)
return value; return value;
} }
#endif // RNET_IMPLEMENTATION #endif // RNET_IMPLEMENTATION

View File

@ -26,8 +26,9 @@
* supported by default, to remove support, just comment unrequired #define in this module * supported by default, to remove support, just comment unrequired #define in this module
* *
* DEPENDENCIES: * DEPENDENCIES:
* miniaudio.h - Audio device management lib (https://github.com/dr-soft/miniaudio) * miniaudio.h - Audio device management lib (https://github.com/mackron/miniaudio)
* stb_vorbis.h - Ogg audio files loading (http://www.nothings.org/stb_vorbis/) * stb_vorbis.h - Ogg audio files loading (http://www.nothings.org/stb_vorbis/)
* dr_wav.h - WAV audio files loading (http://github.com/mackron/dr_libs)
* dr_mp3.h - MP3 audio file loading (https://github.com/mackron/dr_libs) * dr_mp3.h - MP3 audio file loading (https://github.com/mackron/dr_libs)
* dr_flac.h - FLAC audio file loading (https://github.com/mackron/dr_libs) * dr_flac.h - FLAC audio file loading (https://github.com/mackron/dr_libs)
* jar_xm.h - XM module file loading * jar_xm.h - XM module file loading
@ -877,14 +878,14 @@ void UnloadSound(Sound sound)
} }
// Update sound buffer with new data // Update sound buffer with new data
void UpdateSound(Sound sound, const void *data, int samplesCount) void UpdateSound(Sound sound, const void *data, int sampleCount)
{ {
if (sound.stream.buffer != NULL) if (sound.stream.buffer != NULL)
{ {
StopAudioBuffer(sound.stream.buffer); StopAudioBuffer(sound.stream.buffer);
// TODO: May want to lock/unlock this since this data buffer is read at mixing time // TODO: May want to lock/unlock this since this data buffer is read at mixing time
memcpy(sound.stream.buffer->data, data, samplesCount*ma_get_bytes_per_frame(sound.stream.buffer->converter.config.formatIn, sound.stream.buffer->converter.config.channelsIn)); memcpy(sound.stream.buffer->data, data, sampleCount*ma_get_bytes_per_frame(sound.stream.buffer->converter.config.formatIn, sound.stream.buffer->converter.config.channelsIn));
} }
} }
@ -942,19 +943,19 @@ bool ExportWaveAsCode(Wave wave, const char *fileName)
// NOTE: Text data buffer size is estimated considering wave data size in bytes // NOTE: Text data buffer size is estimated considering wave data size in bytes
// and requiring 6 char bytes for every byte: "0x00, " // and requiring 6 char bytes for every byte: "0x00, "
char *txtData = (char *)RL_CALLOC(6*waveDataSize + 2000, sizeof(char)); char *txtData = (char *)RL_CALLOC(waveDataSize*6 + 2000, sizeof(char));
int bytesCount = 0; int byteCount = 0;
bytesCount += sprintf(txtData + bytesCount, "\n//////////////////////////////////////////////////////////////////////////////////\n"); byteCount += sprintf(txtData + byteCount, "\n//////////////////////////////////////////////////////////////////////////////////\n");
bytesCount += sprintf(txtData + bytesCount, "// //\n"); byteCount += sprintf(txtData + byteCount, "// //\n");
bytesCount += sprintf(txtData + bytesCount, "// WaveAsCode exporter v1.0 - Wave data exported as an array of bytes //\n"); byteCount += sprintf(txtData + byteCount, "// WaveAsCode exporter v1.0 - Wave data exported as an array of bytes //\n");
bytesCount += sprintf(txtData + bytesCount, "// //\n"); byteCount += sprintf(txtData + byteCount, "// //\n");
bytesCount += sprintf(txtData + bytesCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n");
bytesCount += sprintf(txtData + bytesCount, "// feedback and support: ray[at]raylib.com //\n"); byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n");
bytesCount += sprintf(txtData + bytesCount, "// //\n"); byteCount += sprintf(txtData + byteCount, "// //\n");
bytesCount += sprintf(txtData + bytesCount, "// Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n"); byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2021 Ramon Santamaria (@raysan5) //\n");
bytesCount += sprintf(txtData + bytesCount, "// //\n"); byteCount += sprintf(txtData + byteCount, "// //\n");
bytesCount += sprintf(txtData + bytesCount, "//////////////////////////////////////////////////////////////////////////////////\n\n"); byteCount += sprintf(txtData + byteCount, "//////////////////////////////////////////////////////////////////////////////////\n\n");
char varFileName[256] = { 0 }; char varFileName[256] = { 0 };
#if !defined(RAUDIO_STANDALONE) #if !defined(RAUDIO_STANDALONE)
@ -965,17 +966,18 @@ bool ExportWaveAsCode(Wave wave, const char *fileName)
strcpy(varFileName, fileName); strcpy(varFileName, fileName);
#endif #endif
bytesCount += sprintf(txtData + bytesCount, "// Wave data information\n"); byteCount += sprintf(txtData + byteCount, "// Wave data information\n");
bytesCount += sprintf(txtData + bytesCount, "#define %s_FRAME_COUNT %u\n", varFileName, wave.frameCount); byteCount += sprintf(txtData + byteCount, "#define %s_FRAME_COUNT %u\n", varFileName, wave.frameCount);
bytesCount += sprintf(txtData + bytesCount, "#define %s_SAMPLE_COUNT %u\n", varFileName, wave.frameCount*wave.channels); byteCount += sprintf(txtData + byteCount, "#define %s_FRAME_COUNT %u\n", varFileName, wave.frameCount);
bytesCount += sprintf(txtData + bytesCount, "#define %s_SAMPLE_RATE %u\n", varFileName, wave.sampleRate); byteCount += sprintf(txtData + byteCount, "#define %s_SAMPLE_RATE %u\n", varFileName, wave.sampleRate);
bytesCount += sprintf(txtData + bytesCount, "#define %s_SAMPLE_SIZE %u\n", varFileName, wave.sampleSize); byteCount += sprintf(txtData + byteCount, "#define %s_SAMPLE_SIZE %u\n", varFileName, wave.sampleSize);
bytesCount += sprintf(txtData + bytesCount, "#define %s_CHANNELS %u\n\n", varFileName, wave.channels); byteCount += sprintf(txtData + byteCount, "#define %s_CHANNELS %u\n\n", varFileName, wave.channels);
// Write byte data as hexadecimal text // Write byte data as hexadecimal text
bytesCount += sprintf(txtData + bytesCount, "static unsigned char %s_DATA[%i] = { ", varFileName, waveDataSize); // NOTE: Frame data exported is interlaced: Frame01[Sample-Channel01, Sample-Channel02, ...], Frame02[], Frame03[]
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]); byteCount += sprintf(txtData + byteCount, "static unsigned char %s_DATA[%i] = { ", varFileName, waveDataSize);
bytesCount += sprintf(txtData + bytesCount, "0x%x };\n", ((unsigned char *)wave.data)[waveDataSize - 1]); for (int i = 0; i < waveDataSize - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)wave.data)[i]);
byteCount += sprintf(txtData + byteCount, "0x%x };\n", ((unsigned char *)wave.data)[waveDataSize - 1]);
// NOTE: Text data length exported is determined by '\0' (NULL) character // NOTE: Text data length exported is determined by '\0' (NULL) character
success = SaveFileText(fileName, txtData); success = SaveFileText(fileName, txtData);
@ -1504,9 +1506,7 @@ Music LoadMusicStreamFromMemory(const char *fileType, unsigned char *data, int d
// Copy data to allocated memory for default UnloadMusicStream // Copy data to allocated memory for default UnloadMusicStream
unsigned char *newData = (unsigned char *)RL_MALLOC(dataSize); unsigned char *newData = (unsigned char *)RL_MALLOC(dataSize);
int it = dataSize/sizeof(unsigned char); int it = dataSize/sizeof(unsigned char);
for (int i = 0; i < it; i++){ for (int i = 0; i < it; i++) newData[i] = data[i];
newData[i] = data[i];
}
// Memory loaded version for jar_mod_load_file() // Memory loaded version for jar_mod_load_file()
if (dataSize && dataSize < 32*1024*1024) if (dataSize && dataSize < 32*1024*1024)
@ -1656,6 +1656,34 @@ void StopMusicStream(Music music)
} }
} }
// Seek music to a certain position (in seconds)
void SeekMusicStream(Music music, float position)
{
// Seeking is not supported in module formats
if ((music.ctxType == MUSIC_MODULE_XM) || (music.ctxType == MUSIC_MODULE_MOD)) return;
unsigned int positionInFrames = (unsigned int)(position*music.stream.sampleRate);
switch (music.ctxType)
{
#if defined(SUPPORT_FILEFORMAT_WAV)
case MUSIC_AUDIO_WAV: drwav_seek_to_pcm_frame((drwav *)music.ctxData, positionInFrames); break;
#endif
#if defined(SUPPORT_FILEFORMAT_OGG)
case MUSIC_AUDIO_OGG: stb_vorbis_seek_frame((stb_vorbis *)music.ctxData, positionInFrames); break;
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
case MUSIC_AUDIO_FLAC: drflac_seek_to_pcm_frame((drflac *)music.ctxData, positionInFrames); break;
#endif
#if defined(SUPPORT_FILEFORMAT_MP3)
case MUSIC_AUDIO_MP3: drmp3_seek_to_pcm_frame((drmp3 *)music.ctxData, positionInFrames); break;
#endif
default: break;
}
music.stream.buffer->framesProcessed = positionInFrames;
}
// Update (re-fill) music buffers if data already processed // Update (re-fill) music buffers if data already processed
void UpdateMusicStream(Music music) void UpdateMusicStream(Music music)
{ {
@ -1715,7 +1743,7 @@ void UpdateMusicStream(Music music)
#if defined(SUPPORT_FILEFORMAT_XM) #if defined(SUPPORT_FILEFORMAT_XM)
case MUSIC_MODULE_XM: case MUSIC_MODULE_XM:
{ {
// NOTE: Internally we consider 2 channels generation, so samplesCount/2 // NOTE: Internally we consider 2 channels generation, so sampleCount/2
if (AUDIO_DEVICE_FORMAT == ma_format_f32) jar_xm_generate_samples((jar_xm_context_t *)music.ctxData, (float *)pcm, frameCountToStream); if (AUDIO_DEVICE_FORMAT == ma_format_f32) jar_xm_generate_samples((jar_xm_context_t *)music.ctxData, (float *)pcm, frameCountToStream);
else if (AUDIO_DEVICE_FORMAT == ma_format_s16) jar_xm_generate_samples_16bit((jar_xm_context_t *)music.ctxData, (short *)pcm, frameCountToStream); else if (AUDIO_DEVICE_FORMAT == ma_format_s16) jar_xm_generate_samples_16bit((jar_xm_context_t *)music.ctxData, (short *)pcm, frameCountToStream);
else if (AUDIO_DEVICE_FORMAT == ma_format_u8) jar_xm_generate_samples_8bit((jar_xm_context_t *)music.ctxData, (char *)pcm, frameCountToStream); else if (AUDIO_DEVICE_FORMAT == ma_format_u8) jar_xm_generate_samples_8bit((jar_xm_context_t *)music.ctxData, (char *)pcm, frameCountToStream);

View File

@ -171,6 +171,7 @@ void UpdateMusicStream(Music music); // Updates buffe
void StopMusicStream(Music music); // Stop music playing void StopMusicStream(Music music); // Stop music playing
void PauseMusicStream(Music music); // Pause music playing void PauseMusicStream(Music music); // Pause music playing
void ResumeMusicStream(Music music); // Resume playing paused music void ResumeMusicStream(Music music); // Resume playing paused music
void SeekMusicStream(Music music, float position); // Seek music to a position (in seconds)
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)
float GetMusicTimeLength(Music music); // Get music time length (in seconds) float GetMusicTimeLength(Music music); // Get music time length (in seconds)

View File

@ -1,8 +1,8 @@
GLFW_ICON ICON "raylib.ico" GLFW_ICON ICON "raylib.ico"
1 VERSIONINFO 1 VERSIONINFO
FILEVERSION 3,7,0,0 FILEVERSION 4,0,0,0
PRODUCTVERSION 3,7,0,0 PRODUCTVERSION 4,0,0,0
BEGIN BEGIN
BLOCK "StringFileInfo" BLOCK "StringFileInfo"
BEGIN BEGIN
@ -11,12 +11,12 @@ BEGIN
BEGIN BEGIN
//VALUE "CompanyName", "raylib technologies" //VALUE "CompanyName", "raylib technologies"
VALUE "FileDescription", "raylib dynamic library (www.raylib.com)" VALUE "FileDescription", "raylib dynamic library (www.raylib.com)"
VALUE "FileVersion", "3.7.0" VALUE "FileVersion", "4.0.0"
VALUE "InternalName", "raylib.dll" VALUE "InternalName", "raylib.dll"
VALUE "LegalCopyright", "(c) 2021 Ramon Santamaria (@raysan5)" VALUE "LegalCopyright", "(c) 2021 Ramon Santamaria (@raysan5)"
VALUE "OriginalFilename", "raylib.dll" VALUE "OriginalFilename", "raylib.dll"
VALUE "ProductName", "raylib" VALUE "ProductName", "raylib"
VALUE "ProductVersion", "3.7.0" VALUE "ProductVersion", "4.0.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

Binary file not shown.

View File

@ -287,11 +287,11 @@ typedef struct GlyphInfo {
// Font, font texture and GlyphInfo array data // Font, font texture and GlyphInfo array data
typedef struct Font { typedef struct Font {
int baseSize; // Base size (default chars height) int baseSize; // Base size (default chars height)
int charsCount; // Number of characters int glyphCount; // Number of glyph characters
int charsPadding; // Padding around the chars int glyphPadding; // Padding around the glyph characters
Texture2D texture; // Characters texture atlas Texture2D texture; // Texture atlas containing the glyphs
Rectangle *recs; // Characters rectangles in texture Rectangle *recs; // Rectangles in texture for the glyphs
GlyphInfo *chars; // Characters glyphs info data GlyphInfo *glyphs; // Glyphs info data
} Font; } Font;
// Camera, defines position/orientation in 3d space // Camera, defines position/orientation in 3d space
@ -841,7 +841,7 @@ typedef enum {
BLEND_CUSTOM // Belnd textures using custom src/dst factors (use rlSetBlendMode()) BLEND_CUSTOM // Belnd textures using custom src/dst factors (use rlSetBlendMode())
} BlendMode; } BlendMode;
// Gestures // Gesture
// NOTE: It could be used as flags to enable only some gestures // NOTE: It could be used as flags to enable only some gestures
typedef enum { typedef enum {
GESTURE_NONE = 0, // No gesture GESTURE_NONE = 0, // No gesture
@ -1009,6 +1009,7 @@ RLAPI double GetTime(void); // Get elapsed
// Misc. functions // Misc. functions
RLAPI int GetRandomValue(int min, int max); // Get a random value between min and max (both included) RLAPI int GetRandomValue(int min, int max); // Get a random value between min and max (both included)
RLAPI void SetRandomSeed(unsigned int seed); // Set the seed for the random number generator
RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (filename extension defines format) RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (filename extension defines format)
RLAPI void SetConfigFlags(unsigned int flags); // Setup init configuration flags (view FLAGS) RLAPI void SetConfigFlags(unsigned int flags); // Setup init configuration flags (view FLAGS)
@ -1104,14 +1105,16 @@ RLAPI void SetMouseCursor(int cursor); // Set mouse curso
RLAPI int GetTouchX(void); // Get touch position X for touch point 0 (relative to screen size) RLAPI int GetTouchX(void); // Get touch position X for touch point 0 (relative to screen size)
RLAPI int GetTouchY(void); // Get touch position Y for touch point 0 (relative to screen size) RLAPI int GetTouchY(void); // Get touch position Y for touch point 0 (relative to screen size)
RLAPI Vector2 GetTouchPosition(int index); // Get touch position XY for a touch point index (relative to screen size) RLAPI Vector2 GetTouchPosition(int index); // Get touch position XY for a touch point index (relative to screen size)
RLAPI int GetTouchPointId(int index); // Get touch point identifier for given index
RLAPI int GetTouchPointCount(void); // Get number of touch points
RLAPI int GetTouchEvent(void); // Get last touch event registered
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Gestures and Touch Handling Functions (Module: gestures) // Gestures and Touch Handling Functions (Module: rgestures)
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
RLAPI void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags RLAPI void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags
RLAPI bool IsGestureDetected(int gesture); // Check if a gesture have been detected RLAPI bool IsGestureDetected(int gesture); // Check if a gesture have been detected
RLAPI int GetGestureDetected(void); // Get latest detected gesture RLAPI int GetGestureDetected(void); // Get latest detected gesture
RLAPI int GetTouchPointsCount(void); // Get touch points count
RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds
RLAPI Vector2 GetGestureDragVector(void); // Get gesture drag vector RLAPI Vector2 GetGestureDragVector(void); // Get gesture drag vector
RLAPI float GetGestureDragAngle(void); // Get gesture drag angle RLAPI float GetGestureDragAngle(void); // Get gesture drag angle
@ -1119,7 +1122,7 @@ RLAPI Vector2 GetGesturePinchVector(void); // Get gesture pinch del
RLAPI float GetGesturePinchAngle(void); // Get gesture pinch angle RLAPI float GetGesturePinchAngle(void); // Get gesture pinch angle
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Camera System Functions (Module: camera) // Camera System Functions (Module: rcamera)
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
RLAPI void SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available) RLAPI void SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available)
RLAPI void UpdateCamera(Camera *camera); // Update camera position for selected mode RLAPI void UpdateCamera(Camera *camera); // Update camera position for selected mode
@ -1145,7 +1148,7 @@ RLAPI void DrawLineV(Vector2 startPos, Vector2 endPos, Color color);
RLAPI void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line defining thickness RLAPI void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line defining thickness
RLAPI void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line using cubic-bezier curves in-out RLAPI void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line using cubic-bezier curves in-out
RLAPI void DrawLineBezierQuad(Vector2 startPos, Vector2 endPos, Vector2 controlPos, float thick, Color color); //Draw line using quadratic bezier curves with a control point RLAPI void DrawLineBezierQuad(Vector2 startPos, Vector2 endPos, Vector2 controlPos, float thick, Color color); //Draw line using quadratic bezier curves with a control point
RLAPI void DrawLineStrip(Vector2 *points, int pointsCount, Color color); // Draw lines sequence RLAPI void DrawLineStrip(Vector2 *points, int pointCount, Color color); // Draw lines sequence
RLAPI void DrawCircle(int centerX, int centerY, float radius, Color color); // Draw a color-filled circle RLAPI void DrawCircle(int centerX, int centerY, float radius, Color color); // Draw a color-filled circle
RLAPI void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw a piece of a circle RLAPI void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw a piece of a circle
RLAPI void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw circle sector outline RLAPI void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw circle sector outline
@ -1169,8 +1172,8 @@ RLAPI void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Co
RLAPI void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, float lineThick, Color color); // Draw rectangle with rounded edges outline RLAPI void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, float lineThick, Color color); // Draw rectangle with rounded edges outline
RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw a color-filled triangle (vertex in counter-clockwise order!) RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw a color-filled triangle (vertex in counter-clockwise order!)
RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline (vertex in counter-clockwise order!) RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline (vertex in counter-clockwise order!)
RLAPI void DrawTriangleFan(Vector2 *points, int pointsCount, Color color); // Draw a triangle fan defined by points (first vertex is the center) RLAPI void DrawTriangleFan(Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points (first vertex is the center)
RLAPI void DrawTriangleStrip(Vector2 *points, int pointsCount, Color color); // Draw a triangle strip defined by points RLAPI void DrawTriangleStrip(Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points
RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version) RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version)
RLAPI void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a polygon outline of n sides RLAPI void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a polygon outline of n sides
RLAPI void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float lineThick, Color color); // Draw a polygon outline of n sides with extended parameters RLAPI void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float lineThick, Color color); // Draw a polygon outline of n sides with extended parameters
@ -1239,7 +1242,7 @@ RLAPI void ImageColorContrast(Image *image, float contrast);
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 *LoadImageColors(Image image); // Load color data from image as a Color array (RGBA - 32bit) RLAPI Color *LoadImageColors(Image image); // Load color data from image as a Color array (RGBA - 32bit)
RLAPI Color *LoadImagePalette(Image image, int maxPaletteSize, int *colorsCount); // Load colors palette from image as a Color array (RGBA - 32bit) RLAPI Color *LoadImagePalette(Image image, int maxPaletteSize, int *colorCount); // Load colors palette from image as a Color array (RGBA - 32bit)
RLAPI void UnloadImageColors(Color *colors); // Unload color data loaded with LoadImageColors() RLAPI void UnloadImageColors(Color *colors); // Unload color data loaded with LoadImageColors()
RLAPI void UnloadImagePalette(Color *colors); // Unload colors palette loaded with LoadImagePalette() RLAPI void UnloadImagePalette(Color *colors); // Unload colors palette loaded with LoadImagePalette()
RLAPI Rectangle GetImageAlphaBorder(Image image, float threshold); // Get image alpha border rectangle RLAPI Rectangle GetImageAlphaBorder(Image image, float threshold); // Get image alpha border rectangle
@ -1286,7 +1289,7 @@ RLAPI void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Re
RLAPI void DrawTextureTiled(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, float scale, Color tint); // Draw part of a texture (defined by a rectangle) with rotation and scale tiled into dest. RLAPI void DrawTextureTiled(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, float scale, Color tint); // Draw part of a texture (defined by a rectangle) with rotation and scale tiled into dest.
RLAPI void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters RLAPI void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters
RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draws a texture (or part of it) that stretches or shrinks nicely RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draws a texture (or part of it) that stretches or shrinks nicely
RLAPI void DrawTexturePoly(Texture2D texture, Vector2 center, Vector2 *points, Vector2 *texcoords, int pointsCount, Color tint); // Draw a textured polygon RLAPI void DrawTexturePoly(Texture2D texture, Vector2 center, Vector2 *points, Vector2 *texcoords, int pointCount, Color tint); // Draw a textured polygon
// Color/pixel related functions // Color/pixel related functions
RLAPI Color Fade(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f RLAPI Color Fade(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f
@ -1309,12 +1312,12 @@ RLAPI int GetPixelDataSize(int width, int height, int format); // G
// Font loading/unloading functions // Font loading/unloading functions
RLAPI Font GetFontDefault(void); // Get the default Font RLAPI Font GetFontDefault(void); // Get the default Font
RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM) RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM)
RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCount); // Load font from file with extended parameters RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int glyphCount); // Load font from file with extended parameters
RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style) RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style)
RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf' RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int glyphCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf'
RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount, int type); // Load font data for further use RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int glyphCount, int type); // Load font data for further use
RLAPI Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **recs, int charsCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info RLAPI Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **recs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info
RLAPI void UnloadFontData(GlyphInfo *chars, int charsCount); // Unload font chars info data (RAM) RLAPI void UnloadFontData(GlyphInfo *chars, int glyphCount); // Unload font chars info data (RAM)
RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM) RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM)
// Text drawing functions // Text drawing functions
@ -1334,9 +1337,9 @@ RLAPI Rectangle GetGlyphAtlasRec(Font font, int codepoint);
// Text codepoints management functions (unicode characters) // Text codepoints management functions (unicode characters)
RLAPI int *LoadCodepoints(const char *text, int *count); // Load all codepoints from a UTF-8 text string, codepoints count returned by parameter RLAPI int *LoadCodepoints(const char *text, int *count); // Load all codepoints from a UTF-8 text string, codepoints count returned by parameter
RLAPI void UnloadCodepoints(int *codepoints); // Unload codepoints data from memory RLAPI void UnloadCodepoints(int *codepoints); // Unload codepoints data from memory
RLAPI int GetCodepointsCount(const char *text); // Get total number of codepoints in a UTF-8 encoded string RLAPI int GetCodepointCount(const char *text); // Get total number of codepoints in a UTF-8 encoded string
RLAPI int GetCodepoint(const char *text, int *bytesProcessed); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure RLAPI int GetCodepoint(const char *text, int *bytesProcessed); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
RLAPI const char *CodepointToUTF8(int codepoint, int *byteLength); // Encode one codepoint into UTF-8 byte array (array length returned as parameter) RLAPI const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode one codepoint into UTF-8 byte array (array length returned as parameter)
RLAPI char *TextCodepointsToUTF8(int *codepoints, int length); // Encode text as codepoints array into UTF-8 text string (WARNING: memory must be freed!) RLAPI char *TextCodepointsToUTF8(int *codepoints, int length); // Encode text as codepoints array into UTF-8 text string (WARNING: memory must be freed!)
// Text strings management functions (no UTF-8 strings, only byte chars) // Text strings management functions (no UTF-8 strings, only byte chars)
@ -1366,12 +1369,13 @@ RLAPI void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color);
RLAPI void DrawPoint3D(Vector3 position, Color color); // Draw a point in 3D space, actually a small line RLAPI void DrawPoint3D(Vector3 position, Color color); // Draw a point in 3D space, actually a small line
RLAPI void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color); // Draw a circle in 3D world space RLAPI void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color); // Draw a circle in 3D world space
RLAPI void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color); // Draw a color-filled triangle (vertex in counter-clockwise order!) RLAPI void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color); // Draw a color-filled triangle (vertex in counter-clockwise order!)
RLAPI void DrawTriangleStrip3D(Vector3 *points, int pointsCount, Color color); // Draw a triangle strip defined by points RLAPI void DrawTriangleStrip3D(Vector3 *points, int pointCount, Color color); // Draw a triangle strip defined by points
RLAPI void DrawCube(Vector3 position, float width, float height, float length, Color color); // Draw cube RLAPI void DrawCube(Vector3 position, float width, float height, float length, Color color); // Draw cube
RLAPI void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version) RLAPI void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version)
RLAPI void DrawCubeWires(Vector3 position, float width, float height, float length, Color color); // Draw cube wires RLAPI void DrawCubeWires(Vector3 position, float width, float height, float length, Color color); // Draw cube wires
RLAPI void DrawCubeWiresV(Vector3 position, Vector3 size, Color color); // Draw cube wires (Vector version) RLAPI void DrawCubeWiresV(Vector3 position, Vector3 size, Color color); // Draw cube wires (Vector version)
RLAPI void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float length, Color color); // Draw cube textured RLAPI void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float length, Color color); // Draw cube textured
RLAPI void DrawCubeTextureRec(Texture2D texture, Rectangle source, Vector3 position, float width, float height, float length, Color color); // Draw cube with a region of a texture
RLAPI void DrawSphere(Vector3 centerPos, float radius, Color color); // Draw sphere RLAPI void DrawSphere(Vector3 centerPos, float radius, Color color); // Draw sphere
RLAPI void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere with extended parameters RLAPI void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere with extended parameters
RLAPI void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere wires RLAPI void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere wires
@ -1400,7 +1404,7 @@ RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis,
RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires)
RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float size, Color tint); // Draw a billboard texture RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float size, Color tint); // Draw a billboard texture
RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint); // Draw a billboard texture defined by source RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint); // Draw a billboard texture defined by source
RLAPI void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Vector2 origin, float rotation, Color tint); // Draw a billboard texture defined by source and rotation RLAPI void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint); // Draw a billboard texture defined by source and rotation
// Mesh management functions // Mesh management functions
RLAPI void UploadMesh(Mesh *mesh, bool dynamic); // Upload mesh vertex data in GPU and provide VAO/VBO ids RLAPI void UploadMesh(Mesh *mesh, bool dynamic); // Upload mesh vertex data in GPU and provide VAO/VBO ids
@ -1434,7 +1438,7 @@ RLAPI void SetMaterialTexture(Material *material, int mapType, Texture2D texture
RLAPI void SetModelMeshMaterial(Model *model, int meshId, int materialId); // Set material for a mesh RLAPI void SetModelMeshMaterial(Model *model, int meshId, int materialId); // Set material for a mesh
// Model animations loading/unloading functions // Model animations loading/unloading functions
RLAPI ModelAnimation *LoadModelAnimations(const char *fileName, int *animsCount); // Load model animations from file RLAPI ModelAnimation *LoadModelAnimations(const char *fileName, unsigned int *animCount); // Load model animations from file
RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame); // Update model animation pose RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame); // Update model animation pose
RLAPI void UnloadModelAnimation(ModelAnimation anim); // Unload animation data RLAPI void UnloadModelAnimation(ModelAnimation anim); // Unload animation data
RLAPI void UnloadModelAnimations(ModelAnimation* animations, unsigned int count); // Unload animation array data RLAPI void UnloadModelAnimations(ModelAnimation* animations, unsigned int count); // Unload animation array data
@ -1466,7 +1470,7 @@ RLAPI Wave LoadWave(const char *fileName); // Load wa
RLAPI Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load wave from memory buffer, fileType refers to extension: i.e. '.wav' RLAPI Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load wave from memory buffer, fileType refers to extension: i.e. '.wav'
RLAPI Sound LoadSound(const char *fileName); // Load sound from file RLAPI Sound LoadSound(const char *fileName); // Load sound from file
RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data
RLAPI void UpdateSound(Sound sound, const void *data, int samplesCount);// Update sound buffer with new data RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data
RLAPI void UnloadWave(Wave wave); // Unload wave data RLAPI void UnloadWave(Wave wave); // Unload wave data
RLAPI void UnloadSound(Sound sound); // Unload sound RLAPI void UnloadSound(Sound sound); // Unload sound
RLAPI bool ExportWave(Wave wave, const char *fileName); // Export wave data to file, returns true on success RLAPI bool ExportWave(Wave wave, const char *fileName); // Export wave data to file, returns true on success
@ -1499,6 +1503,7 @@ RLAPI void UpdateMusicStream(Music music); // Updates
RLAPI void StopMusicStream(Music music); // Stop music playing RLAPI void StopMusicStream(Music music); // Stop music playing
RLAPI void PauseMusicStream(Music music); // Pause music playing RLAPI void PauseMusicStream(Music music); // Pause music playing
RLAPI void ResumeMusicStream(Music music); // Resume playing paused music RLAPI void ResumeMusicStream(Music music); // Resume playing paused music
RLAPI void SeekMusicStream(Music music, float position); // Seek music to a position (in seconds)
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 float GetMusicTimeLength(Music music); // Get music time length (in seconds) RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds)
@ -1507,7 +1512,7 @@ RLAPI float GetMusicTimePlayed(Music music); // Get cur
// AudioStream management functions // AudioStream management functions
RLAPI AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Load audio stream (to stream raw audio pcm data) RLAPI AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Load audio stream (to stream raw audio pcm data)
RLAPI void UnloadAudioStream(AudioStream stream); // Unload audio stream and free memory RLAPI void UnloadAudioStream(AudioStream stream); // Unload audio stream and free memory
RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int framesCount); // Update audio stream buffers with data RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int frameCount); // Update audio stream buffers with data
RLAPI bool IsAudioStreamProcessed(AudioStream stream); // Check if any audio stream buffers requires refill RLAPI bool IsAudioStreamProcessed(AudioStream stream); // Check if any audio stream buffers requires refill
RLAPI void PlayAudioStream(AudioStream stream); // Play audio stream RLAPI void PlayAudioStream(AudioStream stream); // Play audio stream
RLAPI void PauseAudioStream(AudioStream stream); // Pause audio stream RLAPI void PauseAudioStream(AudioStream stream); // Pause audio stream

View File

@ -1,8 +1,8 @@
GLFW_ICON ICON "raylib.ico" GLFW_ICON ICON "raylib.ico"
1 VERSIONINFO 1 VERSIONINFO
FILEVERSION 3,7,0,0 FILEVERSION 4,0,0,0
PRODUCTVERSION 3,7,0,0 PRODUCTVERSION 4,0,0,0
BEGIN BEGIN
BLOCK "StringFileInfo" BLOCK "StringFileInfo"
BEGIN BEGIN
@ -11,12 +11,12 @@ BEGIN
BEGIN BEGIN
//VALUE "CompanyName", "raylib technologies" //VALUE "CompanyName", "raylib technologies"
VALUE "FileDescription", "raylib application (www.raylib.com)" VALUE "FileDescription", "raylib application (www.raylib.com)"
VALUE "FileVersion", "3.7.0" VALUE "FileVersion", "4.0.0"
VALUE "InternalName", "raylib app" VALUE "InternalName", "raylib app"
VALUE "LegalCopyright", "(c) 2021 Ramon Santamaria (@raysan5)" VALUE "LegalCopyright", "(c) 2021 Ramon Santamaria (@raysan5)"
//VALUE "OriginalFilename", "raylib_app.exe" //VALUE "OriginalFilename", "raylib_app.exe"
VALUE "ProductName", "raylib app" VALUE "ProductName", "raylib app"
VALUE "ProductVersion", "3.7.0" VALUE "ProductVersion", "4.0.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

Binary file not shown.

View File

@ -88,7 +88,6 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if !defined(RL_VECTOR2_TYPE) #if !defined(RL_VECTOR2_TYPE)
// Vector2 type // Vector2 type
typedef struct Vector2 { typedef struct Vector2 {

View File

@ -1,6 +1,6 @@
/******************************************************************************************* /*******************************************************************************************
* *
* raylib.camera - Camera system with multiple modes support * rcamera - Basic camera system for multiple camera modes
* *
* NOTE: Memory footprint of this library is aproximately 52 bytes (global variables) * NOTE: Memory footprint of this library is aproximately 52 bytes (global variables)
* *
@ -41,8 +41,8 @@
* *
**********************************************************************************************/ **********************************************************************************************/
#ifndef CAMERA_H #ifndef RCAMERA_H
#define CAMERA_H #define RCAMERA_H
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros
@ -204,6 +204,7 @@ typedef struct {
float targetDistance; // Camera distance from position to target float targetDistance; // Camera distance from position to target
float playerEyesPosition; // Player eyes position from ground (in meters) float playerEyesPosition; // Player eyes position from ground (in meters)
Vector2 angle; // Camera angle in plane XZ Vector2 angle; // Camera angle in plane XZ
Vector2 previousMousePosition; // Previous mouse position
// Camera movement control keys // Camera movement control keys
int moveControl[6]; // Move controls (CAMERA_FIRST_PERSON) int moveControl[6]; // Move controls (CAMERA_FIRST_PERSON)
@ -220,6 +221,7 @@ static CameraData CAMERA = { // Global CAMERA state context
.targetDistance = 0, .targetDistance = 0,
.playerEyesPosition = 1.85f, .playerEyesPosition = 1.85f,
.angle = { 0 }, .angle = { 0 },
.previousMousePosition = { 0 },
.moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' }, .moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' },
.smoothZoomControl = 341, // raylib: KEY_LEFT_CONTROL .smoothZoomControl = 341, // raylib: KEY_LEFT_CONTROL
.altControl = 342, // raylib: KEY_LEFT_ALT .altControl = 342, // raylib: KEY_LEFT_ALT
@ -263,6 +265,8 @@ void SetCameraMode(Camera camera, int mode)
CAMERA.playerEyesPosition = camera.position.y; // Init player eyes position to camera Y position CAMERA.playerEyesPosition = camera.position.y; // Init player eyes position to camera Y position
CAMERA.previousMousePosition = GetMousePosition(); // Init mouse position
// Lock cursor for first person and third person cameras // Lock cursor for first person and third person cameras
if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor(); if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor();
else EnableCursor(); else EnableCursor();
@ -279,7 +283,6 @@ void SetCameraMode(Camera camera, int mode)
void UpdateCamera(Camera *camera) void UpdateCamera(Camera *camera)
{ {
static int swingCounter = 0; // Used for 1st person swinging movement static int swingCounter = 0; // Used for 1st person swinging movement
static Vector2 previousMousePosition = { 0.0f, 0.0f };
// TODO: Compute CAMERA.targetDistance and CAMERA.angle here (?) // TODO: Compute CAMERA.targetDistance and CAMERA.angle here (?)
@ -302,10 +305,10 @@ void UpdateCamera(Camera *camera)
if (CAMERA.mode != CAMERA_CUSTOM) if (CAMERA.mode != CAMERA_CUSTOM)
{ {
mousePositionDelta.x = mousePosition.x - previousMousePosition.x; mousePositionDelta.x = mousePosition.x - CAMERA.previousMousePosition.x;
mousePositionDelta.y = mousePosition.y - previousMousePosition.y; mousePositionDelta.y = mousePosition.y - CAMERA.previousMousePosition.y;
previousMousePosition = mousePosition; CAMERA.previousMousePosition = mousePosition;
} }
// Support for multiple automatic camera modes // Support for multiple automatic camera modes

View File

@ -1,6 +1,6 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raylib.core - Basic functions to manage windows, OpenGL context and input on multiple platforms * rcore - Basic functions to manage windows, OpenGL context and input on multiple platforms
* *
* PLATFORMS SUPPORTED: * PLATFORMS SUPPORTED:
* - PLATFORM_DESKTOP: Windows (Win32, Win64) * - PLATFORM_DESKTOP: Windows (Win32, Win64)
@ -39,10 +39,10 @@
* NOTE: If enabled, uses external module functions to load default raylib font (module: text) * NOTE: If enabled, uses external module functions to load default raylib font (module: text)
* *
* #define SUPPORT_CAMERA_SYSTEM * #define SUPPORT_CAMERA_SYSTEM
* Camera module is included (camera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital * Camera module is included (rcamera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital
* *
* #define SUPPORT_GESTURES_SYSTEM * #define SUPPORT_GESTURES_SYSTEM
* Gestures module is included (gestures.h) to support gestures detection: tap, hold, swipe, drag * Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag
* *
* #define SUPPORT_MOUSE_GESTURES * #define SUPPORT_MOUSE_GESTURES
* Mouse gestures are directly mapped like touches and processed by gestures system. * Mouse gestures are directly mapped like touches and processed by gestures system.
@ -129,12 +129,12 @@
#if defined(SUPPORT_GESTURES_SYSTEM) #if defined(SUPPORT_GESTURES_SYSTEM)
#define GESTURES_IMPLEMENTATION #define GESTURES_IMPLEMENTATION
#include "gestures.h" // Gestures detection functionality #include "rgestures.h" // Gestures detection functionality
#endif #endif
#if defined(SUPPORT_CAMERA_SYSTEM) #if defined(SUPPORT_CAMERA_SYSTEM)
#define CAMERA_IMPLEMENTATION #define CAMERA_IMPLEMENTATION
#include "camera.h" // Camera system functionality #include "rcamera.h" // Camera system functionality
#endif #endif
#if defined(SUPPORT_GIF_RECORDING) #if defined(SUPPORT_GIF_RECORDING)
@ -298,7 +298,7 @@
#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad) #define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
#endif #endif
#ifndef MAX_TOUCH_POINTS #ifndef MAX_TOUCH_POINTS
#define MAX_TOUCH_POINTS 10 // Maximum number of touch points supported #define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
#endif #endif
#ifndef MAX_KEY_PRESSED_QUEUE #ifndef MAX_KEY_PRESSED_QUEUE
#define MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue #define MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue
@ -385,7 +385,7 @@ typedef struct CoreData {
Matrix screenScale; // Matrix to scale screen (framebuffer rendering) Matrix screenScale; // Matrix to scale screen (framebuffer rendering)
char **dropFilesPath; // Store dropped files paths as strings char **dropFilesPath; // Store dropped files paths as strings
int dropFilesCount; // Count dropped files strings int dropFileCount; // Count dropped files strings
} Window; } Window;
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
@ -411,7 +411,7 @@ typedef struct CoreData {
int keyPressedQueue[MAX_KEY_PRESSED_QUEUE]; // Input keys queue int keyPressedQueue[MAX_KEY_PRESSED_QUEUE]; // Input keys queue
int keyPressedQueueCount; // Input keys queue count int keyPressedQueueCount; // Input keys queue count
int charPressedQueue[MAX_CHAR_PRESSED_QUEUE]; // Input characters queue int charPressedQueue[MAX_CHAR_PRESSED_QUEUE]; // Input characters queue (unicode)
int charPressedQueueCount; // Input characters queue count int charPressedQueueCount; // Input characters queue count
#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) #if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
@ -443,6 +443,8 @@ typedef struct CoreData {
#endif #endif
} Mouse; } Mouse;
struct { struct {
int pointCount; // Number of touch points active
int pointId[MAX_TOUCH_POINTS]; // Point identifiers
Vector2 position[MAX_TOUCH_POINTS]; // Touch position on screen Vector2 position[MAX_TOUCH_POINTS]; // Touch position on screen
char currentTouchState[MAX_TOUCH_POINTS]; // Registers current touch state char currentTouchState[MAX_TOUCH_POINTS]; // Registers current touch state
char previousTouchState[MAX_TOUCH_POINTS]; // Registers previous touch state char previousTouchState[MAX_TOUCH_POINTS]; // Registers previous touch state
@ -454,10 +456,10 @@ typedef struct CoreData {
char currentButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Current gamepad buttons state char currentButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Current gamepad buttons state
char previousButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Previous gamepad buttons state char previousButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Previous gamepad buttons state
float axisState[MAX_GAMEPADS][MAX_GAMEPAD_AXIS]; // Gamepad axis state float axisState[MAX_GAMEPADS][MAX_GAMEPAD_AXIS]; // Gamepad axis state
#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) #if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_WEB)
pthread_t threadId; // Gamepad reading thread id pthread_t threadId; // Gamepad reading thread id
int streamId[MAX_GAMEPADS]; // Gamepad device file descriptor int streamId[MAX_GAMEPADS]; // Gamepad device file descriptor
char name[64]; // Gamepad name holder char name[MAX_GAMEPADS][64]; // Gamepad name holder
#endif #endif
} Gamepad; } Gamepad;
} Input; } Input;
@ -481,14 +483,14 @@ typedef struct CoreData {
static CoreData CORE = { 0 }; // Global CORE state context static CoreData CORE = { 0 }; // Global CORE state context
static char **dirFilesPath = NULL; // Store directory files paths as strings static char **dirFilesPath = NULL; // Store directory files paths as strings
static int dirFilesCount = 0; // Count directory files strings static int dirFileCount = 0; // Count directory files strings
#if defined(SUPPORT_SCREEN_CAPTURE) #if defined(SUPPORT_SCREEN_CAPTURE)
static int screenshotCounter = 0; // Screenshots counter static int screenshotCounter = 0; // Screenshots counter
#endif #endif
#if defined(SUPPORT_GIF_RECORDING) #if defined(SUPPORT_GIF_RECORDING)
static int gifFramesCounter = 0; // GIF frames counter static int gifFrameCounter = 0; // GIF frames counter
static bool gifRecording = false; // GIF recording state static bool gifRecording = false; // GIF recording state
static MsfGifState gifState = { 0 }; // MSGIF context state static MsfGifState gifState = { 0 }; // MSGIF context state
#endif #endif
@ -1079,7 +1081,7 @@ bool IsWindowMaximized(void)
bool IsWindowFocused(void) bool IsWindowFocused(void)
{ {
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
return ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) == 0); // TODO! return ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) == 0);
#else #else
return true; return true;
#endif #endif
@ -1926,10 +1928,10 @@ void EndDrawing(void)
if (gifRecording) if (gifRecording)
{ {
#define GIF_RECORD_FRAMERATE 10 #define GIF_RECORD_FRAMERATE 10
gifFramesCounter++; gifFrameCounter++;
// NOTE: We record one gif frame every 10 game frames // NOTE: We record one gif frame every 10 game frames
if ((gifFramesCounter%GIF_RECORD_FRAMERATE) == 0) if ((gifFrameCounter%GIF_RECORD_FRAMERATE) == 0)
{ {
// Get image data for the current frame (from backbuffer) // Get image data for the current frame (from backbuffer)
// NOTE: This process is quite slow... :( // NOTE: This process is quite slow... :(
@ -1939,7 +1941,7 @@ void EndDrawing(void)
RL_FREE(screenData); // Free image data RL_FREE(screenData); // Free image data
} }
if (((gifFramesCounter/15)%2) == 1) if (((gifFrameCounter/15)%2) == 1)
{ {
DrawCircle(30, CORE.Window.screen.height - 20, 10, MAROON); DrawCircle(30, CORE.Window.screen.height - 20, 10, MAROON);
DrawText("GIF RECORDING", 50, CORE.Window.screen.height - 25, 10, RED); DrawText("GIF RECORDING", 50, CORE.Window.screen.height - 25, 10, RED);
@ -1953,9 +1955,9 @@ void EndDrawing(void)
// Draw record/play indicator // Draw record/play indicator
if (eventsRecording) if (eventsRecording)
{ {
gifFramesCounter++; gifFrameCounter++;
if (((gifFramesCounter/15)%2) == 1) if (((gifFrameCounter/15)%2) == 1)
{ {
DrawCircle(30, CORE.Window.screen.height - 20, 10, MAROON); DrawCircle(30, CORE.Window.screen.height - 20, 10, MAROON);
DrawText("EVENTS RECORDING", 50, CORE.Window.screen.height - 25, 10, RED); DrawText("EVENTS RECORDING", 50, CORE.Window.screen.height - 25, 10, RED);
@ -1965,9 +1967,9 @@ void EndDrawing(void)
} }
else if (eventsPlaying) else if (eventsPlaying)
{ {
gifFramesCounter++; gifFrameCounter++;
if (((gifFramesCounter/15)%2) == 1) if (((gifFrameCounter/15)%2) == 1)
{ {
DrawCircle(30, CORE.Window.screen.height - 20, 10, LIME); DrawCircle(30, CORE.Window.screen.height - 20, 10, LIME);
DrawText("EVENTS PLAYING", 50, CORE.Window.screen.height - 25, 10, GREEN); DrawText("EVENTS PLAYING", 50, CORE.Window.screen.height - 25, 10, GREEN);
@ -2667,6 +2669,12 @@ int GetRandomValue(int min, int max)
return (rand()%(abs(max - min) + 1) + min); return (rand()%(abs(max - min) + 1) + min);
} }
// Set the seed for the random number generator
void SetRandomSeed(unsigned int seed)
{
srand(seed);
}
// Check if the file exists // Check if the file exists
bool FileExists(const char *fileName) bool FileExists(const char *fileName)
{ {
@ -2767,9 +2775,9 @@ const char *GetFileNameWithoutExt(const char *filePath)
if (filePath != NULL) strcpy(fileName, GetFileName(filePath)); // Get filename with extension if (filePath != NULL) strcpy(fileName, GetFileName(filePath)); // Get filename with extension
int len = (int)strlen(fileName); int size = (int)strlen(fileName); // Get size in bytes
for (int i = 0; (i < len) && (i < MAX_FILENAMEWITHOUTEXT_LENGTH); i++) for (int i = 0; (i < size) && (i < MAX_FILENAMEWITHOUTEXT_LENGTH); i++)
{ {
if (fileName[i] == '.') if (fileName[i] == '.')
{ {
@ -2895,8 +2903,8 @@ char **GetDirectoryFiles(const char *dirPath, int *fileCount)
} }
else TRACELOG(LOG_WARNING, "FILEIO: Failed to open requested directory"); // Maybe it's a file... else TRACELOG(LOG_WARNING, "FILEIO: Failed to open requested directory"); // Maybe it's a file...
dirFilesCount = counter; dirFileCount = counter;
*fileCount = dirFilesCount; *fileCount = dirFileCount;
return dirFilesPath; return dirFilesPath;
} }
@ -2904,14 +2912,14 @@ char **GetDirectoryFiles(const char *dirPath, int *fileCount)
// Clear directory files paths buffers // Clear directory files paths buffers
void ClearDirectoryFiles(void) void ClearDirectoryFiles(void)
{ {
if (dirFilesCount > 0) if (dirFileCount > 0)
{ {
for (int i = 0; i < MAX_DIRECTORY_FILES; i++) RL_FREE(dirFilesPath[i]); for (int i = 0; i < MAX_DIRECTORY_FILES; i++) RL_FREE(dirFilesPath[i]);
RL_FREE(dirFilesPath); RL_FREE(dirFilesPath);
} }
dirFilesCount = 0; dirFileCount = 0;
} }
// Change working directory, returns true on success // Change working directory, returns true on success
@ -2927,27 +2935,27 @@ bool ChangeDirectory(const char *dir)
// Check if a file has been dropped into window // Check if a file has been dropped into window
bool IsFileDropped(void) bool IsFileDropped(void)
{ {
if (CORE.Window.dropFilesCount > 0) return true; if (CORE.Window.dropFileCount > 0) return true;
else return false; else return false;
} }
// Get dropped files names // Get dropped files names
char **GetDroppedFiles(int *count) char **GetDroppedFiles(int *count)
{ {
*count = CORE.Window.dropFilesCount; *count = CORE.Window.dropFileCount;
return CORE.Window.dropFilesPath; return CORE.Window.dropFilesPath;
} }
// Clear dropped files paths buffer // Clear dropped files paths buffer
void ClearDroppedFiles(void) void ClearDroppedFiles(void)
{ {
if (CORE.Window.dropFilesCount > 0) if (CORE.Window.dropFileCount > 0)
{ {
for (int i = 0; i < CORE.Window.dropFilesCount; i++) RL_FREE(CORE.Window.dropFilesPath[i]); for (int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilesPath[i]);
RL_FREE(CORE.Window.dropFilesPath); RL_FREE(CORE.Window.dropFilesPath);
CORE.Window.dropFilesCount = 0; CORE.Window.dropFileCount = 0;
} }
} }
@ -3271,8 +3279,11 @@ const char *GetGamepadName(int gamepad)
else return NULL; else return NULL;
#endif #endif
#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) #if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
if (CORE.Input.Gamepad.ready[gamepad]) ioctl(CORE.Input.Gamepad.streamId[gamepad], JSIOCGNAME(64), &CORE.Input.Gamepad.name); if (CORE.Input.Gamepad.ready[gamepad]) ioctl(CORE.Input.Gamepad.streamId[gamepad], JSIOCGNAME(64), &CORE.Input.Gamepad.name[gamepad]);
return CORE.Input.Gamepad.name; return CORE.Input.Gamepad.name[gamepad];
#endif
#if defined(PLATFORM_WEB)
return CORE.Input.Gamepad.name[gamepad];
#endif #endif
return NULL; return NULL;
} }
@ -3564,6 +3575,22 @@ Vector2 GetTouchPosition(int index)
return position; return position;
} }
// Get touch point identifier for given index
int GetTouchPointId(int index)
{
int id = -1;
if (index < MAX_TOUCH_POINTS) id = CORE.Input.Touch.pointId[index];
return id;
}
// Get number of touch points
int GetTouchPointCount(void)
{
return CORE.Input.Touch.pointCount;
}
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Definition // Module specific Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -4848,7 +4875,9 @@ static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *
// NOTE: Window resizing not allowed by default // NOTE: Window resizing not allowed by default
static void WindowSizeCallback(GLFWwindow *window, int width, int height) static void WindowSizeCallback(GLFWwindow *window, int width, int height)
{ {
SetupViewport(width, height); // Reset viewport and projection matrix for new size // Reset viewport and projection matrix for new size
SetupViewport(width, height);
CORE.Window.currentFbo.width = width; CORE.Window.currentFbo.width = width;
CORE.Window.currentFbo.height = height; CORE.Window.currentFbo.height = height;
CORE.Window.resizedLastFrame = true; CORE.Window.resizedLastFrame = true;
@ -4858,8 +4887,8 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height)
// Set current screen size // Set current screen size
CORE.Window.screen.width = width; CORE.Window.screen.width = width;
CORE.Window.screen.height = height; CORE.Window.screen.height = height;
// NOTE: Postprocessing texture is not scaled to new size // NOTE: Postprocessing texture is not scaled to new size
} }
// GLFW3 WindowIconify Callback, runs when window is minimized/restored // GLFW3 WindowIconify Callback, runs when window is minimized/restored
@ -4922,7 +4951,7 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
else else
{ {
gifRecording = true; gifRecording = true;
gifFramesCounter = 0; gifFrameCounter = 0;
msf_gif_begin(&gifState, CORE.Window.screen.width, CORE.Window.screen.height); msf_gif_begin(&gifState, CORE.Window.screen.width, CORE.Window.screen.height);
screenshotCounter++; screenshotCounter++;
@ -4997,18 +5026,18 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int
// but future releases may add more actions (i.e. GLFW_REPEAT) // but future releases may add more actions (i.e. GLFW_REPEAT)
CORE.Input.Mouse.currentButtonState[button] = action; CORE.Input.Mouse.currentButtonState[button] = action;
#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) #if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) // PLATFORM_DESKTOP
// Process mouse events as touches to be able to use mouse-gestures // Process mouse events as touches to be able to use mouse-gestures
GestureEvent gestureEvent = { 0 }; GestureEvent gestureEvent = { 0 };
// Register touch actions // Register touch actions
if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) gestureEvent.touchAction = TOUCH_DOWN; if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) gestureEvent.touchAction = TOUCH_ACTION_DOWN;
else if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) gestureEvent.touchAction = TOUCH_UP; else if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) gestureEvent.touchAction = TOUCH_ACTION_UP;
// NOTE: TOUCH_MOVE event is registered in MouseCursorPosCallback() // NOTE: TOUCH_ACTION_MOVE event is registered in MouseCursorPosCallback()
// Assign a pointer ID // Assign a pointer ID
gestureEvent.pointerId[0] = 0; gestureEvent.pointId[0] = 0;
// Register touch points count // Register touch points count
gestureEvent.pointCount = 1; gestureEvent.pointCount = 1;
@ -5032,14 +5061,14 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
CORE.Input.Mouse.currentPosition.y = (float)y; CORE.Input.Mouse.currentPosition.y = (float)y;
CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) #if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) // PLATFORM_DESKTOP
// Process mouse events as touches to be able to use mouse-gestures // Process mouse events as touches to be able to use mouse-gestures
GestureEvent gestureEvent = { 0 }; GestureEvent gestureEvent = { 0 };
gestureEvent.touchAction = TOUCH_MOVE; gestureEvent.touchAction = TOUCH_ACTION_MOVE;
// Assign a pointer ID // Assign a pointer ID
gestureEvent.pointerId[0] = 0; gestureEvent.pointId[0] = 0;
// Register touch points count // Register touch points count
gestureEvent.pointCount = 1; gestureEvent.pointCount = 1;
@ -5085,7 +5114,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths
strcpy(CORE.Window.dropFilesPath[i], paths[i]); strcpy(CORE.Window.dropFilesPath[i], paths[i]);
} }
CORE.Window.dropFilesCount = count; CORE.Window.dropFileCount = count;
} }
#endif #endif
@ -5145,7 +5174,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
/* /*
if (assetsReloadRequired) if (assetsReloadRequired)
{ {
for (int i = 0; i < assetsCount; i++) for (int i = 0; i < assetCount; i++)
{ {
// TODO: Unload old asset if required // TODO: Unload old asset if required
@ -5271,64 +5300,48 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
return 0; return 0;
} }
CORE.Input.Touch.position[0].x = AMotionEvent_getX(event, 0); // Register touch points count
CORE.Input.Touch.position[0].y = AMotionEvent_getY(event, 0); CORE.Input.Touch.pointCount = AMotionEvent_getPointerCount(event);
unsigned int touchCount = AMotionEvent_getPointerCount(event); for (int i = 0; (i < CORE.Input.Touch.pointCount) && (i < MAX_TOUCH_POINTS); i++)
for (int i = 1; i < touchCount && i < MAX_TOUCH_POINTS; i++)
{ {
CORE.Input.Touch.position[i].x = AMotionEvent_getX(event, i); // Register touch points id
CORE.Input.Touch.position[i].y = AMotionEvent_getY(event, i); CORE.Input.Touch.pointId[i] = AMotionEvent_getPointerId(event, i);
// Register touch points position
CORE.Input.Touch.position[i] = (Vector2){ AMotionEvent_getX(event, i), AMotionEvent_getY(event, i) };
// Normalize CORE.Input.Touch.position[x] for screenWidth and screenHeight
CORE.Input.Touch.position[i].x /= (float)GetScreenWidth();
CORE.Input.Touch.position[i].y /= (float)GetScreenHeight();
} }
int32_t action = AMotionEvent_getAction(event); int32_t action = AMotionEvent_getAction(event);
unsigned int flags = action & AMOTION_EVENT_ACTION_MASK; unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
if (flags == AMOTION_EVENT_ACTION_DOWN || flags == AMOTION_EVENT_ACTION_MOVE) if (flags == AMOTION_EVENT_ACTION_DOWN || flags == AMOTION_EVENT_ACTION_MOVE) CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = 1;
{ else if (flags == AMOTION_EVENT_ACTION_UP) CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = 0;
CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = 1;
}
else if (flags == AMOTION_EVENT_ACTION_UP)
{
CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = 0;
}
#if defined(SUPPORT_GESTURES_SYSTEM) #if defined(SUPPORT_GESTURES_SYSTEM) // PLATFORM_ANDROID
GestureEvent gestureEvent = { 0 }; GestureEvent gestureEvent = { 0 };
gestureEvent.pointCount = CORE.Input.Touch.pointCount;
// Register touch actions // Register touch actions
if (flags == AMOTION_EVENT_ACTION_DOWN) gestureEvent.touchAction = TOUCH_DOWN; if (flags == AMOTION_EVENT_ACTION_DOWN) gestureEvent.touchAction = TOUCH_ACTION_DOWN;
else if (flags == AMOTION_EVENT_ACTION_UP) gestureEvent.touchAction = TOUCH_UP; else if (flags == AMOTION_EVENT_ACTION_UP) gestureEvent.touchAction = TOUCH_ACTION_UP;
else if (flags == AMOTION_EVENT_ACTION_MOVE) gestureEvent.touchAction = TOUCH_MOVE; else if (flags == AMOTION_EVENT_ACTION_MOVE) gestureEvent.touchAction = TOUCH_ACTION_MOVE;
else if (flags == AMOTION_EVENT_ACTION_CANCEL) gestureEvent.touchAction = TOUCH_ACTION_CANCEL;
// Register touch points count for (int i = 0; (i < gestureEvent.pointCount) && (i < MAX_TOUCH_POINTS); i++)
// NOTE: Documentation says pointerCount is Always >= 1,
// but in practice it can be 0 or over a million
gestureEvent.pointCount = AMotionEvent_getPointerCount(event);
// Only enable gestures for 1-3 touch points
if ((gestureEvent.pointCount > 0) && (gestureEvent.pointCount < 4))
{ {
// Register touch points id gestureEvent.pointId[i] = CORE.Input.Touch.pointId[i];
// NOTE: Only two points registered gestureEvent.position[i] = CORE.Input.Touch.position[i];
gestureEvent.pointerId[0] = AMotionEvent_getPointerId(event, 0);
gestureEvent.pointerId[1] = AMotionEvent_getPointerId(event, 1);
// Register touch points position
gestureEvent.position[0] = (Vector2){ AMotionEvent_getX(event, 0), AMotionEvent_getY(event, 0) };
gestureEvent.position[1] = (Vector2){ AMotionEvent_getX(event, 1), AMotionEvent_getY(event, 1) };
// Normalize gestureEvent.position[x] for screenWidth and screenHeight
gestureEvent.position[0].x /= (float)GetScreenWidth();
gestureEvent.position[0].y /= (float)GetScreenHeight();
gestureEvent.position[1].x /= (float)GetScreenWidth();
gestureEvent.position[1].y /= (float)GetScreenHeight();
// Gesture data is sent to gestures system for processing
ProcessGestureEvent(gestureEvent);
} }
// Gesture data is sent to gestures system for processing
ProcessGestureEvent(gestureEvent);
#endif #endif
return 0; return 0;
@ -5346,64 +5359,51 @@ static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent
// Register touch input events // Register touch input events
static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData) static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
{ {
for (int i = 0; i < touchEvent->numTouches; i++)
{
if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) CORE.Input.Touch.currentTouchState[i] = 1;
else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) CORE.Input.Touch.currentTouchState[i] = 0;
}
#if defined(SUPPORT_GESTURES_SYSTEM)
GestureEvent gestureEvent = { 0 };
// Register touch actions
if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) gestureEvent.touchAction = TOUCH_DOWN;
else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) gestureEvent.touchAction = TOUCH_UP;
else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) gestureEvent.touchAction = TOUCH_MOVE;
// Register touch points count // Register touch points count
gestureEvent.pointCount = touchEvent->numTouches; CORE.Input.Touch.pointCount = touchEvent->numTouches;
// Register touch points id double canvasWidth = 0.0;
gestureEvent.pointerId[0] = touchEvent->touches[0].identifier; double canvasHeight = 0.0;
gestureEvent.pointerId[1] = touchEvent->touches[1].identifier;
// Register touch points position
// NOTE: Only two points registered
gestureEvent.position[0] = (Vector2){ touchEvent->touches[0].targetX, touchEvent->touches[0].targetY };
gestureEvent.position[1] = (Vector2){ touchEvent->touches[1].targetX, touchEvent->touches[1].targetY };
double canvasWidth, canvasHeight;
// NOTE: emscripten_get_canvas_element_size() returns canvas.width and canvas.height but // NOTE: emscripten_get_canvas_element_size() returns canvas.width and canvas.height but
// we are looking for actual CSS size: canvas.style.width and canvas.style.height // we are looking for actual CSS size: canvas.style.width and canvas.style.height
//EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight); //EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight);
emscripten_get_element_css_size("#canvas", &canvasWidth, &canvasHeight); emscripten_get_element_css_size("#canvas", &canvasWidth, &canvasHeight);
for (int i = 0; (i < CORE.Input.Touch.pointCount) && (i < MAX_TOUCH_POINTS); i++)
{
// Register touch points id
CORE.Input.Touch.pointId[i] = touchEvent->touches[i].identifier;
// Normalize gestureEvent.position[x] for CORE.Window.screen.width and CORE.Window.screen.height // Register touch points position
gestureEvent.position[0].x *= ((float)GetScreenWidth()/(float)canvasWidth); CORE.Input.Touch.position[i] = (Vector2){ touchEvent->touches[i].targetX, touchEvent->touches[i].targetY };
gestureEvent.position[0].y *= ((float)GetScreenHeight()/(float)canvasHeight);
gestureEvent.position[1].x *= ((float)GetScreenWidth()/(float)canvasWidth);
gestureEvent.position[1].y *= ((float)GetScreenHeight()/(float)canvasHeight);
CORE.Input.Touch.position[0] = gestureEvent.position[0]; // Normalize gestureEvent.position[x] for CORE.Window.screen.width and CORE.Window.screen.height
CORE.Input.Touch.position[1] = gestureEvent.position[1]; CORE.Input.Touch.position[i].x *= ((float)GetScreenWidth()/(float)canvasWidth);
CORE.Input.Touch.position[i].y *= ((float)GetScreenHeight()/(float)canvasHeight);
if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) CORE.Input.Touch.currentTouchState[i] = 1;
else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) CORE.Input.Touch.currentTouchState[i] = 0;
}
#if defined(SUPPORT_GESTURES_SYSTEM) // PLATFORM_WEB
GestureEvent gestureEvent = { 0 };
gestureEvent.pointCount = CORE.Input.Touch.pointCount;
// Register touch actions
if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) gestureEvent.touchAction = TOUCH_ACTION_DOWN;
else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) gestureEvent.touchAction = TOUCH_ACTION_UP;
else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) gestureEvent.touchAction = TOUCH_ACTION_MOVE;
else if (eventType == EMSCRIPTEN_EVENT_TOUCHCANCEL) gestureEvent.touchAction = TOUCH_ACTION_CANCEL;
for (int i = 0; (i < gestureEvent.pointCount) && (i < MAX_TOUCH_POINTS); i++)
{
gestureEvent.pointId[i] = CORE.Input.Touch.pointId[i];
gestureEvent.position[i] = CORE.Input.Touch.position[i];
}
// Gesture data is sent to gestures system for processing // Gesture data is sent to gestures system for processing
ProcessGestureEvent(gestureEvent); ProcessGestureEvent(gestureEvent);
#else
// Support only simple touch position
if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART)
{
// Get first touch position
CORE.Input.Touch.position[0] = (Vector2){ touchEvent->touches[0].targetX, touchEvent->touches[0].targetY };
double canvasWidth, canvasHeight;
//EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight);
emscripten_get_element_css_size("#canvas", &canvasWidth, &canvasHeight);
// Normalize gestureEvent.position[x] for screenWidth and screenHeight
CORE.Input.Touch.position[0].x *= ((float)GetScreenWidth()/(float)canvasWidth);
CORE.Input.Touch.position[0].y *= ((float)GetScreenHeight()/(float)canvasHeight);
}
#endif #endif
return 1; return 1;
@ -5421,7 +5421,11 @@ static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadE
for (int i = 0; i < gamepadEvent->numButtons; ++i) TRACELOGD("Button %d: Digital: %d, Analog: %g", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]); for (int i = 0; i < gamepadEvent->numButtons; ++i) TRACELOGD("Button %d: Digital: %d, Analog: %g", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]);
*/ */
if ((gamepadEvent->connected) && (gamepadEvent->index < MAX_GAMEPADS)) CORE.Input.Gamepad.ready[gamepadEvent->index] = true; if ((gamepadEvent->connected) && (gamepadEvent->index < MAX_GAMEPADS))
{
CORE.Input.Gamepad.ready[gamepadEvent->index] = true;
sprintf(CORE.Input.Gamepad.name[gamepadEvent->index],"%s",gamepadEvent->id);
}
else CORE.Input.Gamepad.ready[gamepadEvent->index] = false; else CORE.Input.Gamepad.ready[gamepadEvent->index] = false;
// TODO: Test gamepadEvent->index // TODO: Test gamepadEvent->index
@ -5923,8 +5927,8 @@ static void *EventThread(void *arg)
struct input_event event = { 0 }; struct input_event event = { 0 };
InputEventWorker *worker = (InputEventWorker *)arg; InputEventWorker *worker = (InputEventWorker *)arg;
int touchAction = -1; int touchAction = -1; // 0-TOUCH_ACTION_UP, 1-TOUCH_ACTION_DOWN, 2-TOUCH_ACTION_MOVE
bool gestureUpdate = false; bool gestureUpdate = false; // Flag to note gestures require to update
while (!CORE.Window.shouldClose) while (!CORE.Window.shouldClose)
{ {
@ -5939,10 +5943,8 @@ static void *EventThread(void *arg)
CORE.Input.Mouse.currentPosition.x += event.value; CORE.Input.Mouse.currentPosition.x += event.value;
CORE.Input.Touch.position[0].x = CORE.Input.Mouse.currentPosition.x; CORE.Input.Touch.position[0].x = CORE.Input.Mouse.currentPosition.x;
#if defined(SUPPORT_GESTURES_SYSTEM) touchAction = 2; // TOUCH_ACTION_MOVE
touchAction = TOUCH_MOVE;
gestureUpdate = true; gestureUpdate = true;
#endif
} }
if (event.code == REL_Y) if (event.code == REL_Y)
@ -5950,10 +5952,8 @@ static void *EventThread(void *arg)
CORE.Input.Mouse.currentPosition.y += event.value; CORE.Input.Mouse.currentPosition.y += event.value;
CORE.Input.Touch.position[0].y = CORE.Input.Mouse.currentPosition.y; CORE.Input.Touch.position[0].y = CORE.Input.Mouse.currentPosition.y;
#if defined(SUPPORT_GESTURES_SYSTEM) touchAction = 2; // TOUCH_ACTION_MOVE
touchAction = TOUCH_MOVE;
gestureUpdate = true; gestureUpdate = true;
#endif
} }
if (event.code == REL_WHEEL) CORE.Input.Mouse.currentWheelMove += event.value; if (event.code == REL_WHEEL) CORE.Input.Mouse.currentWheelMove += event.value;
@ -5968,10 +5968,8 @@ static void *EventThread(void *arg)
CORE.Input.Mouse.currentPosition.x = (event.value - worker->absRange.x)*CORE.Window.screen.width/worker->absRange.width; // Scale acording to absRange CORE.Input.Mouse.currentPosition.x = (event.value - worker->absRange.x)*CORE.Window.screen.width/worker->absRange.width; // Scale acording to absRange
CORE.Input.Touch.position[0].x = (event.value - worker->absRange.x)*CORE.Window.screen.width/worker->absRange.width; // Scale acording to absRange CORE.Input.Touch.position[0].x = (event.value - worker->absRange.x)*CORE.Window.screen.width/worker->absRange.width; // Scale acording to absRange
#if defined(SUPPORT_GESTURES_SYSTEM) touchAction = 2; // TOUCH_ACTION_MOVE
touchAction = TOUCH_MOVE;
gestureUpdate = true; gestureUpdate = true;
#endif
} }
if (event.code == ABS_Y) if (event.code == ABS_Y)
@ -5979,10 +5977,8 @@ static void *EventThread(void *arg)
CORE.Input.Mouse.currentPosition.y = (event.value - worker->absRange.y)*CORE.Window.screen.height/worker->absRange.height; // Scale acording to absRange CORE.Input.Mouse.currentPosition.y = (event.value - worker->absRange.y)*CORE.Window.screen.height/worker->absRange.height; // Scale acording to absRange
CORE.Input.Touch.position[0].y = (event.value - worker->absRange.y)*CORE.Window.screen.height/worker->absRange.height; // Scale acording to absRange CORE.Input.Touch.position[0].y = (event.value - worker->absRange.y)*CORE.Window.screen.height/worker->absRange.height; // Scale acording to absRange
#if defined(SUPPORT_GESTURES_SYSTEM) touchAction = 2; // TOUCH_ACTION_MOVE
touchAction = TOUCH_MOVE;
gestureUpdate = true; gestureUpdate = true;
#endif
} }
// Multitouch movement // Multitouch movement
@ -6017,20 +6013,16 @@ static void *EventThread(void *arg)
{ {
CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 0; CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 0;
#if defined(SUPPORT_GESTURES_SYSTEM) touchAction = 0; // TOUCH_ACTION_UP
touchAction = TOUCH_UP;
gestureUpdate = true; gestureUpdate = true;
#endif
} }
if (event.value && !previousMouseLeftButtonState) if (event.value && !previousMouseLeftButtonState)
{ {
CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 1; CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 1;
#if defined(SUPPORT_GESTURES_SYSTEM) touchAction = 1; // TOUCH_ACTION_DOWN
touchAction = TOUCH_DOWN;
gestureUpdate = true; gestureUpdate = true;
#endif
} }
} }
@ -6044,11 +6036,9 @@ static void *EventThread(void *arg)
{ {
CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = event.value; CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = event.value;
#if defined(SUPPORT_GESTURES_SYSTEM) if (event.value > 0) touchAction = 1; // TOUCH_ACTION_DOWN
if (event.value > 0) touchAction = TOUCH_DOWN; else touchAction = 0; // TOUCH_ACTION_UP
else touchAction = TOUCH_UP;
gestureUpdate = true; gestureUpdate = true;
#endif
} }
if (event.code == BTN_RIGHT) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_RIGHT] = event.value; if (event.code == BTN_RIGHT) CORE.Input.Mouse.currentButtonStateEvdev[MOUSE_BUTTON_RIGHT] = event.value;
@ -6069,7 +6059,7 @@ static void *EventThread(void *arg)
if (CORE.Input.Mouse.currentPosition.y > CORE.Window.screen.height/CORE.Input.Mouse.scale.y) CORE.Input.Mouse.currentPosition.y = CORE.Window.screen.height/CORE.Input.Mouse.scale.y; if (CORE.Input.Mouse.currentPosition.y > CORE.Window.screen.height/CORE.Input.Mouse.scale.y) CORE.Input.Mouse.currentPosition.y = CORE.Window.screen.height/CORE.Input.Mouse.scale.y;
} }
#if defined(SUPPORT_GESTURES_SYSTEM) #if defined(SUPPORT_GESTURES_SYSTEM) // PLATFORM_RPI, PLATFORM_DRM
if (gestureUpdate) if (gestureUpdate)
{ {
GestureEvent gestureEvent = { 0 }; GestureEvent gestureEvent = { 0 };
@ -6082,10 +6072,10 @@ static void *EventThread(void *arg)
if (CORE.Input.Touch.position[2].x >= 0) gestureEvent.pointCount++; if (CORE.Input.Touch.position[2].x >= 0) gestureEvent.pointCount++;
if (CORE.Input.Touch.position[3].x >= 0) gestureEvent.pointCount++; if (CORE.Input.Touch.position[3].x >= 0) gestureEvent.pointCount++;
gestureEvent.pointerId[0] = 0; gestureEvent.pointId[0] = 0;
gestureEvent.pointerId[1] = 1; gestureEvent.pointId[1] = 1;
gestureEvent.pointerId[2] = 2; gestureEvent.pointId[2] = 2;
gestureEvent.pointerId[3] = 3; gestureEvent.pointId[3] = 3;
gestureEvent.position[0] = CORE.Input.Touch.position[0]; gestureEvent.position[0] = CORE.Input.Touch.position[0];
gestureEvent.position[1] = CORE.Input.Touch.position[1]; gestureEvent.position[1] = CORE.Input.Touch.position[1];
@ -6627,7 +6617,7 @@ static void PlayAutomationEvent(unsigned int frame)
{ {
CORE.Input.Gamepad.axisState[events[i].params[0]][events[i].params[1]] = ((float)events[i].params[2]/32768.0f); CORE.Input.Gamepad.axisState[events[i].params[0]][events[i].params[1]] = ((float)events[i].params[2]/32768.0f);
} break; } break;
case INPUT_GESTURE: GESTURES.current = events[i].params[0]; break; // param[0]: gesture (enum Gesture) -> gestures.h: GESTURES.current case INPUT_GESTURE: GESTURES.current = events[i].params[0]; break; // param[0]: gesture (enum Gesture) -> rgestures.h: GESTURES.current
// Window events // Window events
case WINDOW_CLOSE: CORE.Window.shouldClose = true; break; case WINDOW_CLOSE: CORE.Window.shouldClose = true; break;

View File

@ -1,6 +1,6 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raylib.gestures - Gestures system, gestures processing based on input events (touch/mouse) * rgestures - Gestures system, gestures processing based on input events (touch/mouse)
* *
* NOTE: Memory footprint of this library is aproximately 128 bytes (global variables) * NOTE: Memory footprint of this library is aproximately 128 bytes (global variables)
* *
@ -43,8 +43,8 @@
* *
**********************************************************************************************/ **********************************************************************************************/
#ifndef GESTURES_H #ifndef RGESTURES_H
#define GESTURES_H #define RGESTURES_H
#ifndef PI #ifndef PI
#define PI 3.14159265358979323846 #define PI 3.14159265358979323846
@ -53,50 +53,60 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
//... #ifndef MAX_TOUCH_POINTS
#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
#endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
// NOTE: Below types are required for GESTURES_STANDALONE usage // NOTE: Below types are required for GESTURES_STANDALONE usage
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(GESTURES_STANDALONE) // Boolean type
#ifndef __cplusplus #if defined(__STDC__) && __STDC_VERSION__ >= 199901L
// Boolean type #include <stdbool.h>
typedef enum { false, true } bool; #elif !defined(__cplusplus) && !defined(bool) && !defined(RL_BOOL_TYPE)
#endif typedef enum bool { false, true } bool;
// Vector2 type
typedef struct Vector2 {
float x;
float y;
} Vector2;
// Gestures type
// NOTE: It could be used as flags to enable only some gestures
typedef enum {
GESTURE_NONE = 0,
GESTURE_TAP = 1,
GESTURE_DOUBLETAP = 2,
GESTURE_HOLD = 4,
GESTURE_DRAG = 8,
GESTURE_SWIPE_RIGHT = 16,
GESTURE_SWIPE_LEFT = 32,
GESTURE_SWIPE_UP = 64,
GESTURE_SWIPE_DOWN = 128,
GESTURE_PINCH_IN = 256,
GESTURE_PINCH_OUT = 512
} Gestures;
#endif #endif
typedef enum { TOUCH_UP, TOUCH_DOWN, TOUCH_MOVE } TouchAction; #if !defined(RL_VECTOR2_TYPE)
// Vector2 type
typedef struct Vector2 {
float x;
float y;
} Vector2;
#endif
#if defined(GESTURES_STANDALONE)
// Gestures type
// NOTE: It could be used as flags to enable only some gestures
typedef enum {
GESTURE_NONE = 0,
GESTURE_TAP = 1,
GESTURE_DOUBLETAP = 2,
GESTURE_HOLD = 4,
GESTURE_DRAG = 8,
GESTURE_SWIPE_RIGHT = 16,
GESTURE_SWIPE_LEFT = 32,
GESTURE_SWIPE_UP = 64,
GESTURE_SWIPE_DOWN = 128,
GESTURE_PINCH_IN = 256,
GESTURE_PINCH_OUT = 512
} Gesture;
#endif
typedef enum {
TOUCH_ACTION_UP = 0,
TOUCH_ACTION_DOWN,
TOUCH_ACTION_MOVE,
TOUCH_ACTION_CANCEL
} TouchAction;
// Gesture event // Gesture event
// NOTE: MAX_TOUCH_POINTS fixed to 4
typedef struct { typedef struct {
int touchAction; int touchAction;
int pointCount; int pointCount;
int pointerId[4]; int pointId[MAX_TOUCH_POINTS];
Vector2 position[4]; Vector2 position[MAX_TOUCH_POINTS];
} GestureEvent; } GestureEvent;
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -114,11 +124,12 @@ extern "C" { // Prevents name mangling of functions
void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures
void UpdateGestures(void); // Update gestures detected (must be called every frame) void UpdateGestures(void); // Update gestures detected (must be called every frame)
#if defined(GESTURES_STANDALONE) #if defined(GESTURES_STANDALONE)
void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags
bool IsGestureDetected(int gesture); // Check if a gesture have been detected bool IsGestureDetected(int gesture); // Check if a gesture have been detected
int GetGestureDetected(void); // Get latest detected gesture int GetGestureDetected(void); // Get latest detected gesture
int GetTouchPointsCount(void); // Get touch points count
float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds
Vector2 GetGestureDragVector(void); // Get gesture drag vector Vector2 GetGestureDragVector(void); // Get gesture drag vector
float GetGestureDragAngle(void); // Get gesture drag angle float GetGestureDragAngle(void); // Get gesture drag angle
@ -193,7 +204,7 @@ typedef struct {
Vector2 downDragPosition; // Touch drag position Vector2 downDragPosition; // Touch drag position
Vector2 moveDownPositionA; // First touch down position on move Vector2 moveDownPositionA; // First touch down position on move
Vector2 moveDownPositionB; // Second touch down position on move Vector2 moveDownPositionB; // Second touch down position on move
int tapCounter; // TAP counter (one tap implies TOUCH_DOWN and TOUCH_UP actions) int tapCounter; // TAP counter (one tap implies TOUCH_ACTION_DOWN and TOUCH_ACTION_UP actions)
} Touch; } Touch;
struct { struct {
bool resetRequired; // HOLD reset to get first touch point again bool resetRequired; // HOLD reset to get first touch point again
@ -221,19 +232,16 @@ typedef struct {
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
static GesturesData GESTURES = { static GesturesData GESTURES = {
.Touch.firstId = -1, .Touch.firstId = -1,
.current = GESTURE_NONE, // No current gesture detected .current = GESTURE_NONE, // No current gesture detected
.enabledFlags = 0b0000001111111111 // All gestures supported by default .enabledFlags = 0b0000001111111111 // All gestures supported by default
}; };
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Declaration // Module specific Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(GESTURES_STANDALONE) static float rgVector2Angle(Vector2 initialPosition, Vector2 finalPosition);
// Some required math functions provided by raymath.h static float rgVector2Distance(Vector2 v1, Vector2 v2);
static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition); static double rgGetCurrentTime(void);
static float Vector2Distance(Vector2 v1, Vector2 v2);
#endif
static double GetCurrentTime(void);
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition // Module Functions Definition
@ -258,14 +266,14 @@ void ProcessGestureEvent(GestureEvent event)
// Reset required variables // Reset required variables
GESTURES.Touch.pointCount = event.pointCount; // Required on UpdateGestures() GESTURES.Touch.pointCount = event.pointCount; // Required on UpdateGestures()
if (GESTURES.Touch.pointCount < 2) if (GESTURES.Touch.pointCount == 1) // One touch point
{ {
if (event.touchAction == TOUCH_DOWN) if (event.touchAction == TOUCH_ACTION_DOWN)
{ {
GESTURES.Touch.tapCounter++; // Tap counter GESTURES.Touch.tapCounter++; // Tap counter
// Detect GESTURE_DOUBLE_TAP // Detect GESTURE_DOUBLE_TAP
if ((GESTURES.current == GESTURE_NONE) && (GESTURES.Touch.tapCounter >= 2) && ((GetCurrentTime() - GESTURES.Touch.eventTime) < TAP_TIMEOUT) && (Vector2Distance(GESTURES.Touch.downPositionA, event.position[0]) < DOUBLETAP_RANGE)) if ((GESTURES.current == GESTURE_NONE) && (GESTURES.Touch.tapCounter >= 2) && ((rgGetCurrentTime() - GESTURES.Touch.eventTime) < TAP_TIMEOUT) && (rgVector2Distance(GESTURES.Touch.downPositionA, event.position[0]) < DOUBLETAP_RANGE))
{ {
GESTURES.current = GESTURE_DOUBLETAP; GESTURES.current = GESTURE_DOUBLETAP;
GESTURES.Touch.tapCounter = 0; GESTURES.Touch.tapCounter = 0;
@ -280,27 +288,27 @@ void ProcessGestureEvent(GestureEvent event)
GESTURES.Touch.downDragPosition = event.position[0]; GESTURES.Touch.downDragPosition = event.position[0];
GESTURES.Touch.upPosition = GESTURES.Touch.downPositionA; GESTURES.Touch.upPosition = GESTURES.Touch.downPositionA;
GESTURES.Touch.eventTime = GetCurrentTime(); GESTURES.Touch.eventTime = rgGetCurrentTime();
GESTURES.Touch.firstId = event.pointerId[0]; GESTURES.Touch.firstId = event.pointId[0];
GESTURES.Drag.vector = (Vector2){ 0.0f, 0.0f }; GESTURES.Drag.vector = (Vector2){ 0.0f, 0.0f };
} }
else if (event.touchAction == TOUCH_UP) else if (event.touchAction == TOUCH_ACTION_UP)
{ {
if (GESTURES.current == GESTURE_DRAG) GESTURES.Touch.upPosition = event.position[0]; if (GESTURES.current == GESTURE_DRAG) GESTURES.Touch.upPosition = event.position[0];
// NOTE: GESTURES.Drag.intensity dependend on the resolution of the screen // NOTE: GESTURES.Drag.intensity dependend on the resolution of the screen
GESTURES.Drag.distance = Vector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition); GESTURES.Drag.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition);
GESTURES.Drag.intensity = GESTURES.Drag.distance/(float)((GetCurrentTime() - GESTURES.Swipe.timeDuration)); GESTURES.Drag.intensity = GESTURES.Drag.distance/(float)((rgGetCurrentTime() - GESTURES.Swipe.timeDuration));
GESTURES.Swipe.start = false; GESTURES.Swipe.start = false;
// Detect GESTURE_SWIPE // Detect GESTURE_SWIPE
if ((GESTURES.Drag.intensity > FORCE_TO_SWIPE) && (GESTURES.Touch.firstId == event.pointerId[0])) if ((GESTURES.Drag.intensity > FORCE_TO_SWIPE) && (GESTURES.Touch.firstId == event.pointId[0]))
{ {
// NOTE: Angle should be inverted in Y // NOTE: Angle should be inverted in Y
GESTURES.Drag.angle = 360.0f - Vector2Angle(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition); GESTURES.Drag.angle = 360.0f - rgVector2Angle(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition);
if ((GESTURES.Drag.angle < 30) || (GESTURES.Drag.angle > 330)) GESTURES.current = GESTURE_SWIPE_RIGHT; // Right if ((GESTURES.Drag.angle < 30) || (GESTURES.Drag.angle > 330)) GESTURES.current = GESTURE_SWIPE_RIGHT; // Right
else if ((GESTURES.Drag.angle > 30) && (GESTURES.Drag.angle < 120)) GESTURES.current = GESTURE_SWIPE_UP; // Up else if ((GESTURES.Drag.angle > 30) && (GESTURES.Drag.angle < 120)) GESTURES.current = GESTURE_SWIPE_UP; // Up
@ -320,13 +328,13 @@ void ProcessGestureEvent(GestureEvent event)
GESTURES.Touch.downDragPosition = (Vector2){ 0.0f, 0.0f }; GESTURES.Touch.downDragPosition = (Vector2){ 0.0f, 0.0f };
GESTURES.Touch.pointCount = 0; GESTURES.Touch.pointCount = 0;
} }
else if (event.touchAction == TOUCH_MOVE) else if (event.touchAction == TOUCH_ACTION_MOVE)
{ {
if (GESTURES.current == GESTURE_DRAG) GESTURES.Touch.eventTime = GetCurrentTime(); if (GESTURES.current == GESTURE_DRAG) GESTURES.Touch.eventTime = rgGetCurrentTime();
if (!GESTURES.Swipe.start) if (!GESTURES.Swipe.start)
{ {
GESTURES.Swipe.timeDuration = GetCurrentTime(); GESTURES.Swipe.timeDuration = rgGetCurrentTime();
GESTURES.Swipe.start = true; GESTURES.Swipe.start = true;
} }
@ -339,9 +347,9 @@ void ProcessGestureEvent(GestureEvent event)
GESTURES.Hold.resetRequired = false; GESTURES.Hold.resetRequired = false;
// Detect GESTURE_DRAG // Detect GESTURE_DRAG
if (Vector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_DRAG) if (rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_DRAG)
{ {
GESTURES.Touch.eventTime = GetCurrentTime(); GESTURES.Touch.eventTime = rgGetCurrentTime();
GESTURES.current = GESTURE_DRAG; GESTURES.current = GESTURE_DRAG;
} }
} }
@ -350,24 +358,24 @@ void ProcessGestureEvent(GestureEvent event)
GESTURES.Drag.vector.y = GESTURES.Touch.moveDownPositionA.y - GESTURES.Touch.downDragPosition.y; GESTURES.Drag.vector.y = GESTURES.Touch.moveDownPositionA.y - GESTURES.Touch.downDragPosition.y;
} }
} }
else // Two touch points else if (GESTURES.Touch.pointCount == 2) // Two touch points
{ {
if (event.touchAction == TOUCH_DOWN) if (event.touchAction == TOUCH_ACTION_DOWN)
{ {
GESTURES.Touch.downPositionA = event.position[0]; GESTURES.Touch.downPositionA = event.position[0];
GESTURES.Touch.downPositionB = event.position[1]; GESTURES.Touch.downPositionB = event.position[1];
//GESTURES.Pinch.distance = Vector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.downPositionB); //GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.downPositionB);
GESTURES.Pinch.vector.x = GESTURES.Touch.downPositionB.x - GESTURES.Touch.downPositionA.x; GESTURES.Pinch.vector.x = GESTURES.Touch.downPositionB.x - GESTURES.Touch.downPositionA.x;
GESTURES.Pinch.vector.y = GESTURES.Touch.downPositionB.y - GESTURES.Touch.downPositionA.y; GESTURES.Pinch.vector.y = GESTURES.Touch.downPositionB.y - GESTURES.Touch.downPositionA.y;
GESTURES.current = GESTURE_HOLD; GESTURES.current = GESTURE_HOLD;
GESTURES.Hold.timeDuration = GetCurrentTime(); GESTURES.Hold.timeDuration = rgGetCurrentTime();
} }
else if (event.touchAction == TOUCH_MOVE) else if (event.touchAction == TOUCH_ACTION_MOVE)
{ {
GESTURES.Pinch.distance = Vector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB); GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB);
GESTURES.Touch.downPositionA = GESTURES.Touch.moveDownPositionA; GESTURES.Touch.downPositionA = GESTURES.Touch.moveDownPositionA;
GESTURES.Touch.downPositionB = GESTURES.Touch.moveDownPositionB; GESTURES.Touch.downPositionB = GESTURES.Touch.moveDownPositionB;
@ -378,21 +386,21 @@ void ProcessGestureEvent(GestureEvent event)
GESTURES.Pinch.vector.x = GESTURES.Touch.moveDownPositionB.x - GESTURES.Touch.moveDownPositionA.x; GESTURES.Pinch.vector.x = GESTURES.Touch.moveDownPositionB.x - GESTURES.Touch.moveDownPositionA.x;
GESTURES.Pinch.vector.y = GESTURES.Touch.moveDownPositionB.y - GESTURES.Touch.moveDownPositionA.y; GESTURES.Pinch.vector.y = GESTURES.Touch.moveDownPositionB.y - GESTURES.Touch.moveDownPositionA.y;
if ((Vector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_PINCH) || (Vector2Distance(GESTURES.Touch.downPositionB, GESTURES.Touch.moveDownPositionB) >= MINIMUM_PINCH)) if ((rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_PINCH) || (rgVector2Distance(GESTURES.Touch.downPositionB, GESTURES.Touch.moveDownPositionB) >= MINIMUM_PINCH))
{ {
if ((Vector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB) - GESTURES.Pinch.distance) < 0) GESTURES.current = GESTURE_PINCH_IN; if ((rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB) - GESTURES.Pinch.distance) < 0) GESTURES.current = GESTURE_PINCH_IN;
else GESTURES.current = GESTURE_PINCH_OUT; else GESTURES.current = GESTURE_PINCH_OUT;
} }
else else
{ {
GESTURES.current = GESTURE_HOLD; GESTURES.current = GESTURE_HOLD;
GESTURES.Hold.timeDuration = GetCurrentTime(); GESTURES.Hold.timeDuration = rgGetCurrentTime();
} }
// NOTE: Angle should be inverted in Y // NOTE: Angle should be inverted in Y
GESTURES.Pinch.angle = 360.0f - Vector2Angle(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB); GESTURES.Pinch.angle = 360.0f - rgVector2Angle(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB);
} }
else if (event.touchAction == TOUCH_UP) else if (event.touchAction == TOUCH_ACTION_UP)
{ {
GESTURES.Pinch.distance = 0.0f; GESTURES.Pinch.distance = 0.0f;
GESTURES.Pinch.angle = 0.0f; GESTURES.Pinch.angle = 0.0f;
@ -402,6 +410,10 @@ void ProcessGestureEvent(GestureEvent event)
GESTURES.current = GESTURE_NONE; GESTURES.current = GESTURE_NONE;
} }
} }
else if (GESTURES.Touch.pointCount > 2) // More than two touch points
{
// TODO.
}
} }
// Update gestures detected (must be called every frame) // Update gestures detected (must be called every frame)
@ -413,13 +425,13 @@ void UpdateGestures(void)
if (((GESTURES.current == GESTURE_TAP) || (GESTURES.current == GESTURE_DOUBLETAP)) && (GESTURES.Touch.pointCount < 2)) if (((GESTURES.current == GESTURE_TAP) || (GESTURES.current == GESTURE_DOUBLETAP)) && (GESTURES.Touch.pointCount < 2))
{ {
GESTURES.current = GESTURE_HOLD; GESTURES.current = GESTURE_HOLD;
GESTURES.Hold.timeDuration = GetCurrentTime(); GESTURES.Hold.timeDuration = rgGetCurrentTime();
} }
if (((GetCurrentTime() - GESTURES.Touch.eventTime) > TAP_TIMEOUT) && (GESTURES.current == GESTURE_DRAG) && (GESTURES.Touch.pointCount < 2)) if (((rgGetCurrentTime() - GESTURES.Touch.eventTime) > TAP_TIMEOUT) && (GESTURES.current == GESTURE_DRAG) && (GESTURES.Touch.pointCount < 2))
{ {
GESTURES.current = GESTURE_HOLD; GESTURES.current = GESTURE_HOLD;
GESTURES.Hold.timeDuration = GetCurrentTime(); GESTURES.Hold.timeDuration = rgGetCurrentTime();
GESTURES.Hold.resetRequired = true; GESTURES.Hold.resetRequired = true;
} }
@ -430,14 +442,6 @@ void UpdateGestures(void)
} }
} }
// Get number of touch points
int GetTouchPointsCount(void)
{
// NOTE: point count is calculated when ProcessGestureEvent(GestureEvent event) is called
return GESTURES.Touch.pointCount;
}
// Get latest detected gesture // Get latest detected gesture
int GetGestureDetected(void) int GetGestureDetected(void)
{ {
@ -452,7 +456,7 @@ float GetGestureHoldDuration(void)
double time = 0.0; double time = 0.0;
if (GESTURES.current == GESTURE_HOLD) time = GetCurrentTime() - GESTURES.Hold.timeDuration; if (GESTURES.current == GESTURE_HOLD) time = rgGetCurrentTime() - GESTURES.Hold.timeDuration;
return (float)time; return (float)time;
} }
@ -460,7 +464,7 @@ float GetGestureHoldDuration(void)
// Get drag vector (between initial touch point to current) // Get drag vector (between initial touch point to current)
Vector2 GetGestureDragVector(void) Vector2 GetGestureDragVector(void)
{ {
// NOTE: drag vector is calculated on one touch points TOUCH_MOVE // NOTE: drag vector is calculated on one touch points TOUCH_ACTION_MOVE
return GESTURES.Drag.vector; return GESTURES.Drag.vector;
} }
@ -469,7 +473,7 @@ Vector2 GetGestureDragVector(void)
// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise // NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise
float GetGestureDragAngle(void) float GetGestureDragAngle(void)
{ {
// NOTE: drag angle is calculated on one touch points TOUCH_UP // NOTE: drag angle is calculated on one touch points TOUCH_ACTION_UP
return GESTURES.Drag.angle; return GESTURES.Drag.angle;
} }
@ -477,8 +481,7 @@ float GetGestureDragAngle(void)
// Get distance between two pinch points // Get distance between two pinch points
Vector2 GetGesturePinchVector(void) Vector2 GetGesturePinchVector(void)
{ {
// NOTE: The position values used for GESTURES.Pinch.distance are not modified like the position values of [core.c]-->GetTouchPosition(int index) // NOTE: Pinch distance is calculated on two touch points TOUCH_ACTION_MOVE
// NOTE: pinch distance is calculated on two touch points TOUCH_MOVE
return GESTURES.Pinch.vector; return GESTURES.Pinch.vector;
} }
@ -487,7 +490,7 @@ Vector2 GetGesturePinchVector(void)
// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise // NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise
float GetGesturePinchAngle(void) float GetGesturePinchAngle(void)
{ {
// NOTE: pinch angle is calculated on two touch points TOUCH_MOVE // NOTE: pinch angle is calculated on two touch points TOUCH_ACTION_MOVE
return GESTURES.Pinch.angle; return GESTURES.Pinch.angle;
} }
@ -495,9 +498,8 @@ float GetGesturePinchAngle(void)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Definition // Module specific Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(GESTURES_STANDALONE)
// Get angle from two-points vector with X-axis // Get angle from two-points vector with X-axis
static float Vector2Angle(Vector2 v1, Vector2 v2) static float rgVector2Angle(Vector2 v1, Vector2 v2)
{ {
float angle = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI); float angle = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI);
@ -507,7 +509,7 @@ static float Vector2Angle(Vector2 v1, Vector2 v2)
} }
// Calculate distance between two Vector2 // Calculate distance between two Vector2
static float Vector2Distance(Vector2 v1, Vector2 v2) static float rgVector2Distance(Vector2 v1, Vector2 v2)
{ {
float result; float result;
@ -518,10 +520,9 @@ static float Vector2Distance(Vector2 v1, Vector2 v2)
return result; return result;
} }
#endif
// Time measure returned are milliseconds // Time measure returned are milliseconds
static double GetCurrentTime(void) static double rgGetCurrentTime(void)
{ {
double time = 0; double time = 0;

View File

@ -279,7 +279,7 @@ typedef enum {
// Dynamic vertex buffers (position + texcoords + colors + indices arrays) // Dynamic vertex buffers (position + texcoords + colors + indices arrays)
typedef struct rlVertexBuffer { typedef struct rlVertexBuffer {
int elementsCount; // Number of elements in the buffer (QUADS) int elementCount; // Number of elements in the buffer (QUADS)
int vCounter; // Vertex position counter to process (and draw) from full buffer int vCounter; // Vertex position counter to process (and draw) from full buffer
int tcCounter; // Vertex texcoord counter to process (and draw) from full buffer int tcCounter; // Vertex texcoord counter to process (and draw) from full buffer
@ -316,12 +316,12 @@ typedef struct rlDrawCall {
// rlRenderBatch type // rlRenderBatch type
typedef struct rlRenderBatch { typedef struct rlRenderBatch {
int buffersCount; // Number of vertex buffers (multi-buffering support) int bufferCount; // Number of vertex buffers (multi-buffering support)
int currentBuffer; // Current buffer tracking in case of multi-buffering int currentBuffer; // Current buffer tracking in case of multi-buffering
rlVertexBuffer *vertexBuffer; // Dynamic buffer(s) for vertex data rlVertexBuffer *vertexBuffer; // Dynamic buffer(s) for vertex data
rlDrawCall *draws; // Draw calls array, depends on textureId rlDrawCall *draws; // Draw calls array, depends on textureId
int drawsCounter; // Draw calls counter int drawCounter; // Draw calls counter
float currentDepth; // Current depth value for next draw float currentDepth; // Current depth value for next draw
} rlRenderBatch; } rlRenderBatch;
@ -1210,34 +1210,34 @@ void rlBegin(int mode)
{ {
// Draw mode can be RL_LINES, RL_TRIANGLES and RL_QUADS // Draw mode can be RL_LINES, RL_TRIANGLES and RL_QUADS
// NOTE: In all three cases, vertex are accumulated over default internal vertex buffer // NOTE: In all three cases, vertex are accumulated over default internal vertex buffer
if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode != mode) if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode != mode)
{ {
if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount > 0) if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount > 0)
{ {
// Make sure current RLGL.currentBatch->draws[i].vertexCount is aligned a multiple of 4, // Make sure current RLGL.currentBatch->draws[i].vertexCount is aligned a multiple of 4,
// that way, following QUADS drawing will keep aligned with index processing // that way, following QUADS drawing will keep aligned with index processing
// It implies adding some extra alignment vertex at the end of the draw, // It implies adding some extra alignment vertex at the end of the draw,
// those vertex are not processed but they are considered as an additional offset // those vertex are not processed but they are considered as an additional offset
// for the next set of vertex to be drawn // for the next set of vertex to be drawn
if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode == RL_LINES) RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount < 4)? RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount : RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount%4); if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_LINES) RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount < 4)? RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount : RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%4);
else if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode == RL_TRIANGLES) RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount < 4)? 1 : (4 - (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount%4))); else if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_TRIANGLES) RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount < 4)? 1 : (4 - (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%4)));
else RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = 0; else RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment = 0;
if (!rlCheckRenderBatchLimit(RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment)) if (!rlCheckRenderBatchLimit(RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment))
{ {
RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment; RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment;
RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment; RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment;
RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment; RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment;
RLGL.currentBatch->drawsCounter++; RLGL.currentBatch->drawCounter++;
} }
} }
if (RLGL.currentBatch->drawsCounter >= RL_DEFAULT_BATCH_DRAWCALLS) rlDrawRenderBatch(RLGL.currentBatch); if (RLGL.currentBatch->drawCounter >= RL_DEFAULT_BATCH_DRAWCALLS) rlDrawRenderBatch(RLGL.currentBatch);
RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode = mode; RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode = mode;
RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount = 0; RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount = 0;
RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].textureId = RLGL.State.defaultTextureId; RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId = RLGL.State.defaultTextureId;
} }
} }
@ -1285,7 +1285,7 @@ void rlEnd(void)
// Verify internal buffers limits // Verify internal buffers limits
// NOTE: This check is combined with usage of rlCheckRenderBatchLimit() // NOTE: This check is combined with usage of rlCheckRenderBatchLimit()
if ((RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter) >= if ((RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter) >=
(RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementsCount*4 - 4)) (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementCount*4 - 4))
{ {
// WARNING: If we are between rlPushMatrix() and rlPopMatrix() and we need to force a rlDrawRenderBatch(), // WARNING: If we are between rlPushMatrix() and rlPopMatrix() and we need to force a rlDrawRenderBatch(),
// we need to call rlPopMatrix() before to recover *RLGL.State.currentMatrix (RLGL.State.modelview) for the next forced draw call! // we need to call rlPopMatrix() before to recover *RLGL.State.currentMatrix (RLGL.State.modelview) for the next forced draw call!
@ -1312,14 +1312,14 @@ void rlVertex3f(float x, float y, float z)
} }
// Verify that current vertex buffer elements limit has not been reached // Verify that current vertex buffer elements limit has not been reached
if (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter < (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementsCount*4)) if (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter < (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementCount*4))
{ {
RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter] = tx; RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter] = tx;
RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter + 1] = ty; RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter + 1] = ty;
RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter + 2] = tz; RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter + 2] = tz;
RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter++; RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter++;
RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount++; RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount++;
} }
else TRACELOG(RL_LOG_ERROR, "RLGL: Batch elements overflow"); else TRACELOG(RL_LOG_ERROR, "RLGL: Batch elements overflow");
} }
@ -1390,7 +1390,7 @@ void rlSetTexture(unsigned int id)
#else #else
// NOTE: If quads batch limit is reached, we force a draw call and next batch starts // NOTE: If quads batch limit is reached, we force a draw call and next batch starts
if (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter >= if (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter >=
RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementsCount*4) RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementCount*4)
{ {
rlDrawRenderBatch(RLGL.currentBatch); rlDrawRenderBatch(RLGL.currentBatch);
} }
@ -1401,33 +1401,33 @@ void rlSetTexture(unsigned int id)
#if defined(GRAPHICS_API_OPENGL_11) #if defined(GRAPHICS_API_OPENGL_11)
rlEnableTexture(id); rlEnableTexture(id);
#else #else
if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].textureId != id) if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId != id)
{ {
if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount > 0) if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount > 0)
{ {
// Make sure current RLGL.currentBatch->draws[i].vertexCount is aligned a multiple of 4, // Make sure current RLGL.currentBatch->draws[i].vertexCount is aligned a multiple of 4,
// that way, following QUADS drawing will keep aligned with index processing // that way, following QUADS drawing will keep aligned with index processing
// It implies adding some extra alignment vertex at the end of the draw, // It implies adding some extra alignment vertex at the end of the draw,
// those vertex are not processed but they are considered as an additional offset // those vertex are not processed but they are considered as an additional offset
// for the next set of vertex to be drawn // for the next set of vertex to be drawn
if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode == RL_LINES) RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount < 4)? RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount : RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount%4); if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_LINES) RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount < 4)? RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount : RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%4);
else if (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].mode == RL_TRIANGLES) RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount < 4)? 1 : (4 - (RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount%4))); else if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_TRIANGLES) RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount < 4)? 1 : (4 - (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%4)));
else RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment = 0; else RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment = 0;
if (!rlCheckRenderBatchLimit(RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment)) if (!rlCheckRenderBatchLimit(RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment))
{ {
RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment; RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment;
RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment; RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].cCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment;
RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexAlignment; RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].tcCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment;
RLGL.currentBatch->drawsCounter++; RLGL.currentBatch->drawCounter++;
} }
} }
if (RLGL.currentBatch->drawsCounter >= RL_DEFAULT_BATCH_DRAWCALLS) rlDrawRenderBatch(RLGL.currentBatch); if (RLGL.currentBatch->drawCounter >= RL_DEFAULT_BATCH_DRAWCALLS) rlDrawRenderBatch(RLGL.currentBatch);
RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].textureId = id; RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId = id;
RLGL.currentBatch->draws[RLGL.currentBatch->drawsCounter - 1].vertexCount = 0; RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount = 0;
} }
#endif #endif
} }
@ -1910,12 +1910,12 @@ void rlLoadExtensions(void *loader)
const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string
// NOTE: We have to duplicate string because glGetString() returns a const string // NOTE: We have to duplicate string because glGetString() returns a const string
int len = strlen(extensions) + 1; int size = strlen(extensions) + 1; // Get extensions string size in bytes
char *extensionsDup = (char *)RL_CALLOC(len, sizeof(char)); char *extensionsDup = (char *)RL_CALLOC(size, sizeof(char));
strcpy(extensionsDup, extensions); strcpy(extensionsDup, extensions);
extList[numExt] = extensionsDup; extList[numExt] = extensionsDup;
for (int i = 0; i < len; i++) for (int i = 0; i < size; i++)
{ {
if (extensionsDup[i] == ' ') if (extensionsDup[i] == ' ')
{ {
@ -2169,7 +2169,7 @@ rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements)
for (int i = 0; i < numBuffers; i++) for (int i = 0; i < numBuffers; i++)
{ {
batch.vertexBuffer[i].elementsCount = bufferElements; batch.vertexBuffer[i].elementCount = bufferElements;
batch.vertexBuffer[i].vertices = (float *)RL_MALLOC(bufferElements*3*4*sizeof(float)); // 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(bufferElements*2*4*sizeof(float)); // 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
@ -2274,8 +2274,8 @@ rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements)
//batch.draws[i].RLGL.State.modelview = rlMatrixIdentity(); //batch.draws[i].RLGL.State.modelview = rlMatrixIdentity();
} }
batch.buffersCount = numBuffers; // Record buffer count batch.bufferCount = numBuffers; // Record buffer count
batch.drawsCounter = 1; // Reset draws counter batch.drawCounter = 1; // Reset draws counter
batch.currentDepth = -1.0f; // Reset depth value batch.currentDepth = -1.0f; // Reset depth value
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
#endif #endif
@ -2297,7 +2297,7 @@ void rlUnloadRenderBatch(rlRenderBatch batch)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// Unload all vertex buffers data // Unload all vertex buffers data
for (int i = 0; i < batch.buffersCount; i++) for (int i = 0; i < batch.bufferCount; i++)
{ {
// Delete VBOs from GPU (VRAM) // Delete VBOs from GPU (VRAM)
glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[0]); glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[0]);
@ -2338,17 +2338,17 @@ void rlDrawRenderBatch(rlRenderBatch *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, batch->vertexBuffer[batch->currentBuffer].vCounter*3*sizeof(float), 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].elementCount, 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, batch->vertexBuffer[batch->currentBuffer].vCounter*2*sizeof(float), 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].elementCount, 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, batch->vertexBuffer[batch->currentBuffer].vCounter*4*sizeof(unsigned char), 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].elementCount, batch->vertexBuffer[batch->currentBuffer].colors, GL_DYNAMIC_DRAW); // Update all buffer
// NOTE: glMapBuffer() causes sync issue. // NOTE: glMapBuffer() causes sync issue.
// If GPU is working with this buffer, glMapBuffer() will wait(stall) until GPU to finish its job. // If GPU is working with this buffer, glMapBuffer() will wait(stall) until GPU to finish its job.
@ -2375,12 +2375,12 @@ void rlDrawRenderBatch(rlRenderBatch *batch)
Matrix matProjection = RLGL.State.projection; Matrix matProjection = RLGL.State.projection;
Matrix matModelView = RLGL.State.modelview; Matrix matModelView = RLGL.State.modelview;
int eyesCount = 1; int eyeCount = 1;
if (RLGL.State.stereoRender) eyesCount = 2; if (RLGL.State.stereoRender) eyeCount = 2;
for (int eye = 0; eye < eyesCount; eye++) for (int eye = 0; eye < eyeCount; eye++)
{ {
if (eyesCount == 2) if (eyeCount == 2)
{ {
// Setup current eye viewport (half screen width) // Setup current eye viewport (half screen width)
rlViewport(eye*RLGL.State.framebufferWidth/2, 0, RLGL.State.framebufferWidth/2, RLGL.State.framebufferHeight); rlViewport(eye*RLGL.State.framebufferWidth/2, 0, RLGL.State.framebufferWidth/2, RLGL.State.framebufferHeight);
@ -2447,7 +2447,7 @@ void rlDrawRenderBatch(rlRenderBatch *batch)
// NOTE: Batch system accumulates calls by texture0 changes, additional textures are enabled for all the draw calls // NOTE: Batch system accumulates calls by texture0 changes, additional textures are enabled for all the draw calls
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
for (int i = 0, vertexOffset = 0; i < batch->drawsCounter; i++) for (int i = 0, vertexOffset = 0; i < batch->drawCounter; i++)
{ {
// Bind current draw call texture, activated as GL_TEXTURE0 and binded to sampler2D texture0 by default // Bind current draw call texture, activated as GL_TEXTURE0 and binded to sampler2D texture0 by default
glBindTexture(GL_TEXTURE_2D, batch->draws[i].textureId); glBindTexture(GL_TEXTURE_2D, batch->draws[i].textureId);
@ -2456,7 +2456,7 @@ void rlDrawRenderBatch(rlRenderBatch *batch)
else else
{ {
#if defined(GRAPHICS_API_OPENGL_33) #if defined(GRAPHICS_API_OPENGL_33)
// We need to define the number of indices to be processed: quadsCount*6 // We need to define the number of indices to be processed: elementCount*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 *)(vertexOffset/4*6*sizeof(GLuint))); glDrawElements(GL_TRIANGLES, batch->draws[i].vertexCount/4*6, GL_UNSIGNED_INT, (GLvoid *)(vertexOffset/4*6*sizeof(GLuint)));
@ -2510,12 +2510,12 @@ void rlDrawRenderBatch(rlRenderBatch *batch)
for (int i = 0; i < RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS; i++) RLGL.State.activeTextureId[i] = 0; for (int i = 0; i < RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS; i++) RLGL.State.activeTextureId[i] = 0;
// Reset draws counter to one draw for the batch // Reset draws counter to one draw for the batch
batch->drawsCounter = 1; batch->drawCounter = 1;
//------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------
// Change to next buffer in the list (in case of multi-buffering) // Change to next buffer in the list (in case of multi-buffering)
batch->currentBuffer++; batch->currentBuffer++;
if (batch->currentBuffer >= batch->buffersCount) batch->currentBuffer = 0; if (batch->currentBuffer >= batch->bufferCount) batch->currentBuffer = 0;
#endif #endif
} }
@ -2546,7 +2546,7 @@ bool rlCheckRenderBatchLimit(int vCount)
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
if ((RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter + vCount) >= if ((RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vCounter + vCount) >=
(RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementsCount*4)) (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementCount*4))
{ {
overflow = true; overflow = true;
rlDrawRenderBatch(RLGL.currentBatch); // NOTE: Stereo rendering is checked inside rlDrawRenderBatch(RLGL.currentBatch); // NOTE: Stereo rendering is checked inside
@ -3028,8 +3028,6 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format)
// NOTE: This behaviour could be conditioned by graphic driver... // NOTE: This behaviour could be conditioned by graphic driver...
unsigned int fboId = rlLoadFramebuffer(width, height); unsigned int fboId = rlLoadFramebuffer(width, height);
// TODO: Create depth texture/renderbuffer for fbo?
glBindFramebuffer(GL_FRAMEBUFFER, fboId); glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);

View File

@ -1,6 +1,6 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raylib.models - Basic functions to deal with 3d shapes and 3d models * rmodels - Basic functions to draw 3d shapes and load and draw 3d models
* *
* CONFIGURATION: * CONFIGURATION:
* *
@ -8,6 +8,8 @@
* #define SUPPORT_FILEFORMAT_MTL * #define SUPPORT_FILEFORMAT_MTL
* #define SUPPORT_FILEFORMAT_IQM * #define SUPPORT_FILEFORMAT_IQM
* #define SUPPORT_FILEFORMAT_GLTF * #define SUPPORT_FILEFORMAT_GLTF
* #define SUPPORT_FILEFORMAT_VOX
*
* Selected desired fileformats to be supported for model data loading. * Selected desired fileformats to be supported for model data loading.
* *
* #define SUPPORT_MESH_GENERATION * #define SUPPORT_MESH_GENERATION
@ -68,7 +70,16 @@
#define CGLTF_IMPLEMENTATION #define CGLTF_IMPLEMENTATION
#include "external/cgltf.h" // glTF file format loading #include "external/cgltf.h" // glTF file format loading
#include "external/stb_image.h" // glTF texture images loading #endif
#if defined(SUPPORT_FILEFORMAT_VOX)
#define VOX_MALLOC RL_MALLOC
#define VOX_CALLOC RL_CALLOC
#define VOX_REALLOC RL_REALLOC
#define VOX_FREE RL_FREE
#define VOX_LOADER_IMPLEMENTATION
#include "external/vox_loader.h" // vox file format loading (MagikaVoxel)
#endif #endif
#if defined(SUPPORT_MESH_GENERATION) #if defined(SUPPORT_MESH_GENERATION)
@ -117,19 +128,23 @@ static Model LoadOBJ(const char *fileName); // Load OBJ mesh data
#endif #endif
#if defined(SUPPORT_FILEFORMAT_IQM) #if defined(SUPPORT_FILEFORMAT_IQM)
static Model LoadIQM(const char *fileName); // Load IQM mesh data static Model LoadIQM(const char *fileName); // Load IQM mesh data
static ModelAnimation *LoadIQMModelAnimations(const char *fileName, int *animCount); // Load IQM animation data static ModelAnimation *LoadIQMModelAnimations(const char *fileName, unsigned int *animCount); // Load IQM animation data
#endif #endif
#if defined(SUPPORT_FILEFORMAT_GLTF) #if defined(SUPPORT_FILEFORMAT_GLTF)
static Model LoadGLTF(const char *fileName); // Load GLTF mesh data static Model LoadGLTF(const char *fileName); // Load GLTF mesh data
static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCount); // Load GLTF animation data static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, unsigned int *animCount); // Load GLTF animation data
static void LoadGLTFMaterial(Model *model, const char *fileName, const cgltf_data *data); static void LoadGLTFMaterial(Model *model, const char *fileName, const cgltf_data *data);
static void LoadGLTFMesh(cgltf_data *data, cgltf_mesh* mesh, Model* outModel, Matrix currentTransform, int* primitiveIndex, const char *fileName); static void LoadGLTFMesh(cgltf_data *data, cgltf_node *node, Model *outModel, Matrix currentTransform, int *primitiveIndex, const char *fileName);
static void LoadGLTFNode(cgltf_data *data, cgltf_node* node, Model* outModel, Matrix currentTransform, int* primitiveIndex, const char *fileName); static void LoadGLTFNode(cgltf_data *data, cgltf_node *node, Model *outModel, Matrix currentTransform, int *primitiveIndex, const char *fileName);
static void InitGLTFBones(Model *model, const cgltf_data *data); static void InitGLTFBones(Model *model, const cgltf_data *data);
static void BindGLTFPrimitiveToBones(Model *model, const cgltf_data *data, int primitiveIndex); static void BindGLTFPrimitiveToBones(Model *model, cgltf_node *node, const cgltf_data *data, int primitiveIndex);
static void GetGLTFPrimitiveCount(cgltf_node* node, int* outCount); static void GetGLTFPrimitiveCount(cgltf_node *node, int *outCount);
static bool ReadGLTFValue(cgltf_accessor* acc, unsigned int index, void *variable); static bool ReadGLTFValue(cgltf_accessor *acc, unsigned int index, void *variable);
static void *ReadGLTFValuesAs(cgltf_accessor* acc, cgltf_component_type type, bool adjustOnDownCasting); static void *ReadGLTFValuesAs(cgltf_accessor *acc, cgltf_component_type type, bool adjustOnDownCasting);
static Matrix GetNodeTransformationMatrix(cgltf_node *node, Matrix current);
#endif
#if defined(SUPPORT_FILEFORMAT_VOX)
static Model LoadVOX(const char *filename); // Load VOX mesh data
#endif #endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -201,16 +216,16 @@ void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color)
} }
// Draw a triangle strip defined by points // Draw a triangle strip defined by points
void DrawTriangleStrip3D(Vector3 *points, int pointsCount, Color color) void DrawTriangleStrip3D(Vector3 *points, int pointCount, Color color)
{ {
if (pointsCount >= 3) if (pointCount >= 3)
{ {
rlCheckRenderBatchLimit(3*(pointsCount - 2)); rlCheckRenderBatchLimit(3*(pointCount - 2));
rlBegin(RL_TRIANGLES); rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
for (int i = 2; i < pointsCount; i++) for (int i = 2; i < pointCount; i++)
{ {
if ((i%2) == 0) if ((i%2) == 0)
{ {
@ -449,6 +464,157 @@ void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float hei
rlSetTexture(0); rlSetTexture(0);
} }
void DrawCubeTextureRec(Texture2D texture, Rectangle source, Vector3 position, float width, float height, float length, Color color)
{
float x = position.x;
float y = position.y;
float z = position.z;
float texture_width = (float)texture.width;
float texture_height = (float)texture.height;
rlCheckRenderBatchLimit(36);
rlSetTexture(texture.id);
rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a);
// Front Face
{
// Normal Pointing Towards Viewer
rlNormal3f(0.0f, 0.0f, 1.0f);
// Bottom Left Of The Texture and Quad
rlTexCoord2f(source.x / texture_width, (source.y + source.height) / texture_height);
rlVertex3f(x - width/2, y - height/2, z + length/2);
// Bottom Right Of The Texture and Quad
rlTexCoord2f((source.x + source.width) / texture_width, (source.y + source.height) / texture_height);
rlVertex3f(x + width/2, y - height/2, z + length/2);
// Top Right Of The Texture and Quad
rlTexCoord2f((source.x + source.width) / texture_width, source.y / texture_height);
rlVertex3f(x + width/2, y + height/2, z + length/2);
// Top Left Of The Texture and Quad
rlTexCoord2f(source.x / texture_width, source.y / texture_height);
rlVertex3f(x - width/2, y + height/2, z + length/2);
}
// Back Face
{
// Normal Pointing Away From Viewer
rlNormal3f(0.0f, 0.0f, - 1.0f);
// Bottom Right Of The Texture and Quad
rlTexCoord2f((source.x + source.width) / texture_width, (source.y + source.height) / texture_height);
rlVertex3f(x - width/2, y - height/2, z - length/2);
// Top Right Of The Texture and Quad
rlTexCoord2f((source.x + source.width) / texture_width, source.y / texture_height);
rlVertex3f(x - width/2, y + height/2, z - length/2);
// Top Left Of The Texture and Quad
rlTexCoord2f(source.x / texture_width, source.y / texture_height);
rlVertex3f(x + width/2, y + height/2, z - length/2);
// Bottom Left Of The Texture and Quad
rlTexCoord2f(source.x / texture_width, (source.y + source.height) / texture_height);
rlVertex3f(x + width/2, y - height/2, z - length/2);
}
// Top Face
{
// Normal Pointing Up
rlNormal3f(0.0f, 1.0f, 0.0f);
// Top Left Of The Texture and Quad
rlTexCoord2f(source.x / texture_width, source.y / texture_height);
rlVertex3f(x - width/2, y + height/2, z - length/2);
// Bottom Left Of The Texture and Quad
rlTexCoord2f(source.x / texture_width, (source.y + source.height) / texture_height);
rlVertex3f(x - width/2, y + height/2, z + length/2);
// Bottom Right Of The Texture and Quad
rlTexCoord2f((source.x + source.width) / texture_width, (source.y + source.height) / texture_height);
rlVertex3f(x + width/2, y + height/2, z + length/2);
// Top Right Of The Texture and Quad
rlTexCoord2f((source.x + source.width) / texture_width, source.y / texture_height);
rlVertex3f(x + width/2, y + height/2, z - length/2);
}
// Bottom Face
{
// Normal Pointing Down
rlNormal3f(0.0f, - 1.0f, 0.0f);
// Top Right Of The Texture and Quad
rlTexCoord2f((source.x + source.width) / texture_width, source.y / texture_height);
rlVertex3f(x - width/2, y - height/2, z - length/2);
// Top Left Of The Texture and Quad
rlTexCoord2f(source.x / texture_width, source.y / texture_height);
rlVertex3f(x + width/2, y - height/2, z - length/2);
// Bottom Left Of The Texture and Quad
rlTexCoord2f(source.x / texture_width, (source.y + source.height) / texture_height);
rlVertex3f(x + width/2, y - height/2, z + length/2);
// Bottom Right Of The Texture and Quad
rlTexCoord2f((source.x + source.width) / texture_width, (source.y + source.height) / texture_height);
rlVertex3f(x - width/2, y - height/2, z + length/2);
}
// Right face
{
// Normal Pointing Right
rlNormal3f(1.0f, 0.0f, 0.0f);
// Bottom Right Of The Texture and Quad
rlTexCoord2f((source.x + source.width) / texture_width, (source.y + source.height) / texture_height);
rlVertex3f(x + width/2, y - height/2, z - length/2);
// Top Right Of The Texture and Quad
rlTexCoord2f((source.x + source.width) / texture_width, source.y / texture_height);
rlVertex3f(x + width/2, y + height/2, z - length/2);
// Top Left Of The Texture and Quad
rlTexCoord2f(source.x / texture_width, source.y / texture_height);
rlVertex3f(x + width/2, y + height/2, z + length/2);
// Bottom Left Of The Texture and Quad
rlTexCoord2f(source.x / texture_width, (source.y + source.height) / texture_height);
rlVertex3f(x + width/2, y - height/2, z + length/2);
}
// Left Face
{
// Normal Pointing Left
rlNormal3f( - 1.0f, 0.0f, 0.0f);
// Bottom Left Of The Texture and Quad
rlTexCoord2f(source.x / texture_width, (source.y + source.height) / texture_height);
rlVertex3f(x - width/2, y - height/2, z - length/2);
// Bottom Right Of The Texture and Quad
rlTexCoord2f((source.x + source.width) / texture_width, (source.y + source.height) / texture_height);
rlVertex3f(x - width/2, y - height/2, z + length/2);
// Top Right Of The Texture and Quad
rlTexCoord2f((source.x + source.width) / texture_width, source.y / texture_height);
rlVertex3f(x - width/2, y + height/2, z + length/2);
// Top Left Of The Texture and Quad
rlTexCoord2f(source.x / texture_width, source.y / texture_height);
rlVertex3f(x - width/2, y + height/2, z - length/2);
}
rlEnd();
rlSetTexture(0);
}
// Draw sphere // Draw sphere
void DrawSphere(Vector3 centerPos, float radius, Color color) void DrawSphere(Vector3 centerPos, float radius, Color color)
{ {
@ -718,6 +884,9 @@ Model LoadModel(const char *fileName)
#if defined(SUPPORT_FILEFORMAT_GLTF) #if defined(SUPPORT_FILEFORMAT_GLTF)
if (IsFileExtension(fileName, ".gltf;.glb")) model = LoadGLTF(fileName); if (IsFileExtension(fileName, ".gltf;.glb")) model = LoadGLTF(fileName);
#endif #endif
#if defined(SUPPORT_FILEFORMAT_VOX)
if (IsFileExtension(fileName, ".vox")) model = LoadVOX(fileName);
#endif
// Make sure model transform is set to identity matrix! // Make sure model transform is set to identity matrix!
model.transform = MatrixIdentity(); model.transform = MatrixIdentity();
@ -1144,14 +1313,14 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]); if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]);
} }
int eyesCount = 1; int eyeCount = 1;
if (rlIsStereoRenderEnabled()) eyesCount = 2; if (rlIsStereoRenderEnabled()) eyeCount = 2;
for (int eye = 0; eye < eyesCount; eye++) for (int eye = 0; eye < eyeCount; eye++)
{ {
// Calculate model-view-projection matrix (MVP) // Calculate model-view-projection matrix (MVP)
Matrix matModelViewProjection = MatrixIdentity(); Matrix matModelViewProjection = MatrixIdentity();
if (eyesCount == 1) matModelViewProjection = MatrixMultiply(matModelView, matProjection); if (eyeCount == 1) matModelViewProjection = MatrixMultiply(matModelView, matProjection);
else else
{ {
// Setup current eye viewport (half screen width) // Setup current eye viewport (half screen width)
@ -1359,14 +1528,14 @@ void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int ins
if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]); if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]);
} }
int eyesCount = 1; int eyeCount = 1;
if (rlIsStereoRenderEnabled()) eyesCount = 2; if (rlIsStereoRenderEnabled()) eyeCount = 2;
for (int eye = 0; eye < eyesCount; eye++) for (int eye = 0; eye < eyeCount; eye++)
{ {
// Calculate model-view-projection matrix (MVP) // Calculate model-view-projection matrix (MVP)
Matrix matModelViewProjection = MatrixIdentity(); Matrix matModelViewProjection = MatrixIdentity();
if (eyesCount == 1) matModelViewProjection = MatrixMultiply(matModelView, matProjection); if (eyeCount == 1) matModelViewProjection = MatrixMultiply(matModelView, matProjection);
else else
{ {
// Setup current eye viewport (half screen width) // Setup current eye viewport (half screen width)
@ -1448,43 +1617,43 @@ bool ExportMesh(Mesh mesh, const char *fileName)
// NOTE: Text data buffer size is estimated considering mesh data size // NOTE: Text data buffer size is estimated considering mesh data size
char *txtData = (char *)RL_CALLOC(dataSize + 2000, sizeof(char)); char *txtData = (char *)RL_CALLOC(dataSize + 2000, sizeof(char));
int bytesCount = 0; int byteCount = 0;
bytesCount += sprintf(txtData + bytesCount, "# //////////////////////////////////////////////////////////////////////////////////\n"); byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n");
bytesCount += sprintf(txtData + bytesCount, "# // //\n"); byteCount += sprintf(txtData + byteCount, "# // //\n");
bytesCount += sprintf(txtData + bytesCount, "# // rMeshOBJ exporter v1.0 - Mesh exported as triangle faces and not optimized //\n"); byteCount += sprintf(txtData + byteCount, "# // rMeshOBJ exporter v1.0 - Mesh exported as triangle faces and not optimized //\n");
bytesCount += sprintf(txtData + bytesCount, "# // //\n"); byteCount += sprintf(txtData + byteCount, "# // //\n");
bytesCount += sprintf(txtData + bytesCount, "# // more info and bugs-report: github.com/raysan5/raylib //\n"); byteCount += sprintf(txtData + byteCount, "# // more info and bugs-report: github.com/raysan5/raylib //\n");
bytesCount += sprintf(txtData + bytesCount, "# // feedback and support: ray[at]raylib.com //\n"); byteCount += sprintf(txtData + byteCount, "# // feedback and support: ray[at]raylib.com //\n");
bytesCount += sprintf(txtData + bytesCount, "# // //\n"); byteCount += sprintf(txtData + byteCount, "# // //\n");
bytesCount += sprintf(txtData + bytesCount, "# // Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n"); byteCount += sprintf(txtData + byteCount, "# // Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n");
bytesCount += sprintf(txtData + bytesCount, "# // //\n"); byteCount += sprintf(txtData + byteCount, "# // //\n");
bytesCount += sprintf(txtData + bytesCount, "# //////////////////////////////////////////////////////////////////////////////////\n\n"); byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n\n");
bytesCount += sprintf(txtData + bytesCount, "# Vertex Count: %i\n", mesh.vertexCount); byteCount += sprintf(txtData + byteCount, "# Vertex Count: %i\n", mesh.vertexCount);
bytesCount += sprintf(txtData + bytesCount, "# Triangle Count: %i\n\n", mesh.triangleCount); byteCount += sprintf(txtData + byteCount, "# Triangle Count: %i\n\n", mesh.triangleCount);
bytesCount += sprintf(txtData + bytesCount, "g mesh\n"); byteCount += sprintf(txtData + byteCount, "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)
{ {
bytesCount += sprintf(txtData + bytesCount, "v %.2f %.2f %.2f\n", mesh.vertices[v], mesh.vertices[v + 1], mesh.vertices[v + 2]); byteCount += sprintf(txtData + byteCount, "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)
{ {
bytesCount += sprintf(txtData + bytesCount, "vt %.3f %.3f\n", mesh.texcoords[v], mesh.texcoords[v + 1]); byteCount += sprintf(txtData + byteCount, "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)
{ {
bytesCount += sprintf(txtData + bytesCount, "vn %.3f %.3f %.3f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]); byteCount += sprintf(txtData + byteCount, "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)
{ {
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); byteCount += sprintf(txtData + byteCount, "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, "\n"); byteCount += sprintf(txtData + byteCount, "\n");
// NOTE: Text data length exported is determined by '\0' (NULL) character // NOTE: Text data length exported is determined by '\0' (NULL) character
success = SaveFileText(fileName, txtData); success = SaveFileText(fileName, txtData);
@ -1590,7 +1759,7 @@ 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, unsigned int *animCount)
{ {
ModelAnimation *animations = NULL; ModelAnimation *animations = NULL;
@ -1614,72 +1783,93 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
for (int m = 0; m < model.meshCount; m++) for (int m = 0; m < model.meshCount; m++)
{ {
Mesh mesh = model.meshes[m];
if (mesh.boneIds == NULL || mesh.boneWeights == NULL)
{
TRACELOG(LOG_WARNING, "MODEL: UpdateModelAnimation Mesh %i has no connection to bones",m);
continue;
}
bool updated = false; // set to true when anim vertex information is updated
Vector3 animVertex = { 0 }; Vector3 animVertex = { 0 };
Vector3 animNormal = { 0 }; Vector3 animNormal = { 0 };
Vector3 inTranslation = { 0 }; Vector3 inTranslation = { 0 };
Quaternion inRotation = { 0 }; Quaternion inRotation = { 0 };
//Vector3 inScale = { 0 }; // Not used... // Vector3 inScale = { 0 };
Vector3 outTranslation = { 0 }; Vector3 outTranslation = { 0 };
Quaternion outRotation = { 0 }; Quaternion outRotation = { 0 };
Vector3 outScale = { 0 }; Vector3 outScale = { 0 };
int vCounter = 0;
int boneCounter = 0;
int boneId = 0; int boneId = 0;
int boneCounter = 0;
float boneWeight = 0.0; float boneWeight = 0.0;
for (int i = 0; i < model.meshes[m].vertexCount; i++) const int vValues = mesh.vertexCount*3;
for (int vCounter = 0; vCounter < vValues; vCounter+=3)
{ {
model.meshes[m].animVertices[vCounter] = 0; mesh.animVertices[vCounter] = 0;
model.meshes[m].animVertices[vCounter + 1] = 0; mesh.animVertices[vCounter + 1] = 0;
model.meshes[m].animVertices[vCounter + 2] = 0; mesh.animVertices[vCounter + 2] = 0;
model.meshes[m].animNormals[vCounter] = 0; if (mesh.animNormals!=NULL)
model.meshes[m].animNormals[vCounter + 1] = 0;
model.meshes[m].animNormals[vCounter + 2] = 0;
for (int j = 0; j < 4; j++)
{ {
boneId = model.meshes[m].boneIds[boneCounter]; mesh.animNormals[vCounter] = 0;
boneWeight = model.meshes[m].boneWeights[boneCounter]; mesh.animNormals[vCounter + 1] = 0;
mesh.animNormals[vCounter + 2] = 0;
}
// Iterates over 4 bones per vertex
for (int j = 0; j < 4; j++, boneCounter++)
{
boneWeight = mesh.boneWeights[boneCounter];
// early stop when no transformation will be applied
if (boneWeight == 0.0f)
{
continue;
}
boneId = mesh.boneIds[boneCounter];
int boneIdParent = model.bones[boneId].parent;
inTranslation = model.bindPose[boneId].translation; inTranslation = model.bindPose[boneId].translation;
inRotation = model.bindPose[boneId].rotation; inRotation = model.bindPose[boneId].rotation;
//inScale = model.bindPose[boneId].scale; // inScale = model.bindPose[boneId].scale;
outTranslation = anim.framePoses[frame][boneId].translation; outTranslation = anim.framePoses[frame][boneId].translation;
outRotation = anim.framePoses[frame][boneId].rotation; outRotation = anim.framePoses[frame][boneId].rotation;
outScale = anim.framePoses[frame][boneId].scale; outScale = anim.framePoses[frame][boneId].scale;
// Vertices processing // Vertices processing
// NOTE: We use meshes.vertices (default vertex position) to calculate meshes.animVertices (animated vertex position) // NOTE: We use meshes.vertices (default vertex position) to calculate meshes.animVertices (animated vertex position)
animVertex = (Vector3){ model.meshes[m].vertices[vCounter], model.meshes[m].vertices[vCounter + 1], model.meshes[m].vertices[vCounter + 2] }; animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] };
animVertex = Vector3Multiply(animVertex, outScale); animVertex = Vector3Multiply(animVertex, outScale);
animVertex = Vector3Subtract(animVertex, inTranslation); animVertex = Vector3Subtract(animVertex, inTranslation);
animVertex = Vector3RotateByQuaternion(animVertex, QuaternionMultiply(outRotation, QuaternionInvert(inRotation))); animVertex = Vector3RotateByQuaternion(animVertex, QuaternionMultiply(outRotation, QuaternionInvert(inRotation)));
animVertex = Vector3Add(animVertex, outTranslation); animVertex = Vector3Add(animVertex, outTranslation);
model.meshes[m].animVertices[vCounter] += animVertex.x*boneWeight; // animVertex = Vector3Transform(animVertex, model.transform);
model.meshes[m].animVertices[vCounter + 1] += animVertex.y*boneWeight; mesh.animVertices[vCounter] += animVertex.x*boneWeight;
model.meshes[m].animVertices[vCounter + 2] += animVertex.z*boneWeight; mesh.animVertices[vCounter + 1] += animVertex.y*boneWeight;
mesh.animVertices[vCounter + 2] += animVertex.z*boneWeight;
updated = true;
// Normals processing // Normals processing
// NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals) // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
if (model.meshes[m].normals != NULL) if (mesh.normals != NULL)
{ {
animNormal = (Vector3){ model.meshes[m].normals[vCounter], model.meshes[m].normals[vCounter + 1], model.meshes[m].normals[vCounter + 2] }; animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] };
animNormal = Vector3RotateByQuaternion(animNormal, QuaternionMultiply(outRotation, QuaternionInvert(inRotation))); animNormal = Vector3RotateByQuaternion(animNormal, QuaternionMultiply(outRotation, QuaternionInvert(inRotation)));
model.meshes[m].animNormals[vCounter] += animNormal.x*boneWeight; mesh.animNormals[vCounter] += animNormal.x*boneWeight;
model.meshes[m].animNormals[vCounter + 1] += animNormal.y*boneWeight; mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight;
model.meshes[m].animNormals[vCounter + 2] += animNormal.z*boneWeight; mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight;
} }
boneCounter += 1;
} }
vCounter += 3;
} }
// Upload new vertex data to GPU for model drawing // Upload new vertex data to GPU for model drawing
rlUpdateVertexBuffer(model.meshes[m].vboId[0], model.meshes[m].animVertices, model.meshes[m].vertexCount*3*sizeof(float), 0); // Update vertex position // Only update data when values changed.
rlUpdateVertexBuffer(model.meshes[m].vboId[2], model.meshes[m].animNormals, model.meshes[m].vertexCount*3*sizeof(float), 0); // Update vertex normals if (updated){
rlUpdateVertexBuffer(mesh.vboId[0], mesh.animVertices, mesh.vertexCount*3*sizeof(float), 0); // Update vertex position
rlUpdateVertexBuffer(mesh.vboId[2], mesh.animNormals, mesh.vertexCount*3*sizeof(float), 0); // Update vertex normals
}
} }
} }
} }
@ -3080,10 +3270,13 @@ void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float siz
// Draw a billboard (part of a texture defined by a rectangle) // Draw a billboard (part of a texture defined by a rectangle)
void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint) void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint)
{ {
DrawBillboardPro(camera, texture, source, position, size, Vector2Zero(), 0.0f, tint); // NOTE: Billboard locked on axis-Y
Vector3 up = { 0.0f, 1.0f, 0.0f };
DrawBillboardPro(camera, texture, source, position, up, size, Vector2Zero(), 0.0f, tint);
} }
void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Vector2 origin, float rotation, Color tint) void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint)
{ {
// NOTE: Billboard size will maintain source rectangle aspect ratio, size will represent billboard width // NOTE: Billboard size will maintain source rectangle aspect ratio, size will represent billboard width
Vector2 sizeRatio = { size.y, size.x*(float)source.height/source.width }; Vector2 sizeRatio = { size.y, size.x*(float)source.height/source.width };
@ -3093,9 +3286,6 @@ void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector
Vector3 right = { matView.m0, matView.m4, matView.m8 }; Vector3 right = { matView.m0, matView.m4, matView.m8 };
//Vector3 up = { matView.m1, matView.m5, matView.m9 }; //Vector3 up = { matView.m1, matView.m5, matView.m9 };
// NOTE: Billboard locked on axis-Y
Vector3 up = { 0.0f, 1.0f, 0.0f };
Vector3 rightScaled = Vector3Scale(right, sizeRatio.x/2); Vector3 rightScaled = Vector3Scale(right, sizeRatio.x/2);
Vector3 upScaled = Vector3Scale(up, sizeRatio.y/2); Vector3 upScaled = Vector3Scale(up, sizeRatio.y/2);
@ -3491,6 +3681,11 @@ RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Ve
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(SUPPORT_FILEFORMAT_OBJ) #if defined(SUPPORT_FILEFORMAT_OBJ)
// Load OBJ mesh data // Load OBJ mesh data
//
// Keep the following information in mind when reading this
// - A mesh is created for every material present in the obj file
// - the model.meshCount is therefore the materialCount returned from tinyobj
// - the mesh is automatically triangulated by tinyobj
static Model LoadOBJ(const char *fileName) static Model LoadOBJ(const char *fileName)
{ {
Model model = { 0 }; Model model = { 0 };
@ -3540,17 +3735,24 @@ static Model LoadOBJ(const char *fileName)
model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
// Count the faces for each material // Count the faces for each material
int *matFaces = RL_CALLOC(materialCount, sizeof(int)); int *matFaces = RL_CALLOC(model.meshCount, sizeof(int));
for (unsigned int mi = 0; mi < meshCount; mi++) // iff no materials are present use all faces on one mesh
if (materialCount > 0)
{ {
for (unsigned int fi = 0; fi < meshes[mi].length; fi++) for (int fi = 0; fi< attrib.num_faces; fi++)
{ {
int idx = attrib.material_ids[meshes[mi].face_offset + fi]; //tinyobj_vertex_index_t face = attrib.faces[fi];
if (idx == -1) idx = 0; // for no material face (which could be the whole model) int idx = attrib.material_ids[fi];
matFaces[idx]++; matFaces[idx]++;
} }
} }
else
{
matFaces[0] = attrib.num_faces;
}
//-------------------------------------- //--------------------------------------
// Create the material meshes // Create the material meshes
@ -4043,7 +4245,7 @@ static Model LoadIQM(const char *fileName)
} }
// Load IQM animation data // Load IQM animation data
static ModelAnimation* LoadIQMModelAnimations(const char *fileName, int *animCount) static ModelAnimation* LoadIQMModelAnimations(const char *fileName, unsigned 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
@ -4353,16 +4555,9 @@ static Image LoadImageFromCgltfImage(cgltf_image *image, const char *texPath, Co
int size = 0; int size = 0;
unsigned char *data = DecodeBase64(image->uri + i + 1, &size); unsigned char *data = DecodeBase64(image->uri + i + 1, &size);
int width, height; rimage = LoadImageFromMemory(".png", data, size);
unsigned char *raw = stbi_load_from_memory(data, size, &width, &height, NULL, 4);
RL_FREE(data); RL_FREE(data);
rimage.data = raw;
rimage.width = width;
rimage.height = height;
rimage.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
rimage.mipmaps = 1;
// TODO: Tint shouldn't be applied here! // TODO: Tint shouldn't be applied here!
ImageColorTint(&rimage, tint); ImageColorTint(&rimage, tint);
} }
@ -4387,16 +4582,9 @@ static Image LoadImageFromCgltfImage(cgltf_image *image, const char *texPath, Co
n += stride; n += stride;
} }
int width, height; rimage = LoadImageFromMemory(".png", data, (int)image->buffer_view->size);
unsigned char *raw = stbi_load_from_memory(data, (int)image->buffer_view->size, &width, &height, NULL, 4);
RL_FREE(data); RL_FREE(data);
rimage.data = raw;
rimage.width = width;
rimage.height = height;
rimage.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
rimage.mipmaps = 1;
// TODO: Tint shouldn't be applied here! // TODO: Tint shouldn't be applied here!
ImageColorTint(&rimage, tint); ImageColorTint(&rimage, tint);
} }
@ -4856,14 +5044,14 @@ static Model LoadGLTF(const char *fileName)
if (data->scenes_count > 1) TRACELOG(LOG_INFO, "MODEL: [%s] Has multiple scenes but only the first one will be loaded", fileName); if (data->scenes_count > 1) TRACELOG(LOG_INFO, "MODEL: [%s] Has multiple scenes but only the first one will be loaded", fileName);
int primitivesCount = 0; int primitiveCount = 0;
for (unsigned int i = 0; i < data->scene->nodes_count; i++) for (unsigned int i = 0; i < data->scene->nodes_count; i++)
{ {
GetGLTFPrimitiveCount(data->scene->nodes[i], &primitivesCount); GetGLTFPrimitiveCount(data->scene->nodes[i], &primitiveCount);
} }
// Process glTF data and map to model // Process glTF data and map to model
model.meshCount = primitivesCount; model.meshCount = primitiveCount;
model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh)); model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh));
model.materialCount = (int)data->materials_count + 1; model.materialCount = (int)data->materials_count + 1;
model.materials = RL_MALLOC(model.materialCount*sizeof(Material)); model.materials = RL_MALLOC(model.materialCount*sizeof(Material));
@ -4891,7 +5079,7 @@ static Model LoadGLTF(const char *fileName)
return model; return model;
} }
static void InitGLTFBones(Model* model, const cgltf_data* data) static void InitGLTFBones(Model *model, const cgltf_data *data)
{ {
for (unsigned int j = 0; j < data->nodes_count; j++) for (unsigned int j = 0; j < data->nodes_count; j++)
{ {
@ -4914,7 +5102,7 @@ static void InitGLTFBones(Model* model, const cgltf_data* data)
} }
{ {
bool* completedBones = RL_CALLOC(model->boneCount, sizeof(bool)); bool *completedBones = RL_CALLOC(model->boneCount, sizeof(bool));
int numberCompletedBones = 0; int numberCompletedBones = 0;
while (numberCompletedBones < model->boneCount) while (numberCompletedBones < model->boneCount)
@ -5022,37 +5210,33 @@ static void LoadGLTFMaterial(Model *model, const char *fileName, const cgltf_dat
model->materials[model->materialCount - 1] = LoadMaterialDefault(); model->materials[model->materialCount - 1] = LoadMaterialDefault();
} }
static void BindGLTFPrimitiveToBones(Model* model, const cgltf_data* data, int primitiveIndex) static void BindGLTFPrimitiveToBones(Model *model, cgltf_node *node, const cgltf_data *data, int primitiveIndex)
{ {
for (unsigned int nodeId = 0; nodeId < data->nodes_count; nodeId++) int nodeId = node - data->nodes;
{
if (data->nodes[nodeId].mesh == &(data->meshes[primitiveIndex]))
{
if (model->meshes[primitiveIndex].boneIds == NULL)
{
model->meshes[primitiveIndex].boneIds = RL_CALLOC(4*model->meshes[primitiveIndex].vertexCount, sizeof(int));
model->meshes[primitiveIndex].boneWeights = RL_CALLOC(4*model->meshes[primitiveIndex].vertexCount, sizeof(float));
for (int b = 0; b < 4*model->meshes[primitiveIndex].vertexCount; b++) if (model->meshes[primitiveIndex].boneIds == NULL)
{ {
if (b % 4 == 0) model->meshes[primitiveIndex].boneIds = RL_CALLOC(model->meshes[primitiveIndex].vertexCount*4, sizeof(int));
{ model->meshes[primitiveIndex].boneWeights = RL_CALLOC(model->meshes[primitiveIndex].vertexCount*4, sizeof(float));
model->meshes[primitiveIndex].boneIds[b] = nodeId;
model->meshes[primitiveIndex].boneWeights[b] = 1.0f; for (int b = 0; b < model->meshes[primitiveIndex].vertexCount*4; b++)
} {
else if (b%4 == 0)
{ {
model->meshes[primitiveIndex].boneIds[b] = 0; model->meshes[primitiveIndex].boneIds[b] = nodeId;
model->meshes[primitiveIndex].boneWeights[b] = 0.0f; model->meshes[primitiveIndex].boneWeights[b] = 1.0f;
} }
} else
{
model->meshes[primitiveIndex].boneIds[b] = 0;
model->meshes[primitiveIndex].boneWeights[b] = 0.0f;
} }
} }
} }
} }
// LoadGLTF loads in animation data from given filename // LoadGLTF loads in animation data from given filename
static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCount) static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, unsigned int *animCount)
{ {
/*********************************************************************************** /***********************************************************************************
@ -5087,7 +5271,7 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo
result = cgltf_load_buffers(&options, data, fileName); result = cgltf_load_buffers(&options, data, fileName);
if (result != cgltf_result_success) TRACELOG(LOG_WARNING, "MODEL: [%s] unable to load glTF animations data", fileName); if (result != cgltf_result_success) TRACELOG(LOG_WARNING, "MODEL: [%s] unable to load glTF animations data", fileName);
animations = RL_MALLOC(data->animations_count*sizeof(ModelAnimation)); animations = RL_MALLOC(data->animations_count*sizeof(ModelAnimation));
*animCount = (int)data->animations_count; *animCount = (unsigned int)data->animations_count;
for (unsigned int a = 0; a < data->animations_count; a++) for (unsigned int a = 0; a < data->animations_count; a++)
{ {
@ -5112,7 +5296,7 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo
// Getting the max animation time to consider for animation duration // Getting the max animation time to consider for animation duration
for (unsigned int i = 0; i < animation->channels_count; i++) for (unsigned int i = 0; i < animation->channels_count; i++)
{ {
cgltf_animation_channel* channel = animation->channels + i; cgltf_animation_channel *channel = animation->channels + i;
int frameCounts = (int)channel->sampler->input->count; int frameCounts = (int)channel->sampler->input->count;
float lastFrameTime = 0.0f; float lastFrameTime = 0.0f;
@ -5159,8 +5343,8 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo
// for each single transformation type on single bone // for each single transformation type on single bone
for (unsigned int channelId = 0; channelId < animation->channels_count; channelId++) for (unsigned int channelId = 0; channelId < animation->channels_count; channelId++)
{ {
cgltf_animation_channel* channel = animation->channels + channelId; cgltf_animation_channel *channel = animation->channels + channelId;
cgltf_animation_sampler* sampler = channel->sampler; cgltf_animation_sampler *sampler = channel->sampler;
int boneId = (int)(channel->target_node - data->nodes); int boneId = (int)(channel->target_node - data->nodes);
@ -5217,13 +5401,16 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo
translationStart.y = values[1]; translationStart.y = values[1];
translationStart.z = values[2]; translationStart.z = values[2];
success = ReadGLTFValue(sampler->output, outputMax, values) || success; success = ReadGLTFValue(sampler->output, outputMax, values) && success;
translationEnd.x = values[0]; translationEnd.x = values[0];
translationEnd.y = values[1]; translationEnd.y = values[1];
translationEnd.z = values[2]; translationEnd.z = values[2];
if (success) output->framePoses[frame][boneId].translation = Vector3Lerp(translationStart, translationEnd, lerpPercent); if (success)
{
output->framePoses[frame][boneId].translation = Vector3Lerp(translationStart, translationEnd, lerpPercent);
}
} }
if (channel->target_path == cgltf_animation_path_type_rotation) if (channel->target_path == cgltf_animation_path_type_rotation)
{ {
@ -5239,7 +5426,7 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo
rotationStart.z = values[2]; rotationStart.z = values[2];
rotationStart.w = values[3]; rotationStart.w = values[3];
success = ReadGLTFValue(sampler->output, outputMax, &values) || success; success = ReadGLTFValue(sampler->output, outputMax, &values) && success;
rotationEnd.x = values[0]; rotationEnd.x = values[0];
rotationEnd.y = values[1]; rotationEnd.y = values[1];
@ -5264,13 +5451,16 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo
scaleStart.y = values[1]; scaleStart.y = values[1];
scaleStart.z = values[2]; scaleStart.z = values[2];
success = ReadGLTFValue(sampler->output, outputMax, &values) || success; success = ReadGLTFValue(sampler->output, outputMax, &values) && success;
scaleEnd.x = values[0]; scaleEnd.x = values[0];
scaleEnd.y = values[1]; scaleEnd.y = values[1];
scaleEnd.z = values[2]; scaleEnd.z = values[2];
if (success) output->framePoses[frame][boneId].scale = Vector3Lerp(scaleStart, scaleEnd, lerpPercent); if (success)
{
output->framePoses[frame][boneId].scale = Vector3Lerp(scaleStart, scaleEnd, lerpPercent);
}
} }
} }
} }
@ -5285,7 +5475,10 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo
{ {
for (int i = 0; i < output->boneCount; i++) for (int i = 0; i < output->boneCount; i++)
{ {
if (completedBones[i]) continue; if (completedBones[i])
{
continue;
}
if (output->bones[i].parent < 0) if (output->bones[i].parent < 0)
{ {
@ -5294,7 +5487,10 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo
continue; continue;
} }
if (!completedBones[output->bones[i].parent]) continue; if (!completedBones[output->bones[i].parent])
{
continue;
}
output->framePoses[frame][i].rotation = QuaternionMultiply(output->framePoses[frame][output->bones[i].parent].rotation, output->framePoses[frame][i].rotation); output->framePoses[frame][i].rotation = QuaternionMultiply(output->framePoses[frame][output->bones[i].parent].rotation, output->framePoses[frame][i].rotation);
output->framePoses[frame][i].translation = Vector3RotateByQuaternion(output->framePoses[frame][i].translation, output->framePoses[frame][output->bones[i].parent].rotation); output->framePoses[frame][i].translation = Vector3RotateByQuaternion(output->framePoses[frame][i].translation, output->framePoses[frame][output->bones[i].parent].rotation);
@ -5304,7 +5500,6 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo
numberCompletedBones++; numberCompletedBones++;
} }
} }
RL_FREE(completedBones); RL_FREE(completedBones);
} }
} }
@ -5318,8 +5513,9 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo
return animations; return animations;
} }
void LoadGLTFMesh(cgltf_data* data, cgltf_mesh* mesh, Model* outModel, Matrix currentTransform, int* primitiveIndex, const char *fileName) void LoadGLTFMesh(cgltf_data *data, cgltf_node *node, Model *outModel, Matrix currentTransform, int *primitiveIndex, const char *fileName)
{ {
cgltf_mesh *mesh = node->mesh;
for (unsigned int p = 0; p < mesh->primitives_count; p++) for (unsigned int p = 0; p < mesh->primitives_count; p++)
{ {
for (unsigned int j = 0; j < mesh->primitives[p].attributes_count; j++) for (unsigned int j = 0; j < mesh->primitives[p].attributes_count; j++)
@ -5386,23 +5582,16 @@ void LoadGLTFMesh(cgltf_data* data, cgltf_mesh* mesh, Model* outModel, Matrix cu
cgltf_accessor *acc = mesh->primitives[p].attributes[j].data; cgltf_accessor *acc = mesh->primitives[p].attributes[j].data;
unsigned int boneCount = acc->count; unsigned int boneCount = acc->count;
unsigned int totalBoneWeights = boneCount*4; unsigned int totalBoneWeights = boneCount*4;
outModel->meshes[(*primitiveIndex)].boneIds = RL_MALLOC(totalBoneWeights*sizeof(int)); outModel->meshes[(*primitiveIndex)].boneIds = RL_MALLOC(totalBoneWeights*sizeof(int));
short *bones = ReadGLTFValuesAs(acc, cgltf_component_type_r_16, false); short *bones = ReadGLTFValuesAs(acc, cgltf_component_type_r_16, false);
// Find skin joint
for (unsigned int a = 0; a < totalBoneWeights; a++) for (unsigned int a = 0; a < totalBoneWeights; a++)
{ {
outModel->meshes[(*primitiveIndex)].boneIds[a] = 0; outModel->meshes[(*primitiveIndex)].boneIds[a] = 0;
if (bones[a] < 0) continue; if (bones[a] < 0) continue;
cgltf_node* skinJoint = node->skin->joints[bones[a]];
cgltf_node* skinJoint = data->skins->joints[bones[a]]; unsigned int skinJointId = skinJoint - data->nodes;
for (unsigned int k = 0; k < data->nodes_count; k++) outModel->meshes[(*primitiveIndex)].boneIds[a] = skinJointId;
{
if (data->nodes + k == skinJoint)
{
outModel->meshes[(*primitiveIndex)].boneIds[a] = k;
break;
}
}
} }
RL_FREE(bones); RL_FREE(bones);
} }
@ -5437,28 +5626,62 @@ void LoadGLTFMesh(cgltf_data* data, cgltf_mesh* mesh, Model* outModel, Matrix cu
} }
else outModel->meshMaterial[(*primitiveIndex)] = outModel->materialCount - 1; else outModel->meshMaterial[(*primitiveIndex)] = outModel->materialCount - 1;
BindGLTFPrimitiveToBones(outModel, data, *primitiveIndex); BindGLTFPrimitiveToBones(outModel, node, data, *primitiveIndex);
(*primitiveIndex) = (*primitiveIndex) + 1; (*primitiveIndex) = (*primitiveIndex) + 1;
} }
} }
void LoadGLTFNode(cgltf_data* data, cgltf_node* node, Model* outModel, Matrix currentTransform, int* primitiveIndex, const char *fileName) static Matrix GetNodeTransformationMatrix(cgltf_node *node, Matrix current)
{ {
Matrix nodeTransform = { if (node->has_matrix)
{
Matrix nodeTransform = {
node->matrix[0], node->matrix[4], node->matrix[8], node->matrix[12], node->matrix[0], node->matrix[4], node->matrix[8], node->matrix[12],
node->matrix[1], node->matrix[5], node->matrix[9], node->matrix[13], node->matrix[1], node->matrix[5], node->matrix[9], node->matrix[13],
node->matrix[2], node->matrix[6], node->matrix[10], node->matrix[14], node->matrix[2], node->matrix[6], node->matrix[10], node->matrix[14],
node->matrix[3], node->matrix[7], node->matrix[11], node->matrix[15] }; node->matrix[3], node->matrix[7], node->matrix[11], node->matrix[15] };
current= MatrixMultiply(nodeTransform, current);
}
if (node->has_translation)
{
Matrix tl = MatrixTranslate(node->translation[0],node->translation[1],node->translation[2]);
current = MatrixMultiply(tl, current);
}
if (node->has_rotation)
{
Matrix rot = QuaternionToMatrix((Quaternion){node->rotation[0],node->rotation[1],node->rotation[2],node->rotation[3]});
current = MatrixMultiply(rot, current);
}
if (node->has_scale)
{
Matrix scale = MatrixScale(node->scale[0],node->scale[1],node->scale[2]);
current = MatrixMultiply(scale, current);
}
return current;
}
currentTransform = MatrixMultiply(nodeTransform, currentTransform); void LoadGLTFNode(cgltf_data *data, cgltf_node *node, Model *outModel, Matrix currentTransform, int *primitiveIndex, const char *fileName)
{
if (node->mesh != NULL) LoadGLTFMesh(data, node->mesh, outModel, currentTransform, primitiveIndex, fileName); // Apply the transforms if they exist (Will still be applied even if no mesh is present to support emptys and bone structures)
Matrix localTransform = GetNodeTransformationMatrix(node, MatrixIdentity());
currentTransform = MatrixMultiply(localTransform, currentTransform);
// Load mesh if it exists
if (node->mesh != NULL)
{
// Check if skinning is enabled and load Mesh accordingly
Matrix vertexTransform = currentTransform;
if ((node->skin != NULL) && (node->parent != NULL))
{
vertexTransform = localTransform;
TRACELOG(LOG_WARNING,"MODEL: GLTF Node %s is skinned but not root node! Parent transformations will be ignored (NODE_SKINNED_MESH_NON_ROOT)",node->name);
}
LoadGLTFMesh(data, node, outModel, vertexTransform, primitiveIndex, fileName);
}
for (unsigned int i = 0; i < node->children_count; i++) LoadGLTFNode(data, node->children[i], outModel, currentTransform, primitiveIndex, fileName); for (unsigned int i = 0; i < node->children_count; i++) LoadGLTFNode(data, node->children[i], outModel, currentTransform, primitiveIndex, fileName);
} }
static void GetGLTFPrimitiveCount(cgltf_node* node, int* outCount) static void GetGLTFPrimitiveCount(cgltf_node *node, int *outCount)
{ {
if (node->mesh != NULL) *outCount += node->mesh->primitives_count; if (node->mesh != NULL) *outCount += node->mesh->primitives_count;
@ -5466,3 +5689,108 @@ static void GetGLTFPrimitiveCount(cgltf_node* node, int* outCount)
} }
#endif #endif
#if defined(SUPPORT_FILEFORMAT_VOX)
// Load VOX (MagicaVoxel) mesh data
static Model LoadVOX(const char *fileName)
{
Model model = { 0 };
int nbvertices = 0;
int meshescount = 0;
unsigned int readed = 0;
unsigned char* fileData;
//Read vox file into buffer
fileData = LoadFileData(fileName, &readed);
if (fileData == 0)
{
TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load VOX file", fileName);
return model;
}
//Read and build voxarray description
VoxArray3D voxarray = { 0 };
int ret = Vox_LoadFromMemory(fileData, readed, &voxarray);
if (ret != VOX_SUCCESS)
{
// Error
UnloadFileData(fileData);
TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load VOX data", fileName);
return model;
}
else
{
// Success: Compute meshes count
nbvertices = voxarray.vertices.used;
meshescount = 1 + (nbvertices/65536);
TRACELOG(LOG_INFO, "MODEL: [%s] VOX data loaded successfully : %i vertices/%i meshes", fileName, nbvertices, meshescount);
}
// Build models from meshes
model.transform = MatrixIdentity();
model.meshCount = meshescount;
model.meshes = (Mesh *)MemAlloc(model.meshCount*sizeof(Mesh));
model.meshMaterial = (int *)MemAlloc(model.meshCount*sizeof(int));
model.materialCount = 1;
model.materials = (Material *)MemAlloc(model.materialCount*sizeof(Material));
model.materials[0] = LoadMaterialDefault();
// Init model meshes
int verticesRemain = voxarray.vertices.used;
int verticesMax = 65532; // 5461 voxels x 12 vertices per voxel -> 65532 (must be inf 65536)
Vector3 *pvertices = voxarray.vertices.array; // 6*4 = 12 vertices per voxel
Color *pcolors = voxarray.colors.array;
unsigned short *pindices = voxarray.indices.array; // 5461*6*6 = 196596 indices max per mesh
int size = 0;
for (int idxMesh = 0; idxMesh < meshescount; idxMesh++)
{
Mesh *pmesh = &model.meshes[idxMesh];
memset(pmesh, 0, sizeof(Mesh));
// Copy vertices
pmesh->vertexCount = (int)fmin(verticesMax, verticesRemain);
size = pmesh->vertexCount*sizeof(float)*3;
pmesh->vertices = MemAlloc(size);
memcpy(pmesh->vertices, pvertices, size);
// Copy indices
// TODO: Compute globals indices array
size = voxarray.indices.used * sizeof(unsigned short);
pmesh->indices = MemAlloc(size);
memcpy(pmesh->indices, pindices, size);
pmesh->triangleCount = (pmesh->vertexCount/4)*2;
// Copy colors
size = pmesh->vertexCount*sizeof(Color);
pmesh->colors = MemAlloc(size);
memcpy(pmesh->colors, pcolors, size);
// First material index
model.meshMaterial[idxMesh] = 0;
// Upload mesh data to GPU
UploadMesh(pmesh, false);
verticesRemain -= verticesMax;
pvertices += verticesMax;
pcolors += verticesMax;
}
//Free buffers
Vox_FreeArrays(&voxarray);
UnloadFileData(fileData);
return model;
}
#endif

View File

@ -1,6 +1,6 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raylib.shapes - Basic functions to draw 2d Shapes and check collisions * rshapes - Basic functions to draw 2d shapes and check collisions
* *
* CONFIGURATION: * CONFIGURATION:
* *
@ -190,16 +190,16 @@ void DrawLineBezierQuad(Vector2 startPos, Vector2 endPos, Vector2 controlPos, fl
} }
// Draw lines sequence // Draw lines sequence
void DrawLineStrip(Vector2 *points, int pointsCount, Color color) void DrawLineStrip(Vector2 *points, int pointCount, Color color)
{ {
if (pointsCount >= 2) if (pointCount >= 2)
{ {
rlCheckRenderBatchLimit(pointsCount); rlCheckRenderBatchLimit(pointCount);
rlBegin(RL_LINES); rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
for (int i = 0; i < pointsCount - 1; i++) for (int i = 0; i < pointCount - 1; i++)
{ {
rlVertex2f(points[i].x, points[i].y); rlVertex2f(points[i].x, points[i].y);
rlVertex2f(points[i + 1].x, points[i + 1].y); rlVertex2f(points[i + 1].x, points[i + 1].y);
@ -1318,17 +1318,17 @@ void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
// Draw a triangle fan defined by points // Draw a triangle fan defined by points
// NOTE: First vertex provided is the center, shared by all triangles // NOTE: First vertex provided is the center, shared by all triangles
// By default, following vertex should be provided in counter-clockwise order // By default, following vertex should be provided in counter-clockwise order
void DrawTriangleFan(Vector2 *points, int pointsCount, Color color) void DrawTriangleFan(Vector2 *points, int pointCount, Color color)
{ {
if (pointsCount >= 3) if (pointCount >= 3)
{ {
rlCheckRenderBatchLimit((pointsCount - 2)*4); rlCheckRenderBatchLimit((pointCount - 2)*4);
rlSetTexture(texShapes.id); rlSetTexture(texShapes.id);
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
for (int i = 1; i < pointsCount - 1; i++) for (int i = 1; i < pointCount - 1; i++)
{ {
rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(points[0].x, points[0].y); rlVertex2f(points[0].x, points[0].y);
@ -1349,16 +1349,16 @@ void DrawTriangleFan(Vector2 *points, int pointsCount, Color color)
// Draw a triangle strip defined by points // Draw a triangle strip defined by points
// NOTE: Every new vertex connects with previous two // NOTE: Every new vertex connects with previous two
void DrawTriangleStrip(Vector2 *points, int pointsCount, Color color) void DrawTriangleStrip(Vector2 *points, int pointCount, Color color)
{ {
if (pointsCount >= 3) if (pointCount >= 3)
{ {
rlCheckRenderBatchLimit(3*(pointsCount - 2)); rlCheckRenderBatchLimit(3*(pointCount - 2));
rlBegin(RL_TRIANGLES); rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
for (int i = 2; i < pointsCount; i++) for (int i = 2; i < pointCount; i++)
{ {
if ((i%2) == 0) if ((i%2) == 0)
{ {

View File

@ -1,6 +1,6 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raylib.text - Basic functions to load Fonts and draw Text * rtext - Basic functions to load fonts and draw text
* *
* CONFIGURATION: * CONFIGURATION:
* *
@ -129,8 +129,8 @@ extern void LoadFontDefault(void)
// NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement // NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement
// Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl // Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl
defaultFont.charsCount = 224; // Number of chars included in our default font defaultFont.glyphCount = 224; // Number of chars included in our default font
defaultFont.charsPadding = 0; // Characters padding defaultFont.glyphPadding = 0; // Characters padding
// Default font is directly defined here (data generated from a sprite font image) // Default font is directly defined here (data generated from a sprite font image)
// This way, we reconstruct Font without creating large global variables // This way, we reconstruct Font without creating large global variables
@ -220,21 +220,21 @@ extern void LoadFontDefault(void)
defaultFont.texture = LoadTextureFromImage(imFont); defaultFont.texture = LoadTextureFromImage(imFont);
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, charsCount // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Allocate space for our characters info data // Allocate space for our characters info data
// NOTE: This memory should be freed at end! --> CloseWindow() // NOTE: This memory should be freed at end! --> CloseWindow()
defaultFont.chars = (GlyphInfo *)RL_MALLOC(defaultFont.charsCount*sizeof(GlyphInfo)); defaultFont.glyphs = (GlyphInfo *)RL_MALLOC(defaultFont.glyphCount*sizeof(GlyphInfo));
defaultFont.recs = (Rectangle *)RL_MALLOC(defaultFont.charsCount*sizeof(Rectangle)); defaultFont.recs = (Rectangle *)RL_MALLOC(defaultFont.glyphCount*sizeof(Rectangle));
int currentLine = 0; int currentLine = 0;
int currentPosX = charsDivisor; int currentPosX = charsDivisor;
int testPosX = charsDivisor; int testPosX = charsDivisor;
for (int i = 0; i < defaultFont.charsCount; i++) for (int i = 0; i < defaultFont.glyphCount; i++)
{ {
defaultFont.chars[i].value = 32 + i; // First char is 32 defaultFont.glyphs[i].value = 32 + i; // First char is 32
defaultFont.recs[i].x = (float)currentPosX; defaultFont.recs[i].x = (float)currentPosX;
defaultFont.recs[i].y = (float)(charsDivisor + currentLine*(charsHeight + charsDivisor)); defaultFont.recs[i].y = (float)(charsDivisor + currentLine*(charsHeight + charsDivisor));
@ -255,27 +255,27 @@ extern void LoadFontDefault(void)
else currentPosX = testPosX; else currentPosX = testPosX;
// NOTE: On default font character offsets and xAdvance are not required // NOTE: On default font character offsets and xAdvance are not required
defaultFont.chars[i].offsetX = 0; defaultFont.glyphs[i].offsetX = 0;
defaultFont.chars[i].offsetY = 0; defaultFont.glyphs[i].offsetY = 0;
defaultFont.chars[i].advanceX = 0; defaultFont.glyphs[i].advanceX = 0;
// Fill character image data from fontClear data // Fill character image data from fontClear data
defaultFont.chars[i].image = ImageFromImage(imFont, defaultFont.recs[i]); defaultFont.glyphs[i].image = ImageFromImage(imFont, defaultFont.recs[i]);
} }
UnloadImage(imFont); UnloadImage(imFont);
defaultFont.baseSize = (int)defaultFont.recs[0].height; defaultFont.baseSize = (int)defaultFont.recs[0].height;
TRACELOG(LOG_INFO, "FONT: [ID %i] Default font texture loaded successfully", defaultFont.texture.id); TRACELOG(LOG_INFO, "FONT: Default font loaded successfully (%i glyphs)", defaultFont.glyphCount);
} }
// Unload raylib default font // Unload raylib default font
extern void UnloadFontDefault(void) extern void UnloadFontDefault(void)
{ {
for (int i = 0; i < defaultFont.charsCount; i++) UnloadImage(defaultFont.chars[i].image); for (int i = 0; i < defaultFont.glyphCount; i++) UnloadImage(defaultFont.glyphs[i].image);
UnloadTexture(defaultFont.texture); UnloadTexture(defaultFont.texture);
RL_FREE(defaultFont.chars); RL_FREE(defaultFont.glyphs);
RL_FREE(defaultFont.recs); RL_FREE(defaultFont.recs);
} }
#endif // SUPPORT_DEFAULT_FONT #endif // SUPPORT_DEFAULT_FONT
@ -337,7 +337,7 @@ Font LoadFont(const char *fileName)
// Load Font from TTF font file with generation parameters // Load Font from TTF font file with generation parameters
// NOTE: You can pass an array with desired characters, those characters should be available in the font // NOTE: You can pass an array with desired characters, those characters should be available in the font
// if array is NULL, default char set is selected 32..126 // if array is NULL, default char set is selected 32..126
Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCount) Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int glyphCount)
{ {
Font font = { 0 }; Font font = { 0 };
@ -348,7 +348,7 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou
if (fileData != NULL) if (fileData != NULL)
{ {
// Loading font from memory data // Loading font from memory data
font = LoadFontFromMemory(GetFileExtension(fileName), fileData, fileSize, fontSize, fontChars, charsCount); font = LoadFontFromMemory(GetFileExtension(fileName), fileData, fileSize, fontSize, fontChars, glyphCount);
RL_FREE(fileData); RL_FREE(fileData);
} }
@ -449,28 +449,28 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
Font font = { 0 }; Font font = { 0 };
font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
font.charsCount = index; font.glyphCount = index;
font.charsPadding = 0; font.glyphPadding = 0;
// We got tempCharValues and tempCharsRecs populated with chars data // We got tempCharValues and tempCharsRecs populated with chars data
// Now we move temp data to sized charValues and charRecs arrays // Now we move temp data to sized charValues and charRecs arrays
font.chars = (GlyphInfo *)RL_MALLOC(font.charsCount*sizeof(GlyphInfo)); font.glyphs = (GlyphInfo *)RL_MALLOC(font.glyphCount*sizeof(GlyphInfo));
font.recs = (Rectangle *)RL_MALLOC(font.charsCount*sizeof(Rectangle)); font.recs = (Rectangle *)RL_MALLOC(font.glyphCount*sizeof(Rectangle));
for (int i = 0; i < font.charsCount; i++) for (int i = 0; i < font.glyphCount; i++)
{ {
font.chars[i].value = tempCharValues[i]; font.glyphs[i].value = tempCharValues[i];
// Get character rectangle in the font atlas texture // Get character rectangle in the font atlas texture
font.recs[i] = tempCharRecs[i]; font.recs[i] = tempCharRecs[i];
// NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0) // NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0)
font.chars[i].offsetX = 0; font.glyphs[i].offsetX = 0;
font.chars[i].offsetY = 0; font.glyphs[i].offsetY = 0;
font.chars[i].advanceX = 0; font.glyphs[i].advanceX = 0;
// Fill character image data from fontClear data // Fill character image data from fontClear data
font.chars[i].image = ImageFromImage(fontClear, tempCharRecs[i]); font.glyphs[i].image = ImageFromImage(fontClear, tempCharRecs[i]);
} }
UnloadImage(fontClear); // Unload processed image once converted to texture UnloadImage(fontClear); // Unload processed image once converted to texture
@ -481,7 +481,7 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
} }
// Load font from memory buffer, fileType refers to extension: i.e. ".ttf" // Load font from memory buffer, fileType refers to extension: i.e. ".ttf"
Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount) Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int glyphCount)
{ {
Font font = { 0 }; Font font = { 0 };
@ -493,25 +493,27 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int
TextIsEqual(fileExtLower, ".otf")) TextIsEqual(fileExtLower, ".otf"))
{ {
font.baseSize = fontSize; font.baseSize = fontSize;
font.charsCount = (charsCount > 0)? charsCount : 95; font.glyphCount = (glyphCount > 0)? glyphCount : 95;
font.charsPadding = 0; font.glyphPadding = 0;
font.chars = LoadFontData(fileData, dataSize, font.baseSize, fontChars, font.charsCount, FONT_DEFAULT); font.glyphs = LoadFontData(fileData, dataSize, font.baseSize, fontChars, font.glyphCount, FONT_DEFAULT);
if (font.chars != NULL) if (font.glyphs != NULL)
{ {
font.charsPadding = FONT_TTF_DEFAULT_CHARS_PADDING; font.glyphPadding = FONT_TTF_DEFAULT_CHARS_PADDING;
Image atlas = GenImageFontAtlas(font.chars, &font.recs, font.charsCount, font.baseSize, font.charsPadding, 0); Image atlas = GenImageFontAtlas(font.glyphs, &font.recs, font.glyphCount, font.baseSize, font.glyphPadding, 0);
font.texture = LoadTextureFromImage(atlas); font.texture = LoadTextureFromImage(atlas);
// Update chars[i].image to use alpha, required to be used on ImageDrawText() // Update glyphs[i].image to use alpha, required to be used on ImageDrawText()
for (int i = 0; i < font.charsCount; i++) for (int i = 0; i < font.glyphCount; i++)
{ {
UnloadImage(font.chars[i].image); UnloadImage(font.glyphs[i].image);
font.chars[i].image = ImageFromImage(atlas, font.recs[i]); font.glyphs[i].image = ImageFromImage(atlas, font.recs[i]);
} }
UnloadImage(atlas); UnloadImage(atlas);
// TRACELOG(LOG_INFO, "FONT: Font loaded successfully (%i glyphs)", font.glyphCount);
} }
else font = GetFontDefault(); else font = GetFontDefault();
} }
@ -524,7 +526,7 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int
// Load font data for further use // Load font data for further use
// NOTE: Requires TTF font memory data and can generate SDF data // NOTE: Requires TTF font memory data and can generate SDF data
GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount, int type) GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int glyphCount, int type)
{ {
// NOTE: Using some SDF generation default values, // NOTE: Using some SDF generation default values,
// trades off precision with ability to handle *smaller* sizes // trades off precision with ability to handle *smaller* sizes
@ -562,22 +564,22 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap); stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap);
// In case no chars count provided, default to 95 // In case no chars count provided, default to 95
charsCount = (charsCount > 0)? charsCount : 95; glyphCount = (glyphCount > 0)? glyphCount : 95;
// Fill fontChars in case not provided externally // Fill fontChars in case not provided externally
// NOTE: By default we fill charsCount consecutevely, starting at 32 (Space) // NOTE: By default we fill glyphCount consecutevely, starting at 32 (Space)
if (fontChars == NULL) if (fontChars == NULL)
{ {
fontChars = (int *)RL_MALLOC(charsCount*sizeof(int)); fontChars = (int *)RL_MALLOC(glyphCount*sizeof(int));
for (int i = 0; i < charsCount; i++) fontChars[i] = i + 32; for (int i = 0; i < glyphCount; i++) fontChars[i] = i + 32;
genFontChars = true; genFontChars = true;
} }
chars = (GlyphInfo *)RL_MALLOC(charsCount*sizeof(GlyphInfo)); chars = (GlyphInfo *)RL_MALLOC(glyphCount*sizeof(GlyphInfo));
// NOTE: Using simple packaging, one char after another // NOTE: Using simple packaging, one char after another
for (int i = 0; i < charsCount; i++) for (int i = 0; i < glyphCount; i++)
{ {
int chw = 0, chh = 0; // Character width and height (on generation) int chw = 0, chh = 0; // Character width and height (on generation)
int ch = fontChars[i]; // Character value to get info for int ch = fontChars[i]; // Character value to get info for
@ -650,7 +652,7 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
// Generate image font atlas using chars info // Generate image font atlas using chars info
// NOTE: Packing method: 0-Default, 1-Skyline // NOTE: Packing method: 0-Default, 1-Skyline
#if defined(SUPPORT_FILEFORMAT_TTF) #if defined(SUPPORT_FILEFORMAT_TTF)
Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int charsCount, int fontSize, int padding, int packMethod) Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int glyphCount, int fontSize, int padding, int packMethod)
{ {
Image atlas = { 0 }; Image atlas = { 0 };
@ -663,17 +665,17 @@ Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int charsC
*charRecs = NULL; *charRecs = NULL;
// In case no chars count provided we suppose default of 95 // In case no chars count provided we suppose default of 95
charsCount = (charsCount > 0)? charsCount : 95; glyphCount = (glyphCount > 0)? glyphCount : 95;
// NOTE: Rectangles memory is loaded here! // NOTE: Rectangles memory is loaded here!
Rectangle *recs = (Rectangle *)RL_MALLOC(charsCount*sizeof(Rectangle)); Rectangle *recs = (Rectangle *)RL_MALLOC(glyphCount*sizeof(Rectangle));
// Calculate image size based on required pixel area // Calculate image size based on required pixel area
// NOTE 1: Image is forced to be squared and POT... very conservative! // NOTE 1: Image is forced to be squared and POT... very conservative!
// NOTE 2: SDF font characters already contain an internal padding, // NOTE 2: SDF font characters already contain an internal padding,
// so image size would result bigger than default font type // so image size would result bigger than default font type
float requiredArea = 0; float requiredArea = 0;
for (int i = 0; i < charsCount; i++) requiredArea += ((chars[i].image.width + 2*padding)*(chars[i].image.height + 2*padding)); for (int i = 0; i < glyphCount; i++) requiredArea += ((chars[i].image.width + 2*padding)*(chars[i].image.height + 2*padding));
float guessSize = sqrtf(requiredArea)*1.3f; float guessSize = sqrtf(requiredArea)*1.3f;
int imageSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT int imageSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT
@ -692,7 +694,7 @@ Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int charsC
int offsetY = padding; int offsetY = padding;
// NOTE: Using simple packaging, one char after another // NOTE: Using simple packaging, one char after another
for (int i = 0; i < charsCount; i++) for (int i = 0; i < glyphCount; i++)
{ {
// Copy pixel data from fc.data to atlas // Copy pixel data from fc.data to atlas
for (int y = 0; y < chars[i].image.height; y++) for (int y = 0; y < chars[i].image.height; y++)
@ -728,13 +730,13 @@ Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int charsC
else if (packMethod == 1) // Use Skyline rect packing algorythm (stb_pack_rect) else if (packMethod == 1) // Use Skyline rect packing algorythm (stb_pack_rect)
{ {
stbrp_context *context = (stbrp_context *)RL_MALLOC(sizeof(*context)); stbrp_context *context = (stbrp_context *)RL_MALLOC(sizeof(*context));
stbrp_node *nodes = (stbrp_node *)RL_MALLOC(charsCount*sizeof(*nodes)); stbrp_node *nodes = (stbrp_node *)RL_MALLOC(glyphCount*sizeof(*nodes));
stbrp_init_target(context, atlas.width, atlas.height, nodes, charsCount); stbrp_init_target(context, atlas.width, atlas.height, nodes, glyphCount);
stbrp_rect *rects = (stbrp_rect *)RL_MALLOC(charsCount*sizeof(stbrp_rect)); stbrp_rect *rects = (stbrp_rect *)RL_MALLOC(glyphCount*sizeof(stbrp_rect));
// Fill rectangles for packaging // Fill rectangles for packaging
for (int i = 0; i < charsCount; i++) for (int i = 0; i < glyphCount; i++)
{ {
rects[i].id = i; rects[i].id = i;
rects[i].w = chars[i].image.width + 2*padding; rects[i].w = chars[i].image.width + 2*padding;
@ -742,9 +744,9 @@ Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int charsC
} }
// Package rectangles into atlas // Package rectangles into atlas
stbrp_pack_rects(context, rects, charsCount); stbrp_pack_rects(context, rects, glyphCount);
for (int i = 0; i < charsCount; i++) for (int i = 0; i < glyphCount; i++)
{ {
// It return char rectangles in atlas // It return char rectangles in atlas
recs[i].x = rects[i].x + (float)padding; recs[i].x = rects[i].x + (float)padding;
@ -792,12 +794,12 @@ Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int charsC
} }
#endif #endif
// Unload font chars info data (RAM) // Unload font glyphs info data (RAM)
void UnloadFontData(GlyphInfo *chars, int charsCount) void UnloadFontData(GlyphInfo *glyphs, int glyphCount)
{ {
for (int i = 0; i < charsCount; i++) UnloadImage(chars[i].image); for (int i = 0; i < glyphCount; i++) UnloadImage(glyphs[i].image);
RL_FREE(chars); RL_FREE(glyphs);
} }
// Unload Font from GPU memory (VRAM) // Unload Font from GPU memory (VRAM)
@ -806,7 +808,7 @@ void UnloadFont(Font font)
// NOTE: Make sure font is not default font (fallback) // NOTE: Make sure font is not default font (fallback)
if (font.texture.id != GetFontDefault().texture.id) if (font.texture.id != GetFontDefault().texture.id)
{ {
UnloadFontData(font.chars, font.charsCount); UnloadFontData(font.glyphs, font.glyphCount);
UnloadTexture(font.texture); UnloadTexture(font.texture);
RL_FREE(font.recs); RL_FREE(font.recs);
@ -851,14 +853,14 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f
{ {
if (font.texture.id == 0) font = GetFontDefault(); // Security check in case of not valid font if (font.texture.id == 0) font = GetFontDefault(); // Security check in case of not valid font
int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop int size = TextLength(text); // Total size in bytes of the text, scanned by codepoints in loop
int textOffsetY = 0; // Offset between lines (on line break '\n') int textOffsetY = 0; // Offset between lines (on line break '\n')
float textOffsetX = 0.0f; // Offset X to next character to draw float textOffsetX = 0.0f; // Offset X to next character to draw
float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor
for (int i = 0; i < length;) for (int i = 0; i < size;)
{ {
// Get next codepoint from byte string and glyph index in font // Get next codepoint from byte string and glyph index in font
int codepointByteCount = 0; int codepointByteCount = 0;
@ -883,8 +885,8 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f
DrawTextCodepoint(font, codepoint, (Vector2){ position.x + textOffsetX, position.y + textOffsetY }, fontSize, tint); DrawTextCodepoint(font, codepoint, (Vector2){ position.x + textOffsetX, position.y + textOffsetY }, fontSize, tint);
} }
if (font.chars[index].advanceX == 0) textOffsetX += ((float)font.recs[index].width*scaleFactor + spacing); if (font.glyphs[index].advanceX == 0) textOffsetX += ((float)font.recs[index].width*scaleFactor + spacing);
else textOffsetX += ((float)font.chars[index].advanceX*scaleFactor + spacing); else textOffsetX += ((float)font.glyphs[index].advanceX*scaleFactor + spacing);
} }
i += codepointByteCount; // Move text bytes counter to next codepoint i += codepointByteCount; // Move text bytes counter to next codepoint
@ -914,16 +916,16 @@ void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSiz
float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor
// Character destination rectangle on screen // Character destination rectangle on screen
// NOTE: We consider charsPadding on drawing // NOTE: We consider glyphPadding on drawing
Rectangle dstRec = { position.x + font.chars[index].offsetX*scaleFactor - (float)font.charsPadding*scaleFactor, Rectangle dstRec = { position.x + font.glyphs[index].offsetX*scaleFactor - (float)font.glyphPadding*scaleFactor,
position.y + font.chars[index].offsetY*scaleFactor - (float)font.charsPadding*scaleFactor, position.y + font.glyphs[index].offsetY*scaleFactor - (float)font.glyphPadding*scaleFactor,
(font.recs[index].width + 2.0f*font.charsPadding)*scaleFactor, (font.recs[index].width + 2.0f*font.glyphPadding)*scaleFactor,
(font.recs[index].height + 2.0f*font.charsPadding)*scaleFactor }; (font.recs[index].height + 2.0f*font.glyphPadding)*scaleFactor };
// Character source rectangle from font texture atlas // Character source rectangle from font texture atlas
// NOTE: We consider chars padding when drawing, it could be required for outline/glow shader effects // NOTE: We consider chars padding when drawing, it could be required for outline/glow shader effects
Rectangle srcRec = { font.recs[index].x - (float)font.charsPadding, font.recs[index].y - (float)font.charsPadding, Rectangle srcRec = { font.recs[index].x - (float)font.glyphPadding, font.recs[index].y - (float)font.glyphPadding,
font.recs[index].width + 2.0f*font.charsPadding, font.recs[index].height + 2.0f*font.charsPadding }; font.recs[index].width + 2.0f*font.glyphPadding, font.recs[index].height + 2.0f*font.glyphPadding };
// Draw the character texture on the screen // Draw the character texture on the screen
DrawTexturePro(font.texture, srcRec, dstRec, (Vector2){ 0, 0 }, 0.0f, tint); DrawTexturePro(font.texture, srcRec, dstRec, (Vector2){ 0, 0 }, 0.0f, tint);
@ -950,9 +952,9 @@ int MeasureText(const char *text, int fontSize)
// Measure string size for Font // Measure string size for Font
Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing) Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing)
{ {
int len = TextLength(text); int size = TextLength(text); // Get size in bytes of text
int tempLen = 0; // Used to count longer text line num chars int tempByteCounter = 0; // Used to count longer text line num chars
int lenCounter = 0; int byteCounter = 0;
float textWidth = 0.0f; float textWidth = 0.0f;
float tempTextWidth = 0.0f; // Used to count longer text line width float tempTextWidth = 0.0f; // Used to count longer text line width
@ -963,9 +965,9 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
int letter = 0; // Current character int letter = 0; // Current character
int index = 0; // Index position in sprite font int index = 0; // Index position in sprite font
for (int i = 0; i < len; i++) for (int i = 0; i < size; i++)
{ {
lenCounter++; byteCounter++;
int next = 0; int next = 0;
letter = GetCodepoint(&text[i], &next); letter = GetCodepoint(&text[i], &next);
@ -978,24 +980,24 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
if (letter != '\n') if (letter != '\n')
{ {
if (font.chars[index].advanceX != 0) textWidth += font.chars[index].advanceX; if (font.glyphs[index].advanceX != 0) textWidth += font.glyphs[index].advanceX;
else textWidth += (font.recs[index].width + font.chars[index].offsetX); else textWidth += (font.recs[index].width + font.glyphs[index].offsetX);
} }
else else
{ {
if (tempTextWidth < textWidth) tempTextWidth = textWidth; if (tempTextWidth < textWidth) tempTextWidth = textWidth;
lenCounter = 0; byteCounter = 0;
textWidth = 0; textWidth = 0;
textHeight += ((float)font.baseSize*1.5f); // NOTE: Fixed line spacing of 1.5 lines textHeight += ((float)font.baseSize*1.5f); // NOTE: Fixed line spacing of 1.5 lines
} }
if (tempLen < lenCounter) tempLen = lenCounter; if (tempByteCounter < byteCounter) tempByteCounter = byteCounter;
} }
if (tempTextWidth < textWidth) tempTextWidth = textWidth; if (tempTextWidth < textWidth) tempTextWidth = textWidth;
Vector2 vec = { 0 }; Vector2 vec = { 0 };
vec.x = tempTextWidth*scaleFactor + (float)((tempLen - 1)*spacing); // Adds chars spacing to measure vec.x = tempTextWidth*scaleFactor + (float)((tempByteCounter - 1)*spacing); // Adds chars spacing to measure
vec.y = textHeight*scaleFactor; vec.y = textHeight*scaleFactor;
return vec; return vec;
@ -1014,9 +1016,9 @@ int GetGlyphIndex(Font font, int codepoint)
#if defined(SUPPORT_UNORDERED_CHARSET) #if defined(SUPPORT_UNORDERED_CHARSET)
int index = GLYPH_NOTFOUND_CHAR_FALLBACK; int index = GLYPH_NOTFOUND_CHAR_FALLBACK;
for (int i = 0; i < font.charsCount; i++) for (int i = 0; i < font.glyphCount; i++)
{ {
if (font.chars[i].value == codepoint) if (font.glyphs[i].value == codepoint)
{ {
index = i; index = i;
break; break;
@ -1035,7 +1037,7 @@ GlyphInfo GetGlyphInfo(Font font, int codepoint)
{ {
GlyphInfo info = { 0 }; GlyphInfo info = { 0 };
info = font.chars[GetGlyphIndex(font, codepoint)]; info = font.glyphs[GetGlyphIndex(font, codepoint)];
return info; return info;
} }
@ -1429,28 +1431,28 @@ char *TextCodepointsToUTF8(int *codepoints, int length)
// Encode codepoint into utf8 text (char array length returned as parameter) // Encode codepoint into utf8 text (char array length returned as parameter)
// NOTE: It uses a static array to store UTF-8 bytes // NOTE: It uses a static array to store UTF-8 bytes
RLAPI const char *CodepointToUTF8(int codepoint, int *byteLength) RLAPI const char *CodepointToUTF8(int codepoint, int *byteSize)
{ {
static char utf8[6] = { 0 }; static char utf8[6] = { 0 };
int length = 0; int size = 0; // Byte size of codepoint
if (codepoint <= 0x7f) if (codepoint <= 0x7f)
{ {
utf8[0] = (char)codepoint; utf8[0] = (char)codepoint;
length = 1; size = 1;
} }
else if (codepoint <= 0x7ff) else if (codepoint <= 0x7ff)
{ {
utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0); utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0);
utf8[1] = (char)((codepoint & 0x3f) | 0x80); utf8[1] = (char)((codepoint & 0x3f) | 0x80);
length = 2; size = 2;
} }
else if (codepoint <= 0xffff) else if (codepoint <= 0xffff)
{ {
utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0); utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0);
utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80); utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
utf8[2] = (char)((codepoint & 0x3f) | 0x80); utf8[2] = (char)((codepoint & 0x3f) | 0x80);
length = 3; size = 3;
} }
else if (codepoint <= 0x10ffff) else if (codepoint <= 0x10ffff)
{ {
@ -1458,10 +1460,10 @@ RLAPI const char *CodepointToUTF8(int codepoint, int *byteLength)
utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80); utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80);
utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80); utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
utf8[3] = (char)((codepoint & 0x3f) | 0x80); utf8[3] = (char)((codepoint & 0x3f) | 0x80);
length = 4; size = 4;
} }
*byteLength = length; *byteSize = size;
return utf8; return utf8;
} }
@ -1472,22 +1474,22 @@ int *LoadCodepoints(const char *text, int *count)
int textLength = TextLength(text); int textLength = TextLength(text);
int bytesProcessed = 0; int bytesProcessed = 0;
int codepointsCount = 0; int codepointCount = 0;
// Allocate a big enough buffer to store as many codepoints as text bytes // Allocate a big enough buffer to store as many codepoints as text bytes
int *codepoints = RL_CALLOC(textLength, sizeof(int)); int *codepoints = RL_CALLOC(textLength, sizeof(int));
for (int i = 0; i < textLength; codepointsCount++) for (int i = 0; i < textLength; codepointCount++)
{ {
codepoints[codepointsCount] = GetCodepoint(text + i, &bytesProcessed); codepoints[codepointCount] = GetCodepoint(text + i, &bytesProcessed);
i += bytesProcessed; i += bytesProcessed;
} }
// Re-allocate buffer to the actual number of codepoints loaded // Re-allocate buffer to the actual number of codepoints loaded
void *temp = RL_REALLOC(codepoints, codepointsCount*sizeof(int)); void *temp = RL_REALLOC(codepoints, codepointCount*sizeof(int));
if (temp != NULL) codepoints = temp; if (temp != NULL) codepoints = temp;
*count = codepointsCount; *count = codepointCount;
return codepoints; return codepoints;
} }
@ -1500,9 +1502,9 @@ void UnloadCodepoints(int *codepoints)
// Get total number of characters(codepoints) in a UTF-8 encoded text, until '\0' is found // Get total number of characters(codepoints) in a UTF-8 encoded text, until '\0' is found
// NOTE: If an invalid UTF-8 sequence is encountered a '?'(0x3f) codepoint is counted instead // NOTE: If an invalid UTF-8 sequence is encountered a '?'(0x3f) codepoint is counted instead
int GetCodepointsCount(const char *text) int GetCodepointCount(const char *text)
{ {
unsigned int len = 0; unsigned int length = 0;
char *ptr = (char *)&text[0]; char *ptr = (char *)&text[0];
while (*ptr != '\0') while (*ptr != '\0')
@ -1513,19 +1515,18 @@ int GetCodepointsCount(const char *text)
if (letter == 0x3f) ptr += 1; if (letter == 0x3f) ptr += 1;
else ptr += next; else ptr += next;
len++; length++;
} }
return len; return length;
} }
#endif // SUPPORT_TEXT_MANIPULATION #endif // SUPPORT_TEXT_MANIPULATION
// Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found // Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found
// When a invalid UTF-8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned // When a invalid UTF-8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
// Total number of bytes processed are returned as a parameter // Total number of bytes processed are returned as a parameter
// NOTE: the standard says U+FFFD should be returned in case of errors // NOTE: The standard says U+FFFD should be returned in case of errors
// but that character is not supported by the default font in raylib // but that character is not supported by the default font in raylib
// TODO: Optimize this code for speed!!
int GetCodepoint(const char *text, int *bytesProcessed) int GetCodepoint(const char *text, int *bytesProcessed)
{ {
/* /*
@ -1657,7 +1658,7 @@ static Font LoadBMFont(const char *fileName)
char *searchPoint = NULL; char *searchPoint = NULL;
int fontSize = 0; int fontSize = 0;
int charsCount = 0; int glyphCount = 0;
int imWidth = 0; int imWidth = 0;
int imHeight = 0; int imHeight = 0;
@ -1694,10 +1695,10 @@ static Font LoadBMFont(const char *fileName)
lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE); lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
searchPoint = strstr(buffer, "count"); searchPoint = strstr(buffer, "count");
sscanf(searchPoint, "count=%i", &charsCount); sscanf(searchPoint, "count=%i", &glyphCount);
fileTextPtr += (lineBytes + 1); fileTextPtr += (lineBytes + 1);
TRACELOGD(" > Chars count: %i", charsCount); TRACELOGD(" > Chars count: %i", glyphCount);
// Compose correct path using route of .fnt file (fileName) and imFileName // Compose correct path using route of .fnt file (fileName) and imFileName
char *imPath = NULL; char *imPath = NULL;
@ -1746,14 +1747,14 @@ static Font LoadBMFont(const char *fileName)
// Fill font characters info data // Fill font characters info data
font.baseSize = fontSize; font.baseSize = fontSize;
font.charsCount = charsCount; font.glyphCount = glyphCount;
font.charsPadding = 0; font.glyphPadding = 0;
font.chars = (GlyphInfo *)RL_MALLOC(charsCount*sizeof(GlyphInfo)); font.glyphs = (GlyphInfo *)RL_MALLOC(glyphCount*sizeof(GlyphInfo));
font.recs = (Rectangle *)RL_MALLOC(charsCount*sizeof(Rectangle)); font.recs = (Rectangle *)RL_MALLOC(glyphCount*sizeof(Rectangle));
int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX; int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX;
for (int i = 0; i < charsCount; i++) for (int i = 0; i < glyphCount; i++)
{ {
lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE); 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",
@ -1764,13 +1765,13 @@ static Font LoadBMFont(const char *fileName)
font.recs[i] = (Rectangle){ (float)charX, (float)charY, (float)charWidth, (float)charHeight }; font.recs[i] = (Rectangle){ (float)charX, (float)charY, (float)charWidth, (float)charHeight };
// Save data properly in sprite font // Save data properly in sprite font
font.chars[i].value = charId; font.glyphs[i].value = charId;
font.chars[i].offsetX = charOffsetX; font.glyphs[i].offsetX = charOffsetX;
font.chars[i].offsetY = charOffsetY; font.glyphs[i].offsetY = charOffsetY;
font.chars[i].advanceX = charAdvanceX; font.glyphs[i].advanceX = charAdvanceX;
// Fill character image data from imFont data // Fill character image data from imFont data
font.chars[i].image = ImageFromImage(imFont, font.recs[i]); font.glyphs[i].image = ImageFromImage(imFont, font.recs[i]);
} }
UnloadImage(imFont); UnloadImage(imFont);
@ -1782,7 +1783,7 @@ static Font LoadBMFont(const char *fileName)
font = GetFontDefault(); font = GetFontDefault();
TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load texture, reverted to default font", fileName); TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load texture, reverted to default font", fileName);
} }
else TRACELOG(LOG_INFO, "FONT: [%s] Font loaded successfully", fileName); else TRACELOG(LOG_INFO, "FONT: [%s] Font loaded successfully (%i glyphs)", fileName, font.glyphCount);
return font; return font;
} }

View File

@ -1,6 +1,6 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raylib.textures - Basic functions to load and draw Textures (2d) * rtextures - Basic functions to load and draw textures
* *
* CONFIGURATION: * CONFIGURATION:
* *
@ -258,7 +258,7 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int
Image LoadImageAnim(const char *fileName, int *frames) Image LoadImageAnim(const char *fileName, int *frames)
{ {
Image image = { 0 }; Image image = { 0 };
int framesCount = 1; int frameCount = 1;
#if defined(SUPPORT_FILEFORMAT_GIF) #if defined(SUPPORT_FILEFORMAT_GIF)
if (IsFileExtension(fileName, ".gif")) if (IsFileExtension(fileName, ".gif"))
@ -269,8 +269,8 @@ Image LoadImageAnim(const char *fileName, int *frames)
if (fileData != NULL) if (fileData != NULL)
{ {
int comp = 0; int comp = 0;
int **delays = NULL; int *delays = NULL;
image.data = stbi_load_gif_from_memory(fileData, dataSize, delays, &image.width, &image.height, &framesCount, &comp, 4); image.data = stbi_load_gif_from_memory(fileData, dataSize, &delays, &image.width, &image.height, &frameCount, &comp, 4);
image.mipmaps = 1; image.mipmaps = 1;
image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
@ -286,7 +286,7 @@ Image LoadImageAnim(const char *fileName, int *frames)
// TODO: Support APNG animated images? // TODO: Support APNG animated images?
*frames = framesCount; *frames = frameCount;
return image; return image;
} }
@ -518,19 +518,19 @@ bool ExportImageAsCode(Image image, const char *fileName)
// NOTE: Text data buffer size is estimated considering image data size in bytes // NOTE: Text data buffer size is estimated considering image data size in bytes
// and requiring 6 char bytes for every byte: "0x00, " // and requiring 6 char bytes for every byte: "0x00, "
char *txtData = (char *)RL_CALLOC(6*dataSize + 2000, sizeof(char)); char *txtData = (char *)RL_CALLOC(dataSize*6 + 2000, sizeof(char));
int bytesCount = 0; int byteCount = 0;
bytesCount += sprintf(txtData + bytesCount, "////////////////////////////////////////////////////////////////////////////////////////\n"); byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n");
bytesCount += sprintf(txtData + bytesCount, "// //\n"); byteCount += sprintf(txtData + byteCount, "// //\n");
bytesCount += sprintf(txtData + bytesCount, "// ImageAsCode exporter v1.0 - Image pixel data exported as an array of bytes //\n"); byteCount += sprintf(txtData + byteCount, "// ImageAsCode exporter v1.0 - Image pixel data exported as an array of bytes //\n");
bytesCount += sprintf(txtData + bytesCount, "// //\n"); byteCount += sprintf(txtData + byteCount, "// //\n");
bytesCount += sprintf(txtData + bytesCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n");
bytesCount += sprintf(txtData + bytesCount, "// feedback and support: ray[at]raylib.com //\n"); byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n");
bytesCount += sprintf(txtData + bytesCount, "// //\n"); byteCount += sprintf(txtData + byteCount, "// //\n");
bytesCount += sprintf(txtData + bytesCount, "// Copyright (c) 2020 Ramon Santamaria (@raysan5) //\n"); byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2021 Ramon Santamaria (@raysan5) //\n");
bytesCount += sprintf(txtData + bytesCount, "// //\n"); byteCount += sprintf(txtData + byteCount, "// //\n");
bytesCount += sprintf(txtData + bytesCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n"); byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
// Get file name from path and convert variable name to uppercase // Get file name from path and convert variable name to uppercase
char varFileName[256] = { 0 }; char varFileName[256] = { 0 };
@ -538,16 +538,16 @@ bool ExportImageAsCode(Image image, const char *fileName)
for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; } for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; }
// Add image information // Add image information
bytesCount += sprintf(txtData + bytesCount, "// Image data information\n"); byteCount += sprintf(txtData + byteCount, "// Image data information\n");
bytesCount += sprintf(txtData + bytesCount, "#define %s_WIDTH %i\n", varFileName, image.width); byteCount += sprintf(txtData + byteCount, "#define %s_WIDTH %i\n", varFileName, image.width);
bytesCount += sprintf(txtData + bytesCount, "#define %s_HEIGHT %i\n", varFileName, image.height); byteCount += sprintf(txtData + byteCount, "#define %s_HEIGHT %i\n", varFileName, image.height);
bytesCount += sprintf(txtData + bytesCount, "#define %s_FORMAT %i // raylib internal pixel format\n\n", varFileName, image.format); byteCount += sprintf(txtData + byteCount, "#define %s_FORMAT %i // raylib internal pixel format\n\n", varFileName, image.format);
bytesCount += sprintf(txtData + bytesCount, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize); byteCount += sprintf(txtData + byteCount, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize);
for (int i = 0; i < dataSize - 1; i++) bytesCount += sprintf(txtData + bytesCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)image.data)[i]); for (int i = 0; i < dataSize - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)image.data)[i]);
bytesCount += sprintf(txtData + bytesCount, "0x%x };\n", ((unsigned char *)image.data)[dataSize - 1]); byteCount += sprintf(txtData + byteCount, "0x%x };\n", ((unsigned char *)image.data)[dataSize - 1]);
// NOTE: Text data length exported is determined by '\0' (NULL) character // NOTE: Text data size exported is determined by '\0' (NULL) character
success = SaveFileText(fileName, txtData); success = SaveFileText(fileName, txtData);
RL_FREE(txtData); RL_FREE(txtData);
@ -765,11 +765,11 @@ Image GenImageCellular(int width, int height, int tileSize)
int seedsPerRow = width/tileSize; int seedsPerRow = width/tileSize;
int seedsPerCol = height/tileSize; int seedsPerCol = height/tileSize;
int seedsCount = seedsPerRow*seedsPerCol; int seedCount = seedsPerRow*seedsPerCol;
Vector2 *seeds = (Vector2 *)RL_MALLOC(seedsCount*sizeof(Vector2)); Vector2 *seeds = (Vector2 *)RL_MALLOC(seedCount*sizeof(Vector2));
for (int i = 0; i < seedsCount; i++) for (int i = 0; i < seedCount; i++)
{ {
int y = (i/seedsPerRow)*tileSize + GetRandomValue(0, tileSize - 1); int y = (i/seedsPerRow)*tileSize + GetRandomValue(0, tileSize - 1);
int x = (i%seedsPerRow)*tileSize + GetRandomValue(0, tileSize - 1); int x = (i%seedsPerRow)*tileSize + GetRandomValue(0, tileSize - 1);
@ -871,8 +871,6 @@ Image ImageFromImage(Image image, Rectangle rec)
int bytesPerPixel = GetPixelDataSize(1, 1, image.format); int bytesPerPixel = GetPixelDataSize(1, 1, image.format);
// TODO: Check rec is valid?
result.width = (int)rec.width; result.width = (int)rec.width;
result.height = (int)rec.height; result.height = (int)rec.height;
result.data = RL_CALLOC((int)(rec.width*rec.height)*bytesPerPixel, 1); result.data = RL_CALLOC((int)(rec.width*rec.height)*bytesPerPixel, 1);
@ -1147,7 +1145,7 @@ Image ImageText(const char *text, int fontSize, Color color)
// Create an image from text (custom sprite font) // Create an image from text (custom sprite font)
Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint) Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint)
{ {
int length = (int)strlen(text); int size = (int)strlen(text); // Get size in bytes of text
int textOffsetX = 0; // Image drawing position X int textOffsetX = 0; // Image drawing position X
int textOffsetY = 0; // Offset between lines (on line break '\n') int textOffsetY = 0; // Offset between lines (on line break '\n')
@ -1158,7 +1156,7 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
// Create image to store text // Create image to store text
Image imText = GenImageColor((int)imSize.x, (int)imSize.y, BLANK); Image imText = GenImageColor((int)imSize.x, (int)imSize.y, BLANK);
for (int i = 0; i < length; i++) for (int i = 0; i < size; i++)
{ {
// Get next codepoint from byte string and glyph index in font // Get next codepoint from byte string and glyph index in font
int codepointByteCount = 0; int codepointByteCount = 0;
@ -1180,12 +1178,12 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
{ {
if ((codepoint != ' ') && (codepoint != '\t')) if ((codepoint != ' ') && (codepoint != '\t'))
{ {
Rectangle rec = { (float)(textOffsetX + font.chars[index].offsetX), (float)(textOffsetY + font.chars[index].offsetY), (float)font.recs[index].width, (float)font.recs[index].height }; Rectangle rec = { (float)(textOffsetX + font.glyphs[index].offsetX), (float)(textOffsetY + font.glyphs[index].offsetY), (float)font.recs[index].width, (float)font.recs[index].height };
ImageDraw(&imText, font.chars[index].image, (Rectangle){ 0, 0, (float)font.chars[index].image.width, (float)font.chars[index].image.height }, rec, tint); ImageDraw(&imText, font.glyphs[index].image, (Rectangle){ 0, 0, (float)font.glyphs[index].image.width, (float)font.glyphs[index].image.height }, rec, tint);
} }
if (font.chars[index].advanceX == 0) textOffsetX += (int)(font.recs[index].width + spacing); if (font.glyphs[index].advanceX == 0) textOffsetX += (int)(font.recs[index].width + spacing);
else textOffsetX += font.chars[index].advanceX + (int)spacing; else textOffsetX += font.glyphs[index].advanceX + (int)spacing;
} }
i += (codepointByteCount - 1); // Move text bytes counter to next codepoint i += (codepointByteCount - 1); // Move text bytes counter to next codepoint
@ -2185,7 +2183,7 @@ Color *LoadImageColors(Image image)
// Load colors palette from image as a Color array (RGBA - 32bit) // Load colors palette from image as a Color array (RGBA - 32bit)
// NOTE: Memory allocated should be freed using UnloadImagePalette() // NOTE: Memory allocated should be freed using UnloadImagePalette()
Color *LoadImagePalette(Image image, int maxPaletteSize, int *colorsCount) Color *LoadImagePalette(Image image, int maxPaletteSize, int *colorCount)
{ {
#define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a)) #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a))
@ -2234,7 +2232,7 @@ Color *LoadImagePalette(Image image, int maxPaletteSize, int *colorsCount)
UnloadImageColors(pixels); UnloadImageColors(pixels);
} }
*colorsCount = palCount; *colorCount = palCount;
return palette; return palette;
} }
@ -3487,9 +3485,9 @@ void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest,
// Draw textured polygon, defined by vertex and texturecoordinates // Draw textured polygon, defined by vertex and texturecoordinates
// NOTE: Polygon center must have straight line path to all points // NOTE: Polygon center must have straight line path to all points
// without crossing perimeter, points must be in anticlockwise order // without crossing perimeter, points must be in anticlockwise order
void DrawTexturePoly(Texture2D texture, Vector2 center, Vector2 *points, Vector2 *texcoords, int pointsCount, Color tint) void DrawTexturePoly(Texture2D texture, Vector2 center, Vector2 *points, Vector2 *texcoords, int pointCount, Color tint)
{ {
rlCheckRenderBatchLimit((pointsCount - 1)*4); rlCheckRenderBatchLimit((pointCount - 1)*4);
rlSetTexture(texture.id); rlSetTexture(texture.id);
@ -3498,7 +3496,7 @@ void DrawTexturePoly(Texture2D texture, Vector2 center, Vector2 *points, Vector2
rlColor4ub(tint.r, tint.g, tint.b, tint.a); rlColor4ub(tint.r, tint.g, tint.b, tint.a);
for (int i = 0; i < pointsCount - 1; i++) for (int i = 0; i < pointCount - 1; i++)
{ {
rlTexCoord2f(0.5f, 0.5f); rlTexCoord2f(0.5f, 0.5f);
rlVertex2f(center.x, center.y); rlVertex2f(center.x, center.y);

View File

@ -192,7 +192,8 @@ jwE50AGjLCVuS8Yt4H7OgZLKK5EKOsLviEWJSL/+0uMi7gLUSBseYwqEbXvSHCec1CJvZPyHCmYQffaB
<script type='text/javascript'> <script type='text/javascript'>
function saveFileFromMEMFSToDisk(memoryFSname, localFSname) // This can be called by C/C++ code function saveFileFromMEMFSToDisk(memoryFSname, localFSname) // This can be called by C/C++ code
{ {
var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); var isSafari = false; // Not supported, navigator.userAgent access is being restricted
//var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
var data = FS.readFile(memoryFSname); var data = FS.readFile(memoryFSname);
var blob; var blob;