diff --git a/.github/workflows/webassembly.yml b/.github/workflows/webassembly.yml index f9e51680d..f676877fd 100644 --- a/.github/workflows/webassembly.yml +++ b/.github/workflows/webassembly.yml @@ -29,7 +29,7 @@ jobs: - name: Setup emsdk uses: mymindstorm/setup-emsdk@v14 with: - version: 3.1.54 + version: 3.1.64 actions-cache-folder: 'emsdk-cache' - name: Setup Release Version diff --git a/.gitignore b/.gitignore index eeb1ed09d..d857bf2d4 100644 --- a/.gitignore +++ b/.gitignore @@ -104,6 +104,7 @@ GRTAGS GTAGS # Zig programming language +.zig-cache/ zig-cache/ zig-out/ build/ diff --git a/BINDINGS.md b/BINDINGS.md index 22b740588..e79d39c36 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -9,6 +9,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers | [raylib](https://github.com/raysan5/raylib) | **5.0** | [C/C++](https://en.wikipedia.org/wiki/C_(programming_language)) | Zlib | | [raylib-beef](https://github.com/Starpelly/raylib-beef) | **5.0** | [Beef](https://www.beeflang.org) | MIT | | [raylib-boo](https://github.com/Rabios/raylib-boo) | 3.7 | [Boo](http://boo-language.github.io) | MIT | +| [raybit](https://github.com/Alex-Velez/raybit) | **5.0** | [Brainfuck](https://en.wikipedia.org/wiki/Brainfuck) | MIT | | [Raylib-cs](https://github.com/ChrisDill/Raylib-cs) | **5.0** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | Zlib | | [Raylib-CsLo](https://github.com/NotNotTech/Raylib-CsLo) | 4.2 | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MPL-2.0 | | [Raylib-CSharp-Vinculum](https://github.com/ZeroElectric/Raylib-CSharp-Vinculum) | **5.0** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MPL-2.0 | @@ -21,7 +22,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers | [ray-cyber](https://github.com/fubark/ray-cyber) | **5.0** | [Cyber](https://cyberscript.dev) | MIT | | [dart-raylib](https://gitlab.com/wolfenrain/dart-raylib) | 4.0 | [Dart](https://dart.dev) | MIT | | [bindbc-raylib3](https://github.com/o3o/bindbc-raylib3) | **5.0** | [D](https://dlang.org) | BSL-1.0 | -| [dray](https://github.com/redthing1/dray) | 4.2 | [D](https://dlang.org) | Apache-2.0 | +| [dray](https://github.com/redthing1/dray) | **5.0** | [D](https://dlang.org) | Apache-2.0 | | [raylib-d](https://github.com/schveiguy/raylib-d) | **5.0** | [D](https://dlang.org) | Zlib | | [rayex](https://github.com/shiryel/rayex) | 3.7 | [elixir](https://elixir-lang.org) | Apache-2.0 | | [raylib-factor](https://github.com/factor/factor/blob/master/extra/raylib/raylib.factor) | 4.5 | [Factor](https://factorcode.org) | BSD | @@ -77,11 +78,12 @@ Some people ported raylib to other languages in the form of bindings or wrappers | [raylib-zig-bindings](https://github.com/L-Briand/raylib-zig-bindings) | **5.0** | [Zig](https://ziglang.org) | Zlib | | [hare-raylib](https://git.sr.ht/~evantj/hare-raylib) | **auto** | [Hare](https://harelang.org) | Zlib | | [raylib-sunder](https://github.com/ashn-dot-dev/raylib-sunder) | **auto** | [Sunder](https://github.com/ashn-dot-dev/sunder) | 0BSD | -| [rayed-bqn](https://github.com/Brian-ED/rayed-bqn) | **auto** | [BQN](https://mlochbaum.github.io/BQN) | MIT | +| [raylib-bqn](https://github.com/Brian-ED/raylib-bqn) | **5.0** | [BQN](https://mlochbaum.github.io/BQN) | MIT | | [rayjs](https://github.com/mode777/rayjs) | 4.6-dev | [QuickJS](https://bellard.org/quickjs) | MIT | | [raylib-raku](https://github.com/vushu/raylib-raku) | **auto** | [Raku](https://www.raku.org) | Artistic License 2.0 | -| [Raylib.lean](https://github.com/KislyjKisel/Raylib.lean) | 4.5 | [Lean4](https://lean-lang.org) | BSD-3-Clause | +| [Raylib.lean](https://github.com/KislyjKisel/Raylib.lean) | **5.5-dev** | [Lean4](https://lean-lang.org) | BSD-3-Clause | | [raylib-cobol](https://codeberg.org/glowiak/raylib-cobol) | **auto** | [COBOL](https://gnucobol.sourceforge.io) | Public domain | +| [raylib-apl](https://github.com/Brian-ED/raylib-apl) | **5.0** | [Dyalog APL](https://www.dyalog.com/) | MIT | ### Utility Wrapers @@ -90,6 +92,7 @@ These are utility wrappers for specific languages, they are not required to use | ---------------------------------------------------- | :------------: | :------------------------------------------: | :-----: | | [raylib-cpp](https://github.com/robloach/raylib-cpp) | **5.0** | [C++](https://en.wikipedia.org/wiki/C%2B%2B) | Zlib | | [claylib](https://github.com/defun-games/claylib) | 4.5 | [Common Lisp](https://common-lisp.net) | Zlib | +| [rayed-bqn](https://github.com/Brian-ED/rayed-bqn) | **5.0** | [BQN](https://mlochbaum.github.io/BQN) | MIT | ### Older or Unmaintained Language Bindings @@ -149,7 +152,7 @@ These are older raylib bindings that are more than 2 versions old or have not be | [ray.mod](https://github.com/bmx-ng/ray.mod) | 3.0 | [BlitzMax](https://blitzmax.org) | | [raylib-mosaic](https://github.com/pluckyporcupine/raylib-mosaic) | 3.0 | [Mosaic](https://github.com/sal55/langs/tree/master/Mosaic) | | [raylib-xdpw](https://github.com/vtereshkov/raylib-xdpw) | 2.6 | [XD Pascal](https://github.com/vtereshkov/xdpw) | -| [raylib-carp](https://github.com/pluckyporcupine/raylib-carp) | 3.0 | [Carp](https://github.com/carp-lang/Carp) | +| [raylib-carp](https://github.com/sacredbirdman/raylib-carp) | 3.0 | [Carp](https://github.com/carp-lang/Carp) | | [raylib-fb](https://github.com/IchMagBier/raylib-fb) | 3.0 | [FreeBasic](https://www.freebasic.net) | | [raylib-purebasic](https://github.com/D-a-n-i-l-o/raylib-purebasic) | 3.0 | [PureBasic](https://www.purebasic.com) | | [raylib-ats2](https://github.com/mephistopheles-8/raylib-ats2) | 3.0 | [ATS2](http://www.ats-lang.org) | diff --git a/CMakeLists.txt b/CMakeLists.txt index a5e3408c8..678d8e372 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,9 +36,6 @@ include(CompilerFlags) # Registers build options that are exposed to cmake include(CMakeOptions.txt) -# Enforces a few environment and compiler configurations -include(BuildOptions) - if (UNIX AND NOT APPLE) if (NOT GLFW_BUILD_WAYLAND AND NOT GLFW_BUILD_X11) MESSAGE(FATAL_ERROR "Cannot disable both Wayland and X11") diff --git a/CMakeOptions.txt b/CMakeOptions.txt index 2c58cd5cc..ce9141e22 100644 --- a/CMakeOptions.txt +++ b/CMakeOptions.txt @@ -1,4 +1,4 @@ -### Config options ### +# ## Config options ### include(CMakeDependentOption) include(EnumOption) @@ -9,14 +9,13 @@ enum_option(OPENGL_VERSION "OFF;4.3;3.3;2.1;1.1;ES 2.0;ES 3.0" "Force a specific # Configuration options option(BUILD_EXAMPLES "Build the examples." ${RAYLIB_IS_MAIN}) option(CUSTOMIZE_BUILD "Show options for customizing your Raylib library build." OFF) -option(ENABLE_ASAN "Enable AddressSanitizer (ASAN) for debugging (degrades performance)" OFF) +option(ENABLE_ASAN "Enable AddressSanitizer (ASAN) for debugging (degrades performance)" OFF) option(ENABLE_UBSAN "Enable UndefinedBehaviorSanitizer (UBSan) for debugging" OFF) option(ENABLE_MSAN "Enable MemorySanitizer (MSan) for debugging (not recommended to run with ASAN)" OFF) # Shared library is always PIC. Static library should be PIC too if linked into a shared library option(WITH_PIC "Compile static library as position-independent code" OFF) option(BUILD_SHARED_LIBS "Build raylib as a shared library" OFF) -option(MACOS_FATLIB "Build fat library for both i386 and x86_64 on macOS" OFF) cmake_dependent_option(USE_AUDIO "Build raylib with audio module" ON CUSTOMIZE_BUILD ON) enum_option(USE_EXTERNAL_GLFW "OFF;IF_POSSIBLE;ON" "Link raylib against system GLFW instead of embedded one") @@ -28,77 +27,9 @@ option(GLFW_BUILD_X11 "Build the bundled GLFW with X11 support" ON) 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") -# raylib modules included -cmake_dependent_option(SUPPORT_MODULE_RSHAPES "Include module: rshapes" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_MODULE_RTEXTURES "Include module: rtextures" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_MODULE_RTEXT "Include module: rtext" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_MODULE_RMODELS "Include module: rmodels" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_MODULE_RAUDIO "Include module: raudio" ON CUSTOMIZE_BUILD ON) +include(ParseConfigHeader) -# rcore.c -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 (rgestures.h) to support gestures detection: tap, hold, swipe, drag" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_RPRAND_GENERATOR "Include pseudo-random numbers generator (rprand.h), based on Xoshiro128** and SplitMix64" 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" 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) -cmake_dependent_option(SUPPORT_SCREEN_CAPTURE "Allow automatic screen capture of current screen pressing F12, defined in KeyCallback()" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_GIF_RECORDING "Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback()" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_BUSY_WAIT_LOOP "Use busy wait loop for timing sync instead of a high-resolution timer" OFF CUSTOMIZE_BUILD OFF) -cmake_dependent_option(SUPPORT_EVENTS_WAITING "Wait for events passively (sleeping while no events) instead of polling them actively every frame" OFF CUSTOMIZE_BUILD OFF) -cmake_dependent_option(SUPPORT_WINMM_HIGHRES_TIMER "Setting a higher resolution can improve the accuracy of time-out intervals in wait functions" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_COMPRESSION_API "Support for compression API" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_EVENTS_AUTOMATION "Support automatic generated events, loading and recording of those events when required" OFF CUSTOMIZE_BUILD OFF) -cmake_dependent_option(SUPPORT_CUSTOM_FRAME_CONTROL "Enabling this flag allows manual control of the frame processes, use at your own risk" OFF CUSTOMIZE_BUILD OFF) - -# 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) - -# rtextures.c -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_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_FILEFORMAT_PNG "Support loading PNG as textures" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_FILEFORMAT_DDS "Support loading DDS as textures" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_FILEFORMAT_HDR "Support loading HDR as textures" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_FILEFORMAT_PIC "Support loading PIC as textures" ${OFF} CUSTOMIZE_BUILD OFF) -cmake_dependent_option(SUPPORT_FILEFORMAT_PNM "Support loading PNM as textures" ${OFF} CUSTOMIZE_BUILD OFF) -cmake_dependent_option(SUPPORT_FILEFORMAT_KTX "Support loading KTX as textures" ${OFF} CUSTOMIZE_BUILD OFF) -cmake_dependent_option(SUPPORT_FILEFORMAT_ASTC "Support loading ASTC as textures" ${OFF} CUSTOMIZE_BUILD OFF) -cmake_dependent_option(SUPPORT_FILEFORMAT_BMP "Support loading BMP as textures" ${OFF} CUSTOMIZE_BUILD OFF) -cmake_dependent_option(SUPPORT_FILEFORMAT_TGA "Support loading TGA as textures" ${OFF} CUSTOMIZE_BUILD OFF) -cmake_dependent_option(SUPPORT_FILEFORMAT_JPG "Support loading JPG as textures" ${OFF} CUSTOMIZE_BUILD OFF) -cmake_dependent_option(SUPPORT_FILEFORMAT_GIF "Support loading GIF as textures" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_FILEFORMAT_QOI "Support loading QOI as textures" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_FILEFORMAT_PSD "Support loading PSD 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_SVG "Support loading SVG as textures" ${OFF} CUSTOMIZE_BUILD OFF) - -# rtext.c -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_TEXT_MANIPULATION "Support text manipulation functions" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_FONT_ATLAS_WHITE_REC "Support white rec on font atlas bottom-right corner" ON CUSTOMIZE_BUILD ON) - -# 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_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_IQM "Support loading IQM file format" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_FILEFORMAT_GLTF "Support loading GLTF file format" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_FILEFORMAT_VOX "Support loading VOX file format" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_FILEFORMAT_M3D "Support loading M3D file format" ON CUSTOMIZE_BUILD ON) - -# raudio.c -cmake_dependent_option(SUPPORT_FILEFORMAT_WAV "Support loading WAV for sound" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_FILEFORMAT_OGG "Support loading OGG for sound" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_FILEFORMAT_XM "Support loading XM for sound" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_FILEFORMAT_MOD "Support loading MOD for sound" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_FILEFORMAT_MP3 "Support loading MP3 for sound" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_FILEFORMAT_QOA "Support loading QOA for sound" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_FILEFORMAT_FLAC "Support loading FLAC for sound" ${OFF} CUSTOMIZE_BUILD OFF) - -# utils.c -cmake_dependent_option(SUPPORT_STANDARD_FILEIO "Support standard file io library (stdio.h)" ON CUSTOMIZE_BUILD ON) -cmake_dependent_option(SUPPORT_TRACELOG "Show TraceLog() output messages. NOTE: By default LOG_DEBUG traces not shown" ON CUSTOMIZE_BUILD ON) +foreach(FLAG IN LISTS CONFIG_HEADER_FLAGS) + string(REGEX MATCH "([^=]+)=(.+)" _ ${FLAG}) + cmake_dependent_option(${CMAKE_MATCH_1} "" ${CMAKE_MATCH_2} CUSTOMIZE_BUILD ${CMAKE_MATCH_2}) +endforeach() diff --git a/README.md b/README.md index 79e883034..303bbcdd1 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Ready to learn? Jump to [code examples!](https://www.raylib.com/examples.html) [![License](https://img.shields.io/badge/license-zlib%2Flibpng-blue.svg)](LICENSE) [![Discord Members](https://img.shields.io/discord/426912293134270465.svg?label=Discord&logo=discord)](https://discord.gg/raylib) -[![Subreddit Subscribers](https://img.shields.io/reddit/subreddit-subscribers/raylib?label=reddit%20r%2Fraylib&logo=reddit)](https://www.reddit.com/r/raylib/) +[![Reddit Static Badge](https://img.shields.io/badge/-r%2Fraylib-red?style=flat&logo=reddit&label=reddit)](https://www.reddit.com/r/raylib/) [![Youtube Subscribers](https://img.shields.io/youtube/channel/subscribers/UC8WIBkhYb5sBNqXO1mZ7WSQ?style=flat&label=Youtube&logo=youtube)](https://www.youtube.com/c/raylib) [![Twitch Status](https://img.shields.io/twitch/status/raysan5?style=flat&label=Twitch&logo=twitch)](https://www.twitch.tv/raysan5) diff --git a/cmake/BuildOptions.cmake b/cmake/BuildOptions.cmake deleted file mode 100644 index 0fce64292..000000000 --- a/cmake/BuildOptions.cmake +++ /dev/null @@ -1,18 +0,0 @@ -if(${PLATFORM} MATCHES "Desktop" AND APPLE) - if(MACOS_FATLIB) - if (CMAKE_OSX_ARCHITECTURES) - message(FATAL_ERROR "User supplied -DCMAKE_OSX_ARCHITECTURES overrides -DMACOS_FATLIB=ON") - else() - set(CMAKE_OSX_ARCHITECTURES "x86_64;i386") - endif() - endif() -endif() - -# This helps support the case where emsdk toolchain file is used -# either by setting it with -DCMAKE_TOOLCHAIN_FILE=/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -# or by using "emcmake cmake -B build -S ." as described in https://emscripten.org/docs/compiling/Building-Projects.html -if(EMSCRIPTEN) - SET(PLATFORM Web CACHE STRING "Forcing PLATFORM_WEB because EMSCRIPTEN was detected") -endif() - -# vim: ft=cmake diff --git a/cmake/CompileDefinitions.cmake b/cmake/CompileDefinitions.cmake index cc8324c4b..cefafdeb7 100644 --- a/cmake/CompileDefinitions.cmake +++ b/cmake/CompileDefinitions.cmake @@ -3,126 +3,21 @@ target_compile_definitions("raylib" PUBLIC "${PLATFORM_CPP}") target_compile_definitions("raylib" PUBLIC "${GRAPHICS}") function(define_if target variable) - if (${${variable}}) + if(${${variable}}) message(STATUS "${variable}=${${variable}}") - target_compile_definitions(${target} PUBLIC "${variable}") - endif () + target_compile_definitions(${target} PRIVATE "${variable}") + endif() endfunction() -if (${CUSTOMIZE_BUILD}) - target_compile_definitions("raylib" PUBLIC EXTERNAL_CONFIG_FLAGS) - define_if("raylib" USE_AUDIO) - define_if("raylib" SUPPORT_MODULE_RSHAPES) - define_if("raylib" SUPPORT_MODULE_RTEXTURES) - define_if("raylib" SUPPORT_MODULE_RTEXT) - define_if("raylib" SUPPORT_MODULE_RMODELS) - define_if("raylib" SUPPORT_MODULE_RAUDIO) - define_if("raylib" SUPPORT_CAMERA_SYSTEM) - define_if("raylib" SUPPORT_GESTURES_SYSTEM) - define_if("raylib" SUPPORT_MOUSE_GESTURES) - define_if("raylib" SUPPORT_SSH_KEYBOARD_RPI) - define_if("raylib" SUPPORT_DEFAULT_FONT) - define_if("raylib" SUPPORT_SCREEN_CAPTURE) - define_if("raylib" SUPPORT_GIF_RECORDING) - define_if("raylib" SUPPORT_BUSY_WAIT_LOOP) - define_if("raylib" SUPPORT_EVENTS_WAITING) - define_if("raylib" SUPPORT_WINMM_HIGHRES_TIMER) - define_if("raylib" SUPPORT_COMPRESSION_API) - define_if("raylib" SUPPORT_EVENTS_AUTOMATION) - define_if("raylib" SUPPORT_CUSTOM_FRAME_CONTROL) - define_if("raylib" SUPPORT_QUADS_DRAW_MODE) - define_if("raylib" SUPPORT_IMAGE_EXPORT) - define_if("raylib" SUPPORT_IMAGE_GENERATION) - define_if("raylib" SUPPORT_IMAGE_MANIPULATION) - define_if("raylib" SUPPORT_FILEFORMAT_PNG) - define_if("raylib" SUPPORT_FILEFORMAT_DDS) - define_if("raylib" SUPPORT_FILEFORMAT_HDR) - define_if("raylib" SUPPORT_FILEFORMAT_PIC) - define_if("raylib" SUPPORT_FILEFORMAT_PNM) - define_if("raylib" SUPPORT_FILEFORMAT_KTX) - define_if("raylib" SUPPORT_FILEFORMAT_ASTC) - define_if("raylib" SUPPORT_FILEFORMAT_BMP) - define_if("raylib" SUPPORT_FILEFORMAT_TGA) - define_if("raylib" SUPPORT_FILEFORMAT_JPG) - define_if("raylib" SUPPORT_FILEFORMAT_GIF) - define_if("raylib" SUPPORT_FILEFORMAT_QOI) - define_if("raylib" SUPPORT_FILEFORMAT_PSD) - define_if("raylib" SUPPORT_FILEFORMAT_PKM) - define_if("raylib" SUPPORT_FILEFORMAT_PVR) - define_if("raylib" SUPPORT_FILEFORMAT_SVG) - define_if("raylib" SUPPORT_FILEFORMAT_FNT) - define_if("raylib" SUPPORT_FILEFORMAT_TTF) - define_if("raylib" SUPPORT_TEXT_MANIPULATION) - define_if("raylib" SUPPORT_MESH_GENERATION) - define_if("raylib" SUPPORT_FILEFORMAT_OBJ) - define_if("raylib" SUPPORT_FILEFORMAT_MTL) - define_if("raylib" SUPPORT_FILEFORMAT_IQM) - define_if("raylib" SUPPORT_FILEFORMAT_GLTF) - define_if("raylib" SUPPORT_FILEFORMAT_VOX) - define_if("raylib" SUPPORT_FILEFORMAT_M3D) - define_if("raylib" SUPPORT_FILEFORMAT_WAV) - define_if("raylib" SUPPORT_FILEFORMAT_OGG) - define_if("raylib" SUPPORT_FILEFORMAT_XM) - define_if("raylib" SUPPORT_FILEFORMAT_MOD) - define_if("raylib" SUPPORT_FILEFORMAT_MP3) - define_if("raylib" SUPPORT_FILEFORMAT_QOA) - define_if("raylib" SUPPORT_FILEFORMAT_FLAC) - define_if("raylib" SUPPORT_STANDARD_FILEIO) - define_if("raylib" SUPPORT_TRACELOG) +if(${CUSTOMIZE_BUILD}) + target_compile_definitions("raylib" PRIVATE EXTERNAL_CONFIG_FLAGS) - if (UNIX AND NOT APPLE) - target_compile_definitions("raylib" PUBLIC "MAX_FILEPATH_LENGTH=4096") - else () - target_compile_definitions("raylib" PUBLIC "MAX_FILEPATH_LENGTH=512") - endif () - - target_compile_definitions("raylib" PUBLIC "MAX_GAMEPADS=4") - target_compile_definitions("raylib" PUBLIC "MAX_GAMEPAD_AXIS=8") - target_compile_definitions("raylib" PUBLIC "MAX_GAMEPAD_BUTTONS=32") - target_compile_definitions("raylib" PUBLIC "MAX_TOUCH_POINTS=10") - target_compile_definitions("raylib" PUBLIC "MAX_KEY_PRESSED_QUEUE=16") - - target_compile_definitions("raylib" PUBLIC "STORAGE_DATA_FILE=\"storage.data\"") - target_compile_definitions("raylib" PUBLIC "MAX_CHAR_PRESSED_QUEUE=16") - target_compile_definitions("raylib" PUBLIC "MAX_DECOMPRESSION_SIZE=64") - - if (${GRAPHICS} MATCHES "GRAPHICS_API_OPENGL_33" OR ${GRAPHICS} MATCHES "GRAPHICS_API_OPENGL_11") - target_compile_definitions("raylib" PUBLIC "DEFAULT_BATCH_BUFFER_ELEMENTS=8192") - elseif (${GRAPHICS} MATCHES "GRAPHICS_API_OPENGL_ES2") - target_compile_definitions("raylib" PUBLIC "DEFAULT_BATCH_BUFFER_ELEMENTS=2048") - endif () - - target_compile_definitions("raylib" PUBLIC "DEFAULT_BATCH_DRAWCALLS=256") - target_compile_definitions("raylib" PUBLIC "MAX_MATRIX_STACK_SIZE=32") - target_compile_definitions("raylib" PUBLIC "MAX_SHADER_LOCATIONS=32") - target_compile_definitions("raylib" PUBLIC "MAX_MATERIAL_MAPS=12") - target_compile_definitions("raylib" PUBLIC "RL_CULL_DISTANCE_NEAR=0.01") - target_compile_definitions("raylib" PUBLIC "RL_CULL_DISTANCE_FAR=1000.0") - - target_compile_definitions("raylib" PUBLIC "RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION=0") - target_compile_definitions("raylib" PUBLIC "RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD=1") - target_compile_definitions("raylib" PUBLIC "RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL=2") - target_compile_definitions("raylib" PUBLIC "RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR=3") - target_compile_definitions("raylib" PUBLIC "RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT=4") - target_compile_definitions("raylib" PUBLIC "RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2=5") - - target_compile_definitions("raylib" PUBLIC "RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION=\"vertexPosition\"") - target_compile_definitions("raylib" PUBLIC "RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD=\"vertexTexCoord\"") - target_compile_definitions("raylib" PUBLIC "RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL=\"vertexNormal\"") - target_compile_definitions("raylib" PUBLIC "RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR=\"vertexColor\"") - target_compile_definitions("raylib" PUBLIC "RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT=\"vertexTangent\"") - target_compile_definitions("raylib" PUBLIC "RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2=\"vertexTexCoord2\"") - - target_compile_definitions("raylib" PUBLIC "MAX_TEXT_BUFFER_LENGTH=1024") - target_compile_definitions("raylib" PUBLIC "MAX_TEXT_UNICODE_CHARS=512") - target_compile_definitions("raylib" PUBLIC "MAX_TEXTSPLIT_COUNT=128") - - target_compile_definitions("raylib" PUBLIC "AUDIO_DEVICE_FORMAT=ma_format_f32") - target_compile_definitions("raylib" PUBLIC "AUDIO_DEVICE_CHANNELS=2") - target_compile_definitions("raylib" PUBLIC "AUDIO_DEVICE_SAMPLE_RATE=44100") - target_compile_definitions("raylib" PUBLIC "DEFAULT_AUDIO_BUFFER_SIZE=4096") - - target_compile_definitions("raylib" PUBLIC "MAX_TRACELOG_MSG_LENGTH=128") - target_compile_definitions("raylib" PUBLIC "MAX_UWP_MESSAGES=512") -endif () + foreach(FLAG IN LISTS CONFIG_HEADER_FLAGS) + string(REGEX MATCH "([^=]+)=(.+)" _ ${FLAG}) + define_if("raylib" ${CMAKE_MATCH_1}) + endforeach() + foreach(VALUE IN LISTS CONFIG_HEADER_VALUES) + target_compile_definitions("raylib" PRIVATE ${VALUE}) + endforeach() +endif() diff --git a/cmake/LibraryConfigurations.cmake b/cmake/LibraryConfigurations.cmake index 23a7ec2f0..fb7898306 100644 --- a/cmake/LibraryConfigurations.cmake +++ b/cmake/LibraryConfigurations.cmake @@ -58,8 +58,9 @@ if (${PLATFORM} MATCHES "Desktop") elseif (${PLATFORM} MATCHES "Web") set(PLATFORM_CPP "PLATFORM_WEB") - set(GRAPHICS "GRAPHICS_API_OPENGL_ES2") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 --profiling") + if(NOT GRAPHICS) + set(GRAPHICS "GRAPHICS_API_OPENGL_ES2") + endif() set(CMAKE_STATIC_LIBRARY_SUFFIX ".a") elseif (${PLATFORM} MATCHES "Android") @@ -99,9 +100,10 @@ elseif ("${PLATFORM}" MATCHES "SDL") endif () if (NOT ${OPENGL_VERSION} MATCHES "OFF") - set(${SUGGESTED_GRAPHICS} "${GRAPHICS}") + set(SUGGESTED_GRAPHICS "${GRAPHICS}") + if (${OPENGL_VERSION} MATCHES "4.3") - set(GRAPHICS "GRAPHICS_API_OPENGL_43") + set(GRAPHICS "GRAPHICS_API_OPENGL_43") elseif (${OPENGL_VERSION} MATCHES "3.3") set(GRAPHICS "GRAPHICS_API_OPENGL_33") elseif (${OPENGL_VERSION} MATCHES "2.1") @@ -113,8 +115,8 @@ if (NOT ${OPENGL_VERSION} MATCHES "OFF") elseif (${OPENGL_VERSION} MATCHES "ES 3.0") set(GRAPHICS "GRAPHICS_API_OPENGL_ES3") endif () - if ("${SUGGESTED_GRAPHICS}" AND NOT "${SUGGESTED_GRAPHICS}" STREQUAL "${GRAPHICS}") - message(WARNING "You are overriding the suggested GRAPHICS=${SUGGESTED_GRAPHICS} with ${GRAPHICS}! This may fail") + if (NOT "${SUGGESTED_GRAPHICS}" STREQUAL "" AND NOT "${SUGGESTED_GRAPHICS}" STREQUAL "${GRAPHICS}") + message(WARNING "You are overriding the suggested GRAPHICS=${SUGGESTED_GRAPHICS} with ${GRAPHICS}! This may fail.") endif () endif () diff --git a/cmake/ParseConfigHeader.cmake b/cmake/ParseConfigHeader.cmake new file mode 100644 index 000000000..797eea3cd --- /dev/null +++ b/cmake/ParseConfigHeader.cmake @@ -0,0 +1,17 @@ +file(READ "${CMAKE_CURRENT_SOURCE_DIR}/src/config.h" CONFIG_HEADER_CONTENT) + +set(BLANK_OR_BACKSLASH_PATTERN "[ \t\r\n\\]") +set(VALID_IDENTIFIER_PATTERN "[A-Za-z_]+[A-Za-z_0-9]*") +set(VALID_VALUE_PATTERN [=["?[A-Za-z_0-9.-]+"?]=]) # not really correct but does the job since the config.h file hopefully will have been checked by a C preprocessor. +set(MACRO_REGEX "(//${BLANK_OR_BACKSLASH_PATTERN}*)?\#define${BLANK_OR_BACKSLASH_PATTERN}+(${VALID_IDENTIFIER_PATTERN})${BLANK_OR_BACKSLASH_PATTERN}+(${VALID_VALUE_PATTERN})") + +string(REGEX MATCHALL ${MACRO_REGEX} MACRO_LIST ${CONFIG_HEADER_CONTENT}) + +set(CONFIG_HEADER_FLAGS ${MACRO_LIST}) +list(FILTER CONFIG_HEADER_FLAGS INCLUDE REGEX "^.+SUPPORT_") +list(TRANSFORM CONFIG_HEADER_FLAGS REPLACE ${MACRO_REGEX} [[\2=OFF]] REGEX "^//") +list(TRANSFORM CONFIG_HEADER_FLAGS REPLACE ${MACRO_REGEX} [[\2=ON]]) + +set(CONFIG_HEADER_VALUES ${MACRO_LIST}) +list(FILTER CONFIG_HEADER_VALUES EXCLUDE REGEX "(^.+SUPPORT_)|(^//)") +list(TRANSFORM CONFIG_HEADER_VALUES REPLACE ${MACRO_REGEX} [[\2=\3]]) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 28550eaec..64b6d7604 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -96,10 +96,9 @@ if (${PLATFORM} MATCHES "Android") list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/shaders/shaders_basic_lighting.c) elseif (${PLATFORM} MATCHES "Web") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Os -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Os") # Since WASM is used, ALLOW_MEMORY_GROWTH has no extra overheads - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s ALLOW_MEMORY_GROWTH=1 --no-heap-copy") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --shell-file ${CMAKE_SOURCE_DIR}/src/shell.html") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s WASM=1 -s ASYNCIFY -s ALLOW_MEMORY_GROWTH=1 --shell-file ${CMAKE_SOURCE_DIR}/src/shell.html") set(CMAKE_EXECUTABLE_SUFFIX ".html") list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/others/raylib_opengl_interop.c) diff --git a/examples/Makefile b/examples/Makefile index 3c39e09e5..c17258427 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -4,7 +4,9 @@ # # This file supports building raylib examples for the following platforms: # -# > PLATFORM_DESKTOP (GLFW backend): +# > PLATFORM_DESKTOP +# - Defaults to PLATFORM_DESKTOP_GLFW +# > PLATFORM_DESKTOP_GFLW (GLFW backend): # - Windows (Win32, Win64) # - Linux (X11/Wayland desktop mode) # - macOS/OSX (x64, arm64) @@ -52,9 +54,15 @@ # Define target platform: PLATFORM_DESKTOP, PLATFORM_DESKTOP_SDL, PLATFORM_DRM, PLATFORM_ANDROID, PLATFORM_WEB PLATFORM ?= PLATFORM_DESKTOP +ifeq ($(PLATFORM), PLATFORM_DESKTOP) + TARGET_PLATFORM = PLATFORM_DESKTOP_GLFW +else + TARGET_PLATFORM = $(PLATFORM) +endif + # Define required raylib variables PROJECT_NAME ?= raylib_examples -RAYLIB_VERSION ?= 5.0.0 +RAYLIB_VERSION ?= 5.5.0 RAYLIB_PATH ?= .. # Define raylib source code path @@ -62,8 +70,9 @@ RAYLIB_SRC_PATH ?= ../src # Locations of raylib.h and libraylib.a/libraylib.so # NOTE: Those variables are only used for PLATFORM_OS: LINUX, BSD -RAYLIB_INCLUDE_PATH ?= /usr/local/include -RAYLIB_LIB_PATH ?= /usr/local/lib +DESTDIR ?= /usr/local +RAYLIB_INCLUDE_PATH ?= $(DESTDIR)/include +RAYLIB_LIB_PATH ?= $(DESTDIR)/lib # Library type compilation: STATIC (.a) or SHARED (.so/.dll) RAYLIB_LIBTYPE ?= STATIC @@ -91,7 +100,7 @@ BUILD_WEB_RESOURCES ?= TRUE BUILD_WEB_RESOURCES_PATH ?= $(dir $<)resources@resources # Determine PLATFORM_OS when required -ifeq ($(PLATFORM),$(filter $(PLATFORM),PLATFORM_DESKTOP PLATFORM_DESKTOP_SDL PLATFORM_WEB PLATFORM_DESKTOP_RGFW)) +ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW PLATFORM_DESKTOP_SDL PLATFORM_DESKTOP_RGFW PLATFORM_WEB)) # No uname.exe on MinGW!, but OS=Windows_NT on Windows! # ifeq ($(UNAME),Msys) -> Windows ifeq ($(OS),Windows_NT) @@ -118,7 +127,7 @@ ifeq ($(PLATFORM),$(filter $(PLATFORM),PLATFORM_DESKTOP PLATFORM_DESKTOP_SDL PLA endif endif endif -ifeq ($(PLATFORM),PLATFORM_DRM) +ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) UNAMEOS = $(shell uname) ifeq ($(UNAMEOS),Linux) PLATFORM_OS = LINUX @@ -127,7 +136,7 @@ endif # RAYLIB_PATH adjustment for LINUX platform # TODO: Do we really need this? -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) ifeq ($(PLATFORM_OS),LINUX) RAYLIB_PREFIX ?= .. RAYLIB_PATH = $(realpath $(RAYLIB_PREFIX)) @@ -135,14 +144,14 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) endif # Default path for raylib on Raspberry Pi -ifeq ($(PLATFORM),PLATFORM_DRM) +ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) RAYLIB_PATH ?= /home/pi/raylib endif # Define raylib release directory for compiled library RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/src -ifeq ($(PLATFORM),PLATFORM_WEB) +ifeq ($(TARGET_PLATFORM),PLATFORM_WEB) ifeq ($(PLATFORM_OS),WINDOWS) # Emscripten required variables EMSDK_PATH ?= C:/emsdk @@ -158,7 +167,7 @@ endif #------------------------------------------------------------------------------------------------ CC = gcc -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) ifeq ($(PLATFORM_OS),OSX) # OSX default compiler CC = clang @@ -168,7 +177,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) CC = clang endif endif -ifeq ($(PLATFORM),PLATFORM_WEB) +ifeq ($(TARGET_PLATFORM),PLATFORM_WEB) # HTML5 emscripten compiler # WARNING: To compile to HTML5, code must be redesigned # to use emscripten.h and emscripten_set_main_loop() @@ -179,15 +188,15 @@ endif #------------------------------------------------------------------------------------------------ MAKE ?= make -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) ifeq ($(PLATFORM_OS),WINDOWS) MAKE = mingw32-make endif endif -ifeq ($(PLATFORM),PLATFORM_ANDROID) +ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID) MAKE = mingw32-make endif -ifeq ($(PLATFORM),PLATFORM_WEB) +ifeq ($(TARGET_PLATFORM),PLATFORM_WEB) MAKE = emmake make endif @@ -206,11 +215,11 @@ CFLAGS = -Wall -std=c99 -D_DEFAULT_SOURCE -Wno-missing-braces -Wunused-result ifeq ($(BUILD_MODE),DEBUG) CFLAGS += -g -D_DEBUG - ifeq ($(PLATFORM),PLATFORM_WEB) + ifeq ($(TARGET_PLATFORM),PLATFORM_WEB) CFLAGS += -sASSERTIONS=1 --profiling endif else - ifeq ($(PLATFORM),PLATFORM_WEB) + ifeq ($(TARGET_PLATFORM),PLATFORM_WEB) ifeq ($(BUILD_WEB_ASYNCIFY),TRUE) CFLAGS += -O3 else @@ -227,7 +236,7 @@ endif # -Wstrict-prototypes warn if a function is declared or defined without specifying the argument types # -Werror=implicit-function-declaration catch function calls without prior declaration #CFLAGS += -Wextra -Wmissing-prototypes -Wstrict-prototypes -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) ifeq ($(PLATFORM_OS),LINUX) ifeq ($(RAYLIB_LIBTYPE),STATIC) CFLAGS += -D_DEFAULT_SOURCE @@ -238,7 +247,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) endif endif endif -ifeq ($(PLATFORM),PLATFORM_DRM) +ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) CFLAGS += -std=gnu99 -DEGL_NO_X11 endif @@ -248,7 +257,7 @@ endif INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external # Define additional directories containing required header files -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) ifeq ($(PLATFORM_OS),BSD) INCLUDE_PATHS += -I$(RAYLIB_INCLUDE_PATH) endif @@ -256,10 +265,10 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) INCLUDE_PATHS += -I$(RAYLIB_INCLUDE_PATH) endif endif -ifeq ($(PLATFORM),PLATFORM_DESKTOP_SDL) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL) INCLUDE_PATHS += -I$(SDL_INCLUDE_PATH) endif -ifeq ($(PLATFORM),PLATFORM_DRM) +ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) INCLUDE_PATHS += -I$(RAYLIB_INCLUDE_PATH) INCLUDE_PATHS += -I/usr/include/libdrm endif @@ -273,7 +282,7 @@ endif #------------------------------------------------------------------------------------------------ LDFLAGS = -L. -L$(RAYLIB_RELEASE_PATH) -L$(RAYLIB_PATH)/src -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) ifeq ($(PLATFORM_OS),WINDOWS) # NOTE: The resource .rc file contains windows executable icon and properties LDFLAGS += $(RAYLIB_PATH)/src/raylib.rc.data @@ -289,7 +298,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) LDFLAGS += -Lsrc -L$(RAYLIB_LIB_PATH) endif endif -ifeq ($(PLATFORM),PLATFORM_DESKTOP_SDL) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL) ifeq ($(PLATFORM_OS),WINDOWS) # NOTE: The resource .rc file contains windows executable icon and properties LDFLAGS += $(RAYLIB_PATH)/src/raylib.rc.data @@ -300,7 +309,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP_SDL) endif LDFLAGS += -L$(SDL_LIBRARY_PATH) endif -ifeq ($(PLATFORM),PLATFORM_WEB) +ifeq ($(TARGET_PLATFORM),PLATFORM_WEB) # -Os # size optimization # -O2 # optimization level 2, if used, also set --memory-init-file 0 # -sUSE_GLFW=3 # Use glfw3 library (context/input management) @@ -347,7 +356,7 @@ endif # Define libraries required on linking: LDLIBS # NOTE: To link libraries (lib.so or lib.a), use -l #------------------------------------------------------------------------------------------------ -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) ifeq ($(PLATFORM_OS),WINDOWS) # Libraries for Windows desktop compilation # NOTE: WinMM library required to set high-res timer resolution @@ -393,7 +402,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) LDLIBS += -lglfw endif endif -ifeq ($(PLATFORM),PLATFORM_DESKTOP_SDL) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL) ifeq ($(PLATFORM_OS),WINDOWS) # Libraries for Windows desktop compilation LDLIBS = -lraylib -lSDL2 -lSDL2main -lopengl32 -lgdi32 @@ -421,7 +430,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP_SDL) LDLIBS += -latomic endif endif -ifeq ($(PLATFORM),PLATFORM_DESKTOP_RGFW) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW) ifeq ($(PLATFORM_OS),WINDOWS) # Libraries for Windows desktop compilation LDLIBS = ..\src\libraylib.a -lgdi32 -lwinmm -lopengl32 @@ -446,12 +455,12 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP_RGFW) LDLIBS += -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo endif endif -ifeq ($(PLATFORM),PLATFORM_DRM) +ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) # Libraries for DRM compiling # NOTE: Required packages: libasound2-dev (ALSA) LDLIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lgbm -ldrm -ldl -latomic endif -ifeq ($(PLATFORM),PLATFORM_WEB) +ifeq ($(TARGET_PLATFORM),PLATFORM_WEB) # Libraries for web (HTML5) compiling LDLIBS = $(RAYLIB_RELEASE_PATH)/libraylib.a endif @@ -471,6 +480,7 @@ CORE = \ core/core_automation_events \ core/core_basic_screen_manager \ core/core_basic_window \ + core/core_basic_window_web \ core/core_custom_frame_control \ core/core_custom_logging \ core/core_drop_files \ @@ -520,6 +530,7 @@ TEXTURES = \ textures/textures_draw_tiled \ textures/textures_fog_of_war \ textures/textures_gif_player \ + textures/textures_image_channel \ textures/textures_image_drawing \ textures/textures_image_generation \ textures/textures_image_kernel \ @@ -558,6 +569,7 @@ TEXT = \ MODELS = \ models/models_animation \ models/models_billboard \ + models/models_bone_socket \ models/models_box_collisions \ models/models_cubicmap \ models/models_draw_cube_texture \ @@ -571,13 +583,16 @@ MODELS = \ models/models_mesh_generation \ models/models_mesh_picking \ models/models_orthographic_projection \ + models/models_point_rendering \ models/models_rlgl_solar_system \ models/models_skybox \ models/models_waving_cubes \ - models/models_yaw_pitch_roll + models/models_yaw_pitch_roll \ + models/models_gpu_skinning SHADERS = \ shaders/shaders_basic_lighting \ + shaders/shaders_basic_pbr \ shaders/shaders_custom_uniform \ shaders/shaders_deferred_render \ shaders/shaders_eratosthenes \ @@ -600,7 +615,8 @@ SHADERS = \ shaders/shaders_texture_outline \ shaders/shaders_texture_tiling \ shaders/shaders_texture_waves \ - shaders/shaders_write_depth + shaders/shaders_write_depth \ + shaders/shaders_vertex_displacement AUDIO = \ audio/audio_mixed_processor \ @@ -638,17 +654,17 @@ others: $(OTHERS) # Generic compilation pattern # NOTE: Examples must be ready for Android compilation! %: %.c -ifeq ($(PLATFORM),PLATFORM_ANDROID) +ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID) $(MAKE) -f Makefile.Android PROJECT_NAME=$@ PROJECT_SOURCE_FILES=$< -else ifeq ($(PLATFORM),PLATFORM_WEB) +else ifeq ($(TARGET_PLATFORM),PLATFORM_WEB) $(MAKE) -f Makefile.Web $@ else - $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) -D$(TARGET_PLATFORM) endif # Clean everything clean: -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) ifeq ($(PLATFORM_OS),WINDOWS) del *.o *.exe /s endif @@ -661,11 +677,11 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) rm -f *.o endif endif -ifeq ($(PLATFORM),PLATFORM_DRM) +ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) find . -type f -executable -delete rm -fv *.o endif -ifeq ($(PLATFORM),PLATFORM_WEB) +ifeq ($(TARGET_PLATFORM),PLATFORM_WEB) ifeq ($(PLATFORM_OS),WINDOWS) del *.wasm *.html *.js *.data else diff --git a/examples/Makefile.Web b/examples/Makefile.Web index af3325aa5..bd48c2a4a 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -35,8 +35,9 @@ RAYLIB_PATH ?= .. # Locations of raylib.h and libraylib.a/libraylib.so # NOTE: Those variables are only used for PLATFORM_OS: LINUX, BSD -RAYLIB_INCLUDE_PATH ?= /usr/local/include -RAYLIB_LIB_PATH ?= /usr/local/lib +DESTDIR ?= /usr/local +RAYLIB_INCLUDE_PATH ?= $(DESTDIR)/include +RAYLIB_LIB_PATH ?= $(DESTDIR)/lib # Library type compilation: STATIC (.a) or SHARED (.so/.dll) RAYLIB_LIBTYPE ?= STATIC @@ -447,6 +448,7 @@ MODELS = \ models/models_mesh_generation \ models/models_mesh_picking \ models/models_orthographic_projection \ + models/models_point_rendering \ models/models_rlgl_solar_system \ models/models_skybox \ models/models_waving_cubes \ @@ -476,7 +478,8 @@ SHADERS = \ shaders/shaders_texture_outline \ shaders/shaders_texture_tiling \ shaders/shaders_texture_waves \ - shaders/shaders_write_depth + shaders/shaders_write_depth \ + shaders/shaders_vertex_displacement AUDIO = \ audio/audio_mixed_processor \ diff --git a/examples/README.md b/examples/README.md index d790f7d84..d573ff23e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -147,11 +147,12 @@ Examples using raylib models functionality, including models loading/generation | 91 | [models_loading_vox](models/models_loading_vox.c) | models_loading_vox | ⭐️☆☆☆ | **4.0** | **4.0** | [Johann Nadalutti](https://github.com/procfxgen) | | 92 | [models_loading_m3d](models/models_loading_m3d.c) | models_loading_m3d | ⭐️☆☆☆ | **4.2** | **4.2** | [bzt](https://bztsrc.gitlab.io/model3d) | | 93 | [models_orthographic_projection](models/models_orthographic_projection.c) | models_orthographic_projection | ⭐️☆☆☆ | 2.0 | 3.7 | [Max Danielsson](https://github.com/autious) | -| 94 | [models_rlgl_solar_system](models/models_rlgl_solar_system.c) | models_rlgl_solar_system | ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) | -| 95 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) | models_yaw_pitch_roll | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Berni](https://github.com/Berni8k) | -| 96 | [models_waving_cubes](models/models_waving_cubes.c) | models_waving_cubes | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [codecat](https://github.com/codecat) | -| 97 | [models_heightmap](models/models_heightmap.c) | models_heightmap | ⭐️☆☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) | -| 98 | [models_skybox](models/models_skybox.c) | models_skybox | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) | +| 94 | [models_point_rendering](models/models_point_rendering.c) | models_point_rendering | ⭐️⭐️☆☆ | 5.0 | 5.0 | [Reese Gallagher](https://github.com/satchelfrost) | +| 95 | [models_rlgl_solar_system](models/models_rlgl_solar_system.c) | models_rlgl_solar_system | ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) | +| 96 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) | models_yaw_pitch_roll | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Berni](https://github.com/Berni8k) | +| 97 | [models_waving_cubes](models/models_waving_cubes.c) | models_waving_cubes | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [codecat](https://github.com/codecat) | +| 98 | [models_heightmap](models/models_heightmap.c) | models_heightmap | ⭐️☆☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) | +| 99 | [models_skybox](models/models_skybox.c) | models_skybox | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) | ### category: shaders @@ -159,25 +160,25 @@ Examples using raylib shaders functionality, including shaders loading, paramete | ## | example | image | difficulty
level | version
created | last version
updated | original
developer | |----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------| -| 99 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) | shaders_basic_lighting | ⭐️⭐️⭐️⭐️ | 3.0 | **4.2** | [Chris Camacho](https://github.com/codifies) | -| 100 | [shaders_model_shader](shaders/shaders_model_shader.c) | shaders_model_shader | ⭐️⭐️☆☆ | 1.3 | 3.7 | [Ray](https://github.com/raysan5) | -| 101 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) | shaders_shapes_textures | ⭐️⭐️☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) | -| 102 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) | shaders_custom_uniform | ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | -| 103 | [shaders_postprocessing](shaders/shaders_postprocessing.c) | shaders_postprocessing | ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | -| 104 | [shaders_palette_switch](shaders/shaders_palette_switch.c) | shaders_palette_switch | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Marco Lizza](https://github.com/MarcoLizza) | -| 105 | [shaders_raymarching](shaders/shaders_raymarching.c) | shaders_raymarching | ⭐️⭐️⭐️⭐️ | 2.0 | **4.2** | [Ray](https://github.com/raysan5) | -| 106 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) | shaders_texture_drawing | ⭐️⭐️☆☆ | 2.0 | 3.7 | [Michał Ciesielski](https://github.com/) | -| 107 | [shaders_texture_outline](shaders/shaders_texture_outline.c) | shaders_texture_outline | ⭐️⭐️⭐️☆ | **4.0** | **4.0** | [Samuel Skiff](https://github.com/GoldenThumbs) | -| 108 | [shaders_texture_waves](shaders/shaders_texture_waves.c) | shaders_texture_waves | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) | -| 109 | [shaders_julia_set](shaders/shaders_julia_set.c) | shaders_julia_set | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [eggmund](https://github.com/eggmund) | -| 110 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) | shaders_eratosthenes | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [ProfJski](https://github.com/ProfJski) | -| 111 | [shaders_fog](shaders/shaders_fog.c) | shaders_fog | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | -| 112 | [shaders_simple_mask](shaders/shaders_simple_mask.c) | shaders_simple_mask | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | -| 113 | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) | shaders_hot_reloading | ⭐️⭐️⭐️☆ | 3.0 | 3.5 | [Ray](https://github.com/raysan5) | -| 114 | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) | shaders_mesh_instancing | ⭐️⭐️⭐️⭐️ | 3.7 | **4.2** | [seanpringle](https://github.com/seanpringle) | -| 115 | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) | shaders_multi_sample2d | ⭐️⭐️☆☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) | -| 116 | [shaders_spotlight](shaders/shaders_spotlight.c) | shaders_spotlight | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | -| 117 | [shaders_deferred_render](shaders/shaders_deferred_render.c) | shaders_deferred_render | ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [Justin Andreas Lacoste](https://github.com/27justin) | +| 100 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) | shaders_basic_lighting | ⭐️⭐️⭐️⭐️ | 3.0 | **4.2** | [Chris Camacho](https://github.com/codifies) | +| 101 | [shaders_model_shader](shaders/shaders_model_shader.c) | shaders_model_shader | ⭐️⭐️☆☆ | 1.3 | 3.7 | [Ray](https://github.com/raysan5) | +| 102 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) | shaders_shapes_textures | ⭐️⭐️☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) | +| 103 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) | shaders_custom_uniform | ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | +| 104 | [shaders_postprocessing](shaders/shaders_postprocessing.c) | shaders_postprocessing | ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | +| 105 | [shaders_palette_switch](shaders/shaders_palette_switch.c) | shaders_palette_switch | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Marco Lizza](https://github.com/MarcoLizza) | +| 106 | [shaders_raymarching](shaders/shaders_raymarching.c) | shaders_raymarching | ⭐️⭐️⭐️⭐️ | 2.0 | **4.2** | [Ray](https://github.com/raysan5) | +| 107 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) | shaders_texture_drawing | ⭐️⭐️☆☆ | 2.0 | 3.7 | [Michał Ciesielski](https://github.com/) | +| 108 | [shaders_texture_outline](shaders/shaders_texture_outline.c) | shaders_texture_outline | ⭐️⭐️⭐️☆ | **4.0** | **4.0** | [Samuel Skiff](https://github.com/GoldenThumbs) | +| 109 | [shaders_texture_waves](shaders/shaders_texture_waves.c) | shaders_texture_waves | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) | +| 110 | [shaders_julia_set](shaders/shaders_julia_set.c) | shaders_julia_set | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [eggmund](https://github.com/eggmund) | +| 111 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) | shaders_eratosthenes | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [ProfJski](https://github.com/ProfJski) | +| 112 | [shaders_fog](shaders/shaders_fog.c) | shaders_fog | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | +| 113 | [shaders_simple_mask](shaders/shaders_simple_mask.c) | shaders_simple_mask | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | +| 114 | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) | shaders_hot_reloading | ⭐️⭐️⭐️☆ | 3.0 | 3.5 | [Ray](https://github.com/raysan5) | +| 115 | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) | shaders_mesh_instancing | ⭐️⭐️⭐️⭐️ | 3.7 | **4.2** | [seanpringle](https://github.com/seanpringle) | +| 116 | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) | shaders_multi_sample2d | ⭐️⭐️☆☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) | +| 117 | [shaders_spotlight](shaders/shaders_spotlight.c) | shaders_spotlight | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | +| 118 | [shaders_deferred_render](shaders/shaders_deferred_render.c) | shaders_deferred_render | ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [Justin Andreas Lacoste](https://github.com/27justin) | ### category: audio @@ -185,10 +186,10 @@ Examples using raylib audio functionality, including sound/music loading and pla | ## | example | image | difficulty
level | version
created | last version
updated | original
developer | |----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------| -| 118 | [audio_module_playing](audio/audio_module_playing.c) | audio_module_playing | ⭐️☆☆☆ | 1.5 | 3.5 | [Ray](https://github.com/raysan5) | -| 119 | [audio_music_stream](audio/audio_music_stream.c) | audio_music_stream | ⭐️☆☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) | -| 120 | [audio_raw_stream](audio/audio_raw_stream.c) | audio_raw_stream | ⭐️⭐️⭐️☆ | 1.6 | **4.2** | [Ray](https://github.com/raysan5) | -| 121 | [audio_sound_loading](audio/audio_sound_loading.c) | audio_sound_loading | ⭐️☆☆☆ | 1.1 | 3.5 | [Ray](https://github.com/raysan5) | +| 119 | [audio_module_playing](audio/audio_module_playing.c) | audio_module_playing | ⭐️☆☆☆ | 1.5 | 3.5 | [Ray](https://github.com/raysan5) | +| 120 | [audio_music_stream](audio/audio_music_stream.c) | audio_music_stream | ⭐️☆☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) | +| 121 | [audio_raw_stream](audio/audio_raw_stream.c) | audio_raw_stream | ⭐️⭐️⭐️☆ | 1.6 | **4.2** | [Ray](https://github.com/raysan5) | +| 122 | [audio_sound_loading](audio/audio_sound_loading.c) | audio_sound_loading | ⭐️☆☆☆ | 1.1 | 3.5 | [Ray](https://github.com/raysan5) | ### category: others @@ -196,11 +197,11 @@ Examples showing raylib misc functionality that does not fit in other categories | ## | example | image | difficulty
level | version
created | last version
updated | original
developer | |----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------| -| 122 | [rlgl_standalone](others/rlgl_standalone.c) | rlgl_standalone | ⭐️⭐️⭐️⭐️ | 1.6 | **4.0** | [Ray](https://github.com/raysan5) | -| 123 | [rlgl_compute_shader](others/rlgl_compute_shader.c) | rlgl_compute_shader | ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Teddy Astie](https://github.com/tsnake41) | -| 124 | [easings_testbed](others/easings_testbed.c) | easings_testbed | ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Juan Miguel López](https://github.com/flashback-fx) | -| 125 | [raylib_opengl_interop](others/raylib_opengl_interop.c) | raylib_opengl_interop | ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Stephan Soller](https://github.com/arkanis) | -| 126 | [embedded_files_loading](others/embedded_files_loading.c) | embedded_files_loading | ⭐️⭐️☆☆ | 3.5 | 3.5 | [Kristian Holmgren](https://github.com/defutura) | +| 123 | [rlgl_standalone](others/rlgl_standalone.c) | rlgl_standalone | ⭐️⭐️⭐️⭐️ | 1.6 | **4.0** | [Ray](https://github.com/raysan5) | +| 124 | [rlgl_compute_shader](others/rlgl_compute_shader.c) | rlgl_compute_shader | ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Teddy Astie](https://github.com/tsnake41) | +| 125 | [easings_testbed](others/easings_testbed.c) | easings_testbed | ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Juan Miguel López](https://github.com/flashback-fx) | +| 126 | [raylib_opengl_interop](others/raylib_opengl_interop.c) | raylib_opengl_interop | ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Stephan Soller](https://github.com/arkanis) | +| 127 | [embedded_files_loading](others/embedded_files_loading.c) | embedded_files_loading | ⭐️⭐️☆☆ | 3.5 | 3.5 | [Kristian Holmgren](https://github.com/defutura) | As always contributions are welcome, feel free to send new examples! Here is an [examples template](examples_template.c) to start with! diff --git a/examples/audio/audio_mixed_processor.c b/examples/audio/audio_mixed_processor.c index 3a008f3e2..df46edc4e 100644 --- a/examples/audio/audio_mixed_processor.c +++ b/examples/audio/audio_mixed_processor.c @@ -97,7 +97,7 @@ int main(void) DrawRectangle(199, 199, 402, 34, LIGHTGRAY); for (int i = 0; i < 400; i++) { - DrawLine(201 + i, 232 - averageVolume[i] * 32, 201 + i, 232, MAROON); + DrawLine(201 + i, 232 - (int)(averageVolume[i] * 32), 201 + i, 232, MAROON); } DrawRectangleLines(199, 199, 402, 34, GRAY); diff --git a/examples/build.zig b/examples/build.zig index 5a17382ca..df0cdf8c1 100644 --- a/examples/build.zig +++ b/examples/build.zig @@ -75,6 +75,7 @@ fn add_module(comptime module: []const u8, b: *std.Build, target: std.Build.Reso const install_cmd = b.addInstallArtifact(exe, .{}); const run_cmd = b.addRunArtifact(exe); + run_cmd.cwd = b.path(module); run_cmd.step.dependOn(&install_cmd.step); const run_step = b.step(name, name); diff --git a/examples/core/core_2d_camera_platformer.c b/examples/core/core_2d_camera_platformer.c index 75fd6cf6a..3743de80b 100644 --- a/examples/core/core_2d_camera_platformer.c +++ b/examples/core/core_2d_camera_platformer.c @@ -133,10 +133,10 @@ int main(void) for (int i = 0; i < envItemsLength; i++) DrawRectangleRec(envItems[i].rect, envItems[i].color); - Rectangle playerRect = { player.position.x - 20, player.position.y - 40, 40, 40 }; + Rectangle playerRect = { player.position.x - 20, player.position.y - 40, 40.0f, 40.0f }; DrawRectangleRec(playerRect, RED); - DrawCircle(player.position.x, player.position.y, 5, GOLD); + DrawCircleV(player.position, 5.0f, GOLD); EndMode2D(); diff --git a/examples/core/core_automation_events.c b/examples/core/core_automation_events.c index 319b013ba..64ca51fda 100644 --- a/examples/core/core_automation_events.c +++ b/examples/core/core_automation_events.c @@ -88,7 +88,7 @@ int main(void) // Update //---------------------------------------------------------------------------------- float deltaTime = 0.015f;//GetFrameTime(); - + // Dropped files logic //---------------------------------------------------------------------------------- if (IsFileDropped()) @@ -157,11 +157,6 @@ int main(void) } else player.canJump = true; - camera.zoom += ((float)GetMouseWheelMove()*0.05f); - - if (camera.zoom > 3.0f) camera.zoom = 3.0f; - else if (camera.zoom < 0.25f) camera.zoom = 0.25f; - if (IsKeyPressed(KEY_R)) { // Reset game state @@ -176,12 +171,44 @@ int main(void) } //---------------------------------------------------------------------------------- + // Events playing + // NOTE: Logic must be before Camera update because it depends on mouse-wheel value, + // that can be set by the played event... but some other inputs could be affected + //---------------------------------------------------------------------------------- + if (eventPlaying) + { + // NOTE: Multiple events could be executed in a single frame + while (playFrameCounter == aelist.events[currentPlayFrame].frame) + { + PlayAutomationEvent(aelist.events[currentPlayFrame]); + currentPlayFrame++; + + if (currentPlayFrame == aelist.count) + { + eventPlaying = false; + currentPlayFrame = 0; + playFrameCounter = 0; + + TraceLog(LOG_INFO, "FINISH PLAYING!"); + break; + } + } + + playFrameCounter++; + } + //---------------------------------------------------------------------------------- + // Update camera //---------------------------------------------------------------------------------- camera.target = player.position; camera.offset = (Vector2){ screenWidth/2.0f, screenHeight/2.0f }; float minX = 1000, minY = 1000, maxX = -1000, maxY = -1000; + // WARNING: On event replay, mouse-wheel internal value is set + camera.zoom += ((float)GetMouseWheelMove()*0.05f); + if (camera.zoom > 3.0f) camera.zoom = 3.0f; + else if (camera.zoom < 0.25f) camera.zoom = 0.25f; + for (int i = 0; i < MAX_ENVIRONMENT_ELEMENTS; i++) { EnvElement *element = &envElements[i]; @@ -200,8 +227,8 @@ int main(void) if (min.y > 0) camera.offset.y = screenHeight/2 - min.y; //---------------------------------------------------------------------------------- - // Toggle events recording - if (IsKeyPressed(KEY_S)) + // Events management + if (IsKeyPressed(KEY_S)) // Toggle events recording { if (!eventPlaying) { @@ -222,7 +249,7 @@ int main(void) } } } - else if (IsKeyPressed(KEY_A)) + else if (IsKeyPressed(KEY_A)) // Toggle events playing (WARNING: Starts next frame) { if (!eventRecording && (aelist.count > 0)) { @@ -241,32 +268,7 @@ int main(void) camera.zoom = 1.0f; } } - - if (eventPlaying) - { - // NOTE: Multiple events could be executed in a single frame - while (playFrameCounter == aelist.events[currentPlayFrame].frame) - { - TraceLog(LOG_INFO, "PLAYING: PlayFrameCount: %i | currentPlayFrame: %i | Event Frame: %i, param: %i", - playFrameCounter, currentPlayFrame, aelist.events[currentPlayFrame].frame, aelist.events[currentPlayFrame].params[0]); - - PlayAutomationEvent(aelist.events[currentPlayFrame]); - currentPlayFrame++; - if (currentPlayFrame == aelist.count) - { - eventPlaying = false; - currentPlayFrame = 0; - playFrameCounter = 0; - - TraceLog(LOG_INFO, "FINISH PLAYING!"); - break; - } - } - - playFrameCounter++; - } - if (eventRecording || eventPlaying) frameCounter++; else frameCounter = 0; //---------------------------------------------------------------------------------- diff --git a/examples/core/core_input_gamepad_info.c b/examples/core/core_input_gamepad_info.c index 66fedda90..096294681 100644 --- a/examples/core/core_input_gamepad_info.c +++ b/examples/core/core_input_gamepad_info.c @@ -47,25 +47,25 @@ int main(void) ClearBackground(RAYWHITE); - for (int i = 0, y = 10; i < 4; i++) // MAX_GAMEPADS = 4 + for (int i = 0, y = 5; i < 4; i++) // MAX_GAMEPADS = 4 { if (IsGamepadAvailable(i)) { - DrawText(TextFormat("Gamepad name: %s", GetGamepadName(i)), 10, y, 20, BLACK); - y += 30; - DrawText(TextFormat("\tAxis count: %d", GetGamepadAxisCount(i)), 10, y, 20, BLACK); - y += 30; + DrawText(TextFormat("Gamepad name: %s", GetGamepadName(i)), 10, y, 10, BLACK); + y += 11; + DrawText(TextFormat("\tAxis count: %d", GetGamepadAxisCount(i)), 10, y, 10, BLACK); + y += 11; for (int axis = 0; axis < GetGamepadAxisCount(i); axis++) { - DrawText(TextFormat("\tAxis %d = %f", axis, GetGamepadAxisMovement(i, axis)), 10, y, 20, BLACK); - y += 30; + DrawText(TextFormat("\tAxis %d = %f", axis, GetGamepadAxisMovement(i, axis)), 10, y, 10, BLACK); + y += 11; } for (int button = 0; button < 32; button++) { - DrawText(TextFormat("\tButton %d = %d", button, IsGamepadButtonDown(i, button)), 10, y, 20, BLACK); - y += 30; + DrawText(TextFormat("\tButton %d = %d", button, IsGamepadButtonDown(i, button)), 10, y, 10, BLACK); + y += 11; } } } @@ -80,4 +80,4 @@ int main(void) //-------------------------------------------------------------------------------------- CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- -} \ No newline at end of file +} diff --git a/examples/core/core_input_mouse_wheel.c b/examples/core/core_input_mouse_wheel.c index 54f33545e..d261e9348 100644 --- a/examples/core/core_input_mouse_wheel.c +++ b/examples/core/core_input_mouse_wheel.c @@ -36,7 +36,7 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - boxPositionY -= (GetMouseWheelMove()*scrollSpeed); + boxPositionY -= (int)(GetMouseWheelMove()*scrollSpeed); //---------------------------------------------------------------------------------- // Draw diff --git a/examples/core/core_random_sequence.c b/examples/core/core_random_sequence.c index c946b64da..2f7c3be95 100644 --- a/examples/core/core_random_sequence.c +++ b/examples/core/core_random_sequence.c @@ -41,7 +41,7 @@ int main(void) { int rectCount = 20; float rectSize = (float)screenWidth/rectCount; - ColorRect* rectangles = GenerateRandomColorRectSequence(rectCount, rectSize, screenWidth, 0.75f * screenHeight); + ColorRect* rectangles = GenerateRandomColorRectSequence((float)rectCount, rectSize, (float)screenWidth, 0.75f * screenHeight); SetTargetFPS(60); //-------------------------------------------------------------------------------------- @@ -62,7 +62,7 @@ int main(void) { rectCount++; rectSize = (float)screenWidth/rectCount; free(rectangles); - rectangles = GenerateRandomColorRectSequence(rectCount, rectSize, screenWidth, 0.75f * screenHeight); + rectangles = GenerateRandomColorRectSequence((float)rectCount, rectSize, (float)screenWidth, 0.75f * screenHeight); } if(IsKeyPressed(KEY_DOWN)) @@ -71,7 +71,7 @@ int main(void) { rectCount--; rectSize = (float)screenWidth/rectCount; free(rectangles); - rectangles = GenerateRandomColorRectSequence(rectCount, rectSize, screenWidth, 0.75f * screenHeight); + rectangles = GenerateRandomColorRectSequence((float)rectCount, rectSize, (float)screenWidth, 0.75f * screenHeight); } } @@ -121,17 +121,17 @@ static Color GenerateRandomColor() } static ColorRect* GenerateRandomColorRectSequence(float rectCount, float rectWidth, float screenWidth, float screenHeight){ - int *seq = LoadRandomSequence(rectCount, 0, rectCount-1); - ColorRect* rectangles = (ColorRect *)malloc(rectCount*sizeof(ColorRect)); + int *seq = LoadRandomSequence((unsigned int)rectCount, 0, (unsigned int)rectCount-1); + ColorRect* rectangles = (ColorRect *)malloc((int)rectCount*sizeof(ColorRect)); float rectSeqWidth = rectCount * rectWidth; - int startX = (screenWidth - rectSeqWidth) * 0.5f; + float startX = (screenWidth - rectSeqWidth) * 0.5f; for(int x=0;x distanceRotating) { DrawBillboard(camera, bill, billPositionStatic, 2.0f, WHITE); - DrawBillboardPro(camera, bill, source, billPositionRotating, billUp, (Vector2) {1.0f, 1.0f}, rotateOrigin, rotation, WHITE); + DrawBillboardPro(camera, bill, source, billPositionRotating, billUp, size, origin, rotation, WHITE); } else { - DrawBillboardPro(camera, bill, source, billPositionRotating, billUp, (Vector2) {1.0f, 1.0f}, rotateOrigin, rotation, WHITE); + DrawBillboardPro(camera, bill, source, billPositionRotating, billUp, size, origin, rotation, WHITE); DrawBillboard(camera, bill, billPositionStatic, 2.0f, WHITE); } @@ -108,4 +110,4 @@ int main(void) //-------------------------------------------------------------------------------------- return 0; -} \ No newline at end of file +} diff --git a/examples/models/models_box_collisions.c b/examples/models/models_box_collisions.c index 936f65f38..4d98a776a 100644 --- a/examples/models/models_box_collisions.c +++ b/examples/models/models_box_collisions.c @@ -109,7 +109,7 @@ int main(void) EndMode3D(); - DrawText("Move player with cursors to collide", 220, 40, 20, GRAY); + DrawText("Move player with arrow keys to collide", 220, 40, 20, GRAY); DrawFPS(10, 10); diff --git a/examples/models/models_draw_cube_texture.c b/examples/models/models_draw_cube_texture.c index edcd4b7f8..87d83c8f3 100644 --- a/examples/models/models_draw_cube_texture.c +++ b/examples/models/models_draw_cube_texture.c @@ -67,7 +67,7 @@ int main(void) DrawCubeTexture(texture, (Vector3){ -2.0f, 2.0f, 0.0f }, 2.0f, 4.0f, 2.0f, WHITE); // Draw cube with an applied texture, but only a defined rectangle piece of the texture - DrawCubeTextureRec(texture, (Rectangle){ 0, texture.height/2, texture.width/2, texture.height/2 }, + DrawCubeTextureRec(texture, (Rectangle){ 0.0f, texture.height/2.0f, texture.width/2.0f, texture.height/2.0f }, (Vector3){ 2.0f, 1.0f, 0.0f }, 2.0f, 2.0f, 2.0f, WHITE); DrawGrid(10, 1.0f); // Draw a grid diff --git a/examples/models/models_gpu_skinning.c b/examples/models/models_gpu_skinning.c new file mode 100644 index 000000000..846f0a890 --- /dev/null +++ b/examples/models/models_gpu_skinning.c @@ -0,0 +1,119 @@ +/******************************************************************************************* +* +* raylib [core] example - Doing skinning on the gpu using a vertex shader +* +* Example originally created with raylib 4.5, last time updated with raylib 4.5 +* +* Example contributed by Daniel Holden (@orangeduck) and reviewed by Ramon Santamaria (@raysan5) +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2024 Daniel Holden (@orangeduck) +* +* Note: Due to limitations in the Apple OpenGL driver, this feature does not work on MacOS +* +********************************************************************************************/ + +#include "raylib.h" + +#include "raymath.h" + +#if defined(PLATFORM_DESKTOP) + #define GLSL_VERSION 330 +#else // PLATFORM_ANDROID, PLATFORM_WEB + #define GLSL_VERSION 100 +#endif + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [models] example - GPU skinning"); + + // Define the camera to look into our 3d world + Camera camera = { 0 }; + camera.position = (Vector3){ 5.0f, 5.0f, 5.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 2.0f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type + + // Load gltf model + Model characterModel = LoadModel("resources/models/gltf/greenman.glb"); // Load character model + + // Load skinning shader + Shader skinningShader = LoadShader(TextFormat("resources/shaders/glsl%i/skinning.vs", GLSL_VERSION), + TextFormat("resources/shaders/glsl%i/skinning.fs", GLSL_VERSION)); + + characterModel.materials[1].shader = skinningShader; + + // Load gltf model animations + int animsCount = 0; + unsigned int animIndex = 0; + unsigned int animCurrentFrame = 0; + ModelAnimation *modelAnimations = LoadModelAnimations("resources/models/gltf/greenman.glb", &animsCount); + + Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position + + DisableCursor(); // Limit cursor to relative movement inside the window + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateCamera(&camera, CAMERA_THIRD_PERSON); + + // Select current animation + if (IsKeyPressed(KEY_T)) animIndex = (animIndex + 1)%animsCount; + else if (IsKeyPressed(KEY_G)) animIndex = (animIndex + animsCount - 1)%animsCount; + + // Update model animation + ModelAnimation anim = modelAnimations[animIndex]; + animCurrentFrame = (animCurrentFrame + 1)%anim.frameCount; + UpdateModelAnimationBoneMatrices(characterModel, anim, animCurrentFrame); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + + // Draw character + characterModel.transform = MatrixTranslate(position.x, position.y, position.z); + UpdateModelAnimationBoneMatrices(characterModel, anim, animCurrentFrame); + DrawMesh(characterModel.meshes[0], characterModel.materials[1], characterModel.transform); + + DrawGrid(10, 1.0f); + EndMode3D(); + + DrawText("Use the T/G to switch animation", 10, 10, 20, GRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadModelAnimations(modelAnimations, animsCount); + UnloadModel(characterModel); // Unload character model and meshes/material + UnloadShader(skinningShader); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/models/models_loading_gltf.c b/examples/models/models_loading_gltf.c index e85b30e6c..8b8838c8d 100644 --- a/examples/models/models_loading_gltf.c +++ b/examples/models/models_loading_gltf.c @@ -30,11 +30,11 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [models] example - loading gltf"); + InitWindow(screenWidth, screenHeight, "raylib [models] example - loading gltf animations"); // Define the camera to look into our 3d world Camera camera = { 0 }; - camera.position = (Vector3){ 5.0f, 5.0f, 5.0f }; // Camera position + camera.position = (Vector3){ 6.0f, 6.0f, 6.0f }; // Camera position camera.target = (Vector3){ 0.0f, 2.0f, 0.0f }; // Camera looking at point camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) camera.fovy = 45.0f; // Camera field-of-view Y @@ -42,17 +42,14 @@ int main(void) // Load gltf model Model model = LoadModel("resources/models/gltf/robot.glb"); - + Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position + // Load gltf model animations int animsCount = 0; unsigned int animIndex = 0; unsigned int animCurrentFrame = 0; ModelAnimation *modelAnimations = LoadModelAnimations("resources/models/gltf/robot.glb", &animsCount); - Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position - - DisableCursor(); // Limit cursor to relative movement inside the window - SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -61,7 +58,8 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera, CAMERA_THIRD_PERSON); + UpdateCamera(&camera, CAMERA_ORBITAL); + // Select current animation if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) animIndex = (animIndex + 1)%animsCount; else if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) animIndex = (animIndex + animsCount - 1)%animsCount; @@ -79,10 +77,8 @@ int main(void) ClearBackground(RAYWHITE); BeginMode3D(camera); - DrawModel(model, position, 1.0f, WHITE); // Draw animated model DrawGrid(10, 1.0f); - EndMode3D(); DrawText("Use the LEFT/RIGHT mouse buttons to switch animation", 10, 10, 20, GRAY); @@ -101,3 +97,6 @@ int main(void) return 0; } + + + diff --git a/examples/models/models_point_rendering.c b/examples/models/models_point_rendering.c new file mode 100644 index 000000000..68d498453 --- /dev/null +++ b/examples/models/models_point_rendering.c @@ -0,0 +1,182 @@ +/******************************************************************************************* +* +* raylib example - point rendering +* +* Example originally created with raylib 5.0, last time updated with raylib 5.0 +* +* Example contributed by Reese Gallagher (@satchelfrost) and reviewed by Ramon Santamaria (@raysan5) +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2024 Reese Gallagher (@satchelfrost) +* +********************************************************************************************/ + +#include "raylib.h" + +#include // Required for: rand() +#include // Required for: cos(), sin() + +#define MAX_POINTS 10000000 // 10 million +#define MIN_POINTS 1000 // 1 thousand + +// Generate mesh using points +Mesh GenMeshPoints(int numPoints); + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [models] example - point rendering"); + + Camera camera = { + .position = { 3.0f, 3.0f, 3.0f }, + .target = { 0.0f, 0.0f, 0.0f }, + .up = { 0.0f, 1.0f, 0.0f }, + .fovy = 45.0f, + .projection = CAMERA_PERSPECTIVE + }; + + Vector3 position = { 0.0f, 0.0f, 0.0f }; + bool useDrawModelPoints = true; + bool numPointsChanged = false; + int numPoints = 1000; + + Mesh mesh = GenMeshPoints(numPoints); + Model model = LoadModelFromMesh(mesh); + + //SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while(!WindowShouldClose()) + { + // Update + //---------------------------------------------------------------------------------- + UpdateCamera(&camera, CAMERA_ORBITAL); + + if (IsKeyPressed(KEY_SPACE)) useDrawModelPoints = !useDrawModelPoints; + if (IsKeyPressed(KEY_UP)) + { + numPoints = (numPoints*10 > MAX_POINTS)? MAX_POINTS : numPoints*10; + numPointsChanged = true; + } + if (IsKeyPressed(KEY_DOWN)) + { + numPoints = (numPoints/10 < MIN_POINTS)? MIN_POINTS : numPoints/10; + numPointsChanged = true; + } + + // Upload a different point cloud size + if (numPointsChanged) + { + UnloadModel(model); + mesh = GenMeshPoints(numPoints); + model = LoadModelFromMesh(mesh); + numPointsChanged = false; + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + ClearBackground(BLACK); + + BeginMode3D(camera); + + // The new method only uploads the points once to the GPU + if (useDrawModelPoints) + { + DrawModelPoints(model, position, 1.0f, WHITE); + } + else + { + // The old method must continually draw the "points" (lines) + for (int i = 0; i < numPoints; i++) + { + Vector3 pos = { + .x = mesh.vertices[i*3 + 0], + .y = mesh.vertices[i*3 + 1], + .z = mesh.vertices[i*3 + 2], + }; + Color color = { + .r = mesh.colors[i*4 + 0], + .g = mesh.colors[i*4 + 1], + .b = mesh.colors[i*4 + 2], + .a = mesh.colors[i*4 + 3], + }; + + DrawPoint3D(pos, color); + } + } + + // Draw a unit sphere for reference + DrawSphereWires(position, 1.0f, 10, 10, YELLOW); + + EndMode3D(); + + // Draw UI text + DrawText(TextFormat("Point Count: %d", numPoints), 20, screenHeight - 50, 40, WHITE); + DrawText("Up - increase points", 20, 70, 20, WHITE); + DrawText("Down - decrease points", 20, 100, 20, WHITE); + DrawText("Space - drawing function", 20, 130, 20, WHITE); + + if (useDrawModelPoints) DrawText("Using: DrawModelPoints()", 20, 160, 20, GREEN); + else DrawText("Using: DrawPoint3D()", 20, 160, 20, RED); + + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadModel(model); + + CloseWindow(); + //-------------------------------------------------------------------------------------- + return 0; +} + +// Generate a spherical point cloud +Mesh GenMeshPoints(int numPoints) +{ + Mesh mesh = { + .triangleCount = 1, + .vertexCount = numPoints, + .vertices = (float *)MemAlloc(numPoints*3*sizeof(float)), + .colors = (unsigned char*)MemAlloc(numPoints*4*sizeof(unsigned char)), + }; + + // https://en.wikipedia.org/wiki/Spherical_coordinate_system + for (int i = 0; i < numPoints; i++) + { + float theta = PI*rand()/RAND_MAX; + float phi = 2.0f*PI*rand()/RAND_MAX; + float r = 10.0f*rand()/RAND_MAX; + + mesh.vertices[i*3 + 0] = r*sin(theta)*cos(phi); + mesh.vertices[i*3 + 1] = r*sin(theta)*sin(phi); + mesh.vertices[i*3 + 2] = r*cos(theta); + + Color color = ColorFromHSV(r*360.0f, 1.0f, 1.0f); + + mesh.colors[i*4 + 0] = color.r; + mesh.colors[i*4 + 1] = color.g; + mesh.colors[i*4 + 2] = color.b; + mesh.colors[i*4 + 3] = color.a; + } + + // Upload mesh data from CPU (RAM) to GPU (VRAM) memory + UploadMesh(&mesh, false); + + return mesh; +} diff --git a/examples/models/models_point_rendering.png b/examples/models/models_point_rendering.png new file mode 100644 index 000000000..a1fc718e4 Binary files /dev/null and b/examples/models/models_point_rendering.png differ diff --git a/examples/models/models_skybox.c b/examples/models/models_skybox.c index e0e08f3a1..fc9627b42 100644 --- a/examples/models/models_skybox.c +++ b/examples/models/models_skybox.c @@ -49,7 +49,8 @@ int main(void) Mesh cube = GenMeshCube(1.0f, 1.0f, 1.0f); Model skybox = LoadModelFromMesh(cube); - bool useHDR = true; + // Set this to true to use an HDR Texture, Note that raylib must be built with HDR Support for this to work SUPPORT_FILEFORMAT_HDR + bool useHDR = false; // Load skybox shader and set required locations // NOTE: Some locations are automatically set at shader loading @@ -157,8 +158,6 @@ int main(void) DrawGrid(10, 1.0f); EndMode3D(); - - //DrawTextureEx(panorama, (Vector2){ 0, 0 }, 0.0f, 0.5f, WHITE); if (useHDR) DrawText(TextFormat("Panorama image from hdrihaven.com: %s", GetFileName(skyboxFileName)), 10, GetScreenHeight() - 20, 10, BLACK); else DrawText(TextFormat(": %s", GetFileName(skyboxFileName)), 10, GetScreenHeight() - 20, 10, BLACK); diff --git a/examples/models/models_waving_cubes.c b/examples/models/models_waving_cubes.c index 5dc1fc4aa..521a4afd5 100644 --- a/examples/models/models_waving_cubes.c +++ b/examples/models/models_waving_cubes.c @@ -89,6 +89,8 @@ int main() }; // Pick a color with a hue depending on cube position for the rainbow color effect + // NOTE: This function is quite costly to be done per cube and frame, + // pre-catching the results into a separate array could improve performance Color cubeColor = ColorFromHSV((float)(((x + y + z)*18)%360), 0.75f, 0.9f); // Calculate cube size diff --git a/examples/models/models_yaw_pitch_roll.c b/examples/models/models_yaw_pitch_roll.c index 91a11f73c..5374c035e 100644 --- a/examples/models/models_yaw_pitch_roll.c +++ b/examples/models/models_yaw_pitch_roll.c @@ -114,6 +114,7 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- UnloadModel(model); // Unload model data + UnloadTexture(texture); // Unload texture data CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/examples/models/resources/shaders/glsl100/skinning.fs b/examples/models/resources/shaders/glsl100/skinning.fs new file mode 100644 index 000000000..ef6568036 --- /dev/null +++ b/examples/models/resources/shaders/glsl100/skinning.fs @@ -0,0 +1,17 @@ +#version 100 + +// Input vertex attributes (from vertex shader) +in vec2 fragTexCoord; +in vec4 fragColor; + +// Output fragment color +out vec4 finalColor; + +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +void main() +{ + vec4 texelColor = texture(texture0, fragTexCoord); + finalColor = texelColor*colDiffuse*fragColor; +} diff --git a/examples/models/resources/shaders/glsl100/skinning.vs b/examples/models/resources/shaders/glsl100/skinning.vs new file mode 100644 index 000000000..9c92e2a8c --- /dev/null +++ b/examples/models/resources/shaders/glsl100/skinning.vs @@ -0,0 +1,34 @@ +#version 100 + +in vec3 vertexPosition; +in vec2 vertexTexCoord; +in vec4 vertexColor; +in vec4 vertexBoneIds; +in vec4 vertexBoneWeights; + +#define MAX_BONE_NUM 128 +uniform mat4 boneMatrices[MAX_BONE_NUM]; + +uniform mat4 mvp; + +out vec2 fragTexCoord; +out vec4 fragColor; + +void main() +{ + int boneIndex0 = int(vertexBoneIds.x); + int boneIndex1 = int(vertexBoneIds.y); + int boneIndex2 = int(vertexBoneIds.z); + int boneIndex3 = int(vertexBoneIds.w); + + vec4 skinnedPosition = + vertexBoneWeights.x * (boneMatrices[boneIndex0] * vec4(vertexPosition, 1.0f)) + + vertexBoneWeights.y * (boneMatrices[boneIndex1] * vec4(vertexPosition, 1.0f)) + + vertexBoneWeights.z * (boneMatrices[boneIndex2] * vec4(vertexPosition, 1.0f)) + + vertexBoneWeights.w * (boneMatrices[boneIndex3] * vec4(vertexPosition, 1.0f)); + + fragTexCoord = vertexTexCoord; + fragColor = vertexColor; + + gl_Position = mvp * skinnedPosition; +} \ No newline at end of file diff --git a/examples/models/resources/shaders/glsl330/skinning.fs b/examples/models/resources/shaders/glsl330/skinning.fs new file mode 100644 index 000000000..d4311ffcc --- /dev/null +++ b/examples/models/resources/shaders/glsl330/skinning.fs @@ -0,0 +1,17 @@ +#version 330 + +// Input vertex attributes (from vertex shader) +in vec2 fragTexCoord; +in vec4 fragColor; + +// Output fragment color +out vec4 finalColor; + +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +void main() +{ + vec4 texelColor = texture(texture0, fragTexCoord); + finalColor = texelColor*colDiffuse*fragColor; +} diff --git a/examples/models/resources/shaders/glsl330/skinning.vs b/examples/models/resources/shaders/glsl330/skinning.vs new file mode 100644 index 000000000..2dc976c48 --- /dev/null +++ b/examples/models/resources/shaders/glsl330/skinning.vs @@ -0,0 +1,34 @@ +#version 330 + +in vec3 vertexPosition; +in vec2 vertexTexCoord; +in vec4 vertexColor; +in vec4 vertexBoneIds; +in vec4 vertexBoneWeights; + +#define MAX_BONE_NUM 128 +uniform mat4 boneMatrices[MAX_BONE_NUM]; + +uniform mat4 mvp; + +out vec2 fragTexCoord; +out vec4 fragColor; + +void main() +{ + int boneIndex0 = int(vertexBoneIds.x); + int boneIndex1 = int(vertexBoneIds.y); + int boneIndex2 = int(vertexBoneIds.z); + int boneIndex3 = int(vertexBoneIds.w); + + vec4 skinnedPosition = + vertexBoneWeights.x * (boneMatrices[boneIndex0] * vec4(vertexPosition, 1.0f)) + + vertexBoneWeights.y * (boneMatrices[boneIndex1] * vec4(vertexPosition, 1.0f)) + + vertexBoneWeights.z * (boneMatrices[boneIndex2] * vec4(vertexPosition, 1.0f)) + + vertexBoneWeights.w * (boneMatrices[boneIndex3] * vec4(vertexPosition, 1.0f)); + + fragTexCoord = vertexTexCoord; + fragColor = vertexColor; + + gl_Position = mvp * skinnedPosition; +} \ No newline at end of file diff --git a/examples/raylib.ico b/examples/raylib.ico new file mode 100644 index 000000000..0cedcc55c Binary files /dev/null and b/examples/raylib.ico differ diff --git a/examples/shaders/resources/shaders/glsl100/raymarching.fs b/examples/shaders/resources/shaders/glsl100/raymarching.fs index d58d9d331..a7339d216 100644 --- a/examples/shaders/resources/shaders/glsl100/raymarching.fs +++ b/examples/shaders/resources/shaders/glsl100/raymarching.fs @@ -38,7 +38,7 @@ uniform vec2 resolution; // // More info here: http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm -#define AA 1 // make this 1 is your machine is too slow +#define AA 1 // make this 1 if your machine is too slow //------------------------------------------------------------------ diff --git a/examples/shaders/resources/shaders/glsl100/vertex_displacement.fs b/examples/shaders/resources/shaders/glsl100/vertex_displacement.fs new file mode 100644 index 000000000..3328a91e7 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl100/vertex_displacement.fs @@ -0,0 +1,18 @@ +#version 100 + +precision mediump float; + +// Input vertex attributes (from fragment shader) +varying vec2 fragTexCoord; +varying float height; + + +void main() +{ + vec4 darkblue = vec4(0.0, 0.13, 0.18, 1.0); + vec4 lightblue = vec4(1.0, 1.0, 1.0, 1.0); + // Interpolate between two colors based on height + vec4 finalColor = mix(darkblue, lightblue, height); + + gl_FragColor = finalColor; +} \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl100/vertex_displacement.vs b/examples/shaders/resources/shaders/glsl100/vertex_displacement.vs new file mode 100644 index 000000000..c7b926d4b --- /dev/null +++ b/examples/shaders/resources/shaders/glsl100/vertex_displacement.vs @@ -0,0 +1,45 @@ +#version 100 + +precision mediump float; + +attribute vec3 vertexPosition; +attribute vec2 vertexTexCoord; +attribute vec3 vertexNormal; +attribute vec4 vertexColor; + +uniform mat4 mvp; +uniform mat4 matModel; +uniform mat4 matNormal; + +uniform float time; + +uniform sampler2D perlinNoiseMap; + +varying vec3 fragPosition; +varying vec2 fragTexCoord; +varying vec3 fragNormal; +varying float height; + +void main() +{ + // Calculate animated texture coordinates based on time and vertex position + vec2 animatedTexCoord = sin(vertexTexCoord + vec2(sin(time + vertexPosition.x * 0.1), cos(time + vertexPosition.z * 0.1)) * 0.3); + + // Normalize animated texture coordinates to range [0, 1] + animatedTexCoord = animatedTexCoord * 0.5 + 0.5; + + // Fetch displacement from the perlin noise map + float displacement = texture2D(perlinNoiseMap, animatedTexCoord).r * 7.0; // Amplified displacement + + // Displace vertex position + vec3 displacedPosition = vertexPosition + vec3(0.0, displacement, 0.0); + + // Send vertex attributes to fragment shader + fragPosition = vec3(matModel * vec4(displacedPosition, 1.0)); + fragTexCoord = vertexTexCoord; + fragNormal = normalize(vec3(matNormal * vec4(vertexNormal, 1.0))); + height = displacedPosition.y * 0.2; // send height to fragment shader for coloring + + // Calculate final vertex position + gl_Position = mvp * vec4(displacedPosition, 1.0); +} diff --git a/examples/shaders/resources/shaders/glsl120/pbr.fs b/examples/shaders/resources/shaders/glsl120/pbr.fs index 935bced35..1c5eee00b 100644 --- a/examples/shaders/resources/shaders/glsl120/pbr.fs +++ b/examples/shaders/resources/shaders/glsl120/pbr.fs @@ -1,7 +1,5 @@ #version 120 -precision mediump float; - #define MAX_LIGHTS 4 #define LIGHT_DIRECTIONAL 0 #define LIGHT_POINT 1 @@ -17,12 +15,12 @@ struct Light { }; // Input vertex attributes (from vertex shader) -varying in vec3 fragPosition; -varying in vec2 fragTexCoord; -varying in vec4 fragColor; -varying in vec3 fragNormal; -varying in vec4 shadowPos; -varying in mat3 TBN; +varying vec3 fragPosition; +varying vec2 fragTexCoord; +varying vec4 fragColor; +varying vec3 fragNormal; +varying vec4 shadowPos; +varying mat3 TBN; // Input uniform values @@ -153,4 +151,4 @@ void main() gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/examples/shaders/resources/shaders/glsl120/raymarching.fs b/examples/shaders/resources/shaders/glsl120/raymarching.fs new file mode 100644 index 000000000..efe4fa108 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl120/raymarching.fs @@ -0,0 +1,427 @@ +#version 120 + +// Input vertex attributes (from vertex shader) +varying vec2 fragTexCoord; +varying vec4 fragColor; + +uniform vec3 viewEye; +uniform vec3 viewCenter; +uniform float runTime; +uniform vec2 resolution; + +// The MIT License +// Copyright © 2013 Inigo Quilez +// 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. + +// A list of useful distance function to simple primitives, and an example on how to +// do some interesting boolean operations, repetition and displacement. +// +// More info here: http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm + +#define AA 1 // make this 1 if your machine is too slow + +//------------------------------------------------------------------ + +float sdPlane( vec3 p ) +{ + return p.y; +} + +float sdSphere( vec3 p, float s ) +{ + return length(p)-s; +} + +float sdBox( vec3 p, vec3 b ) +{ + vec3 d = abs(p) - b; + return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0)); +} + +float sdEllipsoid( in vec3 p, in vec3 r ) +{ + return (length( p/r ) - 1.0) * min(min(r.x,r.y),r.z); +} + +float udRoundBox( vec3 p, vec3 b, float r ) +{ + return length(max(abs(p)-b,0.0))-r; +} + +float sdTorus( vec3 p, vec2 t ) +{ + return length( vec2(length(p.xz)-t.x,p.y) )-t.y; +} + +float sdHexPrism( vec3 p, vec2 h ) +{ + vec3 q = abs(p); +#if 0 + return max(q.z-h.y,max((q.x*0.866025+q.y*0.5),q.y)-h.x); +#else + float d1 = q.z-h.y; + float d2 = max((q.x*0.866025+q.y*0.5),q.y)-h.x; + return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.); +#endif +} + +float sdCapsule( vec3 p, vec3 a, vec3 b, float r ) +{ + vec3 pa = p-a, ba = b-a; + float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 ); + return length( pa - ba*h ) - r; +} + +float sdEquilateralTriangle( in vec2 p ) +{ + const float k = sqrt(3.0); + p.x = abs(p.x) - 1.0; + p.y = p.y + 1.0/k; + if( p.x + k*p.y > 0.0 ) p = vec2( p.x - k*p.y, -k*p.x - p.y )/2.0; + p.x += 2.0 - 2.0*clamp( (p.x+2.0)/2.0, 0.0, 1.0 ); + return -length(p)*sign(p.y); +} + +float sdTriPrism( vec3 p, vec2 h ) +{ + vec3 q = abs(p); + float d1 = q.z-h.y; +#if 1 + // distance bound + float d2 = max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5; +#else + // correct distance + h.x *= 0.866025; + float d2 = sdEquilateralTriangle(p.xy/h.x)*h.x; +#endif + return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.); +} + +float sdCylinder( vec3 p, vec2 h ) +{ + vec2 d = abs(vec2(length(p.xz),p.y)) - h; + return min(max(d.x,d.y),0.0) + length(max(d,0.0)); +} + +float sdCone( in vec3 p, in vec3 c ) +{ + vec2 q = vec2( length(p.xz), p.y ); + float d1 = -q.y-c.z; + float d2 = max( dot(q,c.xy), q.y); + return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.); +} + +float sdConeSection( in vec3 p, in float h, in float r1, in float r2 ) +{ + float d1 = -p.y - h; + float q = p.y - h; + float si = 0.5*(r1-r2)/h; + float d2 = max( sqrt( dot(p.xz,p.xz)*(1.0-si*si)) + q*si - r2, q ); + return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.); +} + +float sdPryamid4(vec3 p, vec3 h ) // h = { cos a, sin a, height } +{ + // Tetrahedron = Octahedron - Cube + float box = sdBox( p - vec3(0,-2.0*h.z,0), vec3(2.0*h.z) ); + + float d = 0.0; + d = max( d, abs( dot(p, vec3( -h.x, h.y, 0 )) )); + d = max( d, abs( dot(p, vec3( h.x, h.y, 0 )) )); + d = max( d, abs( dot(p, vec3( 0, h.y, h.x )) )); + d = max( d, abs( dot(p, vec3( 0, h.y,-h.x )) )); + float octa = d - h.z; + return max(-box,octa); // Subtraction + } + +float length2( vec2 p ) +{ + return sqrt( p.x*p.x + p.y*p.y ); +} + +float length6( vec2 p ) +{ + p = p*p*p; p = p*p; + return pow( p.x + p.y, 1.0/6.0 ); +} + +float length8( vec2 p ) +{ + p = p*p; p = p*p; p = p*p; + return pow( p.x + p.y, 1.0/8.0 ); +} + +float sdTorus82( vec3 p, vec2 t ) +{ + vec2 q = vec2(length2(p.xz)-t.x,p.y); + return length8(q)-t.y; +} + +float sdTorus88( vec3 p, vec2 t ) +{ + vec2 q = vec2(length8(p.xz)-t.x,p.y); + return length8(q)-t.y; +} + +float sdCylinder6( vec3 p, vec2 h ) +{ + return max( length6(p.xz)-h.x, abs(p.y)-h.y ); +} + +//------------------------------------------------------------------ + +float opS( float d1, float d2 ) +{ + return max(-d2,d1); +} + +vec2 opU( vec2 d1, vec2 d2 ) +{ + return (d1.x0.0 ) tmax = min( tmax, tp1 ); + float tp2 = (1.6-ro.y)/rd.y; if( tp2>0.0 ) { if( ro.y>1.6 ) tmin = max( tmin, tp2 ); + else tmax = min( tmax, tp2 ); } +#endif + + float t = tmin; + float m = -1.0; + for( int i=0; i<64; i++ ) + { + float precis = 0.0005*t; + vec2 res = map( ro+rd*t ); + if( res.xtmax ) break; + t += res.x; + m = res.y; + } + + if( t>tmax ) m=-1.0; + return vec2( t, m ); +} + + +float calcSoftshadow( in vec3 ro, in vec3 rd, in float mint, in float tmax ) +{ + float res = 1.0; + float t = mint; + for( int i=0; i<16; i++ ) + { + float h = map( ro + rd*t ).x; + res = min( res, 8.0*h/t ); + t += clamp( h, 0.02, 0.10 ); + if( h<0.001 || t>tmax ) break; + } + return clamp( res, 0.0, 1.0 ); +} + +vec3 calcNormal( in vec3 pos ) +{ + vec2 e = vec2(1.0,-1.0)*0.5773*0.0005; + return normalize( e.xyy*map( pos + e.xyy ).x + + e.yyx*map( pos + e.yyx ).x + + e.yxy*map( pos + e.yxy ).x + + e.xxx*map( pos + e.xxx ).x ); + /* + vec3 eps = vec3( 0.0005, 0.0, 0.0 ); + vec3 nor = vec3( + map(pos+eps.xyy).x - map(pos-eps.xyy).x, + map(pos+eps.yxy).x - map(pos-eps.yxy).x, + map(pos+eps.yyx).x - map(pos-eps.yyx).x ); + return normalize(nor); + */ +} + +float calcAO( in vec3 pos, in vec3 nor ) +{ + float occ = 0.0; + float sca = 1.0; + for( int i=0; i<5; i++ ) + { + float hr = 0.01 + 0.12*float(i)/4.0; + vec3 aopos = nor * hr + pos; + float dd = map( aopos ).x; + occ += -(dd-hr)*sca; + sca *= 0.95; + } + return clamp( 1.0 - 3.0*occ, 0.0, 1.0 ); +} + +// http://iquilezles.org/www/articles/checkerfiltering/checkerfiltering.htm +float checkersGradBox( in vec2 p ) +{ + // filter kernel + vec2 w = fwidth(p) + 0.001; + // analytical integral (box filter) + vec2 i = 2.0*(abs(fract((p-0.5*w)*0.5)-0.5)-abs(fract((p+0.5*w)*0.5)-0.5))/w; + // xor pattern + return 0.5 - 0.5*i.x*i.y; +} + +vec3 render( in vec3 ro, in vec3 rd ) +{ + vec3 col = vec3(0.7, 0.9, 1.0) +rd.y*0.8; + vec2 res = castRay(ro,rd); + float t = res.x; + float m = res.y; + if( m>-0.5 ) + { + vec3 pos = ro + t*rd; + vec3 nor = calcNormal( pos ); + vec3 ref = reflect( rd, nor ); + + // material + col = 0.45 + 0.35*sin( vec3(0.05,0.08,0.10)*(m-1.0) ); + if( m<1.5 ) + { + + float f = checkersGradBox( 5.0*pos.xz ); + col = 0.3 + f*vec3(0.1); + } + + // lighting + float occ = calcAO( pos, nor ); + vec3 lig = normalize( vec3(cos(-0.4 * runTime), sin(0.7 * runTime), -0.6) ); + vec3 hal = normalize( lig-rd ); + float amb = clamp( 0.5+0.5*nor.y, 0.0, 1.0 ); + float dif = clamp( dot( nor, lig ), 0.0, 1.0 ); + float bac = clamp( dot( nor, normalize(vec3(-lig.x,0.0,-lig.z))), 0.0, 1.0 )*clamp( 1.0-pos.y,0.0,1.0); + float dom = smoothstep( -0.1, 0.1, ref.y ); + float fre = pow( clamp(1.0+dot(nor,rd),0.0,1.0), 2.0 ); + + dif *= calcSoftshadow( pos, lig, 0.02, 2.5 ); + dom *= calcSoftshadow( pos, ref, 0.02, 2.5 ); + + float spe = pow( clamp( dot( nor, hal ), 0.0, 1.0 ),16.0)* + dif * + (0.04 + 0.96*pow( clamp(1.0+dot(hal,rd),0.0,1.0), 5.0 )); + + vec3 lin = vec3(0.0); + lin += 1.30*dif*vec3(1.00,0.80,0.55); + lin += 0.40*amb*vec3(0.40,0.60,1.00)*occ; + lin += 0.50*dom*vec3(0.40,0.60,1.00)*occ; + lin += 0.50*bac*vec3(0.25,0.25,0.25)*occ; + lin += 0.25*fre*vec3(1.00,1.00,1.00)*occ; + col = col*lin; + col += 10.00*spe*vec3(1.00,0.90,0.70); + + col = mix( col, vec3(0.8,0.9,1.0), 1.0-exp( -0.0002*t*t*t ) ); + } + + return vec3( clamp(col,0.0,1.0) ); +} + +mat3 setCamera( in vec3 ro, in vec3 ta, float cr ) +{ + vec3 cw = normalize(ta-ro); + vec3 cp = vec3(sin(cr), cos(cr),0.0); + vec3 cu = normalize( cross(cw,cp) ); + vec3 cv = normalize( cross(cu,cw) ); + return mat3( cu, cv, cw ); +} + +void main() +{ + vec3 tot = vec3(0.0); +#if AA>1 + for( int m=0; m1 + } + tot /= float(AA*AA); +#endif + + gl_FragColor = vec4( tot, 1.0 ); +} diff --git a/examples/shaders/resources/shaders/glsl120/shadowmap.fs b/examples/shaders/resources/shaders/glsl120/shadowmap.fs index 668fdeb4b..f43e63823 100644 --- a/examples/shaders/resources/shaders/glsl120/shadowmap.fs +++ b/examples/shaders/resources/shaders/glsl120/shadowmap.fs @@ -1,15 +1,13 @@ #version 120 -precision mediump float; - // This shader is based on the basic lighting shader // This only supports one light, which is directional, and it (of course) supports shadows // Input vertex attributes (from vertex shader) -varying in vec3 fragPosition; -varying in vec2 fragTexCoord; +varying vec3 fragPosition; +varying vec2 fragTexCoord; //varying in vec4 fragColor; -varying in vec3 fragNormal; +varying vec3 fragNormal; // Input uniform values uniform sampler2D texture0; diff --git a/examples/shaders/resources/shaders/glsl330/vertex_displacement.fs b/examples/shaders/resources/shaders/glsl330/vertex_displacement.fs new file mode 100644 index 000000000..424f526e4 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl330/vertex_displacement.fs @@ -0,0 +1,16 @@ +#version 330 + +// Input fragment attributes (from fragment shader) +in vec2 fragTexCoord; +in float height; + +// Output fragment color +out vec4 finalColor; + +void main() +{ + vec4 darkblue = vec4(0.0, 0.13, 0.18, 1.0); + vec4 lightblue = vec4(1.0, 1.0, 1.0, 1.0); + // interplate between two colors based on height + finalColor = mix(darkblue, lightblue, height); +} \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl330/vertex_displacement.vs b/examples/shaders/resources/shaders/glsl330/vertex_displacement.vs new file mode 100644 index 000000000..73cf16109 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl330/vertex_displacement.vs @@ -0,0 +1,46 @@ +#version 330 + +// Input vertex attributes +in vec3 vertexPosition; +in vec2 vertexTexCoord; +in vec3 vertexNormal; +in vec4 vertexColor; + +// Input uniform values +uniform mat4 mvp; +uniform mat4 matModel; +uniform mat4 matNormal; + +uniform float time; + +uniform sampler2D perlinNoiseMap; + +// Output vertex attributes (to fragment shader) +out vec3 fragPosition; +out vec2 fragTexCoord; +out vec3 fragNormal; +out float height; + +void main() +{ + // Calculate animated texture coordinates based on time and vertex position + vec2 animatedTexCoord = sin(vertexTexCoord + vec2(sin(time + vertexPosition.x * 0.1), cos(time + vertexPosition.z * 0.1)) * 0.3); + + // Normalize animated texture coordinates to range [0, 1] + animatedTexCoord = animatedTexCoord * 0.5 + 0.5; + + // Fetch displacement from the perlin noise map + float displacement = texture(perlinNoiseMap, animatedTexCoord).r * 7; // Amplified displacement + + // Displace vertex position + vec3 displacedPosition = vertexPosition + vec3(0.0, displacement, 0.0); + + // Send vertex attributes to fragment shader + fragPosition = vec3(matModel*vec4(displacedPosition, 1.0)); + fragTexCoord = vertexTexCoord; + fragNormal = normalize(vec3(matNormal*vec4(vertexNormal, 1.0))); + height = displacedPosition.y * 0.2; // send height to fragment shader for coloring + + // Calculate final vertex position + gl_Position = mvp*vec4(displacedPosition , 1.0); +} diff --git a/examples/shaders/shaders_basic_pbr.c b/examples/shaders/shaders_basic_pbr.c index d025ab8a9..c3f2bad88 100644 --- a/examples/shaders/shaders_basic_pbr.c +++ b/examples/shaders/shaders_basic_pbr.c @@ -236,7 +236,7 @@ int main() float emissiveIntensity = 0.01f; SetShaderValue(shader, emissiveIntensityLoc, &emissiveIntensity, SHADER_UNIFORM_FLOAT); - DrawModel(car, (Vector3){ 0.0f, 0.0f, 0.0f }, 0.005f, WHITE); // Draw car model + DrawModel(car, (Vector3){ 0.0f, 0.0f, 0.0f }, 0.25f, WHITE); // Draw car model // Draw spheres to show the lights positions for (int i = 0; i < MAX_LIGHTS; i++) diff --git a/examples/shaders/shaders_deferred_render.c b/examples/shaders/shaders_deferred_render.c index 1c2db7b50..4f652fe33 100644 --- a/examples/shaders/shaders_deferred_render.c +++ b/examples/shaders/shaders_deferred_render.c @@ -281,7 +281,7 @@ int main(void) .id = gBuffer.positionTexture, .width = screenWidth, .height = screenHeight, - }, (Rectangle) { 0, 0, screenWidth, -screenHeight }, Vector2Zero(), RAYWHITE); + }, (Rectangle) { 0, 0, (float)screenWidth, (float)-screenHeight }, Vector2Zero(), RAYWHITE); DrawText("POSITION TEXTURE", 10, screenHeight - 30, 20, DARKGREEN); } break; @@ -291,7 +291,7 @@ int main(void) .id = gBuffer.normalTexture, .width = screenWidth, .height = screenHeight, - }, (Rectangle) { 0, 0, screenWidth, -screenHeight }, Vector2Zero(), RAYWHITE); + }, (Rectangle) { 0, 0, (float)screenWidth, (float)-screenHeight }, Vector2Zero(), RAYWHITE); DrawText("NORMAL TEXTURE", 10, screenHeight - 30, 20, DARKGREEN); } break; @@ -301,7 +301,7 @@ int main(void) .id = gBuffer.albedoSpecTexture, .width = screenWidth, .height = screenHeight, - }, (Rectangle) { 0, 0, screenWidth, -screenHeight }, Vector2Zero(), RAYWHITE); + }, (Rectangle) { 0, 0, (float)screenWidth, (float)-screenHeight }, Vector2Zero(), RAYWHITE); DrawText("ALBEDO TEXTURE", 10, screenHeight - 30, 20, DARKGREEN); } break; diff --git a/examples/shaders/shaders_lightmap.c b/examples/shaders/shaders_lightmap.c index 01b80a6fb..91ed8bfd2 100644 --- a/examples/shaders/shaders_lightmap.c +++ b/examples/shaders/shaders_lightmap.c @@ -164,6 +164,8 @@ int main(void) //-------------------------------------------------------------------------------------- UnloadMesh(mesh); // Unload the mesh UnloadShader(shader); // Unload shader + UnloadTexture(texture); // Unload texture + UnloadTexture(light); // Unload texture CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/examples/shaders/shaders_texture_drawing.c b/examples/shaders/shaders_texture_drawing.c index 52b8967f6..ada44299d 100644 --- a/examples/shaders/shaders_texture_drawing.c +++ b/examples/shaders/shaders_texture_drawing.c @@ -77,6 +77,7 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- UnloadShader(shader); + UnloadTexture(texture); CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/examples/shaders/shaders_vertex_displacement.c b/examples/shaders/shaders_vertex_displacement.c new file mode 100644 index 000000000..207a237d0 --- /dev/null +++ b/examples/shaders/shaders_vertex_displacement.c @@ -0,0 +1,119 @@ +/******************************************************************************************* +* +* raylib [shaders] example - Vertex displacement +* +* Example originally created with raylib 5.0, last time updated with raylib 4.5 +* +* Example contributed by (@ZzzhHe) and reviewed by Ramon Santamaria (@raysan5) +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2023 (@ZzzhHe) +* +********************************************************************************************/ + +#include "raylib.h" + +#include "rlgl.h" + +#define RLIGHTS_IMPLEMENTATION +#include "rlights.h" + +#if defined(PLATFORM_DESKTOP) + #define GLSL_VERSION 330 +#else // PLATFORM_ANDROID, PLATFORM_WEB + #define GLSL_VERSION 100 +#endif + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [shaders] example - vertex displacement"); + + // set up camera + Camera camera = {0}; + camera.position = (Vector3) {20.0f, 5.0f, -20.0f}; + camera.target = (Vector3) {0.0f, 0.0f, 0.0f}; + camera.up = (Vector3) {0.0f, 1.0f, 0.0f}; + camera.fovy = 60.0f; + camera.projection = CAMERA_PERSPECTIVE; + + // Load vertex and fragment shaders + Shader shader = LoadShader( + TextFormat("resources/shaders/glsl%i/vertex_displacement.vs", GLSL_VERSION), + TextFormat("resources/shaders/glsl%i/vertex_displacement.fs", GLSL_VERSION)); + + // Load perlin noise texture + Image perlinNoiseImage = GenImagePerlinNoise(512, 512, 0, 0, 1.0f); + Texture perlinNoiseMap = LoadTextureFromImage(perlinNoiseImage); + UnloadImage(perlinNoiseImage); + + // Set shader uniform location + int perlinNoiseMapLoc = GetShaderLocation(shader, "perlinNoiseMap"); + rlEnableShader(shader.id); + rlActiveTextureSlot(1); + rlEnableTexture(perlinNoiseMap.id); + rlSetUniformSampler(perlinNoiseMapLoc, 1); + + // Create a plane mesh and model + Mesh planeMesh = GenMeshPlane(50, 50, 50, 50); + Model planeModel = LoadModelFromMesh(planeMesh); + // Set plane model material + planeModel.materials[0].shader = shader; + + float time = 0.0f; + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateCamera(&camera, CAMERA_FREE); // Update camera + + time += GetFrameTime(); // Update time variable + SetShaderValue(shader, GetShaderLocation(shader, "time"), &time, SHADER_UNIFORM_FLOAT); // Send time value to shader + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + + BeginShaderMode(shader); + // Draw plane model + DrawModel(planeModel, (Vector3){ 0.0f, 0.0f, 0.0f }, 1.0f, (Color) {255, 255, 255, 255}); + EndShaderMode(); + + EndMode3D(); + + DrawText("Vertex displacement", 10, 10, 20, DARKGRAY); + DrawFPS(10, 40); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadShader(shader); + UnloadModel(planeModel); + UnloadTexture(perlinNoiseMap); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/shaders/shaders_vertex_displacement.png b/examples/shaders/shaders_vertex_displacement.png new file mode 100644 index 000000000..e7acf5c65 Binary files /dev/null and b/examples/shaders/shaders_vertex_displacement.png differ diff --git a/examples/shapes/raygui.h b/examples/shapes/raygui.h index 623115fce..16e01a28f 100644 --- a/examples/shapes/raygui.h +++ b/examples/shapes/raygui.h @@ -1,6 +1,6 @@ /******************************************************************************************* * -* raygui v4.0 - A simple and easy-to-use immediate-mode gui library +* raygui v4.5-dev - A simple and easy-to-use immediate-mode gui library * * DESCRIPTION: * raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also @@ -26,7 +26,7 @@ * NOTES: * - WARNING: GuiLoadStyle() and GuiLoadStyle{Custom}() functions, allocate memory for * font atlas recs and glyphs, freeing that memory is (usually) up to the user, -* no unload function is explicitly provided... but note that GuiLoadStyleDefaulf() unloads +* no unload function is explicitly provided... but note that GuiLoadStyleDefault() unloads * by default any previously loaded font (texture, recs, glyphs). * - Global UI alpha (guiAlpha) is applied inside GuiDrawRectangle() and GuiDrawText() functions * @@ -141,6 +141,24 @@ * Draw text bounds rectangles for debug * * VERSIONS HISTORY: +* 4.5-dev (Sep-2024) Current dev version... +* ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes +* ADDED: GuiValueBoxFloat() +* ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP +* ADDED: GuiListView() property: LIST_ITEMS_BORDER_WIDTH +* ADDED: Multiple new icons +* REVIEWED: GuiTabBar(), close tab with mouse middle button +* REVIEWED: GuiScrollPanel(), scroll speed proportional to content +* REVIEWED: GuiDropdownBox(), support roll up and hidden arrow +* REVIEWED: GuiTextBox(), cursor position initialization +* REVIEWED: GuiSliderPro(), control value change check +* REVIEWED: GuiGrid(), simplified implementation +* REVIEWED: GuiIconText(), increase buffer size and reviewed padding +* REVIEWED: GuiDrawText(), improved wrap mode drawing +* REVIEWED: GuiScrollBar(), minor tweaks +* REVIEWED: Functions descriptions, removed wrong return value reference +* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion +* * 4.0 (12-Sep-2023) ADDED: GuiToggleSlider() * ADDED: GuiColorPickerHSV() and GuiColorPanelHSV() * ADDED: Multiple new icons, mostly compiler related @@ -314,9 +332,9 @@ #define RAYGUI_H #define RAYGUI_VERSION_MAJOR 4 -#define RAYGUI_VERSION_MINOR 0 +#define RAYGUI_VERSION_MINOR 5 #define RAYGUI_VERSION_PATCH 0 -#define RAYGUI_VERSION "4.0" +#define RAYGUI_VERSION "4.5-dev" #if !defined(RAYGUI_STANDALONE) #include "raylib.h" @@ -441,7 +459,6 @@ } Font; #endif - // Style property // NOTE: Used when exporting style as code for convenience typedef struct GuiStyleProp { @@ -546,7 +563,6 @@ typedef enum { // TEXT_SIZE, TEXT_SPACING, TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE are global and // should be configured by user as needed while defining the UI layout - // Gui extended properties depend on control // NOTE: RAYGUI_MAX_PROPS_EXTENDED properties (by default, max 8 properties) //---------------------------------------------------------------------------------- @@ -562,12 +578,12 @@ typedef enum { TEXT_ALIGNMENT_VERTICAL, // Text vertical alignment inside text bounds (after border and padding) TEXT_WRAP_MODE // Text wrap-mode inside text bounds //TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline - //TEXT_DECORATION_THICK // Text decoration line thikness + //TEXT_DECORATION_THICK // Text decoration line thickness } GuiDefaultProperty; // Other possible text properties: // TEXT_WEIGHT // Normal, Italic, Bold -> Requires specific font change -// TEXT_INDENT // Text indentation -> Now using TEXT_PADDING... +// TEXT_INDENT // Text indentation -> Now using TEXT_PADDING... // Label //typedef enum { } GuiLabelProperty; @@ -615,7 +631,9 @@ typedef enum { // DropdownBox typedef enum { ARROW_PADDING = 16, // DropdownBox arrow separation from border and items - DROPDOWN_ITEMS_SPACING // DropdownBox items separation + DROPDOWN_ITEMS_SPACING, // DropdownBox items separation + DROPDOWN_ARROW_HIDDEN, // DropdownBox arrow hidden + DROPDOWN_ROLL_UP // DropdownBox roll up flag (default rolls down) } GuiDropdownBoxProperty; // TextBox/TextBoxMulti/ValueBox/Spinner @@ -635,6 +653,7 @@ typedef enum { LIST_ITEMS_SPACING, // ListView items separation SCROLLBAR_WIDTH, // ListView scrollbar size (usually width) SCROLLBAR_SIDE, // ListView scrollbar side (0-SCROLLBAR_LEFT_SIDE, 1-SCROLLBAR_RIGHT_SIDE) + LIST_ITEMS_BORDER_WIDTH // ListView items border width } GuiListViewProperty; // ColorPicker @@ -698,7 +717,6 @@ RAYGUIAPI char **GuiLoadIcons(const char *fileName, bool loadIconsName); // Load RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); // Draw icon using pixel size at specified position #endif - // Controls //---------------------------------------------------------------------------------------------------------- // Container/separator controls, useful for controls organization @@ -710,29 +728,30 @@ RAYGUIAPI int GuiTabBar(Rectangle bounds, const char **text, int count, int *act RAYGUIAPI int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view); // Scroll Panel control // Basic controls set -RAYGUIAPI int GuiLabel(Rectangle bounds, const char *text); // Label control, shows text +RAYGUIAPI int GuiLabel(Rectangle bounds, const char *text); // Label control RAYGUIAPI int GuiButton(Rectangle bounds, const char *text); // Button control, returns true when clicked -RAYGUIAPI int GuiLabelButton(Rectangle bounds, const char *text); // Label button control, show true when clicked -RAYGUIAPI int GuiToggle(Rectangle bounds, const char *text, bool *active); // Toggle Button control, returns true when active -RAYGUIAPI int GuiToggleGroup(Rectangle bounds, const char *text, int *active); // Toggle Group control, returns active toggle index -RAYGUIAPI int GuiToggleSlider(Rectangle bounds, const char *text, int *active); // Toggle Slider control, returns true when clicked +RAYGUIAPI int GuiLabelButton(Rectangle bounds, const char *text); // Label button control, returns true when clicked +RAYGUIAPI int GuiToggle(Rectangle bounds, const char *text, bool *active); // Toggle Button control +RAYGUIAPI int GuiToggleGroup(Rectangle bounds, const char *text, int *active); // Toggle Group control +RAYGUIAPI int GuiToggleSlider(Rectangle bounds, const char *text, int *active); // Toggle Slider control RAYGUIAPI int GuiCheckBox(Rectangle bounds, const char *text, bool *checked); // Check Box control, returns true when active -RAYGUIAPI int GuiComboBox(Rectangle bounds, const char *text, int *active); // Combo Box control, returns selected item index +RAYGUIAPI int GuiComboBox(Rectangle bounds, const char *text, int *active); // Combo Box control -RAYGUIAPI int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode); // Dropdown Box control, returns selected item -RAYGUIAPI int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Spinner control, returns selected value +RAYGUIAPI int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode); // Dropdown Box control +RAYGUIAPI int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Spinner control RAYGUIAPI int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Value Box control, updates input text with numbers +RAYGUIAPI int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode); // Value box control for float values RAYGUIAPI int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control, updates input text -RAYGUIAPI int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider control, returns selected value -RAYGUIAPI int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider Bar control, returns selected value -RAYGUIAPI int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Progress Bar control, shows current progress value +RAYGUIAPI int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider control +RAYGUIAPI int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider Bar control +RAYGUIAPI int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Progress Bar control RAYGUIAPI int GuiStatusBar(Rectangle bounds, const char *text); // Status Bar control, shows info text RAYGUIAPI int GuiDummyRec(Rectangle bounds, const char *text); // Dummy control for placeholders -RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell); // Grid control, returns mouse cell position +RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell); // Grid control // Advance controls set -RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control, returns selected list item index +RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control RAYGUIAPI int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollIndex, int *active, int *focus); // List View with extended parameters RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons); // Message Box control, displays a message RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive); // Text Input Box control, ask for text, supports secret @@ -741,10 +760,9 @@ RAYGUIAPI int GuiColorPanel(Rectangle bounds, const char *text, Color *color); RAYGUIAPI int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha); // Color Bar Alpha control RAYGUIAPI int GuiColorBarHue(Rectangle bounds, const char *text, float *value); // Color Bar Hue control RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control that avoids conversion to RGB on each call (multiple color controls) -RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control that returns HSV color value, used by GuiColorPickerHSV() +RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control that updates Hue-Saturation-Value color value, used by GuiColorPickerHSV() //---------------------------------------------------------------------------------------------------------- - #if !defined(RAYGUI_NO_ICONS) #if !defined(RAYGUI_CUSTOM_ICONS) @@ -972,14 +990,14 @@ typedef enum { ICON_FOLDER = 217, ICON_FILE = 218, ICON_SAND_TIMER = 219, - ICON_220 = 220, - ICON_221 = 221, - ICON_222 = 222, - ICON_223 = 223, - ICON_224 = 224, - ICON_225 = 225, - ICON_226 = 226, - ICON_227 = 227, + ICON_WARNING = 220, + ICON_HELP_BOX = 221, + ICON_INFO_BOX = 222, + ICON_PRIORITY = 223, + ICON_LAYERS_ISO = 224, + ICON_LAYERS2 = 225, + ICON_MLAYERS = 226, + ICON_MAPS = 227, ICON_228 = 228, ICON_229 = 229, ICON_230 = 230, @@ -1290,14 +1308,14 @@ static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // ICON_FOLDER 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x00003ffc, // ICON_FILE 0x1ff00000, 0x20082008, 0x17d02fe8, 0x05400ba0, 0x09200540, 0x23881010, 0x2fe827c8, 0x00001ff0, // ICON_SAND_TIMER - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_220 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_221 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_222 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_223 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_224 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_225 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_226 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_227 + 0x01800000, 0x02400240, 0x05a00420, 0x09900990, 0x11881188, 0x21842004, 0x40024182, 0x00003ffc, // ICON_WARNING + 0x7ffe0000, 0x4ff24002, 0x4c324ff2, 0x4f824c02, 0x41824f82, 0x41824002, 0x40024182, 0x00007ffe, // ICON_HELP_BOX + 0x7ffe0000, 0x41824002, 0x40024182, 0x41824182, 0x41824182, 0x41824182, 0x40024182, 0x00007ffe, // ICON_INFO_BOX + 0x01800000, 0x04200240, 0x10080810, 0x7bde2004, 0x0a500a50, 0x08500bd0, 0x08100850, 0x00000ff0, // ICON_PRIORITY + 0x01800000, 0x18180660, 0x80016006, 0x98196006, 0x99996666, 0x19986666, 0x01800660, 0x00000000, // ICON_LAYERS_ISO + 0x07fe0000, 0x1c020402, 0x74021402, 0x54025402, 0x54025402, 0x500857fe, 0x40205ff8, 0x00007fe0, // ICON_LAYERS2 + 0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x422a422a, 0x422e422a, 0x40384e28, 0x00007fe0, // ICON_MLAYERS + 0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x5b2a512a, 0x512e552a, 0x40385128, 0x00007fe0, // ICON_MAPS 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_228 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_229 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_230 @@ -1328,7 +1346,7 @@ static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_255 }; -// NOTE: We keep a pointer to the icons array, useful to point to other sets if required +// NOTE: A pointer to current icons array should be defined static unsigned int *guiIconsPtr = guiIcons; #endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS @@ -1363,8 +1381,8 @@ static unsigned int guiIconScale = 1; // Gui icon default scale (if ic static bool guiTooltip = false; // Tooltip enabled/disabled static const char *guiTooltipPtr = NULL; // Tooltip string pointer (string provided by user) -static bool guiSliderDragging = false; // Gui slider drag state (no inputs processed except dragged slider) -static Rectangle guiSliderActive = { 0 }; // Gui slider active bounds rectangle, used as an unique identifier +static bool guiControlExclusiveMode = false; // Gui control exclusive mode (no inputs processed except current control) +static Rectangle guiControlExclusiveRec = { 0 }; // Gui control exclusive bounds rectangle, used as an unique identifier static int textBoxCursorIndex = 0; // Cursor index, shared by all GuiTextBox*() //static int blinkCursorFrameCounter = 0; // Frame counter for cursor blinking @@ -1450,6 +1468,7 @@ static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed' static const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings static int TextToInteger(const char *text); // Get integer value from text +static float TextToFloat(const char *text); // Get float value from text static int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded text static const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode codepoint into UTF-8 text (char array size returned as parameter) @@ -1744,6 +1763,9 @@ int GuiTabBar(Rectangle bounds, const char **text, int count, int *active) if (toggle) *active = i; } + // Close tab with middle mouse button pressed + if (CheckCollisionPointRec(GetMousePosition(), tabBounds) && IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON)) result = i; + GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); @@ -1775,10 +1797,10 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector { #define RAYGUI_MIN_SCROLLBAR_WIDTH 40 #define RAYGUI_MIN_SCROLLBAR_HEIGHT 40 + #define RAYGUI_MIN_MOUSE_WHEEL_SPEED 20 int result = 0; GuiState state = guiState; - float mouseWheelSpeed = 20.0f; // Default movement speed with mouse wheel Rectangle temp = { 0 }; if (view == NULL) view = &temp; @@ -1820,17 +1842,8 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector }; // Make sure scroll bars have a minimum width/height - // NOTE: If content >>> bounds, size could be very small or even 0 - if (horizontalScrollBar.width < RAYGUI_MIN_SCROLLBAR_WIDTH) - { - horizontalScrollBar.width = RAYGUI_MIN_SCROLLBAR_WIDTH; - mouseWheelSpeed = 30.0f; // TODO: Calculate speed increment based on content.height vs bounds.height - } - if (verticalScrollBar.height < RAYGUI_MIN_SCROLLBAR_HEIGHT) - { - verticalScrollBar.height = RAYGUI_MIN_SCROLLBAR_HEIGHT; - mouseWheelSpeed = 30.0f; // TODO: Calculate speed increment based on content.width vs bounds.width - } + if (horizontalScrollBar.width < RAYGUI_MIN_SCROLLBAR_WIDTH) horizontalScrollBar.width = RAYGUI_MIN_SCROLLBAR_WIDTH; + if (verticalScrollBar.height < RAYGUI_MIN_SCROLLBAR_HEIGHT) verticalScrollBar.height = RAYGUI_MIN_SCROLLBAR_HEIGHT; // Calculate view area (area without the scrollbars) *view = (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? @@ -1873,9 +1886,14 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector #endif float wheelMove = GetMouseWheelMove(); + // Set scrolling speed with mouse wheel based on ratio between bounds and content + Vector2 mouseWheelSpeed = { content.width/bounds.width, content.height/bounds.height }; + if (mouseWheelSpeed.x < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.x = RAYGUI_MIN_MOUSE_WHEEL_SPEED; + if (mouseWheelSpeed.y < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.y = RAYGUI_MIN_MOUSE_WHEEL_SPEED; + // Horizontal and vertical scrolling with mouse wheel - if (hasHorizontalScrollBar && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_LEFT_SHIFT))) scrollPos.x += wheelMove*mouseWheelSpeed; - else scrollPos.y += wheelMove*mouseWheelSpeed; // Vertical scroll + if (hasHorizontalScrollBar && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_LEFT_SHIFT))) scrollPos.x += wheelMove*mouseWheelSpeed.x; + else scrollPos.y += wheelMove*mouseWheelSpeed.y; // Vertical scroll } } @@ -1921,7 +1939,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector } // Draw scrollbar lines depending on current state - GuiDrawRectangle(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + (state*3))), BLANK); + GuiDrawRectangle(bounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + (state*3))), BLANK); // Set scrollbar slider size back to the way it was before GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, slider); @@ -1959,7 +1977,7 @@ int GuiButton(Rectangle bounds, const char *text) // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { Vector2 mousePoint = GetMousePosition(); @@ -1997,7 +2015,7 @@ int GuiLabelButton(Rectangle bounds, const char *text) // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { Vector2 mousePoint = GetMousePosition(); @@ -2020,7 +2038,7 @@ int GuiLabelButton(Rectangle bounds, const char *text) return pressed; } -// Toggle Button control, returns true when active +// Toggle Button control int GuiToggle(Rectangle bounds, const char *text, bool *active) { int result = 0; @@ -2031,7 +2049,7 @@ int GuiToggle(Rectangle bounds, const char *text, bool *active) // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { Vector2 mousePoint = GetMousePosition(); @@ -2068,7 +2086,7 @@ int GuiToggle(Rectangle bounds, const char *text, bool *active) return result; } -// Toggle Group control, returns toggled button codepointIndex +// Toggle Group control int GuiToggleGroup(Rectangle bounds, const char *text, int *active) { #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS) @@ -2117,7 +2135,7 @@ int GuiToggleGroup(Rectangle bounds, const char *text, int *active) return result; } -// Toggle Slider control extended, returns true when clicked +// Toggle Slider control extended int GuiToggleSlider(Rectangle bounds, const char *text, int *active) { int result = 0; @@ -2211,7 +2229,7 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { Vector2 mousePoint = GetMousePosition(); @@ -2256,7 +2274,7 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) return result; } -// Combo Box control, returns selected item codepointIndex +// Combo Box control int GuiComboBox(Rectangle bounds, const char *text, int *active) { int result = 0; @@ -2279,7 +2297,7 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && (itemCount > 1) && !guiSliderDragging) + if ((state != STATE_DISABLED) && !guiLocked && (itemCount > 1) && !guiControlExclusiveMode) { Vector2 mousePoint = GetMousePosition(); @@ -2327,21 +2345,28 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod int result = 0; GuiState state = guiState; + int temp = 0; + if (active == NULL) active = &temp; + int itemSelected = *active; int itemFocused = -1; + int direction = 0; // Dropdown box open direction: down (default) + if (GuiGetStyle(DROPDOWNBOX, DROPDOWN_ROLL_UP) == 1) direction = 1; // Up + // Get substrings items from text (items pointers, lengths and count) int itemCount = 0; const char **items = GuiTextSplit(text, ';', &itemCount, NULL); Rectangle boundsOpen = bounds; boundsOpen.height = (itemCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + if (direction == 1) boundsOpen.y -= itemCount*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)) + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING); Rectangle itemBounds = bounds; // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && (editMode || !guiLocked) && (itemCount > 1) && !guiSliderDragging) + if ((state != STATE_DISABLED) && (editMode || !guiLocked) && (itemCount > 1) && !guiControlExclusiveMode) { Vector2 mousePoint = GetMousePosition(); @@ -2362,7 +2387,8 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod for (int i = 0; i < itemCount; i++) { // Update item rectangle y position for next item - itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + if (direction == 0) itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + else itemBounds.y -= (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); if (CheckCollisionPointRec(mousePoint, itemBounds)) { @@ -2406,7 +2432,8 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod for (int i = 0; i < itemCount; i++) { // Update item rectangle y position for next item - itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + if (direction == 0) itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + else itemBounds.y -= (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); if (i == itemSelected) { @@ -2422,14 +2449,17 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod } } - // Draw arrows (using icon if available) + if (!GuiGetStyle(DROPDOWNBOX, DROPDOWN_ARROW_HIDDEN)) + { + // Draw arrows (using icon if available) #if defined(RAYGUI_NO_ICONS) - GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); + GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); #else - GuiDrawText("#120#", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); // ICON_ARROW_DOWN_FILL + GuiDrawText(direction? "#121#" : "#120#", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); // ICON_ARROW_DOWN_FILL #endif + } //-------------------------------------------------------------------- *active = itemSelected; @@ -2440,7 +2470,7 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod // Text Box control // NOTE: Returns true on ENTER pressed (useful for data validation) -int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode) +int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) { #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) #define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 40 // Frames to wait for autocursor movement @@ -2456,7 +2486,10 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode) int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); Rectangle textBounds = GetTextBounds(TEXTBOX, bounds); - int textWidth = GetTextWidth(text) - GetTextWidth(text + textBoxCursorIndex); + int textLength = (int)strlen(text); // Get current text length + int thisCursorIndex = textBoxCursorIndex; + if (thisCursorIndex > textLength) thisCursorIndex = textLength; + int textWidth = GetTextWidth(text) - GetTextWidth(text + thisCursorIndex); int textIndexOffset = 0; // Text index offset to start drawing in the box // Cursor rectangle @@ -2496,7 +2529,7 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode) if ((state != STATE_DISABLED) && // Control not disabled !GuiGetStyle(TEXTBOX, TEXT_READONLY) && // TextBox not on read-only mode !guiLocked && // Gui not locked - !guiSliderDragging && // No gui slider on dragging + !guiControlExclusiveMode && // No gui slider on dragging (wrapMode == TEXT_WRAP_NONE)) // No wrap mode { Vector2 mousePosition = GetMousePosition(); @@ -2505,6 +2538,8 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode) { state = STATE_PRESSED; + if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength; + // If text does not fit in the textbox and current cursor position is out of bounds, // we add an index offset to text for drawing only what requires depending on cursor while (textWidth >= textBounds.width) @@ -2517,19 +2552,16 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode) textWidth = GetTextWidth(text + textIndexOffset) - GetTextWidth(text + textBoxCursorIndex); } - int textLength = (int)strlen(text); // Get current text length int codepoint = GetCharPressed(); // Get Unicode codepoint if (multiline && IsKeyPressed(KEY_ENTER)) codepoint = (int)'\n'; - if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength; - // Encode codepoint as UTF-8 int codepointSize = 0; const char *charEncoded = CodepointToUTF8(codepoint, &codepointSize); // Add codepoint to text, at current cursor position // NOTE: Make sure we do not overflow buffer size - if (((multiline && (codepoint == (int)'\n')) || (codepoint >= 32)) && ((textLength + codepointSize) < bufferSize)) + if (((multiline && (codepoint == (int)'\n')) || (codepoint >= 32)) && ((textLength + codepointSize) < textSize)) { // Move forward data from cursor position for (int i = (textLength + codepointSize); i > textBoxCursorIndex; i--) text[i] = text[i - codepointSize]; @@ -2564,6 +2596,7 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode) for (int i = textBoxCursorIndex; i < textLength; i++) text[i] = text[i + nextCodepointSize]; textLength -= codepointSize; + if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength; // Make sure text last character is EOL text[textLength] = '\0'; @@ -2583,6 +2616,8 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode) // Move backward text from cursor position for (int i = (textBoxCursorIndex - prevCodepointSize); i < textLength; i++) text[i] = text[i + prevCodepointSize]; + // TODO Check: >= cursor+codepointsize and <= length-codepointsize + // Prevent cursor index from decrementing past 0 if (textBoxCursorIndex > 0) { @@ -2653,7 +2688,7 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode) if (GetMousePosition().x >= (textBounds.x + textEndWidth - glyphWidth/2)) { mouseCursor.x = textBounds.x + textEndWidth; - mouseCursorIndex = (int)strlen(text); + mouseCursorIndex = textLength; } // Place cursor at required index on mouse click @@ -2685,7 +2720,7 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode) if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { - textBoxCursorIndex = (int)strlen(text); // GLOBAL: Place cursor index to the end of current text + textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text result = 1; } } @@ -2727,7 +2762,7 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode) /* // Text Box control with multiple lines and word-wrap // NOTE: This text-box is readonly, no editing supported by default -bool GuiTextBoxMulti(Rectangle bounds, char *text, int bufferSize, bool editMode) +bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode) { bool pressed = false; @@ -2736,7 +2771,7 @@ bool GuiTextBoxMulti(Rectangle bounds, char *text, int bufferSize, bool editMode GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_TOP); // TODO: Implement methods to calculate cursor position properly - pressed = GuiTextBox(bounds, text, bufferSize, editMode); + pressed = GuiTextBox(bounds, text, textSize, editMode); GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_NONE); @@ -2771,7 +2806,7 @@ int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { Vector2 mousePoint = GetMousePosition(); @@ -2846,7 +2881,7 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { Vector2 mousePoint = GetMousePosition(); @@ -2890,7 +2925,13 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in //if (*value > maxValue) *value = maxValue; //else if (*value < minValue) *value = minValue; - if (IsKeyPressed(KEY_ENTER) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) result = 1; + if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) + { + if (*value > maxValue) *value = maxValue; + else if (*value < minValue) *value = minValue; + + result = 1; + } } else { @@ -2930,55 +2971,152 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in return result; } +// Floating point Value Box control, updates input val_str with numbers +// NOTE: Requires static variables: frameCounter +int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode) +{ + #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) + #define RAYGUI_VALUEBOX_MAX_CHARS 32 + #endif + + int result = 0; + GuiState state = guiState; + + //char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0"; + //sprintf(textValue, "%2.2f", *value); + + Rectangle textBounds = {0}; + if (text != NULL) + { + textBounds.width = (float)GetTextWidth(text) + 2; + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING); + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GetMousePosition(); + + bool valueHasChanged = false; + + if (editMode) + { + state = STATE_PRESSED; + + int keyCount = (int)strlen(textValue); + + // Only allow keys in range [48..57] + if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) + { + if (GetTextWidth(textValue) < bounds.width) + { + int key = GetCharPressed(); + if (((key >= 48) && (key <= 57)) || + (key == '.') || + ((keyCount == 0) && (key == '+')) || // NOTE: Sign can only be in first position + ((keyCount == 0) && (key == '-'))) + { + textValue[keyCount] = (char)key; + keyCount++; + + valueHasChanged = true; + } + } + } + + // Pressed backspace + if (IsKeyPressed(KEY_BACKSPACE)) + { + if (keyCount > 0) + { + keyCount--; + textValue[keyCount] = '\0'; + valueHasChanged = true; + } + } + + if (valueHasChanged) *value = TextToFloat(textValue); + + if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) result = 1; + } + else + { + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1; + } + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + Color baseColor = BLANK; + if (state == STATE_PRESSED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED)); + else if (state == STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED)); + + GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), baseColor); + GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3)))); + + // Draw cursor + if (editMode) + { + // NOTE: ValueBox internal text is always centered + Rectangle cursor = {bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 1, + bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4, + bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH)}; + GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED))); + } + + // Draw text label if provided + GuiDrawText(text, textBounds, + (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, + GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + // Slider control with pro parameters // NOTE: Other GuiSlider*() controls use this one int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue, int sliderWidth) { int result = 0; - float oldValue = *value; GuiState state = guiState; float temp = (maxValue - minValue)/2.0f; if (value == NULL) value = &temp; - - int sliderValue = (int)(((*value - minValue)/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))); + float oldValue = *value; Rectangle slider = { bounds.x, bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING), 0, bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) }; - if (sliderWidth > 0) // Slider - { - slider.x += (sliderValue - sliderWidth/2); - slider.width = (float)sliderWidth; - } - else if (sliderWidth == 0) // SliderBar - { - slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH); - slider.width = (float)sliderValue; - } - // Update control //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked) { Vector2 mousePoint = GetMousePosition(); - if (guiSliderDragging) // Keep dragging outside of bounds + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds { if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { - if (CHECK_BOUNDS_ID(bounds, guiSliderActive)) + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) { state = STATE_PRESSED; - // Get equivalent value and slider position from mousePosition.x - *value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue; + *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width-sliderWidth)) + minValue; } } else { - guiSliderDragging = false; - guiSliderActive = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; } } else if (CheckCollisionPointRec(mousePoint, bounds)) @@ -2986,16 +3124,13 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { state = STATE_PRESSED; - guiSliderDragging = true; - guiSliderActive = bounds; // Store bounds as an identifier when dragging starts + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts if (!CheckCollisionPointRec(mousePoint, slider)) { // Get equivalent value and slider position from mousePosition.x - *value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue; - - if (sliderWidth > 0) slider.x = mousePoint.x - slider.width/2; // Slider - else if (sliderWidth == 0) slider.width = (float)sliderValue; // SliderBar + *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width-sliderWidth)) + minValue; } } else state = STATE_FOCUSED; @@ -3006,17 +3141,22 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, } // Control value change check - if(oldValue == *value) result = 0; + if (oldValue == *value) result = 0; else result = 1; - // Bar limits check + // Slider bar limits check + float sliderValue = (((*value - minValue)/(maxValue - minValue))*(bounds.width - sliderWidth - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))); if (sliderWidth > 0) // Slider { + slider.x += sliderValue; + slider.width = (float)sliderWidth; if (slider.x <= (bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH); else if ((slider.x + slider.width) >= (bounds.x + bounds.width)) slider.x = bounds.x + bounds.width - slider.width - GuiGetStyle(SLIDER, BORDER_WIDTH); } else if (sliderWidth == 0) // SliderBar { + slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH); + slider.width = sliderValue; if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH); } //-------------------------------------------------------------------- @@ -3171,7 +3311,7 @@ int GuiDummyRec(Rectangle bounds, const char *text) // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { Vector2 mousePoint = GetMousePosition(); @@ -3238,7 +3378,7 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { Vector2 mousePoint = GetMousePosition(); @@ -3291,6 +3431,8 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd // Draw visible items for (int i = 0; ((i < visibleItems) && (text != NULL)); i++) { + GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_NORMAL)), BLANK); + if (state == STATE_DISABLED) { if ((startIndex + i) == itemSelected) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED))); @@ -3353,83 +3495,32 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd return result; } -// Color Panel control +// Color Panel control - Color (RGBA) variant. int GuiColorPanel(Rectangle bounds, const char *text, Color *color) { int result = 0; - GuiState state = guiState; - Vector2 pickerSelector = { 0 }; - - const Color colWhite = { 255, 255, 255, 255 }; - const Color colBlack = { 0, 0, 0, 255 }; Vector3 vcolor = { (float)color->r/255.0f, (float)color->g/255.0f, (float)color->b/255.0f }; Vector3 hsv = ConvertRGBtoHSV(vcolor); + Vector3 prevHsv = hsv; // workaround to see if GuiColorPanelHSV modifies the hsv. - pickerSelector.x = bounds.x + (float)hsv.y*bounds.width; // HSV: Saturation - pickerSelector.y = bounds.y + (1.0f - (float)hsv.z)*bounds.height; // HSV: Value + GuiColorPanelHSV(bounds, text, &hsv); - Vector3 maxHue = { hsv.x, 1.0f, 1.0f }; - Vector3 rgbHue = ConvertHSVtoRGB(maxHue); - Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), - (unsigned char)(255.0f*rgbHue.y), - (unsigned char)(255.0f*rgbHue.z), 255 }; - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) + // Check if the hsv was changed, only then change the color. + // This is required, because the Color->HSV->Color conversion has precision errors. + // Thus the assignment from HSV to Color should only be made, if the HSV has a new user-entered value. + // Otherwise GuiColorPanel would often modify it's color without user input. + // TODO: GuiColorPanelHSV could return 1 if the slider was dragged, to simplify this check. + if (hsv.x != prevHsv.x || hsv.y != prevHsv.y || hsv.z != prevHsv.z) { - Vector2 mousePoint = GetMousePosition(); + Vector3 rgb = ConvertHSVtoRGB(hsv); - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) - { - state = STATE_PRESSED; - pickerSelector = mousePoint; - - // Calculate color from picker - Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; - - colorPick.x /= (float)bounds.width; // Get normalized value on x - colorPick.y /= (float)bounds.height; // Get normalized value on y - - hsv.y = colorPick.x; - hsv.z = 1.0f - colorPick.y; - - Vector3 rgb = ConvertHSVtoRGB(hsv); - - // NOTE: Vector3ToColor() only available on raylib 1.8.1 - *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), - (unsigned char)(255.0f*rgb.y), - (unsigned char)(255.0f*rgb.z), - (unsigned char)(255.0f*(float)color->a/255.0f) }; - - } - else state = STATE_FOCUSED; - } + // NOTE: Vector3ToColor() only available on raylib 1.8.1 + *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), + (unsigned char)(255.0f*rgb.y), + (unsigned char)(255.0f*rgb.z), + color->a }; } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - if (state != STATE_DISABLED) - { - DrawRectangleGradientEx(bounds, Fade(colWhite, guiAlpha), Fade(colWhite, guiAlpha), Fade(maxHueCol, guiAlpha), Fade(maxHueCol, guiAlpha)); - DrawRectangleGradientEx(bounds, Fade(colBlack, 0), Fade(colBlack, guiAlpha), Fade(colBlack, guiAlpha), Fade(colBlack, 0)); - - // Draw color picker: selector - Rectangle selector = { pickerSelector.x - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, pickerSelector.y - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE), (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE) }; - GuiDrawRectangle(selector, 0, BLANK, colWhite); - } - else - { - DrawRectangleGradientEx(bounds, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.6f), guiAlpha)); - } - - GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); - //-------------------------------------------------------------------- - return result; } @@ -3451,11 +3542,11 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) { Vector2 mousePoint = GetMousePosition(); - if (guiSliderDragging) // Keep dragging outside of bounds + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds { if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { - if (CHECK_BOUNDS_ID(bounds, guiSliderActive)) + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) { state = STATE_PRESSED; @@ -3466,8 +3557,8 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) } else { - guiSliderDragging = false; - guiSliderActive = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; } } else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) @@ -3475,8 +3566,8 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { state = STATE_PRESSED; - guiSliderDragging = true; - guiSliderActive = bounds; // Store bounds as an identifier when dragging starts + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts *alpha = (mousePoint.x - bounds.x)/bounds.width; if (*alpha <= 0.0f) *alpha = 0.0f; @@ -3537,11 +3628,11 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) { Vector2 mousePoint = GetMousePosition(); - if (guiSliderDragging) // Keep dragging outside of bounds + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds { if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { - if (CHECK_BOUNDS_ID(bounds, guiSliderActive)) + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) { state = STATE_PRESSED; @@ -3552,8 +3643,8 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) } else { - guiSliderDragging = false; - guiSliderActive = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; } } else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) @@ -3561,8 +3652,8 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { state = STATE_PRESSED; - guiSliderDragging = true; - guiSliderActive = bounds; // Store bounds as an identifier when dragging starts + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts *hue = (mousePoint.y - bounds.y)*360/bounds.height; if (*hue <= 0.0f) *hue = 0.0f; @@ -3615,6 +3706,7 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) // float GuiColorBarAlpha(Rectangle bounds, float alpha) // float GuiColorBarHue(Rectangle bounds, float value) // NOTE: bounds define GuiColorPanel() size +// NOTE: this picker converts RGB to HSV, which can cause the Hue control to jump. If you have this problem, consider using the HSV variant instead int GuiColorPicker(Rectangle bounds, const char *text, Color *color) { int result = 0; @@ -3627,6 +3719,7 @@ int GuiColorPicker(Rectangle bounds, const char *text, Color *color) Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) }; + // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used. Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ (*color).r/255.0f, (*color).g/255.0f, (*color).b/255.0f }); GuiColorBarHue(boundsHue, NULL, &hsv.x); @@ -3668,8 +3761,7 @@ int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) return result; } -// Color Panel control, returns HSV color value in *colorHsv. -// Used by GuiColorPickerHSV() +// Color Panel control - HSV variant int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) { int result = 0; @@ -3690,15 +3782,47 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) + if ((state != STATE_DISABLED) && !guiLocked) { Vector2 mousePoint = GetMousePosition(); - if (CheckCollisionPointRec(mousePoint, bounds)) + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + pickerSelector = mousePoint; + + if (pickerSelector.x < bounds.x) pickerSelector.x = bounds.x; + if (pickerSelector.x > bounds.x + bounds.width) pickerSelector.x = bounds.x + bounds.width; + if (pickerSelector.y < bounds.y) pickerSelector.y = bounds.y; + if (pickerSelector.y > bounds.y + bounds.height) pickerSelector.y = bounds.y + bounds.height; + + // Calculate color from picker + Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; + + colorPick.x /= (float)bounds.width; // Get normalized value on x + colorPick.y /= (float)bounds.height; // Get normalized value on y + + colorHsv->y = colorPick.x; + colorHsv->z = 1.0f - colorPick.y; + + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds)) { if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { state = STATE_PRESSED; + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; pickerSelector = mousePoint; // Calculate color from picker @@ -3760,9 +3884,9 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons int textWidth = GetTextWidth(message) + 2; Rectangle textBounds = { 0 }; - textBounds.x = bounds.x + bounds.width/2 - textWidth/2; + textBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING; textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + RAYGUI_MESSAGEBOX_BUTTON_PADDING; - textBounds.width = (float)textWidth; + textBounds.width = bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*2; textBounds.height = bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 3*RAYGUI_MESSAGEBOX_BUTTON_PADDING - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT; // Draw control @@ -3905,7 +4029,7 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { if (CheckCollisionPointRec(mousePoint, bounds)) { @@ -3925,14 +4049,14 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect // Draw vertical grid lines for (int i = 0; i < linesV; i++) { - Rectangle lineV = { bounds.x + spacing*i/subdivs, bounds.y, 1, bounds.height }; + Rectangle lineV = { bounds.x + spacing*i/subdivs, bounds.y, 1, bounds.height + 1 }; GuiDrawRectangle(lineV, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA)); } // Draw horizontal grid lines for (int i = 0; i < linesH; i++) { - Rectangle lineH = { bounds.x, bounds.y + spacing*i/subdivs, bounds.width, 1 }; + Rectangle lineH = { bounds.x, bounds.y + spacing*i/subdivs, bounds.width + 1, 1 }; GuiDrawRectangle(lineH, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA)); } } @@ -3954,7 +4078,6 @@ void GuiDisableTooltip(void) { guiTooltip = false; } // Set tooltip string void GuiSetTooltip(const char *tooltip) { guiTooltipPtr = tooltip; } - //---------------------------------------------------------------------------------- // Styles loading functions //---------------------------------------------------------------------------------- @@ -3967,6 +4090,7 @@ void GuiLoadStyle(const char *fileName) #define MAX_LINE_BUFFER_SIZE 256 bool tryBinary = false; + if (!guiStyleLoaded) GuiLoadStyleDefault(); // Try reading the files as text file first FILE *rgsFile = fopen(fileName, "rt"); @@ -4600,7 +4724,7 @@ static int GetTextWidth(const char *text) } } - if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE - ICON_TEXT_PADDING); + if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + ICON_TEXT_PADDING); } return (int)textSize.x; @@ -4773,6 +4897,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C // Get text position depending on alignment and iconId //--------------------------------------------------------------------------------- Vector2 textBoundsPosition = { textBounds.x, textBounds.y }; + float textBoundsWidthOffset = 0.0f; // NOTE: We get text size after icon has been processed // WARNING: GetTextWidth() also processes text icon to get width! -> Really needed? @@ -4798,6 +4923,8 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C default: break; } + if (textSizeX > textBounds.width && (lines[i] != NULL) && (lines[i][0] != '\0')) textBoundsPosition.x = textBounds.x; + switch (alignmentVertical) { // Only valid in case of wordWrap = 0; @@ -4820,7 +4947,8 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C { // NOTE: We consider icon height, probably different than text size GuiDrawIcon(iconId, (int)textBoundsPosition.x, (int)(textBounds.y + textBounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height)), guiIconScale, tint); - textBoundsPosition.x += (RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); + textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); + textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); } #endif // Get size in bytes of text, @@ -4829,9 +4957,15 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C for (int c = 0; (lines[i][c] != '\0') && (lines[i][c] != '\n') && (lines[i][c] != '\r'); c++, lineSize++){ } float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize; + int lastSpaceIndex = 0; + bool tempWrapCharMode = false; + int textOffsetY = 0; float textOffsetX = 0.0f; float glyphWidth = 0; + + int ellipsisWidth = GetTextWidth("..."); + bool textOverflow = false; for (int c = 0, codepointSize = 0; c < lineSize; c += codepointSize) { int codepoint = GetCodepointNext(&lines[i][c], &codepointSize); @@ -4839,36 +4973,51 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) // but we need to draw all of the bad bytes using the '?' symbol moving one byte - if (codepoint == 0x3f) codepointSize = 1; // TODO: Review not recognized codepoints size + if (codepoint == 0x3f) codepointSize = 1; // TODO: Review not recognized codepoints size - // Wrap mode text measuring to space to validate if it can be drawn or - // a new line is required + // Get glyph width to check if it goes out of bounds + if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor); + else glyphWidth = (float)guiFont.glyphs[index].advanceX*scaleFactor; + + // Wrap mode text measuring, to validate if + // it can be drawn or a new line is required if (wrapMode == TEXT_WRAP_CHAR) { - // Get glyph width to check if it goes out of bounds - if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor); - else glyphWidth = (float)guiFont.glyphs[index].advanceX*scaleFactor; - // Jump to next line if current character reach end of the box limits - if ((textOffsetX + glyphWidth) > textBounds.width) + if ((textOffsetX + glyphWidth) > textBounds.width - textBoundsWidthOffset) { textOffsetX = 0.0f; textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING); + + if (tempWrapCharMode) // Wrap at char level when too long words + { + wrapMode = TEXT_WRAP_WORD; + tempWrapCharMode = false; + } } } else if (wrapMode == TEXT_WRAP_WORD) { + if (codepoint == 32) lastSpaceIndex = c; + // Get width to next space in line int nextSpaceIndex = 0; float nextSpaceWidth = GetNextSpaceWidth(lines[i] + c, &nextSpaceIndex); - if ((textOffsetX + nextSpaceWidth) > textBounds.width) + int nextSpaceIndex2 = 0; + float nextWordSize = GetNextSpaceWidth(lines[i] + lastSpaceIndex + 1, &nextSpaceIndex2); + + if (nextWordSize > textBounds.width - textBoundsWidthOffset) + { + // Considering the case the next word is longer than bounds + tempWrapCharMode = true; + wrapMode = TEXT_WRAP_CHAR; + } + else if ((textOffsetX + nextSpaceWidth) > textBounds.width - textBoundsWidthOffset) { textOffsetX = 0.0f; textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING); } - - // TODO: Consider case: (nextSpaceWidth >= textBounds.width) } if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint @@ -4881,7 +5030,23 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C if (wrapMode == TEXT_WRAP_NONE) { // Draw only required text glyphs fitting the textBounds.width - if (textOffsetX <= (textBounds.width - glyphWidth)) + if (textSizeX > textBounds.width) + { + if (textOffsetX <= (textBounds.width - glyphWidth - textBoundsWidthOffset - ellipsisWidth)) + { + DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); + } + else if (!textOverflow) + { + textOverflow = true; + + for (int j = 0; j < ellipsisWidth; j += ellipsisWidth/3) + { + DrawTextCodepoint(guiFont, '.', RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX + j, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); + } + } + } + else { DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); } @@ -4937,7 +5102,7 @@ static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, // Draw tooltip using control bounds static void GuiTooltip(Rectangle controlRec) { - if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiSliderDragging) + if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiControlExclusiveMode) { Vector2 textSize = MeasureTextEx(GuiGetFont(), guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); @@ -5003,7 +5168,7 @@ static const char **GuiTextSplit(const char *text, char delimiter, int *count, i buffer[i] = '\0'; // Set an end of string at this point counter++; - if (counter == RAYGUI_TEXTSPLIT_MAX_ITEMS) break; + if (counter > RAYGUI_TEXTSPLIT_MAX_ITEMS) break; } } @@ -5163,8 +5328,11 @@ static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) if (value > maxValue) value = maxValue; if (value < minValue) value = minValue; - const int valueRange = maxValue - minValue; + int valueRange = maxValue - minValue; + if (valueRange <= 0) valueRange = 1; + int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); + if (sliderSize < 1) sliderSize = 1; // TODO: Consider a minimum slider size // Calculate rectangles for all of the components arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ @@ -5205,13 +5373,13 @@ static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) { Vector2 mousePoint = GetMousePosition(); - if (guiSliderDragging) // Keep dragging outside of bounds + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds { if (IsMouseButtonDown(MOUSE_LEFT_BUTTON) && !CheckCollisionPointRec(mousePoint, arrowUpLeft) && !CheckCollisionPointRec(mousePoint, arrowDownRight)) { - if (CHECK_BOUNDS_ID(bounds, guiSliderActive)) + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) { state = STATE_PRESSED; @@ -5221,8 +5389,8 @@ static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) } else { - guiSliderDragging = false; - guiSliderActive = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; } } else if (CheckCollisionPointRec(mousePoint, bounds)) @@ -5236,8 +5404,8 @@ static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) // Handle mouse button down if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { - guiSliderDragging = true; - guiSliderActive = bounds; // Store bounds as an identifier when dragging starts + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts // Check arrows click if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); @@ -5437,6 +5605,37 @@ static int TextToInteger(const char *text) return value*sign; } +// Get float value from text +// NOTE: This function replaces atof() [stdlib.h] +// WARNING: Only '.' character is understood as decimal point +static float TextToFloat(const char *text) +{ + float value = 0.0f; + float sign = 1.0f; + + if ((text[0] == '+') || (text[0] == '-')) + { + if (text[0] == '-') sign = -1.0f; + text++; + } + + int i = 0; + for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10.0f + (float)(text[i] - '0'); + + if (text[i++] != '.') value *= sign; + else + { + float divisor = 10.0f; + for (; ((text[i] >= '0') && (text[i] <= '9')); i++) + { + value += ((float)(text[i] - '0'))/divisor; + divisor = divisor*10.0f; + } + } + + return value; +} + // Encode codepoint into UTF-8 text (char array size returned as parameter) static const char *CodepointToUTF8(int codepoint, int *byteSize) { @@ -5490,21 +5689,21 @@ static int GetCodepointNext(const char *text, int *codepointSize) if (0xf0 == (0xf8 & ptr[0])) { // 4 byte UTF-8 codepoint - if(((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80) || ((ptr[3] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks + if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80) || ((ptr[3] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks codepoint = ((0x07 & ptr[0]) << 18) | ((0x3f & ptr[1]) << 12) | ((0x3f & ptr[2]) << 6) | (0x3f & ptr[3]); *codepointSize = 4; } else if (0xe0 == (0xf0 & ptr[0])) { // 3 byte UTF-8 codepoint */ - if(((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks + if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks codepoint = ((0x0f & ptr[0]) << 12) | ((0x3f & ptr[1]) << 6) | (0x3f & ptr[2]); *codepointSize = 3; } else if (0xc0 == (0xe0 & ptr[0])) { // 2 byte UTF-8 codepoint - if((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } //10xxxxxx checks + if ((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } //10xxxxxx checks codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]); *codepointSize = 2; } @@ -5515,9 +5714,8 @@ static int GetCodepointNext(const char *text, int *codepointSize) *codepointSize = 1; } - return codepoint; } #endif // RAYGUI_STANDALONE -#endif // RAYGUI_IMPLEMENTATION +#endif // RAYGUI_IMPLEMENTATION \ No newline at end of file diff --git a/examples/shapes/shapes_bouncing_ball.c b/examples/shapes/shapes_bouncing_ball.c index 7a3068163..df0c37c1c 100644 --- a/examples/shapes/shapes_bouncing_ball.c +++ b/examples/shapes/shapes_bouncing_ball.c @@ -62,7 +62,7 @@ int main(void) ClearBackground(RAYWHITE); DrawCircleV(ballPosition, (float)ballRadius, MAROON); - //DrawText("PRESS SPACE to PAUSE BALL MOVEMENT", 10, GetScreenHeight() - 25, 20, LIGHTGRAY); + DrawText("PRESS SPACE to PAUSE BALL MOVEMENT", 10, GetScreenHeight() - 25, 20, LIGHTGRAY); // On pause, we draw a blinking message if (pause && ((framesCounter/30)%2)) DrawText("PAUSED", 350, 200, 30, GRAY); diff --git a/examples/shapes/shapes_draw_circle_sector.c b/examples/shapes/shapes_draw_circle_sector.c index 30eaaf4bd..cb9ab859b 100644 --- a/examples/shapes/shapes_draw_circle_sector.c +++ b/examples/shapes/shapes_draw_circle_sector.c @@ -63,11 +63,11 @@ int main(void) // Draw GUI controls //------------------------------------------------------------------------------ - GuiSliderBar((Rectangle){ 600, 40, 120, 20}, "StartAngle", NULL, &startAngle, 0, 720); - GuiSliderBar((Rectangle){ 600, 70, 120, 20}, "EndAngle", NULL, &endAngle, 0, 720); + GuiSliderBar((Rectangle){ 600, 40, 120, 20}, "StartAngle", TextFormat("%.2f", startAngle), &startAngle, 0, 720); + GuiSliderBar((Rectangle){ 600, 70, 120, 20}, "EndAngle", TextFormat("%.2f", endAngle), &endAngle, 0, 720); - GuiSliderBar((Rectangle){ 600, 140, 120, 20}, "Radius", NULL, &outerRadius, 0, 200); - GuiSliderBar((Rectangle){ 600, 170, 120, 20}, "Segments", NULL, &segments, 0, 100); + GuiSliderBar((Rectangle){ 600, 140, 120, 20}, "Radius", TextFormat("%.2f", outerRadius), &outerRadius, 0, 200); + GuiSliderBar((Rectangle){ 600, 170, 120, 20}, "Segments", TextFormat("%.2f", segments), &segments, 0, 100); //------------------------------------------------------------------------------ minSegments = truncf(ceilf((endAngle - startAngle) / 90)); diff --git a/examples/shapes/shapes_draw_rectangle_rounded.c b/examples/shapes/shapes_draw_rectangle_rounded.c index 19280ed00..58991884c 100644 --- a/examples/shapes/shapes_draw_rectangle_rounded.c +++ b/examples/shapes/shapes_draw_rectangle_rounded.c @@ -66,11 +66,11 @@ int main(void) // Draw GUI controls //------------------------------------------------------------------------------ - GuiSliderBar((Rectangle){ 640, 40, 105, 20 }, "Width", NULL, &width, 0, (float)GetScreenWidth() - 300); - GuiSliderBar((Rectangle){ 640, 70, 105, 20 }, "Height", NULL, &height, 0, (float)GetScreenHeight() - 50); - GuiSliderBar((Rectangle){ 640, 140, 105, 20 }, "Roundness", NULL, &roundness, 0.0f, 1.0f); - GuiSliderBar((Rectangle){ 640, 170, 105, 20 }, "Thickness", NULL, &lineThick, 0, 20); - GuiSliderBar((Rectangle){ 640, 240, 105, 20}, "Segments", NULL, &segments, 0, 60); + GuiSliderBar((Rectangle){ 640, 40, 105, 20 }, "Width", TextFormat("%.2f", width), &width, 0, (float)GetScreenWidth() - 300); + GuiSliderBar((Rectangle){ 640, 70, 105, 20 }, "Height", TextFormat("%.2f", height), &height, 0, (float)GetScreenHeight() - 50); + GuiSliderBar((Rectangle){ 640, 140, 105, 20 }, "Roundness", TextFormat("%.2f", roundness), &roundness, 0.0f, 1.0f); + GuiSliderBar((Rectangle){ 640, 170, 105, 20 }, "Thickness", TextFormat("%.2f", lineThick), &lineThick, 0, 20); + GuiSliderBar((Rectangle){ 640, 240, 105, 20}, "Segments", TextFormat("%.2f", segments), &segments, 0, 60); GuiCheckBox((Rectangle){ 640, 320, 20, 20 }, "DrawRoundedRect", &drawRoundedRect); GuiCheckBox((Rectangle){ 640, 350, 20, 20 }, "DrawRoundedLines", &drawRoundedLines); diff --git a/examples/shapes/shapes_draw_ring.c b/examples/shapes/shapes_draw_ring.c index 60c95a4c0..8bccdf729 100644 --- a/examples/shapes/shapes_draw_ring.c +++ b/examples/shapes/shapes_draw_ring.c @@ -69,13 +69,13 @@ int main(void) // Draw GUI controls //------------------------------------------------------------------------------ - GuiSliderBar((Rectangle){ 600, 40, 120, 20 }, "StartAngle", NULL, &startAngle, -450, 450); - GuiSliderBar((Rectangle){ 600, 70, 120, 20 }, "EndAngle", NULL, &endAngle, -450, 450); + GuiSliderBar((Rectangle){ 600, 40, 120, 20 }, "StartAngle", TextFormat("%.2f", startAngle), &startAngle, -450, 450); + GuiSliderBar((Rectangle){ 600, 70, 120, 20 }, "EndAngle", TextFormat("%.2f", endAngle), &endAngle, -450, 450); - GuiSliderBar((Rectangle){ 600, 140, 120, 20 }, "InnerRadius", NULL, &innerRadius, 0, 100); - GuiSliderBar((Rectangle){ 600, 170, 120, 20 }, "OuterRadius", NULL, &outerRadius, 0, 200); + GuiSliderBar((Rectangle){ 600, 140, 120, 20 }, "InnerRadius", TextFormat("%.2f", innerRadius), &innerRadius, 0, 100); + GuiSliderBar((Rectangle){ 600, 170, 120, 20 }, "OuterRadius", TextFormat("%.2f", outerRadius), &outerRadius, 0, 200); - GuiSliderBar((Rectangle){ 600, 240, 120, 20 }, "Segments", NULL, &segments, 0, 100); + GuiSliderBar((Rectangle){ 600, 240, 120, 20 }, "Segments", TextFormat("%.2f", segments), &segments, 0, 100); GuiCheckBox((Rectangle){ 600, 320, 20, 20 }, "Draw Ring", &drawRing); GuiCheckBox((Rectangle){ 600, 350, 20, 20 }, "Draw RingLines", &drawRingLines); diff --git a/examples/shapes/shapes_lines_bezier.c b/examples/shapes/shapes_lines_bezier.c index eeb7aeed0..1293e16e4 100644 --- a/examples/shapes/shapes_lines_bezier.c +++ b/examples/shapes/shapes_lines_bezier.c @@ -69,8 +69,8 @@ int main(void) DrawLineBezier(startPoint, endPoint, 4.0f, BLUE); // Draw start-end spline circles with some details - DrawCircleV(startPoint, CheckCollisionPointCircle(mouse, startPoint, 10.0f)? 14 : 8, moveStartPoint? RED : BLUE); - DrawCircleV(endPoint, CheckCollisionPointCircle(mouse, endPoint, 10.0f)? 14 : 8, moveEndPoint? RED : BLUE); + DrawCircleV(startPoint, CheckCollisionPointCircle(mouse, startPoint, 10.0f)? 14.0f : 8.0f, moveStartPoint? RED : BLUE); + DrawCircleV(endPoint, CheckCollisionPointCircle(mouse, endPoint, 10.0f)? 14.0f : 8.0f, moveEndPoint? RED : BLUE); EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/examples/shapes/shapes_splines_drawing.c b/examples/shapes/shapes_splines_drawing.c index 8df5f09f4..536b558e1 100644 --- a/examples/shapes/shapes_splines_drawing.c +++ b/examples/shapes/shapes_splines_drawing.c @@ -56,6 +56,10 @@ int main(void) { 710.0f, 260.0f }, }; + // Array required for spline bezier-cubic, + // including control points interleaved with start-end segment points + Vector2 pointsInterleaved[3*(MAX_SPLINE_POINTS - 1) + 1] = { 0 }; + int pointCount = 5; int selectedPoint = -1; int focusedPoint = -1; @@ -63,7 +67,7 @@ int main(void) Vector2 *focusedControlPoint = NULL; // Cubic Bezier control points initialization - ControlPoint control[MAX_SPLINE_POINTS] = { 0 }; + ControlPoint control[MAX_SPLINE_POINTS-1] = { 0 }; for (int i = 0; i < pointCount - 1; i++) { control[i].start = (Vector2){ points[i].x + 50, points[i].y }; @@ -88,6 +92,9 @@ int main(void) if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON) && (pointCount < MAX_SPLINE_POINTS)) { points[pointCount] = GetMousePosition(); + int i = pointCount - 1; + control[i].start = (Vector2){ points[i].x + 50, points[i].y }; + control[i].end = (Vector2){ points[i + 1].x - 50, points[i + 1].y }; pointCount++; } @@ -114,7 +121,7 @@ int main(void) if ((splineTypeActive == SPLINE_BEZIER) && (focusedPoint == -1)) { // Spline control point focus and selection logic - for (int i = 0; i < pointCount; i++) + for (int i = 0; i < pointCount - 1; i++) { if (CheckCollisionPointCircle(GetMousePosition(), control[i].start, 6.0f)) { @@ -185,13 +192,32 @@ int main(void) } else if (splineTypeActive == SPLINE_BEZIER) { + // NOTE: Cubic-bezier spline requires the 2 control points of each segnment to be + // provided interleaved with the start and end point of every segment + for (int i = 0; i < (pointCount - 1); i++) + { + pointsInterleaved[3*i] = points[i]; + pointsInterleaved[3*i + 1] = control[i].start; + pointsInterleaved[3*i + 2] = control[i].end; + } + + pointsInterleaved[3*(pointCount - 1)] = points[pointCount - 1]; + // Draw spline: cubic-bezier (with control points) - for (int i = 0; i < pointCount - 1; i++) + DrawSplineBezierCubic(pointsInterleaved, 3*(pointCount - 1) + 1, splineThickness, RED); + + /* + for (int i = 0; i < 3*(pointCount - 1); i += 3) { // Drawing individual segments, not considering thickness connection compensation - DrawSplineSegmentBezierCubic(points[i], control[i].start, control[i].end, points[i + 1], splineThickness, RED); + DrawSplineSegmentBezierCubic(pointsInterleaved[i], pointsInterleaved[i + 1], pointsInterleaved[i + 2], pointsInterleaved[i + 3], splineThickness, MAROON); + } + */ - // Every cubic bezier point should have two control points + // Draw spline control points + for (int i = 0; i < pointCount - 1; i++) + { + // Every cubic bezier point have two control points DrawCircleV(control[i].start, 6, GOLD); DrawCircleV(control[i].end, 6, GOLD); if (focusedControlPoint == &control[i].start) DrawCircleV(control[i].start, 8, GREEN); @@ -216,7 +242,7 @@ int main(void) (splineTypeActive != SPLINE_BEZIER) && (i < pointCount - 1)) DrawLineV(points[i], points[i + 1], GRAY); - DrawText(TextFormat("[%.0f, %.0f]", points[i].x, points[i].y), points[i].x, points[i].y + 10, 10, BLACK); + DrawText(TextFormat("[%.0f, %.0f]", points[i].x, points[i].y), (int)points[i].x, (int)points[i].y + 10, 10, BLACK); } } @@ -244,4 +270,4 @@ int main(void) //-------------------------------------------------------------------------------------- return 0; -} \ No newline at end of file +} diff --git a/examples/text/text_input_box.c b/examples/text/text_input_box.c index eeb338f1f..c53057711 100644 --- a/examples/text/text_input_box.c +++ b/examples/text/text_input_box.c @@ -35,7 +35,7 @@ int main(void) int framesCounter = 0; - SetTargetFPS(10); // Set our game to run at 10 frames-per-second + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop diff --git a/examples/text/text_writing_anim.c b/examples/text/text_writing_anim.c index 1e7cd569f..8e2820fc9 100644 --- a/examples/text/text_writing_anim.c +++ b/examples/text/text_writing_anim.c @@ -52,7 +52,7 @@ int main(void) DrawText(TextSubtext(message, 0, framesCounter/10), 210, 160, 20, MAROON); DrawText("PRESS [ENTER] to RESTART!", 240, 260, 20, LIGHTGRAY); - DrawText("PRESS [SPACE] to SPEED UP!", 239, 300, 20, LIGHTGRAY); + DrawText("HOLD [SPACE] to SPEED UP!", 239, 300, 20, LIGHTGRAY); EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/examples/textures/textures_blend_modes.c b/examples/textures/textures_blend_modes.c index 660aa57a7..d97432cb2 100644 --- a/examples/textures/textures_blend_modes.c +++ b/examples/textures/textures_blend_modes.c @@ -43,6 +43,9 @@ int main(void) const int blendCountMax = 4; BlendMode blendMode = 0; + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //--------------------------------------------------------------------------------------- + // Main game loop while (!WindowShouldClose()) // Detect window close button or ESC key { diff --git a/examples/textures/textures_image_channel.c b/examples/textures/textures_image_channel.c new file mode 100644 index 000000000..39618c5f4 --- /dev/null +++ b/examples/textures/textures_image_channel.c @@ -0,0 +1,106 @@ +/******************************************************************************************* +* +* raylib [textures] example - Retrive image channel (mask) +* +* NOTE: Images are loaded in CPU memory (RAM); textures are loaded in GPU memory (VRAM) +* +* Example originally created with raylib 5.1-dev, last time updated with raylib 5.1-dev +* +* Example contributed by Bruno Cabral (github.com/brccabral) and reviewed by Ramon Santamaria (@raysan5) +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2024-2024 Bruno Cabral (github.com/brccabral) and Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [textures] example - extract channel from image"); + + Image fudesumiImage = LoadImage("resources/fudesumi.png"); + + Image imageAlpha = ImageFromChannel(fudesumiImage, 3); + ImageAlphaMask(&imageAlpha, imageAlpha); + + Image imageRed = ImageFromChannel(fudesumiImage, 0); + ImageAlphaMask(&imageRed, imageAlpha); + + Image imageGreen = ImageFromChannel(fudesumiImage, 1); + ImageAlphaMask(&imageGreen, imageAlpha); + + Image imageBlue = ImageFromChannel(fudesumiImage, 2); + ImageAlphaMask(&imageBlue, imageAlpha); + + Image backgroundImage = GenImageChecked(screenWidth, screenHeight, screenWidth/20, screenHeight/20, ORANGE, YELLOW); + + Texture2D fudesumiTexture = LoadTextureFromImage(fudesumiImage); + Texture2D textureAlpha = LoadTextureFromImage(imageAlpha); + Texture2D textureRed = LoadTextureFromImage(imageRed); + Texture2D textureGreen = LoadTextureFromImage(imageGreen); + Texture2D textureBlue = LoadTextureFromImage(imageBlue); + Texture2D backgroundTexture = LoadTextureFromImage(backgroundImage); + + UnloadImage(fudesumiImage); + UnloadImage(imageAlpha); + UnloadImage(imageRed); + UnloadImage(imageGreen); + UnloadImage(imageBlue); + UnloadImage(backgroundImage); + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + + Rectangle fudesumiRec = {0, 0, fudesumiImage.width, fudesumiImage.height}; + + Rectangle fudesumiPos = {50, 10, fudesumiImage.width*0.8f, fudesumiImage.height*0.8f}; + Rectangle redPos = { 410, 10, fudesumiPos.width / 2, fudesumiPos.height / 2 }; + Rectangle greenPos = { 600, 10, fudesumiPos.width / 2, fudesumiPos.height / 2 }; + Rectangle bluePos = { 410, 230, fudesumiPos.width / 2, fudesumiPos.height / 2 }; + Rectangle alphaPos = { 600, 230, fudesumiPos.width / 2, fudesumiPos.height / 2 }; + + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + DrawTexture(backgroundTexture, 0, 0, WHITE); + DrawTexturePro(fudesumiTexture, fudesumiRec, fudesumiPos, (Vector2) {0, 0}, 0, WHITE); + + DrawTexturePro(textureRed, fudesumiRec, redPos, (Vector2) {0, 0}, 0, RED); + DrawTexturePro(textureGreen, fudesumiRec, greenPos, (Vector2) {0, 0}, 0, GREEN); + DrawTexturePro(textureBlue, fudesumiRec, bluePos, (Vector2) {0, 0}, 0, BLUE); + DrawTexturePro(textureAlpha, fudesumiRec, alphaPos, (Vector2) {0, 0}, 0, WHITE); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadTexture(backgroundTexture); + UnloadTexture(fudesumiTexture); + UnloadTexture(textureRed); + UnloadTexture(textureGreen); + UnloadTexture(textureBlue); + UnloadTexture(textureAlpha); + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/textures/textures_image_channel.png b/examples/textures/textures_image_channel.png new file mode 100644 index 000000000..55e1d2eaa Binary files /dev/null and b/examples/textures/textures_image_channel.png differ diff --git a/examples/textures/textures_image_drawing.c b/examples/textures/textures_image_drawing.c index f49bc9e77..d0eee999d 100644 --- a/examples/textures/textures_image_drawing.c +++ b/examples/textures/textures_image_drawing.c @@ -47,7 +47,7 @@ int main(void) UnloadImage(cat); // Unload image from RAM - // Load custom font for frawing on image + // Load custom font for drawing on image Font font = LoadFont("resources/custom_jupiter_crash.png"); // Draw over image using custom font @@ -93,4 +93,4 @@ int main(void) //-------------------------------------------------------------------------------------- return 0; -} \ No newline at end of file +} diff --git a/examples/textures/textures_image_rotate.c b/examples/textures/textures_image_rotate.c index 51724e037..94c42034b 100644 --- a/examples/textures/textures_image_rotate.c +++ b/examples/textures/textures_image_rotate.c @@ -43,6 +43,8 @@ int main(void) textures[2] = LoadTextureFromImage(imageNeg90); int currentTexture = 0; + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //--------------------------------------------------------------------------------------- // Main game loop diff --git a/examples/textures/textures_logo_raylib.c b/examples/textures/textures_logo_raylib.c index f170dab48..35baa1223 100644 --- a/examples/textures/textures_logo_raylib.c +++ b/examples/textures/textures_logo_raylib.c @@ -27,6 +27,8 @@ int main(void) // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) Texture2D texture = LoadTexture("resources/raylib_logo.png"); // Texture loading + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //--------------------------------------------------------------------------------------- // Main game loop diff --git a/examples/textures/textures_raw_data.c b/examples/textures/textures_raw_data.c index 38229f1ba..6fb41b143 100644 --- a/examples/textures/textures_raw_data.c +++ b/examples/textures/textures_raw_data.c @@ -63,6 +63,8 @@ int main(void) Texture2D checked = LoadTextureFromImage(checkedIm); UnloadImage(checkedIm); // Unload CPU (RAM) image data (pixels) + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //--------------------------------------------------------------------------------------- // Main game loop diff --git a/examples/textures/textures_sprite_explosion.c b/examples/textures/textures_sprite_explosion.c index 06b4f1dad..a65426cb6 100644 --- a/examples/textures/textures_sprite_explosion.c +++ b/examples/textures/textures_sprite_explosion.c @@ -48,8 +48,8 @@ int main(void) bool active = false; int framesCounter = 0; - SetTargetFPS(120); - //-------------------------------------------------------------------------------------- + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //--------------------------------------------------------------------------------------- // Main game loop while (!WindowShouldClose()) // Detect window close button or ESC key diff --git a/examples/textures/textures_to_image.c b/examples/textures/textures_to_image.c index 2d09623eb..e1d88c4cd 100644 --- a/examples/textures/textures_to_image.c +++ b/examples/textures/textures_to_image.c @@ -38,6 +38,8 @@ int main(void) texture = LoadTextureFromImage(image); // Recreate texture from retrieved image data (RAM -> VRAM) UnloadImage(image); // Unload retrieved image data from CPU memory (RAM) + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //--------------------------------------------------------------------------------------- // Main game loop diff --git a/parser/README.md b/parser/README.md index 45a2689a0..6616cdc51 100644 --- a/parser/README.md +++ b/parser/README.md @@ -41,7 +41,7 @@ OPTIONS: -f, --format : Define output format for parser data. Supported types: DEFAULT, JSON, XML, LUA - -d, --define : Define functions specifiers (i.e. RLAPI for raylib.h, RMDEF for raymath.h, etc.) + -d, --define : Define functions specifiers (i.e. RLAPI for raylib.h, RMAPI for raymath.h, etc.) NOTE: If no specifier defined, defaults to: RLAPI -t, --truncate : Define string to truncate input after (i.e. "RLGL IMPLEMENTATION" for rlgl.h) @@ -56,7 +56,7 @@ EXAMPLES: > raylib_parser --output raylib_data.info --format XML Process to generate as XML text data - > raylib_parser --input raymath.h --output raymath_data.info --format XML + > raylib_parser --input raymath.h --output raymath_data.info --format XML --define RMAPI Process to generate as XML text data ``` diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index 1a38c03ab..58fb9d6a8 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -15,7 +15,7 @@ { "name": "RAYLIB_VERSION_MINOR", "type": "INT", - "value": 1, + "value": 5, "description": "" }, { @@ -27,7 +27,7 @@ { "name": "RAYLIB_VERSION", "type": "STRING", - "value": "5.1-dev", + "value": "5.5-dev", "description": "" }, { @@ -850,12 +850,22 @@ { "type": "unsigned char *", "name": "boneIds", - "description": "Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning)" + "description": "Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) (shader-location = 6)" }, { "type": "float *", "name": "boneWeights", - "description": "Vertex bone weight, up to 4 bones influence by vertex (skinning)" + "description": "Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7)" + }, + { + "type": "Matrix *", + "name": "boneMatrices", + "description": "Bones animated transformation matrices" + }, + { + "type": "int", + "name": "boneCount", + "description": "Number of bones" }, { "type": "unsigned int", @@ -1058,7 +1068,7 @@ { "type": "Vector3", "name": "direction", - "description": "Ray direction" + "description": "Ray direction (normalized)" } ] }, @@ -2518,6 +2528,21 @@ "name": "SHADER_LOC_MAP_BRDF", "value": 25, "description": "Shader location: sampler2d texture: brdf" + }, + { + "name": "SHADER_LOC_VERTEX_BONEIDS", + "value": 26, + "description": "Shader location: vertex attribute: boneIds" + }, + { + "name": "SHADER_LOC_VERTEX_BONEWEIGHTS", + "value": 27, + "description": "Shader location: vertex attribute: boneWeights" + }, + { + "name": "SHADER_LOC_BONE_MATRICES", + "value": 28, + "description": "Shader location: array of matrices uniform: boneMatrices" } ] }, @@ -3215,12 +3240,12 @@ }, { "name": "ToggleFullscreen", - "description": "Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP)", + "description": "Toggle window state: fullscreen/windowed [resizes monitor to match window resolution] (only PLATFORM_DESKTOP)", "returnType": "void" }, { "name": "ToggleBorderlessWindowed", - "description": "Toggle window state: borderless windowed (only PLATFORM_DESKTOP)", + "description": "Toggle window state: borderless windowed [resizes window to match monitor resolution] (only PLATFORM_DESKTOP)", "returnType": "void" }, { @@ -4477,6 +4502,17 @@ "description": "Get the directory of the running application (uses static string)", "returnType": "const char *" }, + { + "name": "MakeDirectory", + "description": "Create directories (including full path requested), returns 0 on success", + "returnType": "int", + "params": [ + { + "type": "const char *", + "name": "dirPath" + } + ] + }, { "name": "ChangeDirectory", "description": "Change working directory, return true on success", @@ -4523,7 +4559,7 @@ }, { "name": "LoadDirectoryFilesEx", - "description": "Load directory filepaths with extension filtering and recursive directory scan", + "description": "Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result", "returnType": "FilePathList", "params": [ { @@ -5238,7 +5274,7 @@ }, { "name": "DrawPixel", - "description": "Draw a pixel", + "description": "Draw a pixel using geometry [Can be slow, use with care]", "returnType": "void", "params": [ { @@ -5257,7 +5293,7 @@ }, { "name": "DrawPixelV", - "description": "Draw a pixel (Vector version)", + "description": "Draw a pixel using geometry (Vector version) [Can be slow, use with care]", "returnType": "void", "params": [ { @@ -5485,11 +5521,11 @@ }, { "type": "Color", - "name": "color1" + "name": "inner" }, { "type": "Color", - "name": "color2" + "name": "outer" } ] }, @@ -5785,11 +5821,11 @@ }, { "type": "Color", - "name": "color1" + "name": "top" }, { "type": "Color", - "name": "color2" + "name": "bottom" } ] }, @@ -5816,11 +5852,11 @@ }, { "type": "Color", - "name": "color1" + "name": "left" }, { "type": "Color", - "name": "color2" + "name": "right" } ] }, @@ -5835,19 +5871,19 @@ }, { "type": "Color", - "name": "col1" + "name": "topLeft" }, { "type": "Color", - "name": "col2" + "name": "bottomLeft" }, { "type": "Color", - "name": "col3" + "name": "topRight" }, { "type": "Color", - "name": "col4" + "name": "bottomRight" } ] }, @@ -7183,6 +7219,21 @@ } ] }, + { + "name": "ImageFromChannel", + "description": "Create an image from a selected channel of another image (GRAYSCALE)", + "returnType": "Image", + "params": [ + { + "type": "Image", + "name": "image" + }, + { + "type": "int", + "name": "selectedChannel" + } + ] + }, { "name": "ImageText", "description": "Create an image from text (default font)", @@ -7351,7 +7402,7 @@ }, { "name": "ImageKernelConvolution", - "description": "Apply Custom Square image convolution kernel", + "description": "Apply custom square convolution kernel to image", "returnType": "void", "params": [ { @@ -7359,7 +7410,7 @@ "name": "image" }, { - "type": "float*", + "type": "const float *", "name": "kernel" }, { @@ -7817,6 +7868,33 @@ } ] }, + { + "name": "ImageDrawLineEx", + "description": "Draw a line defining thickness within an image", + "returnType": "void", + "params": [ + { + "type": "Image *", + "name": "dst" + }, + { + "type": "Vector2", + "name": "start" + }, + { + "type": "Vector2", + "name": "end" + }, + { + "type": "int", + "name": "thick" + }, + { + "type": "Color", + "name": "color" + } + ] + }, { "name": "ImageDrawCircle", "description": "Draw a filled circle within an image", @@ -8013,6 +8091,141 @@ } ] }, + { + "name": "ImageDrawTriangle", + "description": "Draw triangle within an image", + "returnType": "void", + "params": [ + { + "type": "Image *", + "name": "dst" + }, + { + "type": "Vector2", + "name": "v1" + }, + { + "type": "Vector2", + "name": "v2" + }, + { + "type": "Vector2", + "name": "v3" + }, + { + "type": "Color", + "name": "color" + } + ] + }, + { + "name": "ImageDrawTriangleEx", + "description": "Draw triangle with interpolated colors within an image", + "returnType": "void", + "params": [ + { + "type": "Image *", + "name": "dst" + }, + { + "type": "Vector2", + "name": "v1" + }, + { + "type": "Vector2", + "name": "v2" + }, + { + "type": "Vector2", + "name": "v3" + }, + { + "type": "Color", + "name": "c1" + }, + { + "type": "Color", + "name": "c2" + }, + { + "type": "Color", + "name": "c3" + } + ] + }, + { + "name": "ImageDrawTriangleLines", + "description": "Draw triangle outline within an image", + "returnType": "void", + "params": [ + { + "type": "Image *", + "name": "dst" + }, + { + "type": "Vector2", + "name": "v1" + }, + { + "type": "Vector2", + "name": "v2" + }, + { + "type": "Vector2", + "name": "v3" + }, + { + "type": "Color", + "name": "color" + } + ] + }, + { + "name": "ImageDrawTriangleFan", + "description": "Draw a triangle fan defined by points within an image (first vertex is the center)", + "returnType": "void", + "params": [ + { + "type": "Image *", + "name": "dst" + }, + { + "type": "Vector2 *", + "name": "points" + }, + { + "type": "int", + "name": "pointCount" + }, + { + "type": "Color", + "name": "color" + } + ] + }, + { + "name": "ImageDrawTriangleStrip", + "description": "Draw a triangle strip defined by points within an image", + "returnType": "void", + "params": [ + { + "type": "Image *", + "name": "dst" + }, + { + "type": "Vector2 *", + "name": "points" + }, + { + "type": "int", + "name": "pointCount" + }, + { + "type": "Color", + "name": "color" + } + ] + }, { "name": "ImageDraw", "description": "Draw a source image within a destination image (tint applied to source)", @@ -8603,6 +8816,25 @@ } ] }, + { + "name": "ColorLerp", + "description": "Get color lerp interpolation between two colors, factor [0.0f..1.0f]", + "returnType": "Color", + "params": [ + { + "type": "Color", + "name": "color1" + }, + { + "type": "Color", + "name": "color2" + }, + { + "type": "float", + "name": "factor" + } + ] + }, { "name": "GetColor", "description": "Get Color structure from hexadecimal value", @@ -8685,7 +8917,7 @@ }, { "name": "LoadFontEx", - "description": "Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character setFont", + "description": "Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height", "returnType": "Font", "params": [ { @@ -10189,6 +10421,60 @@ } ] }, + { + "name": "DrawModelPoints", + "description": "Draw a model as points", + "returnType": "void", + "params": [ + { + "type": "Model", + "name": "model" + }, + { + "type": "Vector3", + "name": "position" + }, + { + "type": "float", + "name": "scale" + }, + { + "type": "Color", + "name": "tint" + } + ] + }, + { + "name": "DrawModelPointsEx", + "description": "Draw a model as points with extended parameters", + "returnType": "void", + "params": [ + { + "type": "Model", + "name": "model" + }, + { + "type": "Vector3", + "name": "position" + }, + { + "type": "Vector3", + "name": "rotationAxis" + }, + { + "type": "float", + "name": "rotationAngle" + }, + { + "type": "Vector3", + "name": "scale" + }, + { + "type": "Color", + "name": "tint" + } + ] + }, { "name": "DrawBoundingBox", "description": "Draw bounding box (wires)", @@ -10223,7 +10509,7 @@ }, { "type": "float", - "name": "size" + "name": "scale" }, { "type": "Color", @@ -10816,6 +11102,25 @@ } ] }, + { + "name": "UpdateModelAnimationBoneMatrices", + "description": "Update model animation mesh bone matrices (Note GPU skinning does not work on Mac)", + "returnType": "void", + "params": [ + { + "type": "Model", + "name": "model" + }, + { + "type": "ModelAnimation", + "name": "anim" + }, + { + "type": "int", + "name": "frame" + } + ] + }, { "name": "CheckCollisionSpheres", "description": "Check collision between two spheres", diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index 3dec7f371..bea3813cf 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -15,7 +15,7 @@ return { { name = "RAYLIB_VERSION_MINOR", type = "INT", - value = 1, + value = 5, description = "" }, { @@ -27,7 +27,7 @@ return { { name = "RAYLIB_VERSION", type = "STRING", - value = "5.1-dev", + value = "5.5-dev", description = "" }, { @@ -850,12 +850,22 @@ return { { type = "unsigned char *", name = "boneIds", - description = "Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning)" + description = "Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) (shader-location = 6)" }, { type = "float *", name = "boneWeights", - description = "Vertex bone weight, up to 4 bones influence by vertex (skinning)" + description = "Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7)" + }, + { + type = "Matrix *", + name = "boneMatrices", + description = "Bones animated transformation matrices" + }, + { + type = "int", + name = "boneCount", + description = "Number of bones" }, { type = "unsigned int", @@ -1058,7 +1068,7 @@ return { { type = "Vector3", name = "direction", - description = "Ray direction" + description = "Ray direction (normalized)" } } }, @@ -2518,6 +2528,21 @@ return { name = "SHADER_LOC_MAP_BRDF", value = 25, description = "Shader location: sampler2d texture: brdf" + }, + { + name = "SHADER_LOC_VERTEX_BONEIDS", + value = 26, + description = "Shader location: vertex attribute: boneIds" + }, + { + name = "SHADER_LOC_VERTEX_BONEWEIGHTS", + value = 27, + description = "Shader location: vertex attribute: boneWeights" + }, + { + name = "SHADER_LOC_BONE_MATRICES", + value = 28, + description = "Shader location: array of matrices uniform: boneMatrices" } } }, @@ -3158,12 +3183,12 @@ return { }, { name = "ToggleFullscreen", - description = "Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP)", + description = "Toggle window state: fullscreen/windowed [resizes monitor to match window resolution] (only PLATFORM_DESKTOP)", returnType = "void" }, { name = "ToggleBorderlessWindowed", - description = "Toggle window state: borderless windowed (only PLATFORM_DESKTOP)", + description = "Toggle window state: borderless windowed [resizes window to match monitor resolution] (only PLATFORM_DESKTOP)", returnType = "void" }, { @@ -4042,6 +4067,14 @@ return { description = "Get the directory of the running application (uses static string)", returnType = "const char *" }, + { + name = "MakeDirectory", + description = "Create directories (including full path requested), returns 0 on success", + returnType = "int", + params = { + {type = "const char *", name = "dirPath"} + } + }, { name = "ChangeDirectory", description = "Change working directory, return true on success", @@ -4076,7 +4109,7 @@ return { }, { name = "LoadDirectoryFilesEx", - description = "Load directory filepaths with extension filtering and recursive directory scan", + description = "Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result", returnType = "FilePathList", params = { {type = "const char *", name = "basePath"}, @@ -4581,7 +4614,7 @@ return { }, { name = "DrawPixel", - description = "Draw a pixel", + description = "Draw a pixel using geometry [Can be slow, use with care]", returnType = "void", params = { {type = "int", name = "posX"}, @@ -4591,7 +4624,7 @@ return { }, { name = "DrawPixelV", - description = "Draw a pixel (Vector version)", + description = "Draw a pixel using geometry (Vector version) [Can be slow, use with care]", returnType = "void", params = { {type = "Vector2", name = "position"}, @@ -4697,8 +4730,8 @@ return { {type = "int", name = "centerX"}, {type = "int", name = "centerY"}, {type = "float", name = "radius"}, - {type = "Color", name = "color1"}, - {type = "Color", name = "color2"} + {type = "Color", name = "inner"}, + {type = "Color", name = "outer"} } }, { @@ -4835,8 +4868,8 @@ return { {type = "int", name = "posY"}, {type = "int", name = "width"}, {type = "int", name = "height"}, - {type = "Color", name = "color1"}, - {type = "Color", name = "color2"} + {type = "Color", name = "top"}, + {type = "Color", name = "bottom"} } }, { @@ -4848,8 +4881,8 @@ return { {type = "int", name = "posY"}, {type = "int", name = "width"}, {type = "int", name = "height"}, - {type = "Color", name = "color1"}, - {type = "Color", name = "color2"} + {type = "Color", name = "left"}, + {type = "Color", name = "right"} } }, { @@ -4858,10 +4891,10 @@ return { returnType = "void", params = { {type = "Rectangle", name = "rec"}, - {type = "Color", name = "col1"}, - {type = "Color", name = "col2"}, - {type = "Color", name = "col3"}, - {type = "Color", name = "col4"} + {type = "Color", name = "topLeft"}, + {type = "Color", name = "bottomLeft"}, + {type = "Color", name = "topRight"}, + {type = "Color", name = "bottomRight"} } }, { @@ -5521,6 +5554,15 @@ return { {type = "Rectangle", name = "rec"} } }, + { + name = "ImageFromChannel", + description = "Create an image from a selected channel of another image (GRAYSCALE)", + returnType = "Image", + params = { + {type = "Image", name = "image"}, + {type = "int", name = "selectedChannel"} + } + }, { name = "ImageText", description = "Create an image from text (default font)", @@ -5617,11 +5659,11 @@ return { }, { name = "ImageKernelConvolution", - description = "Apply Custom Square image convolution kernel", + description = "Apply custom square convolution kernel to image", returnType = "void", params = { {type = "Image *", name = "image"}, - {type = "float*", name = "kernel"}, + {type = "const float *", name = "kernel"}, {type = "int", name = "kernelSize"} } }, @@ -5879,6 +5921,18 @@ return { {type = "Color", name = "color"} } }, + { + name = "ImageDrawLineEx", + description = "Draw a line defining thickness within an image", + returnType = "void", + params = { + {type = "Image *", name = "dst"}, + {type = "Vector2", name = "start"}, + {type = "Vector2", name = "end"}, + {type = "int", name = "thick"}, + {type = "Color", name = "color"} + } + }, { name = "ImageDrawCircle", description = "Draw a filled circle within an image", @@ -5970,6 +6024,66 @@ return { {type = "Color", name = "color"} } }, + { + name = "ImageDrawTriangle", + description = "Draw triangle within an image", + returnType = "void", + params = { + {type = "Image *", name = "dst"}, + {type = "Vector2", name = "v1"}, + {type = "Vector2", name = "v2"}, + {type = "Vector2", name = "v3"}, + {type = "Color", name = "color"} + } + }, + { + name = "ImageDrawTriangleEx", + description = "Draw triangle with interpolated colors within an image", + returnType = "void", + params = { + {type = "Image *", name = "dst"}, + {type = "Vector2", name = "v1"}, + {type = "Vector2", name = "v2"}, + {type = "Vector2", name = "v3"}, + {type = "Color", name = "c1"}, + {type = "Color", name = "c2"}, + {type = "Color", name = "c3"} + } + }, + { + name = "ImageDrawTriangleLines", + description = "Draw triangle outline within an image", + returnType = "void", + params = { + {type = "Image *", name = "dst"}, + {type = "Vector2", name = "v1"}, + {type = "Vector2", name = "v2"}, + {type = "Vector2", name = "v3"}, + {type = "Color", name = "color"} + } + }, + { + name = "ImageDrawTriangleFan", + description = "Draw a triangle fan defined by points within an image (first vertex is the center)", + returnType = "void", + params = { + {type = "Image *", name = "dst"}, + {type = "Vector2 *", name = "points"}, + {type = "int", name = "pointCount"}, + {type = "Color", name = "color"} + } + }, + { + name = "ImageDrawTriangleStrip", + description = "Draw a triangle strip defined by points within an image", + returnType = "void", + params = { + {type = "Image *", name = "dst"}, + {type = "Vector2 *", name = "points"}, + {type = "int", name = "pointCount"}, + {type = "Color", name = "color"} + } + }, { name = "ImageDraw", description = "Draw a source image within a destination image (tint applied to source)", @@ -6296,6 +6410,16 @@ return { {type = "Color", name = "tint"} } }, + { + name = "ColorLerp", + description = "Get color lerp interpolation between two colors, factor [0.0f..1.0f]", + returnType = "Color", + params = { + {type = "Color", name = "color1"}, + {type = "Color", name = "color2"}, + {type = "float", name = "factor"} + } + }, { name = "GetColor", description = "Get Color structure from hexadecimal value", @@ -6348,7 +6472,7 @@ return { }, { name = "LoadFontEx", - description = "Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character setFont", + description = "Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height", returnType = "Font", params = { {type = "const char *", name = "fileName"}, @@ -7132,6 +7256,30 @@ return { {type = "Color", name = "tint"} } }, + { + name = "DrawModelPoints", + description = "Draw a model as points", + returnType = "void", + params = { + {type = "Model", name = "model"}, + {type = "Vector3", name = "position"}, + {type = "float", name = "scale"}, + {type = "Color", name = "tint"} + } + }, + { + name = "DrawModelPointsEx", + description = "Draw a model as points with extended parameters", + returnType = "void", + params = { + {type = "Model", name = "model"}, + {type = "Vector3", name = "position"}, + {type = "Vector3", name = "rotationAxis"}, + {type = "float", name = "rotationAngle"}, + {type = "Vector3", name = "scale"}, + {type = "Color", name = "tint"} + } + }, { name = "DrawBoundingBox", description = "Draw bounding box (wires)", @@ -7149,7 +7297,7 @@ return { {type = "Camera", name = "camera"}, {type = "Texture2D", name = "texture"}, {type = "Vector3", name = "position"}, - {type = "float", name = "size"}, + {type = "float", name = "scale"}, {type = "Color", name = "tint"} } }, @@ -7471,6 +7619,16 @@ return { {type = "ModelAnimation", name = "anim"} } }, + { + name = "UpdateModelAnimationBoneMatrices", + description = "Update model animation mesh bone matrices (Note GPU skinning does not work on Mac)", + returnType = "void", + params = { + {type = "Model", name = "model"}, + {type = "ModelAnimation", name = "anim"}, + {type = "int", name = "frame"} + } + }, { name = "CheckCollisionSpheres", description = "Check collision between two spheres", diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index 2a33a995f..9a953b768 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -14,7 +14,7 @@ Define 002: RAYLIB_VERSION_MAJOR Define 003: RAYLIB_VERSION_MINOR Name: RAYLIB_VERSION_MINOR Type: INT - Value: 1 + Value: 5 Description: Define 004: RAYLIB_VERSION_PATCH Name: RAYLIB_VERSION_PATCH @@ -24,7 +24,7 @@ Define 004: RAYLIB_VERSION_PATCH Define 005: RAYLIB_VERSION Name: RAYLIB_VERSION Type: STRING - Value: "5.1-dev" + Value: "5.5-dev" Description: Define 006: __declspec(x) Name: __declspec(x) @@ -403,7 +403,7 @@ Struct 14: Camera2D (4 fields) Field[2]: Vector2 target // Camera target (rotation and zoom origin) Field[3]: float rotation // Camera rotation in degrees Field[4]: float zoom // Camera zoom (scaling), should be 1.0f by default -Struct 15: Mesh (15 fields) +Struct 15: Mesh (17 fields) Name: Mesh Description: Mesh, vertex data and vao/vbo Field[1]: int vertexCount // Number of vertices stored in arrays @@ -417,10 +417,12 @@ Struct 15: Mesh (15 fields) Field[9]: unsigned short * indices // Vertex indices (in case vertex data comes indexed) Field[10]: float * animVertices // Animated vertex positions (after bones transformations) Field[11]: float * animNormals // Animated normals (after bones transformations) - Field[12]: unsigned char * boneIds // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) - Field[13]: float * boneWeights // Vertex bone weight, up to 4 bones influence by vertex (skinning) - Field[14]: unsigned int vaoId // OpenGL Vertex Array Object id - Field[15]: unsigned int * vboId // OpenGL Vertex Buffer Objects id (default vertex data) + Field[12]: unsigned char * boneIds // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) (shader-location = 6) + Field[13]: float * boneWeights // Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7) + Field[14]: Matrix * boneMatrices // Bones animated transformation matrices + Field[15]: int boneCount // Number of bones + Field[16]: unsigned int vaoId // OpenGL Vertex Array Object id + Field[17]: unsigned int * vboId // OpenGL Vertex Buffer Objects id (default vertex data) Struct 16: Shader (2 fields) Name: Shader Description: Shader @@ -473,7 +475,7 @@ Struct 23: Ray (2 fields) Name: Ray Description: Ray, ray for raycasting Field[1]: Vector3 position // Ray position (origin) - Field[2]: Vector3 direction // Ray direction + Field[2]: Vector3 direction // Ray direction (normalized) Struct 24: RayCollision (4 fields) Name: RayCollision Description: RayCollision, ray hit information @@ -793,7 +795,7 @@ Enum 08: MaterialMapIndex (11 values) Value[MATERIAL_MAP_IRRADIANCE]: 8 Value[MATERIAL_MAP_PREFILTER]: 9 Value[MATERIAL_MAP_BRDF]: 10 -Enum 09: ShaderLocationIndex (26 values) +Enum 09: ShaderLocationIndex (29 values) Name: ShaderLocationIndex Description: Shader location index Value[SHADER_LOC_VERTEX_POSITION]: 0 @@ -822,6 +824,9 @@ Enum 09: ShaderLocationIndex (26 values) Value[SHADER_LOC_MAP_IRRADIANCE]: 23 Value[SHADER_LOC_MAP_PREFILTER]: 24 Value[SHADER_LOC_MAP_BRDF]: 25 + Value[SHADER_LOC_VERTEX_BONEIDS]: 26 + Value[SHADER_LOC_VERTEX_BONEWEIGHTS]: 27 + Value[SHADER_LOC_BONE_MATRICES]: 28 Enum 10: ShaderUniformDataType (9 values) Name: ShaderUniformDataType Description: Shader uniform data type @@ -984,7 +989,7 @@ Callback 006: AudioCallback() (2 input parameters) Param[1]: bufferData (type: void *) Param[2]: frames (type: unsigned int) -Functions found: 566 +Functions found: 578 Function 001: InitWindow() (3 input parameters) Name: InitWindow @@ -1056,12 +1061,12 @@ Function 013: ClearWindowState() (1 input parameters) Function 014: ToggleFullscreen() (0 input parameters) Name: ToggleFullscreen Return type: void - Description: Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP) + Description: Toggle window state: fullscreen/windowed [resizes monitor to match window resolution] (only PLATFORM_DESKTOP) No input parameters Function 015: ToggleBorderlessWindowed() (0 input parameters) Name: ToggleBorderlessWindowed Return type: void - Description: Toggle window state: borderless windowed (only PLATFORM_DESKTOP) + Description: Toggle window state: borderless windowed [resizes window to match monitor resolution] (only PLATFORM_DESKTOP) No input parameters Function 016: MaximizeWindow() (0 input parameters) Name: MaximizeWindow @@ -1699,373 +1704,378 @@ Function 133: GetApplicationDirectory() (0 input parameters) Return type: const char * Description: Get the directory of the running application (uses static string) No input parameters -Function 134: ChangeDirectory() (1 input parameters) +Function 134: MakeDirectory() (1 input parameters) + Name: MakeDirectory + Return type: int + Description: Create directories (including full path requested), returns 0 on success + Param[1]: dirPath (type: const char *) +Function 135: ChangeDirectory() (1 input parameters) Name: ChangeDirectory Return type: bool Description: Change working directory, return true on success Param[1]: dir (type: const char *) -Function 135: IsPathFile() (1 input parameters) +Function 136: IsPathFile() (1 input parameters) Name: IsPathFile Return type: bool Description: Check if a given path is a file or a directory Param[1]: path (type: const char *) -Function 136: IsFileNameValid() (1 input parameters) +Function 137: IsFileNameValid() (1 input parameters) Name: IsFileNameValid Return type: bool Description: Check if fileName is valid for the platform/OS Param[1]: fileName (type: const char *) -Function 137: LoadDirectoryFiles() (1 input parameters) +Function 138: LoadDirectoryFiles() (1 input parameters) Name: LoadDirectoryFiles Return type: FilePathList Description: Load directory filepaths Param[1]: dirPath (type: const char *) -Function 138: LoadDirectoryFilesEx() (3 input parameters) +Function 139: LoadDirectoryFilesEx() (3 input parameters) Name: LoadDirectoryFilesEx Return type: FilePathList - Description: Load directory filepaths with extension filtering and recursive directory scan + Description: Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result Param[1]: basePath (type: const char *) Param[2]: filter (type: const char *) Param[3]: scanSubdirs (type: bool) -Function 139: UnloadDirectoryFiles() (1 input parameters) +Function 140: UnloadDirectoryFiles() (1 input parameters) Name: UnloadDirectoryFiles Return type: void Description: Unload filepaths Param[1]: files (type: FilePathList) -Function 140: IsFileDropped() (0 input parameters) +Function 141: IsFileDropped() (0 input parameters) Name: IsFileDropped Return type: bool Description: Check if a file has been dropped into window No input parameters -Function 141: LoadDroppedFiles() (0 input parameters) +Function 142: LoadDroppedFiles() (0 input parameters) Name: LoadDroppedFiles Return type: FilePathList Description: Load dropped filepaths No input parameters -Function 142: UnloadDroppedFiles() (1 input parameters) +Function 143: UnloadDroppedFiles() (1 input parameters) Name: UnloadDroppedFiles Return type: void Description: Unload dropped filepaths Param[1]: files (type: FilePathList) -Function 143: GetFileModTime() (1 input parameters) +Function 144: GetFileModTime() (1 input parameters) Name: GetFileModTime Return type: long Description: Get file modification time (last write time) Param[1]: fileName (type: const char *) -Function 144: CompressData() (3 input parameters) +Function 145: CompressData() (3 input parameters) Name: CompressData Return type: unsigned char * Description: Compress data (DEFLATE algorithm), memory must be MemFree() Param[1]: data (type: const unsigned char *) Param[2]: dataSize (type: int) Param[3]: compDataSize (type: int *) -Function 145: DecompressData() (3 input parameters) +Function 146: DecompressData() (3 input parameters) Name: DecompressData Return type: unsigned char * Description: Decompress data (DEFLATE algorithm), memory must be MemFree() Param[1]: compData (type: const unsigned char *) Param[2]: compDataSize (type: int) Param[3]: dataSize (type: int *) -Function 146: EncodeDataBase64() (3 input parameters) +Function 147: EncodeDataBase64() (3 input parameters) Name: EncodeDataBase64 Return type: char * Description: Encode data to Base64 string, memory must be MemFree() Param[1]: data (type: const unsigned char *) Param[2]: dataSize (type: int) Param[3]: outputSize (type: int *) -Function 147: DecodeDataBase64() (2 input parameters) +Function 148: DecodeDataBase64() (2 input parameters) Name: DecodeDataBase64 Return type: unsigned char * Description: Decode Base64 string data, memory must be MemFree() Param[1]: data (type: const unsigned char *) Param[2]: outputSize (type: int *) -Function 148: LoadAutomationEventList() (1 input parameters) +Function 149: LoadAutomationEventList() (1 input parameters) Name: LoadAutomationEventList Return type: AutomationEventList Description: Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS Param[1]: fileName (type: const char *) -Function 149: UnloadAutomationEventList() (1 input parameters) +Function 150: UnloadAutomationEventList() (1 input parameters) Name: UnloadAutomationEventList Return type: void Description: Unload automation events list from file Param[1]: list (type: AutomationEventList) -Function 150: ExportAutomationEventList() (2 input parameters) +Function 151: ExportAutomationEventList() (2 input parameters) Name: ExportAutomationEventList Return type: bool Description: Export automation events list as text file Param[1]: list (type: AutomationEventList) Param[2]: fileName (type: const char *) -Function 151: SetAutomationEventList() (1 input parameters) +Function 152: SetAutomationEventList() (1 input parameters) Name: SetAutomationEventList Return type: void Description: Set automation event list to record to Param[1]: list (type: AutomationEventList *) -Function 152: SetAutomationEventBaseFrame() (1 input parameters) +Function 153: SetAutomationEventBaseFrame() (1 input parameters) Name: SetAutomationEventBaseFrame Return type: void Description: Set automation event internal base frame to start recording Param[1]: frame (type: int) -Function 153: StartAutomationEventRecording() (0 input parameters) +Function 154: StartAutomationEventRecording() (0 input parameters) Name: StartAutomationEventRecording Return type: void Description: Start recording automation events (AutomationEventList must be set) No input parameters -Function 154: StopAutomationEventRecording() (0 input parameters) +Function 155: StopAutomationEventRecording() (0 input parameters) Name: StopAutomationEventRecording Return type: void Description: Stop recording automation events No input parameters -Function 155: PlayAutomationEvent() (1 input parameters) +Function 156: PlayAutomationEvent() (1 input parameters) Name: PlayAutomationEvent Return type: void Description: Play a recorded automation event Param[1]: event (type: AutomationEvent) -Function 156: IsKeyPressed() (1 input parameters) +Function 157: IsKeyPressed() (1 input parameters) Name: IsKeyPressed Return type: bool Description: Check if a key has been pressed once Param[1]: key (type: int) -Function 157: IsKeyPressedRepeat() (1 input parameters) +Function 158: IsKeyPressedRepeat() (1 input parameters) Name: IsKeyPressedRepeat Return type: bool Description: Check if a key has been pressed again (Only PLATFORM_DESKTOP) Param[1]: key (type: int) -Function 158: IsKeyDown() (1 input parameters) +Function 159: IsKeyDown() (1 input parameters) Name: IsKeyDown Return type: bool Description: Check if a key is being pressed Param[1]: key (type: int) -Function 159: IsKeyReleased() (1 input parameters) +Function 160: IsKeyReleased() (1 input parameters) Name: IsKeyReleased Return type: bool Description: Check if a key has been released once Param[1]: key (type: int) -Function 160: IsKeyUp() (1 input parameters) +Function 161: IsKeyUp() (1 input parameters) Name: IsKeyUp Return type: bool Description: Check if a key is NOT being pressed Param[1]: key (type: int) -Function 161: GetKeyPressed() (0 input parameters) +Function 162: GetKeyPressed() (0 input parameters) Name: GetKeyPressed Return type: int Description: Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty No input parameters -Function 162: GetCharPressed() (0 input parameters) +Function 163: GetCharPressed() (0 input parameters) Name: GetCharPressed Return type: int Description: Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty No input parameters -Function 163: SetExitKey() (1 input parameters) +Function 164: SetExitKey() (1 input parameters) Name: SetExitKey Return type: void Description: Set a custom key to exit program (default is ESC) Param[1]: key (type: int) -Function 164: IsGamepadAvailable() (1 input parameters) +Function 165: IsGamepadAvailable() (1 input parameters) Name: IsGamepadAvailable Return type: bool Description: Check if a gamepad is available Param[1]: gamepad (type: int) -Function 165: GetGamepadName() (1 input parameters) +Function 166: GetGamepadName() (1 input parameters) Name: GetGamepadName Return type: const char * Description: Get gamepad internal name id Param[1]: gamepad (type: int) -Function 166: IsGamepadButtonPressed() (2 input parameters) +Function 167: IsGamepadButtonPressed() (2 input parameters) Name: IsGamepadButtonPressed Return type: bool Description: Check if a gamepad button has been pressed once Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 167: IsGamepadButtonDown() (2 input parameters) +Function 168: IsGamepadButtonDown() (2 input parameters) Name: IsGamepadButtonDown Return type: bool Description: Check if a gamepad button is being pressed Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 168: IsGamepadButtonReleased() (2 input parameters) +Function 169: IsGamepadButtonReleased() (2 input parameters) Name: IsGamepadButtonReleased Return type: bool Description: Check if a gamepad button has been released once Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 169: IsGamepadButtonUp() (2 input parameters) +Function 170: IsGamepadButtonUp() (2 input parameters) Name: IsGamepadButtonUp Return type: bool Description: Check if a gamepad button is NOT being pressed Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 170: GetGamepadButtonPressed() (0 input parameters) +Function 171: GetGamepadButtonPressed() (0 input parameters) Name: GetGamepadButtonPressed Return type: int Description: Get the last gamepad button pressed No input parameters -Function 171: GetGamepadAxisCount() (1 input parameters) +Function 172: GetGamepadAxisCount() (1 input parameters) Name: GetGamepadAxisCount Return type: int Description: Get gamepad axis count for a gamepad Param[1]: gamepad (type: int) -Function 172: GetGamepadAxisMovement() (2 input parameters) +Function 173: GetGamepadAxisMovement() (2 input parameters) Name: GetGamepadAxisMovement Return type: float Description: Get axis movement value for a gamepad axis Param[1]: gamepad (type: int) Param[2]: axis (type: int) -Function 173: SetGamepadMappings() (1 input parameters) +Function 174: SetGamepadMappings() (1 input parameters) Name: SetGamepadMappings Return type: int Description: Set internal gamepad mappings (SDL_GameControllerDB) Param[1]: mappings (type: const char *) -Function 174: SetGamepadVibration() (3 input parameters) +Function 175: SetGamepadVibration() (3 input parameters) Name: SetGamepadVibration Return type: void Description: Set gamepad vibration for both motors Param[1]: gamepad (type: int) Param[2]: leftMotor (type: float) Param[3]: rightMotor (type: float) -Function 175: IsMouseButtonPressed() (1 input parameters) +Function 176: IsMouseButtonPressed() (1 input parameters) Name: IsMouseButtonPressed Return type: bool Description: Check if a mouse button has been pressed once Param[1]: button (type: int) -Function 176: IsMouseButtonDown() (1 input parameters) +Function 177: IsMouseButtonDown() (1 input parameters) Name: IsMouseButtonDown Return type: bool Description: Check if a mouse button is being pressed Param[1]: button (type: int) -Function 177: IsMouseButtonReleased() (1 input parameters) +Function 178: IsMouseButtonReleased() (1 input parameters) Name: IsMouseButtonReleased Return type: bool Description: Check if a mouse button has been released once Param[1]: button (type: int) -Function 178: IsMouseButtonUp() (1 input parameters) +Function 179: IsMouseButtonUp() (1 input parameters) Name: IsMouseButtonUp Return type: bool Description: Check if a mouse button is NOT being pressed Param[1]: button (type: int) -Function 179: GetMouseX() (0 input parameters) +Function 180: GetMouseX() (0 input parameters) Name: GetMouseX Return type: int Description: Get mouse position X No input parameters -Function 180: GetMouseY() (0 input parameters) +Function 181: GetMouseY() (0 input parameters) Name: GetMouseY Return type: int Description: Get mouse position Y No input parameters -Function 181: GetMousePosition() (0 input parameters) +Function 182: GetMousePosition() (0 input parameters) Name: GetMousePosition Return type: Vector2 Description: Get mouse position XY No input parameters -Function 182: GetMouseDelta() (0 input parameters) +Function 183: GetMouseDelta() (0 input parameters) Name: GetMouseDelta Return type: Vector2 Description: Get mouse delta between frames No input parameters -Function 183: SetMousePosition() (2 input parameters) +Function 184: SetMousePosition() (2 input parameters) Name: SetMousePosition Return type: void Description: Set mouse position XY Param[1]: x (type: int) Param[2]: y (type: int) -Function 184: SetMouseOffset() (2 input parameters) +Function 185: SetMouseOffset() (2 input parameters) Name: SetMouseOffset Return type: void Description: Set mouse offset Param[1]: offsetX (type: int) Param[2]: offsetY (type: int) -Function 185: SetMouseScale() (2 input parameters) +Function 186: SetMouseScale() (2 input parameters) Name: SetMouseScale Return type: void Description: Set mouse scaling Param[1]: scaleX (type: float) Param[2]: scaleY (type: float) -Function 186: GetMouseWheelMove() (0 input parameters) +Function 187: GetMouseWheelMove() (0 input parameters) Name: GetMouseWheelMove Return type: float Description: Get mouse wheel movement for X or Y, whichever is larger No input parameters -Function 187: GetMouseWheelMoveV() (0 input parameters) +Function 188: GetMouseWheelMoveV() (0 input parameters) Name: GetMouseWheelMoveV Return type: Vector2 Description: Get mouse wheel movement for both X and Y No input parameters -Function 188: SetMouseCursor() (1 input parameters) +Function 189: SetMouseCursor() (1 input parameters) Name: SetMouseCursor Return type: void Description: Set mouse cursor Param[1]: cursor (type: int) -Function 189: GetTouchX() (0 input parameters) +Function 190: GetTouchX() (0 input parameters) Name: GetTouchX Return type: int Description: Get touch position X for touch point 0 (relative to screen size) No input parameters -Function 190: GetTouchY() (0 input parameters) +Function 191: GetTouchY() (0 input parameters) Name: GetTouchY Return type: int Description: Get touch position Y for touch point 0 (relative to screen size) No input parameters -Function 191: GetTouchPosition() (1 input parameters) +Function 192: GetTouchPosition() (1 input parameters) Name: GetTouchPosition Return type: Vector2 Description: Get touch position XY for a touch point index (relative to screen size) Param[1]: index (type: int) -Function 192: GetTouchPointId() (1 input parameters) +Function 193: GetTouchPointId() (1 input parameters) Name: GetTouchPointId Return type: int Description: Get touch point identifier for given index Param[1]: index (type: int) -Function 193: GetTouchPointCount() (0 input parameters) +Function 194: GetTouchPointCount() (0 input parameters) Name: GetTouchPointCount Return type: int Description: Get number of touch points No input parameters -Function 194: SetGesturesEnabled() (1 input parameters) +Function 195: SetGesturesEnabled() (1 input parameters) Name: SetGesturesEnabled Return type: void Description: Enable a set of gestures using flags Param[1]: flags (type: unsigned int) -Function 195: IsGestureDetected() (1 input parameters) +Function 196: IsGestureDetected() (1 input parameters) Name: IsGestureDetected Return type: bool Description: Check if a gesture have been detected Param[1]: gesture (type: unsigned int) -Function 196: GetGestureDetected() (0 input parameters) +Function 197: GetGestureDetected() (0 input parameters) Name: GetGestureDetected Return type: int Description: Get latest detected gesture No input parameters -Function 197: GetGestureHoldDuration() (0 input parameters) +Function 198: GetGestureHoldDuration() (0 input parameters) Name: GetGestureHoldDuration Return type: float Description: Get gesture hold time in milliseconds No input parameters -Function 198: GetGestureDragVector() (0 input parameters) +Function 199: GetGestureDragVector() (0 input parameters) Name: GetGestureDragVector Return type: Vector2 Description: Get gesture drag vector No input parameters -Function 199: GetGestureDragAngle() (0 input parameters) +Function 200: GetGestureDragAngle() (0 input parameters) Name: GetGestureDragAngle Return type: float Description: Get gesture drag angle No input parameters -Function 200: GetGesturePinchVector() (0 input parameters) +Function 201: GetGesturePinchVector() (0 input parameters) Name: GetGesturePinchVector Return type: Vector2 Description: Get gesture pinch delta No input parameters -Function 201: GetGesturePinchAngle() (0 input parameters) +Function 202: GetGesturePinchAngle() (0 input parameters) Name: GetGesturePinchAngle Return type: float Description: Get gesture pinch angle No input parameters -Function 202: UpdateCamera() (2 input parameters) +Function 203: UpdateCamera() (2 input parameters) Name: UpdateCamera Return type: void Description: Update camera position for selected mode Param[1]: camera (type: Camera *) Param[2]: mode (type: int) -Function 203: UpdateCameraPro() (4 input parameters) +Function 204: UpdateCameraPro() (4 input parameters) Name: UpdateCameraPro Return type: void Description: Update camera movement/rotation @@ -2073,36 +2083,36 @@ Function 203: UpdateCameraPro() (4 input parameters) Param[2]: movement (type: Vector3) Param[3]: rotation (type: Vector3) Param[4]: zoom (type: float) -Function 204: SetShapesTexture() (2 input parameters) +Function 205: SetShapesTexture() (2 input parameters) Name: SetShapesTexture Return type: void Description: Set texture and rectangle to be used on shapes drawing Param[1]: texture (type: Texture2D) Param[2]: source (type: Rectangle) -Function 205: GetShapesTexture() (0 input parameters) +Function 206: GetShapesTexture() (0 input parameters) Name: GetShapesTexture Return type: Texture2D Description: Get texture that is used for shapes drawing No input parameters -Function 206: GetShapesTextureRectangle() (0 input parameters) +Function 207: GetShapesTextureRectangle() (0 input parameters) Name: GetShapesTextureRectangle Return type: Rectangle Description: Get texture source rectangle that is used for shapes drawing No input parameters -Function 207: DrawPixel() (3 input parameters) +Function 208: DrawPixel() (3 input parameters) Name: DrawPixel Return type: void - Description: Draw a pixel + Description: Draw a pixel using geometry [Can be slow, use with care] Param[1]: posX (type: int) Param[2]: posY (type: int) Param[3]: color (type: Color) -Function 208: DrawPixelV() (2 input parameters) +Function 209: DrawPixelV() (2 input parameters) Name: DrawPixelV Return type: void - Description: Draw a pixel (Vector version) + Description: Draw a pixel using geometry (Vector version) [Can be slow, use with care] Param[1]: position (type: Vector2) Param[2]: color (type: Color) -Function 209: DrawLine() (5 input parameters) +Function 210: DrawLine() (5 input parameters) Name: DrawLine Return type: void Description: Draw a line @@ -2111,14 +2121,14 @@ Function 209: DrawLine() (5 input parameters) Param[3]: endPosX (type: int) Param[4]: endPosY (type: int) Param[5]: color (type: Color) -Function 210: DrawLineV() (3 input parameters) +Function 211: DrawLineV() (3 input parameters) Name: DrawLineV Return type: void Description: Draw a line (using gl lines) Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: color (type: Color) -Function 211: DrawLineEx() (4 input parameters) +Function 212: DrawLineEx() (4 input parameters) Name: DrawLineEx Return type: void Description: Draw a line (using triangles/quads) @@ -2126,14 +2136,14 @@ Function 211: DrawLineEx() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 212: DrawLineStrip() (3 input parameters) +Function 213: DrawLineStrip() (3 input parameters) Name: DrawLineStrip Return type: void Description: Draw lines sequence (using gl lines) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 213: DrawLineBezier() (4 input parameters) +Function 214: DrawLineBezier() (4 input parameters) Name: DrawLineBezier Return type: void Description: Draw line segment cubic-bezier in-out interpolation @@ -2141,7 +2151,7 @@ Function 213: DrawLineBezier() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 214: DrawCircle() (4 input parameters) +Function 215: DrawCircle() (4 input parameters) Name: DrawCircle Return type: void Description: Draw a color-filled circle @@ -2149,7 +2159,7 @@ Function 214: DrawCircle() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 215: DrawCircleSector() (6 input parameters) +Function 216: DrawCircleSector() (6 input parameters) Name: DrawCircleSector Return type: void Description: Draw a piece of a circle @@ -2159,7 +2169,7 @@ Function 215: DrawCircleSector() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 216: DrawCircleSectorLines() (6 input parameters) +Function 217: DrawCircleSectorLines() (6 input parameters) Name: DrawCircleSectorLines Return type: void Description: Draw circle sector outline @@ -2169,23 +2179,23 @@ Function 216: DrawCircleSectorLines() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 217: DrawCircleGradient() (5 input parameters) +Function 218: DrawCircleGradient() (5 input parameters) Name: DrawCircleGradient Return type: void Description: Draw a gradient-filled circle Param[1]: centerX (type: int) Param[2]: centerY (type: int) Param[3]: radius (type: float) - Param[4]: color1 (type: Color) - Param[5]: color2 (type: Color) -Function 218: DrawCircleV() (3 input parameters) + Param[4]: inner (type: Color) + Param[5]: outer (type: Color) +Function 219: DrawCircleV() (3 input parameters) Name: DrawCircleV Return type: void Description: Draw a color-filled circle (Vector version) Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 219: DrawCircleLines() (4 input parameters) +Function 220: DrawCircleLines() (4 input parameters) Name: DrawCircleLines Return type: void Description: Draw circle outline @@ -2193,14 +2203,14 @@ Function 219: DrawCircleLines() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 220: DrawCircleLinesV() (3 input parameters) +Function 221: DrawCircleLinesV() (3 input parameters) Name: DrawCircleLinesV Return type: void Description: Draw circle outline (Vector version) Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 221: DrawEllipse() (5 input parameters) +Function 222: DrawEllipse() (5 input parameters) Name: DrawEllipse Return type: void Description: Draw ellipse @@ -2209,7 +2219,7 @@ Function 221: DrawEllipse() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 222: DrawEllipseLines() (5 input parameters) +Function 223: DrawEllipseLines() (5 input parameters) Name: DrawEllipseLines Return type: void Description: Draw ellipse outline @@ -2218,7 +2228,7 @@ Function 222: DrawEllipseLines() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 223: DrawRing() (7 input parameters) +Function 224: DrawRing() (7 input parameters) Name: DrawRing Return type: void Description: Draw ring @@ -2229,7 +2239,7 @@ Function 223: DrawRing() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 224: DrawRingLines() (7 input parameters) +Function 225: DrawRingLines() (7 input parameters) Name: DrawRingLines Return type: void Description: Draw ring outline @@ -2240,7 +2250,7 @@ Function 224: DrawRingLines() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 225: DrawRectangle() (5 input parameters) +Function 226: DrawRectangle() (5 input parameters) Name: DrawRectangle Return type: void Description: Draw a color-filled rectangle @@ -2249,20 +2259,20 @@ Function 225: DrawRectangle() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 226: DrawRectangleV() (3 input parameters) +Function 227: DrawRectangleV() (3 input parameters) Name: DrawRectangleV Return type: void Description: Draw a color-filled rectangle (Vector version) Param[1]: position (type: Vector2) Param[2]: size (type: Vector2) Param[3]: color (type: Color) -Function 227: DrawRectangleRec() (2 input parameters) +Function 228: DrawRectangleRec() (2 input parameters) Name: DrawRectangleRec Return type: void Description: Draw a color-filled rectangle Param[1]: rec (type: Rectangle) Param[2]: color (type: Color) -Function 228: DrawRectanglePro() (4 input parameters) +Function 229: DrawRectanglePro() (4 input parameters) Name: DrawRectanglePro Return type: void Description: Draw a color-filled rectangle with pro parameters @@ -2270,7 +2280,7 @@ Function 228: DrawRectanglePro() (4 input parameters) Param[2]: origin (type: Vector2) Param[3]: rotation (type: float) Param[4]: color (type: Color) -Function 229: DrawRectangleGradientV() (6 input parameters) +Function 230: DrawRectangleGradientV() (6 input parameters) Name: DrawRectangleGradientV Return type: void Description: Draw a vertical-gradient-filled rectangle @@ -2278,9 +2288,9 @@ Function 229: DrawRectangleGradientV() (6 input parameters) Param[2]: posY (type: int) Param[3]: width (type: int) Param[4]: height (type: int) - Param[5]: color1 (type: Color) - Param[6]: color2 (type: Color) -Function 230: DrawRectangleGradientH() (6 input parameters) + Param[5]: top (type: Color) + Param[6]: bottom (type: Color) +Function 231: DrawRectangleGradientH() (6 input parameters) Name: DrawRectangleGradientH Return type: void Description: Draw a horizontal-gradient-filled rectangle @@ -2288,18 +2298,18 @@ Function 230: DrawRectangleGradientH() (6 input parameters) Param[2]: posY (type: int) Param[3]: width (type: int) Param[4]: height (type: int) - Param[5]: color1 (type: Color) - Param[6]: color2 (type: Color) -Function 231: DrawRectangleGradientEx() (5 input parameters) + Param[5]: left (type: Color) + Param[6]: right (type: Color) +Function 232: DrawRectangleGradientEx() (5 input parameters) Name: DrawRectangleGradientEx Return type: void Description: Draw a gradient-filled rectangle with custom vertex colors Param[1]: rec (type: Rectangle) - Param[2]: col1 (type: Color) - Param[3]: col2 (type: Color) - Param[4]: col3 (type: Color) - Param[5]: col4 (type: Color) -Function 232: DrawRectangleLines() (5 input parameters) + Param[2]: topLeft (type: Color) + Param[3]: bottomLeft (type: Color) + Param[4]: topRight (type: Color) + Param[5]: bottomRight (type: Color) +Function 233: DrawRectangleLines() (5 input parameters) Name: DrawRectangleLines Return type: void Description: Draw rectangle outline @@ -2308,14 +2318,14 @@ Function 232: DrawRectangleLines() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 233: DrawRectangleLinesEx() (3 input parameters) +Function 234: DrawRectangleLinesEx() (3 input parameters) Name: DrawRectangleLinesEx Return type: void Description: Draw rectangle outline with extended parameters Param[1]: rec (type: Rectangle) Param[2]: lineThick (type: float) Param[3]: color (type: Color) -Function 234: DrawRectangleRounded() (4 input parameters) +Function 235: DrawRectangleRounded() (4 input parameters) Name: DrawRectangleRounded Return type: void Description: Draw rectangle with rounded edges @@ -2323,7 +2333,7 @@ Function 234: DrawRectangleRounded() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 235: DrawRectangleRoundedLines() (4 input parameters) +Function 236: DrawRectangleRoundedLines() (4 input parameters) Name: DrawRectangleRoundedLines Return type: void Description: Draw rectangle lines with rounded edges @@ -2331,7 +2341,7 @@ Function 235: DrawRectangleRoundedLines() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 236: DrawRectangleRoundedLinesEx() (5 input parameters) +Function 237: DrawRectangleRoundedLinesEx() (5 input parameters) Name: DrawRectangleRoundedLinesEx Return type: void Description: Draw rectangle with rounded edges outline @@ -2340,7 +2350,7 @@ Function 236: DrawRectangleRoundedLinesEx() (5 input parameters) Param[3]: segments (type: int) Param[4]: lineThick (type: float) Param[5]: color (type: Color) -Function 237: DrawTriangle() (4 input parameters) +Function 238: DrawTriangle() (4 input parameters) Name: DrawTriangle Return type: void Description: Draw a color-filled triangle (vertex in counter-clockwise order!) @@ -2348,7 +2358,7 @@ Function 237: DrawTriangle() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 238: DrawTriangleLines() (4 input parameters) +Function 239: DrawTriangleLines() (4 input parameters) Name: DrawTriangleLines Return type: void Description: Draw triangle outline (vertex in counter-clockwise order!) @@ -2356,21 +2366,21 @@ Function 238: DrawTriangleLines() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 239: DrawTriangleFan() (3 input parameters) +Function 240: DrawTriangleFan() (3 input parameters) Name: DrawTriangleFan Return type: void Description: Draw a triangle fan defined by points (first vertex is the center) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 240: DrawTriangleStrip() (3 input parameters) +Function 241: DrawTriangleStrip() (3 input parameters) Name: DrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 241: DrawPoly() (5 input parameters) +Function 242: DrawPoly() (5 input parameters) Name: DrawPoly Return type: void Description: Draw a regular polygon (Vector version) @@ -2379,7 +2389,7 @@ Function 241: DrawPoly() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 242: DrawPolyLines() (5 input parameters) +Function 243: DrawPolyLines() (5 input parameters) Name: DrawPolyLines Return type: void Description: Draw a polygon outline of n sides @@ -2388,7 +2398,7 @@ Function 242: DrawPolyLines() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 243: DrawPolyLinesEx() (6 input parameters) +Function 244: DrawPolyLinesEx() (6 input parameters) Name: DrawPolyLinesEx Return type: void Description: Draw a polygon outline of n sides with extended parameters @@ -2398,7 +2408,7 @@ Function 243: DrawPolyLinesEx() (6 input parameters) Param[4]: rotation (type: float) Param[5]: lineThick (type: float) Param[6]: color (type: Color) -Function 244: DrawSplineLinear() (4 input parameters) +Function 245: DrawSplineLinear() (4 input parameters) Name: DrawSplineLinear Return type: void Description: Draw spline: Linear, minimum 2 points @@ -2406,7 +2416,7 @@ Function 244: DrawSplineLinear() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 245: DrawSplineBasis() (4 input parameters) +Function 246: DrawSplineBasis() (4 input parameters) Name: DrawSplineBasis Return type: void Description: Draw spline: B-Spline, minimum 4 points @@ -2414,7 +2424,7 @@ Function 245: DrawSplineBasis() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 246: DrawSplineCatmullRom() (4 input parameters) +Function 247: DrawSplineCatmullRom() (4 input parameters) Name: DrawSplineCatmullRom Return type: void Description: Draw spline: Catmull-Rom, minimum 4 points @@ -2422,7 +2432,7 @@ Function 246: DrawSplineCatmullRom() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 247: DrawSplineBezierQuadratic() (4 input parameters) +Function 248: DrawSplineBezierQuadratic() (4 input parameters) Name: DrawSplineBezierQuadratic Return type: void Description: Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] @@ -2430,7 +2440,7 @@ Function 247: DrawSplineBezierQuadratic() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 248: DrawSplineBezierCubic() (4 input parameters) +Function 249: DrawSplineBezierCubic() (4 input parameters) Name: DrawSplineBezierCubic Return type: void Description: Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...] @@ -2438,7 +2448,7 @@ Function 248: DrawSplineBezierCubic() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 249: DrawSplineSegmentLinear() (4 input parameters) +Function 250: DrawSplineSegmentLinear() (4 input parameters) Name: DrawSplineSegmentLinear Return type: void Description: Draw spline segment: Linear, 2 points @@ -2446,7 +2456,7 @@ Function 249: DrawSplineSegmentLinear() (4 input parameters) Param[2]: p2 (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 250: DrawSplineSegmentBasis() (6 input parameters) +Function 251: DrawSplineSegmentBasis() (6 input parameters) Name: DrawSplineSegmentBasis Return type: void Description: Draw spline segment: B-Spline, 4 points @@ -2456,7 +2466,7 @@ Function 250: DrawSplineSegmentBasis() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 251: DrawSplineSegmentCatmullRom() (6 input parameters) +Function 252: DrawSplineSegmentCatmullRom() (6 input parameters) Name: DrawSplineSegmentCatmullRom Return type: void Description: Draw spline segment: Catmull-Rom, 4 points @@ -2466,7 +2476,7 @@ Function 251: DrawSplineSegmentCatmullRom() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 252: DrawSplineSegmentBezierQuadratic() (5 input parameters) +Function 253: DrawSplineSegmentBezierQuadratic() (5 input parameters) Name: DrawSplineSegmentBezierQuadratic Return type: void Description: Draw spline segment: Quadratic Bezier, 2 points, 1 control point @@ -2475,7 +2485,7 @@ Function 252: DrawSplineSegmentBezierQuadratic() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: thick (type: float) Param[5]: color (type: Color) -Function 253: DrawSplineSegmentBezierCubic() (6 input parameters) +Function 254: DrawSplineSegmentBezierCubic() (6 input parameters) Name: DrawSplineSegmentBezierCubic Return type: void Description: Draw spline segment: Cubic Bezier, 2 points, 2 control points @@ -2485,14 +2495,14 @@ Function 253: DrawSplineSegmentBezierCubic() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 254: GetSplinePointLinear() (3 input parameters) +Function 255: GetSplinePointLinear() (3 input parameters) Name: GetSplinePointLinear Return type: Vector2 Description: Get (evaluate) spline point: Linear Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: t (type: float) -Function 255: GetSplinePointBasis() (5 input parameters) +Function 256: GetSplinePointBasis() (5 input parameters) Name: GetSplinePointBasis Return type: Vector2 Description: Get (evaluate) spline point: B-Spline @@ -2501,7 +2511,7 @@ Function 255: GetSplinePointBasis() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 256: GetSplinePointCatmullRom() (5 input parameters) +Function 257: GetSplinePointCatmullRom() (5 input parameters) Name: GetSplinePointCatmullRom Return type: Vector2 Description: Get (evaluate) spline point: Catmull-Rom @@ -2510,7 +2520,7 @@ Function 256: GetSplinePointCatmullRom() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 257: GetSplinePointBezierQuad() (4 input parameters) +Function 258: GetSplinePointBezierQuad() (4 input parameters) Name: GetSplinePointBezierQuad Return type: Vector2 Description: Get (evaluate) spline point: Quadratic Bezier @@ -2518,7 +2528,7 @@ Function 257: GetSplinePointBezierQuad() (4 input parameters) Param[2]: c2 (type: Vector2) Param[3]: p3 (type: Vector2) Param[4]: t (type: float) -Function 258: GetSplinePointBezierCubic() (5 input parameters) +Function 259: GetSplinePointBezierCubic() (5 input parameters) Name: GetSplinePointBezierCubic Return type: Vector2 Description: Get (evaluate) spline point: Cubic Bezier @@ -2527,13 +2537,13 @@ Function 258: GetSplinePointBezierCubic() (5 input parameters) Param[3]: c3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 259: CheckCollisionRecs() (2 input parameters) +Function 260: CheckCollisionRecs() (2 input parameters) Name: CheckCollisionRecs Return type: bool Description: Check collision between two rectangles Param[1]: rec1 (type: Rectangle) Param[2]: rec2 (type: Rectangle) -Function 260: CheckCollisionCircles() (4 input parameters) +Function 261: CheckCollisionCircles() (4 input parameters) Name: CheckCollisionCircles Return type: bool Description: Check collision between two circles @@ -2541,27 +2551,27 @@ Function 260: CheckCollisionCircles() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector2) Param[4]: radius2 (type: float) -Function 261: CheckCollisionCircleRec() (3 input parameters) +Function 262: CheckCollisionCircleRec() (3 input parameters) Name: CheckCollisionCircleRec Return type: bool Description: Check collision between circle and rectangle Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: rec (type: Rectangle) -Function 262: CheckCollisionPointRec() (2 input parameters) +Function 263: CheckCollisionPointRec() (2 input parameters) Name: CheckCollisionPointRec Return type: bool Description: Check if point is inside rectangle Param[1]: point (type: Vector2) Param[2]: rec (type: Rectangle) -Function 263: CheckCollisionPointCircle() (3 input parameters) +Function 264: CheckCollisionPointCircle() (3 input parameters) Name: CheckCollisionPointCircle Return type: bool Description: Check if point is inside circle Param[1]: point (type: Vector2) Param[2]: center (type: Vector2) Param[3]: radius (type: float) -Function 264: CheckCollisionPointTriangle() (4 input parameters) +Function 265: CheckCollisionPointTriangle() (4 input parameters) Name: CheckCollisionPointTriangle Return type: bool Description: Check if point is inside a triangle @@ -2569,14 +2579,14 @@ Function 264: CheckCollisionPointTriangle() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: p3 (type: Vector2) -Function 265: CheckCollisionPointPoly() (3 input parameters) +Function 266: CheckCollisionPointPoly() (3 input parameters) Name: CheckCollisionPointPoly Return type: bool Description: Check if point is within a polygon described by array of vertices Param[1]: point (type: Vector2) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) -Function 266: CheckCollisionLines() (5 input parameters) +Function 267: CheckCollisionLines() (5 input parameters) Name: CheckCollisionLines Return type: bool Description: Check the collision between two lines defined by two points each, returns collision point by reference @@ -2585,7 +2595,7 @@ Function 266: CheckCollisionLines() (5 input parameters) Param[3]: startPos2 (type: Vector2) Param[4]: endPos2 (type: Vector2) Param[5]: collisionPoint (type: Vector2 *) -Function 267: CheckCollisionPointLine() (4 input parameters) +Function 268: CheckCollisionPointLine() (4 input parameters) Name: CheckCollisionPointLine Return type: bool Description: Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold] @@ -2593,7 +2603,7 @@ Function 267: CheckCollisionPointLine() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: threshold (type: int) -Function 268: CheckCollisionCircleLine() (4 input parameters) +Function 269: CheckCollisionCircleLine() (4 input parameters) Name: CheckCollisionCircleLine Return type: bool Description: Check if circle collides with a line created betweeen two points [p1] and [p2] @@ -2601,18 +2611,18 @@ Function 268: CheckCollisionCircleLine() (4 input parameters) Param[2]: radius (type: float) Param[3]: p1 (type: Vector2) Param[4]: p2 (type: Vector2) -Function 269: GetCollisionRec() (2 input parameters) +Function 270: GetCollisionRec() (2 input parameters) Name: GetCollisionRec Return type: Rectangle Description: Get collision rectangle for two rectangles collision Param[1]: rec1 (type: Rectangle) Param[2]: rec2 (type: Rectangle) -Function 270: LoadImage() (1 input parameters) +Function 271: LoadImage() (1 input parameters) Name: LoadImage Return type: Image Description: Load image from file into CPU memory (RAM) Param[1]: fileName (type: const char *) -Function 271: LoadImageRaw() (5 input parameters) +Function 272: LoadImageRaw() (5 input parameters) Name: LoadImageRaw Return type: Image Description: Load image from RAW file data @@ -2621,20 +2631,20 @@ Function 271: LoadImageRaw() (5 input parameters) Param[3]: height (type: int) Param[4]: format (type: int) Param[5]: headerSize (type: int) -Function 272: LoadImageSvg() (3 input parameters) +Function 273: LoadImageSvg() (3 input parameters) Name: LoadImageSvg Return type: Image Description: Load image from SVG file data or string with specified size Param[1]: fileNameOrString (type: const char *) Param[2]: width (type: int) Param[3]: height (type: int) -Function 273: LoadImageAnim() (2 input parameters) +Function 274: LoadImageAnim() (2 input parameters) Name: LoadImageAnim Return type: Image Description: Load image sequence from file (frames appended to image.data) Param[1]: fileName (type: const char *) Param[2]: frames (type: int *) -Function 274: LoadImageAnimFromMemory() (4 input parameters) +Function 275: LoadImageAnimFromMemory() (4 input parameters) Name: LoadImageAnimFromMemory Return type: Image Description: Load image sequence from memory buffer @@ -2642,60 +2652,60 @@ Function 274: LoadImageAnimFromMemory() (4 input parameters) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) Param[4]: frames (type: int *) -Function 275: LoadImageFromMemory() (3 input parameters) +Function 276: LoadImageFromMemory() (3 input parameters) Name: LoadImageFromMemory Return type: Image Description: Load image from memory buffer, fileType refers to extension: i.e. '.png' Param[1]: fileType (type: const char *) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 276: LoadImageFromTexture() (1 input parameters) +Function 277: LoadImageFromTexture() (1 input parameters) Name: LoadImageFromTexture Return type: Image Description: Load image from GPU texture data Param[1]: texture (type: Texture2D) -Function 277: LoadImageFromScreen() (0 input parameters) +Function 278: LoadImageFromScreen() (0 input parameters) Name: LoadImageFromScreen Return type: Image Description: Load image from screen buffer and (screenshot) No input parameters -Function 278: IsImageReady() (1 input parameters) +Function 279: IsImageReady() (1 input parameters) Name: IsImageReady Return type: bool Description: Check if an image is ready Param[1]: image (type: Image) -Function 279: UnloadImage() (1 input parameters) +Function 280: UnloadImage() (1 input parameters) Name: UnloadImage Return type: void Description: Unload image from CPU memory (RAM) Param[1]: image (type: Image) -Function 280: ExportImage() (2 input parameters) +Function 281: ExportImage() (2 input parameters) Name: ExportImage Return type: bool Description: Export image data to file, returns true on success Param[1]: image (type: Image) Param[2]: fileName (type: const char *) -Function 281: ExportImageToMemory() (3 input parameters) +Function 282: ExportImageToMemory() (3 input parameters) Name: ExportImageToMemory Return type: unsigned char * Description: Export image to memory buffer Param[1]: image (type: Image) Param[2]: fileType (type: const char *) Param[3]: fileSize (type: int *) -Function 282: ExportImageAsCode() (2 input parameters) +Function 283: ExportImageAsCode() (2 input parameters) Name: ExportImageAsCode Return type: bool Description: Export image as code file defining an array of bytes, returns true on success Param[1]: image (type: Image) Param[2]: fileName (type: const char *) -Function 283: GenImageColor() (3 input parameters) +Function 284: GenImageColor() (3 input parameters) Name: GenImageColor Return type: Image Description: Generate image: plain color Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: color (type: Color) -Function 284: GenImageGradientLinear() (5 input parameters) +Function 285: GenImageGradientLinear() (5 input parameters) Name: GenImageGradientLinear Return type: Image Description: Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient @@ -2704,7 +2714,7 @@ Function 284: GenImageGradientLinear() (5 input parameters) Param[3]: direction (type: int) Param[4]: start (type: Color) Param[5]: end (type: Color) -Function 285: GenImageGradientRadial() (5 input parameters) +Function 286: GenImageGradientRadial() (5 input parameters) Name: GenImageGradientRadial Return type: Image Description: Generate image: radial gradient @@ -2713,7 +2723,7 @@ Function 285: GenImageGradientRadial() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 286: GenImageGradientSquare() (5 input parameters) +Function 287: GenImageGradientSquare() (5 input parameters) Name: GenImageGradientSquare Return type: Image Description: Generate image: square gradient @@ -2722,7 +2732,7 @@ Function 286: GenImageGradientSquare() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 287: GenImageChecked() (6 input parameters) +Function 288: GenImageChecked() (6 input parameters) Name: GenImageChecked Return type: Image Description: Generate image: checked @@ -2732,14 +2742,14 @@ Function 287: GenImageChecked() (6 input parameters) Param[4]: checksY (type: int) Param[5]: col1 (type: Color) Param[6]: col2 (type: Color) -Function 288: GenImageWhiteNoise() (3 input parameters) +Function 289: GenImageWhiteNoise() (3 input parameters) Name: GenImageWhiteNoise Return type: Image Description: Generate image: white noise Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: factor (type: float) -Function 289: GenImagePerlinNoise() (5 input parameters) +Function 290: GenImagePerlinNoise() (5 input parameters) Name: GenImagePerlinNoise Return type: Image Description: Generate image: perlin noise @@ -2748,39 +2758,45 @@ Function 289: GenImagePerlinNoise() (5 input parameters) Param[3]: offsetX (type: int) Param[4]: offsetY (type: int) Param[5]: scale (type: float) -Function 290: GenImageCellular() (3 input parameters) +Function 291: GenImageCellular() (3 input parameters) Name: GenImageCellular Return type: Image Description: Generate image: cellular algorithm, bigger tileSize means bigger cells Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: tileSize (type: int) -Function 291: GenImageText() (3 input parameters) +Function 292: GenImageText() (3 input parameters) Name: GenImageText Return type: Image Description: Generate image: grayscale image from text data Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: text (type: const char *) -Function 292: ImageCopy() (1 input parameters) +Function 293: ImageCopy() (1 input parameters) Name: ImageCopy Return type: Image Description: Create an image duplicate (useful for transformations) Param[1]: image (type: Image) -Function 293: ImageFromImage() (2 input parameters) +Function 294: ImageFromImage() (2 input parameters) Name: ImageFromImage Return type: Image Description: Create an image from another image piece Param[1]: image (type: Image) Param[2]: rec (type: Rectangle) -Function 294: ImageText() (3 input parameters) +Function 295: ImageFromChannel() (2 input parameters) + Name: ImageFromChannel + Return type: Image + Description: Create an image from a selected channel of another image (GRAYSCALE) + Param[1]: image (type: Image) + Param[2]: selectedChannel (type: int) +Function 296: ImageText() (3 input parameters) Name: ImageText Return type: Image Description: Create an image from text (default font) Param[1]: text (type: const char *) Param[2]: fontSize (type: int) Param[3]: color (type: Color) -Function 295: ImageTextEx() (5 input parameters) +Function 297: ImageTextEx() (5 input parameters) Name: ImageTextEx Return type: Image Description: Create an image from text (custom sprite font) @@ -2789,76 +2805,76 @@ Function 295: ImageTextEx() (5 input parameters) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) Param[5]: tint (type: Color) -Function 296: ImageFormat() (2 input parameters) +Function 298: ImageFormat() (2 input parameters) Name: ImageFormat Return type: void Description: Convert image data to desired format Param[1]: image (type: Image *) Param[2]: newFormat (type: int) -Function 297: ImageToPOT() (2 input parameters) +Function 299: ImageToPOT() (2 input parameters) Name: ImageToPOT Return type: void Description: Convert image to POT (power-of-two) Param[1]: image (type: Image *) Param[2]: fill (type: Color) -Function 298: ImageCrop() (2 input parameters) +Function 300: ImageCrop() (2 input parameters) Name: ImageCrop Return type: void Description: Crop an image to a defined rectangle Param[1]: image (type: Image *) Param[2]: crop (type: Rectangle) -Function 299: ImageAlphaCrop() (2 input parameters) +Function 301: ImageAlphaCrop() (2 input parameters) Name: ImageAlphaCrop Return type: void Description: Crop image depending on alpha value Param[1]: image (type: Image *) Param[2]: threshold (type: float) -Function 300: ImageAlphaClear() (3 input parameters) +Function 302: ImageAlphaClear() (3 input parameters) Name: ImageAlphaClear Return type: void Description: Clear alpha channel to desired color Param[1]: image (type: Image *) Param[2]: color (type: Color) Param[3]: threshold (type: float) -Function 301: ImageAlphaMask() (2 input parameters) +Function 303: ImageAlphaMask() (2 input parameters) Name: ImageAlphaMask Return type: void Description: Apply alpha mask to image Param[1]: image (type: Image *) Param[2]: alphaMask (type: Image) -Function 302: ImageAlphaPremultiply() (1 input parameters) +Function 304: ImageAlphaPremultiply() (1 input parameters) Name: ImageAlphaPremultiply Return type: void Description: Premultiply alpha channel Param[1]: image (type: Image *) -Function 303: ImageBlurGaussian() (2 input parameters) +Function 305: ImageBlurGaussian() (2 input parameters) Name: ImageBlurGaussian Return type: void Description: Apply Gaussian blur using a box blur approximation Param[1]: image (type: Image *) Param[2]: blurSize (type: int) -Function 304: ImageKernelConvolution() (3 input parameters) +Function 306: ImageKernelConvolution() (3 input parameters) Name: ImageKernelConvolution Return type: void - Description: Apply Custom Square image convolution kernel + Description: Apply custom square convolution kernel to image Param[1]: image (type: Image *) - Param[2]: kernel (type: float*) + Param[2]: kernel (type: const float *) Param[3]: kernelSize (type: int) -Function 305: ImageResize() (3 input parameters) +Function 307: ImageResize() (3 input parameters) Name: ImageResize Return type: void Description: Resize image (Bicubic scaling algorithm) Param[1]: image (type: Image *) Param[2]: newWidth (type: int) Param[3]: newHeight (type: int) -Function 306: ImageResizeNN() (3 input parameters) +Function 308: ImageResizeNN() (3 input parameters) Name: ImageResizeNN Return type: void Description: Resize image (Nearest-Neighbor scaling algorithm) Param[1]: image (type: Image *) Param[2]: newWidth (type: int) Param[3]: newHeight (type: int) -Function 307: ImageResizeCanvas() (6 input parameters) +Function 309: ImageResizeCanvas() (6 input parameters) Name: ImageResizeCanvas Return type: void Description: Resize canvas and fill with color @@ -2868,12 +2884,12 @@ Function 307: ImageResizeCanvas() (6 input parameters) Param[4]: offsetX (type: int) Param[5]: offsetY (type: int) Param[6]: fill (type: Color) -Function 308: ImageMipmaps() (1 input parameters) +Function 310: ImageMipmaps() (1 input parameters) Name: ImageMipmaps Return type: void Description: Compute all mipmap levels for a provided image Param[1]: image (type: Image *) -Function 309: ImageDither() (5 input parameters) +Function 311: ImageDither() (5 input parameters) Name: ImageDither Return type: void Description: Dither image data to 16bpp or lower (Floyd-Steinberg dithering) @@ -2882,109 +2898,109 @@ Function 309: ImageDither() (5 input parameters) Param[3]: gBpp (type: int) Param[4]: bBpp (type: int) Param[5]: aBpp (type: int) -Function 310: ImageFlipVertical() (1 input parameters) +Function 312: ImageFlipVertical() (1 input parameters) Name: ImageFlipVertical Return type: void Description: Flip image vertically Param[1]: image (type: Image *) -Function 311: ImageFlipHorizontal() (1 input parameters) +Function 313: ImageFlipHorizontal() (1 input parameters) Name: ImageFlipHorizontal Return type: void Description: Flip image horizontally Param[1]: image (type: Image *) -Function 312: ImageRotate() (2 input parameters) +Function 314: ImageRotate() (2 input parameters) Name: ImageRotate Return type: void Description: Rotate image by input angle in degrees (-359 to 359) Param[1]: image (type: Image *) Param[2]: degrees (type: int) -Function 313: ImageRotateCW() (1 input parameters) +Function 315: ImageRotateCW() (1 input parameters) Name: ImageRotateCW Return type: void Description: Rotate image clockwise 90deg Param[1]: image (type: Image *) -Function 314: ImageRotateCCW() (1 input parameters) +Function 316: ImageRotateCCW() (1 input parameters) Name: ImageRotateCCW Return type: void Description: Rotate image counter-clockwise 90deg Param[1]: image (type: Image *) -Function 315: ImageColorTint() (2 input parameters) +Function 317: ImageColorTint() (2 input parameters) Name: ImageColorTint Return type: void Description: Modify image color: tint Param[1]: image (type: Image *) Param[2]: color (type: Color) -Function 316: ImageColorInvert() (1 input parameters) +Function 318: ImageColorInvert() (1 input parameters) Name: ImageColorInvert Return type: void Description: Modify image color: invert Param[1]: image (type: Image *) -Function 317: ImageColorGrayscale() (1 input parameters) +Function 319: ImageColorGrayscale() (1 input parameters) Name: ImageColorGrayscale Return type: void Description: Modify image color: grayscale Param[1]: image (type: Image *) -Function 318: ImageColorContrast() (2 input parameters) +Function 320: ImageColorContrast() (2 input parameters) Name: ImageColorContrast Return type: void Description: Modify image color: contrast (-100 to 100) Param[1]: image (type: Image *) Param[2]: contrast (type: float) -Function 319: ImageColorBrightness() (2 input parameters) +Function 321: ImageColorBrightness() (2 input parameters) Name: ImageColorBrightness Return type: void Description: Modify image color: brightness (-255 to 255) Param[1]: image (type: Image *) Param[2]: brightness (type: int) -Function 320: ImageColorReplace() (3 input parameters) +Function 322: ImageColorReplace() (3 input parameters) Name: ImageColorReplace Return type: void Description: Modify image color: replace color Param[1]: image (type: Image *) Param[2]: color (type: Color) Param[3]: replace (type: Color) -Function 321: LoadImageColors() (1 input parameters) +Function 323: LoadImageColors() (1 input parameters) Name: LoadImageColors Return type: Color * Description: Load color data from image as a Color array (RGBA - 32bit) Param[1]: image (type: Image) -Function 322: LoadImagePalette() (3 input parameters) +Function 324: LoadImagePalette() (3 input parameters) Name: LoadImagePalette Return type: Color * Description: Load colors palette from image as a Color array (RGBA - 32bit) Param[1]: image (type: Image) Param[2]: maxPaletteSize (type: int) Param[3]: colorCount (type: int *) -Function 323: UnloadImageColors() (1 input parameters) +Function 325: UnloadImageColors() (1 input parameters) Name: UnloadImageColors Return type: void Description: Unload color data loaded with LoadImageColors() Param[1]: colors (type: Color *) -Function 324: UnloadImagePalette() (1 input parameters) +Function 326: UnloadImagePalette() (1 input parameters) Name: UnloadImagePalette Return type: void Description: Unload colors palette loaded with LoadImagePalette() Param[1]: colors (type: Color *) -Function 325: GetImageAlphaBorder() (2 input parameters) +Function 327: GetImageAlphaBorder() (2 input parameters) Name: GetImageAlphaBorder Return type: Rectangle Description: Get image alpha border rectangle Param[1]: image (type: Image) Param[2]: threshold (type: float) -Function 326: GetImageColor() (3 input parameters) +Function 328: GetImageColor() (3 input parameters) Name: GetImageColor Return type: Color Description: Get image pixel color at (x, y) position Param[1]: image (type: Image) Param[2]: x (type: int) Param[3]: y (type: int) -Function 327: ImageClearBackground() (2 input parameters) +Function 329: ImageClearBackground() (2 input parameters) Name: ImageClearBackground Return type: void Description: Clear image background with given color Param[1]: dst (type: Image *) Param[2]: color (type: Color) -Function 328: ImageDrawPixel() (4 input parameters) +Function 330: ImageDrawPixel() (4 input parameters) Name: ImageDrawPixel Return type: void Description: Draw pixel within an image @@ -2992,14 +3008,14 @@ Function 328: ImageDrawPixel() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: color (type: Color) -Function 329: ImageDrawPixelV() (3 input parameters) +Function 331: ImageDrawPixelV() (3 input parameters) Name: ImageDrawPixelV Return type: void Description: Draw pixel within an image (Vector version) Param[1]: dst (type: Image *) Param[2]: position (type: Vector2) Param[3]: color (type: Color) -Function 330: ImageDrawLine() (6 input parameters) +Function 332: ImageDrawLine() (6 input parameters) Name: ImageDrawLine Return type: void Description: Draw line within an image @@ -3009,7 +3025,7 @@ Function 330: ImageDrawLine() (6 input parameters) Param[4]: endPosX (type: int) Param[5]: endPosY (type: int) Param[6]: color (type: Color) -Function 331: ImageDrawLineV() (4 input parameters) +Function 333: ImageDrawLineV() (4 input parameters) Name: ImageDrawLineV Return type: void Description: Draw line within an image (Vector version) @@ -3017,7 +3033,16 @@ Function 331: ImageDrawLineV() (4 input parameters) Param[2]: start (type: Vector2) Param[3]: end (type: Vector2) Param[4]: color (type: Color) -Function 332: ImageDrawCircle() (5 input parameters) +Function 334: ImageDrawLineEx() (5 input parameters) + Name: ImageDrawLineEx + Return type: void + Description: Draw a line defining thickness within an image + Param[1]: dst (type: Image *) + Param[2]: start (type: Vector2) + Param[3]: end (type: Vector2) + Param[4]: thick (type: int) + Param[5]: color (type: Color) +Function 335: ImageDrawCircle() (5 input parameters) Name: ImageDrawCircle Return type: void Description: Draw a filled circle within an image @@ -3026,7 +3051,7 @@ Function 332: ImageDrawCircle() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 333: ImageDrawCircleV() (4 input parameters) +Function 336: ImageDrawCircleV() (4 input parameters) Name: ImageDrawCircleV Return type: void Description: Draw a filled circle within an image (Vector version) @@ -3034,7 +3059,7 @@ Function 333: ImageDrawCircleV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 334: ImageDrawCircleLines() (5 input parameters) +Function 337: ImageDrawCircleLines() (5 input parameters) Name: ImageDrawCircleLines Return type: void Description: Draw circle outline within an image @@ -3043,7 +3068,7 @@ Function 334: ImageDrawCircleLines() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 335: ImageDrawCircleLinesV() (4 input parameters) +Function 338: ImageDrawCircleLinesV() (4 input parameters) Name: ImageDrawCircleLinesV Return type: void Description: Draw circle outline within an image (Vector version) @@ -3051,7 +3076,7 @@ Function 335: ImageDrawCircleLinesV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 336: ImageDrawRectangle() (6 input parameters) +Function 339: ImageDrawRectangle() (6 input parameters) Name: ImageDrawRectangle Return type: void Description: Draw rectangle within an image @@ -3061,7 +3086,7 @@ Function 336: ImageDrawRectangle() (6 input parameters) Param[4]: width (type: int) Param[5]: height (type: int) Param[6]: color (type: Color) -Function 337: ImageDrawRectangleV() (4 input parameters) +Function 340: ImageDrawRectangleV() (4 input parameters) Name: ImageDrawRectangleV Return type: void Description: Draw rectangle within an image (Vector version) @@ -3069,14 +3094,14 @@ Function 337: ImageDrawRectangleV() (4 input parameters) Param[2]: position (type: Vector2) Param[3]: size (type: Vector2) Param[4]: color (type: Color) -Function 338: ImageDrawRectangleRec() (3 input parameters) +Function 341: ImageDrawRectangleRec() (3 input parameters) Name: ImageDrawRectangleRec Return type: void Description: Draw rectangle within an image Param[1]: dst (type: Image *) Param[2]: rec (type: Rectangle) Param[3]: color (type: Color) -Function 339: ImageDrawRectangleLines() (4 input parameters) +Function 342: ImageDrawRectangleLines() (4 input parameters) Name: ImageDrawRectangleLines Return type: void Description: Draw rectangle lines within an image @@ -3084,7 +3109,52 @@ Function 339: ImageDrawRectangleLines() (4 input parameters) Param[2]: rec (type: Rectangle) Param[3]: thick (type: int) Param[4]: color (type: Color) -Function 340: ImageDraw() (5 input parameters) +Function 343: ImageDrawTriangle() (5 input parameters) + Name: ImageDrawTriangle + Return type: void + Description: Draw triangle within an image + Param[1]: dst (type: Image *) + Param[2]: v1 (type: Vector2) + Param[3]: v2 (type: Vector2) + Param[4]: v3 (type: Vector2) + Param[5]: color (type: Color) +Function 344: ImageDrawTriangleEx() (7 input parameters) + Name: ImageDrawTriangleEx + Return type: void + Description: Draw triangle with interpolated colors within an image + Param[1]: dst (type: Image *) + Param[2]: v1 (type: Vector2) + Param[3]: v2 (type: Vector2) + Param[4]: v3 (type: Vector2) + Param[5]: c1 (type: Color) + Param[6]: c2 (type: Color) + Param[7]: c3 (type: Color) +Function 345: ImageDrawTriangleLines() (5 input parameters) + Name: ImageDrawTriangleLines + Return type: void + Description: Draw triangle outline within an image + Param[1]: dst (type: Image *) + Param[2]: v1 (type: Vector2) + Param[3]: v2 (type: Vector2) + Param[4]: v3 (type: Vector2) + Param[5]: color (type: Color) +Function 346: ImageDrawTriangleFan() (4 input parameters) + Name: ImageDrawTriangleFan + Return type: void + Description: Draw a triangle fan defined by points within an image (first vertex is the center) + Param[1]: dst (type: Image *) + Param[2]: points (type: Vector2 *) + Param[3]: pointCount (type: int) + Param[4]: color (type: Color) +Function 347: ImageDrawTriangleStrip() (4 input parameters) + Name: ImageDrawTriangleStrip + Return type: void + Description: Draw a triangle strip defined by points within an image + Param[1]: dst (type: Image *) + Param[2]: points (type: Vector2 *) + Param[3]: pointCount (type: int) + Param[4]: color (type: Color) +Function 348: ImageDraw() (5 input parameters) Name: ImageDraw Return type: void Description: Draw a source image within a destination image (tint applied to source) @@ -3093,7 +3163,7 @@ Function 340: ImageDraw() (5 input parameters) Param[3]: srcRec (type: Rectangle) Param[4]: dstRec (type: Rectangle) Param[5]: tint (type: Color) -Function 341: ImageDrawText() (6 input parameters) +Function 349: ImageDrawText() (6 input parameters) Name: ImageDrawText Return type: void Description: Draw text (using default font) within an image (destination) @@ -3103,7 +3173,7 @@ Function 341: ImageDrawText() (6 input parameters) Param[4]: posY (type: int) Param[5]: fontSize (type: int) Param[6]: color (type: Color) -Function 342: ImageDrawTextEx() (7 input parameters) +Function 350: ImageDrawTextEx() (7 input parameters) Name: ImageDrawTextEx Return type: void Description: Draw text (custom sprite font) within an image (destination) @@ -3114,79 +3184,79 @@ Function 342: ImageDrawTextEx() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 343: LoadTexture() (1 input parameters) +Function 351: LoadTexture() (1 input parameters) Name: LoadTexture Return type: Texture2D Description: Load texture from file into GPU memory (VRAM) Param[1]: fileName (type: const char *) -Function 344: LoadTextureFromImage() (1 input parameters) +Function 352: LoadTextureFromImage() (1 input parameters) Name: LoadTextureFromImage Return type: Texture2D Description: Load texture from image data Param[1]: image (type: Image) -Function 345: LoadTextureCubemap() (2 input parameters) +Function 353: LoadTextureCubemap() (2 input parameters) Name: LoadTextureCubemap Return type: TextureCubemap Description: Load cubemap from image, multiple image cubemap layouts supported Param[1]: image (type: Image) Param[2]: layout (type: int) -Function 346: LoadRenderTexture() (2 input parameters) +Function 354: LoadRenderTexture() (2 input parameters) Name: LoadRenderTexture Return type: RenderTexture2D Description: Load texture for rendering (framebuffer) Param[1]: width (type: int) Param[2]: height (type: int) -Function 347: IsTextureReady() (1 input parameters) +Function 355: IsTextureReady() (1 input parameters) Name: IsTextureReady Return type: bool Description: Check if a texture is ready Param[1]: texture (type: Texture2D) -Function 348: UnloadTexture() (1 input parameters) +Function 356: UnloadTexture() (1 input parameters) Name: UnloadTexture Return type: void Description: Unload texture from GPU memory (VRAM) Param[1]: texture (type: Texture2D) -Function 349: IsRenderTextureReady() (1 input parameters) +Function 357: IsRenderTextureReady() (1 input parameters) Name: IsRenderTextureReady Return type: bool Description: Check if a render texture is ready Param[1]: target (type: RenderTexture2D) -Function 350: UnloadRenderTexture() (1 input parameters) +Function 358: UnloadRenderTexture() (1 input parameters) Name: UnloadRenderTexture Return type: void Description: Unload render texture from GPU memory (VRAM) Param[1]: target (type: RenderTexture2D) -Function 351: UpdateTexture() (2 input parameters) +Function 359: UpdateTexture() (2 input parameters) Name: UpdateTexture Return type: void Description: Update GPU texture with new data Param[1]: texture (type: Texture2D) Param[2]: pixels (type: const void *) -Function 352: UpdateTextureRec() (3 input parameters) +Function 360: UpdateTextureRec() (3 input parameters) Name: UpdateTextureRec Return type: void Description: Update GPU texture rectangle with new data Param[1]: texture (type: Texture2D) Param[2]: rec (type: Rectangle) Param[3]: pixels (type: const void *) -Function 353: GenTextureMipmaps() (1 input parameters) +Function 361: GenTextureMipmaps() (1 input parameters) Name: GenTextureMipmaps Return type: void Description: Generate GPU mipmaps for a texture Param[1]: texture (type: Texture2D *) -Function 354: SetTextureFilter() (2 input parameters) +Function 362: SetTextureFilter() (2 input parameters) Name: SetTextureFilter Return type: void Description: Set texture scaling filter mode Param[1]: texture (type: Texture2D) Param[2]: filter (type: int) -Function 355: SetTextureWrap() (2 input parameters) +Function 363: SetTextureWrap() (2 input parameters) Name: SetTextureWrap Return type: void Description: Set texture wrapping mode Param[1]: texture (type: Texture2D) Param[2]: wrap (type: int) -Function 356: DrawTexture() (4 input parameters) +Function 364: DrawTexture() (4 input parameters) Name: DrawTexture Return type: void Description: Draw a Texture2D @@ -3194,14 +3264,14 @@ Function 356: DrawTexture() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: tint (type: Color) -Function 357: DrawTextureV() (3 input parameters) +Function 365: DrawTextureV() (3 input parameters) Name: DrawTextureV Return type: void Description: Draw a Texture2D with position defined as Vector2 Param[1]: texture (type: Texture2D) Param[2]: position (type: Vector2) Param[3]: tint (type: Color) -Function 358: DrawTextureEx() (5 input parameters) +Function 366: DrawTextureEx() (5 input parameters) Name: DrawTextureEx Return type: void Description: Draw a Texture2D with extended parameters @@ -3210,7 +3280,7 @@ Function 358: DrawTextureEx() (5 input parameters) Param[3]: rotation (type: float) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 359: DrawTextureRec() (4 input parameters) +Function 367: DrawTextureRec() (4 input parameters) Name: DrawTextureRec Return type: void Description: Draw a part of a texture defined by a rectangle @@ -3218,7 +3288,7 @@ Function 359: DrawTextureRec() (4 input parameters) Param[2]: source (type: Rectangle) Param[3]: position (type: Vector2) Param[4]: tint (type: Color) -Function 360: DrawTexturePro() (6 input parameters) +Function 368: DrawTexturePro() (6 input parameters) Name: DrawTexturePro Return type: void Description: Draw a part of a texture defined by a rectangle with 'pro' parameters @@ -3228,7 +3298,7 @@ Function 360: DrawTexturePro() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 361: DrawTextureNPatch() (6 input parameters) +Function 369: DrawTextureNPatch() (6 input parameters) Name: DrawTextureNPatch Return type: void Description: Draws a texture (or part of it) that stretches or shrinks nicely @@ -3238,127 +3308,134 @@ Function 361: DrawTextureNPatch() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 362: ColorIsEqual() (2 input parameters) +Function 370: ColorIsEqual() (2 input parameters) Name: ColorIsEqual Return type: bool Description: Check if two colors are equal Param[1]: col1 (type: Color) Param[2]: col2 (type: Color) -Function 363: Fade() (2 input parameters) +Function 371: Fade() (2 input parameters) Name: Fade Return type: Color Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f Param[1]: color (type: Color) Param[2]: alpha (type: float) -Function 364: ColorToInt() (1 input parameters) +Function 372: ColorToInt() (1 input parameters) Name: ColorToInt Return type: int Description: Get hexadecimal value for a Color (0xRRGGBBAA) Param[1]: color (type: Color) -Function 365: ColorNormalize() (1 input parameters) +Function 373: ColorNormalize() (1 input parameters) Name: ColorNormalize Return type: Vector4 Description: Get Color normalized as float [0..1] Param[1]: color (type: Color) -Function 366: ColorFromNormalized() (1 input parameters) +Function 374: ColorFromNormalized() (1 input parameters) Name: ColorFromNormalized Return type: Color Description: Get Color from normalized values [0..1] Param[1]: normalized (type: Vector4) -Function 367: ColorToHSV() (1 input parameters) +Function 375: ColorToHSV() (1 input parameters) Name: ColorToHSV Return type: Vector3 Description: Get HSV values for a Color, hue [0..360], saturation/value [0..1] Param[1]: color (type: Color) -Function 368: ColorFromHSV() (3 input parameters) +Function 376: ColorFromHSV() (3 input parameters) Name: ColorFromHSV Return type: Color Description: Get a Color from HSV values, hue [0..360], saturation/value [0..1] Param[1]: hue (type: float) Param[2]: saturation (type: float) Param[3]: value (type: float) -Function 369: ColorTint() (2 input parameters) +Function 377: ColorTint() (2 input parameters) Name: ColorTint Return type: Color Description: Get color multiplied with another color Param[1]: color (type: Color) Param[2]: tint (type: Color) -Function 370: ColorBrightness() (2 input parameters) +Function 378: ColorBrightness() (2 input parameters) Name: ColorBrightness Return type: Color Description: Get color with brightness correction, brightness factor goes from -1.0f to 1.0f Param[1]: color (type: Color) Param[2]: factor (type: float) -Function 371: ColorContrast() (2 input parameters) +Function 379: ColorContrast() (2 input parameters) Name: ColorContrast Return type: Color Description: Get color with contrast correction, contrast values between -1.0f and 1.0f Param[1]: color (type: Color) Param[2]: contrast (type: float) -Function 372: ColorAlpha() (2 input parameters) +Function 380: ColorAlpha() (2 input parameters) Name: ColorAlpha Return type: Color Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f Param[1]: color (type: Color) Param[2]: alpha (type: float) -Function 373: ColorAlphaBlend() (3 input parameters) +Function 381: ColorAlphaBlend() (3 input parameters) Name: ColorAlphaBlend Return type: Color Description: Get src alpha-blended into dst color with tint Param[1]: dst (type: Color) Param[2]: src (type: Color) Param[3]: tint (type: Color) -Function 374: GetColor() (1 input parameters) +Function 382: ColorLerp() (3 input parameters) + Name: ColorLerp + Return type: Color + Description: Get color lerp interpolation between two colors, factor [0.0f..1.0f] + Param[1]: color1 (type: Color) + Param[2]: color2 (type: Color) + Param[3]: factor (type: float) +Function 383: GetColor() (1 input parameters) Name: GetColor Return type: Color Description: Get Color structure from hexadecimal value Param[1]: hexValue (type: unsigned int) -Function 375: GetPixelColor() (2 input parameters) +Function 384: GetPixelColor() (2 input parameters) Name: GetPixelColor Return type: Color Description: Get Color from a source pixel pointer of certain format Param[1]: srcPtr (type: void *) Param[2]: format (type: int) -Function 376: SetPixelColor() (3 input parameters) +Function 385: SetPixelColor() (3 input parameters) Name: SetPixelColor Return type: void Description: Set color formatted into destination pixel pointer Param[1]: dstPtr (type: void *) Param[2]: color (type: Color) Param[3]: format (type: int) -Function 377: GetPixelDataSize() (3 input parameters) +Function 386: GetPixelDataSize() (3 input parameters) Name: GetPixelDataSize Return type: int Description: Get pixel data size in bytes for certain format Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: format (type: int) -Function 378: GetFontDefault() (0 input parameters) +Function 387: GetFontDefault() (0 input parameters) Name: GetFontDefault Return type: Font Description: Get the default Font No input parameters -Function 379: LoadFont() (1 input parameters) +Function 388: LoadFont() (1 input parameters) Name: LoadFont Return type: Font Description: Load font from file into GPU memory (VRAM) Param[1]: fileName (type: const char *) -Function 380: LoadFontEx() (4 input parameters) +Function 389: LoadFontEx() (4 input parameters) Name: LoadFontEx Return type: Font - Description: Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character setFont + Description: Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height Param[1]: fileName (type: const char *) Param[2]: fontSize (type: int) Param[3]: codepoints (type: int *) Param[4]: codepointCount (type: int) -Function 381: LoadFontFromImage() (3 input parameters) +Function 390: LoadFontFromImage() (3 input parameters) Name: LoadFontFromImage Return type: Font Description: Load font from Image (XNA style) Param[1]: image (type: Image) Param[2]: key (type: Color) Param[3]: firstChar (type: int) -Function 382: LoadFontFromMemory() (6 input parameters) +Function 391: LoadFontFromMemory() (6 input parameters) Name: LoadFontFromMemory Return type: Font Description: Load font from memory buffer, fileType refers to extension: i.e. '.ttf' @@ -3368,12 +3445,12 @@ Function 382: LoadFontFromMemory() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: codepoints (type: int *) Param[6]: codepointCount (type: int) -Function 383: IsFontReady() (1 input parameters) +Function 392: IsFontReady() (1 input parameters) Name: IsFontReady Return type: bool Description: Check if a font is ready Param[1]: font (type: Font) -Function 384: LoadFontData() (6 input parameters) +Function 393: LoadFontData() (6 input parameters) Name: LoadFontData Return type: GlyphInfo * Description: Load font data for further use @@ -3383,7 +3460,7 @@ Function 384: LoadFontData() (6 input parameters) Param[4]: codepoints (type: int *) Param[5]: codepointCount (type: int) Param[6]: type (type: int) -Function 385: GenImageFontAtlas() (6 input parameters) +Function 394: GenImageFontAtlas() (6 input parameters) Name: GenImageFontAtlas Return type: Image Description: Generate image font atlas using chars info @@ -3393,30 +3470,30 @@ Function 385: GenImageFontAtlas() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: padding (type: int) Param[6]: packMethod (type: int) -Function 386: UnloadFontData() (2 input parameters) +Function 395: UnloadFontData() (2 input parameters) Name: UnloadFontData Return type: void Description: Unload font chars info data (RAM) Param[1]: glyphs (type: GlyphInfo *) Param[2]: glyphCount (type: int) -Function 387: UnloadFont() (1 input parameters) +Function 396: UnloadFont() (1 input parameters) Name: UnloadFont Return type: void Description: Unload font from GPU memory (VRAM) Param[1]: font (type: Font) -Function 388: ExportFontAsCode() (2 input parameters) +Function 397: ExportFontAsCode() (2 input parameters) Name: ExportFontAsCode Return type: bool Description: Export font as code file, returns true on success Param[1]: font (type: Font) Param[2]: fileName (type: const char *) -Function 389: DrawFPS() (2 input parameters) +Function 398: DrawFPS() (2 input parameters) Name: DrawFPS Return type: void Description: Draw current FPS Param[1]: posX (type: int) Param[2]: posY (type: int) -Function 390: DrawText() (5 input parameters) +Function 399: DrawText() (5 input parameters) Name: DrawText Return type: void Description: Draw text (using default font) @@ -3425,7 +3502,7 @@ Function 390: DrawText() (5 input parameters) Param[3]: posY (type: int) Param[4]: fontSize (type: int) Param[5]: color (type: Color) -Function 391: DrawTextEx() (6 input parameters) +Function 400: DrawTextEx() (6 input parameters) Name: DrawTextEx Return type: void Description: Draw text using font and additional parameters @@ -3435,7 +3512,7 @@ Function 391: DrawTextEx() (6 input parameters) Param[4]: fontSize (type: float) Param[5]: spacing (type: float) Param[6]: tint (type: Color) -Function 392: DrawTextPro() (8 input parameters) +Function 401: DrawTextPro() (8 input parameters) Name: DrawTextPro Return type: void Description: Draw text using Font and pro parameters (rotation) @@ -3447,7 +3524,7 @@ Function 392: DrawTextPro() (8 input parameters) Param[6]: fontSize (type: float) Param[7]: spacing (type: float) Param[8]: tint (type: Color) -Function 393: DrawTextCodepoint() (5 input parameters) +Function 402: DrawTextCodepoint() (5 input parameters) Name: DrawTextCodepoint Return type: void Description: Draw one character (codepoint) @@ -3456,7 +3533,7 @@ Function 393: DrawTextCodepoint() (5 input parameters) Param[3]: position (type: Vector2) Param[4]: fontSize (type: float) Param[5]: tint (type: Color) -Function 394: DrawTextCodepoints() (7 input parameters) +Function 403: DrawTextCodepoints() (7 input parameters) Name: DrawTextCodepoints Return type: void Description: Draw multiple character (codepoint) @@ -3467,18 +3544,18 @@ Function 394: DrawTextCodepoints() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 395: SetTextLineSpacing() (1 input parameters) +Function 404: SetTextLineSpacing() (1 input parameters) Name: SetTextLineSpacing Return type: void Description: Set vertical line spacing when drawing with line-breaks Param[1]: spacing (type: int) -Function 396: MeasureText() (2 input parameters) +Function 405: MeasureText() (2 input parameters) Name: MeasureText Return type: int Description: Measure string width for default font Param[1]: text (type: const char *) Param[2]: fontSize (type: int) -Function 397: MeasureTextEx() (4 input parameters) +Function 406: MeasureTextEx() (4 input parameters) Name: MeasureTextEx Return type: Vector2 Description: Measure string size for Font @@ -3486,195 +3563,195 @@ Function 397: MeasureTextEx() (4 input parameters) Param[2]: text (type: const char *) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) -Function 398: GetGlyphIndex() (2 input parameters) +Function 407: GetGlyphIndex() (2 input parameters) Name: GetGlyphIndex Return type: int Description: Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 399: GetGlyphInfo() (2 input parameters) +Function 408: GetGlyphInfo() (2 input parameters) Name: GetGlyphInfo Return type: GlyphInfo Description: Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 400: GetGlyphAtlasRec() (2 input parameters) +Function 409: GetGlyphAtlasRec() (2 input parameters) Name: GetGlyphAtlasRec Return type: Rectangle Description: Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 401: LoadUTF8() (2 input parameters) +Function 410: LoadUTF8() (2 input parameters) Name: LoadUTF8 Return type: char * Description: Load UTF-8 text encoded from codepoints array Param[1]: codepoints (type: const int *) Param[2]: length (type: int) -Function 402: UnloadUTF8() (1 input parameters) +Function 411: UnloadUTF8() (1 input parameters) Name: UnloadUTF8 Return type: void Description: Unload UTF-8 text encoded from codepoints array Param[1]: text (type: char *) -Function 403: LoadCodepoints() (2 input parameters) +Function 412: LoadCodepoints() (2 input parameters) Name: LoadCodepoints Return type: int * Description: Load all codepoints from a UTF-8 text string, codepoints count returned by parameter Param[1]: text (type: const char *) Param[2]: count (type: int *) -Function 404: UnloadCodepoints() (1 input parameters) +Function 413: UnloadCodepoints() (1 input parameters) Name: UnloadCodepoints Return type: void Description: Unload codepoints data from memory Param[1]: codepoints (type: int *) -Function 405: GetCodepointCount() (1 input parameters) +Function 414: GetCodepointCount() (1 input parameters) Name: GetCodepointCount Return type: int Description: Get total number of codepoints in a UTF-8 encoded string Param[1]: text (type: const char *) -Function 406: GetCodepoint() (2 input parameters) +Function 415: GetCodepoint() (2 input parameters) Name: GetCodepoint Return type: int Description: Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 407: GetCodepointNext() (2 input parameters) +Function 416: GetCodepointNext() (2 input parameters) Name: GetCodepointNext Return type: int Description: Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 408: GetCodepointPrevious() (2 input parameters) +Function 417: GetCodepointPrevious() (2 input parameters) Name: GetCodepointPrevious Return type: int Description: Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 409: CodepointToUTF8() (2 input parameters) +Function 418: CodepointToUTF8() (2 input parameters) Name: CodepointToUTF8 Return type: const char * Description: Encode one codepoint into UTF-8 byte array (array length returned as parameter) Param[1]: codepoint (type: int) Param[2]: utf8Size (type: int *) -Function 410: TextCopy() (2 input parameters) +Function 419: TextCopy() (2 input parameters) Name: TextCopy Return type: int Description: Copy one string to another, returns bytes copied Param[1]: dst (type: char *) Param[2]: src (type: const char *) -Function 411: TextIsEqual() (2 input parameters) +Function 420: TextIsEqual() (2 input parameters) Name: TextIsEqual Return type: bool Description: Check if two text string are equal Param[1]: text1 (type: const char *) Param[2]: text2 (type: const char *) -Function 412: TextLength() (1 input parameters) +Function 421: TextLength() (1 input parameters) Name: TextLength Return type: unsigned int Description: Get text length, checks for '\0' ending Param[1]: text (type: const char *) -Function 413: TextFormat() (2 input parameters) +Function 422: TextFormat() (2 input parameters) Name: TextFormat Return type: const char * Description: Text formatting with variables (sprintf() style) Param[1]: text (type: const char *) Param[2]: args (type: ...) -Function 414: TextSubtext() (3 input parameters) +Function 423: TextSubtext() (3 input parameters) Name: TextSubtext Return type: const char * Description: Get a piece of a text string Param[1]: text (type: const char *) Param[2]: position (type: int) Param[3]: length (type: int) -Function 415: TextReplace() (3 input parameters) +Function 424: TextReplace() (3 input parameters) Name: TextReplace Return type: char * Description: Replace text string (WARNING: memory must be freed!) Param[1]: text (type: const char *) Param[2]: replace (type: const char *) Param[3]: by (type: const char *) -Function 416: TextInsert() (3 input parameters) +Function 425: TextInsert() (3 input parameters) Name: TextInsert Return type: char * Description: Insert text in a position (WARNING: memory must be freed!) Param[1]: text (type: const char *) Param[2]: insert (type: const char *) Param[3]: position (type: int) -Function 417: TextJoin() (3 input parameters) +Function 426: TextJoin() (3 input parameters) Name: TextJoin Return type: const char * Description: Join text strings with delimiter Param[1]: textList (type: const char **) Param[2]: count (type: int) Param[3]: delimiter (type: const char *) -Function 418: TextSplit() (3 input parameters) +Function 427: TextSplit() (3 input parameters) Name: TextSplit Return type: const char ** Description: Split text into multiple strings Param[1]: text (type: const char *) Param[2]: delimiter (type: char) Param[3]: count (type: int *) -Function 419: TextAppend() (3 input parameters) +Function 428: TextAppend() (3 input parameters) Name: TextAppend Return type: void Description: Append text at specific position and move cursor! Param[1]: text (type: char *) Param[2]: append (type: const char *) Param[3]: position (type: int *) -Function 420: TextFindIndex() (2 input parameters) +Function 429: TextFindIndex() (2 input parameters) Name: TextFindIndex Return type: int Description: Find first text occurrence within a string Param[1]: text (type: const char *) Param[2]: find (type: const char *) -Function 421: TextToUpper() (1 input parameters) +Function 430: TextToUpper() (1 input parameters) Name: TextToUpper Return type: const char * Description: Get upper case version of provided string Param[1]: text (type: const char *) -Function 422: TextToLower() (1 input parameters) +Function 431: TextToLower() (1 input parameters) Name: TextToLower Return type: const char * Description: Get lower case version of provided string Param[1]: text (type: const char *) -Function 423: TextToPascal() (1 input parameters) +Function 432: TextToPascal() (1 input parameters) Name: TextToPascal Return type: const char * Description: Get Pascal case notation version of provided string Param[1]: text (type: const char *) -Function 424: TextToSnake() (1 input parameters) +Function 433: TextToSnake() (1 input parameters) Name: TextToSnake Return type: const char * Description: Get Snake case notation version of provided string Param[1]: text (type: const char *) -Function 425: TextToCamel() (1 input parameters) +Function 434: TextToCamel() (1 input parameters) Name: TextToCamel Return type: const char * Description: Get Camel case notation version of provided string Param[1]: text (type: const char *) -Function 426: TextToInteger() (1 input parameters) +Function 435: TextToInteger() (1 input parameters) Name: TextToInteger Return type: int Description: Get integer value from text (negative values not supported) Param[1]: text (type: const char *) -Function 427: TextToFloat() (1 input parameters) +Function 436: TextToFloat() (1 input parameters) Name: TextToFloat Return type: float Description: Get float value from text (negative values not supported) Param[1]: text (type: const char *) -Function 428: DrawLine3D() (3 input parameters) +Function 437: DrawLine3D() (3 input parameters) Name: DrawLine3D Return type: void Description: Draw a line in 3D world space Param[1]: startPos (type: Vector3) Param[2]: endPos (type: Vector3) Param[3]: color (type: Color) -Function 429: DrawPoint3D() (2 input parameters) +Function 438: DrawPoint3D() (2 input parameters) Name: DrawPoint3D Return type: void Description: Draw a point in 3D space, actually a small line Param[1]: position (type: Vector3) Param[2]: color (type: Color) -Function 430: DrawCircle3D() (5 input parameters) +Function 439: DrawCircle3D() (5 input parameters) Name: DrawCircle3D Return type: void Description: Draw a circle in 3D world space @@ -3683,7 +3760,7 @@ Function 430: DrawCircle3D() (5 input parameters) Param[3]: rotationAxis (type: Vector3) Param[4]: rotationAngle (type: float) Param[5]: color (type: Color) -Function 431: DrawTriangle3D() (4 input parameters) +Function 440: DrawTriangle3D() (4 input parameters) Name: DrawTriangle3D Return type: void Description: Draw a color-filled triangle (vertex in counter-clockwise order!) @@ -3691,14 +3768,14 @@ Function 431: DrawTriangle3D() (4 input parameters) Param[2]: v2 (type: Vector3) Param[3]: v3 (type: Vector3) Param[4]: color (type: Color) -Function 432: DrawTriangleStrip3D() (3 input parameters) +Function 441: DrawTriangleStrip3D() (3 input parameters) Name: DrawTriangleStrip3D Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector3 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 433: DrawCube() (5 input parameters) +Function 442: DrawCube() (5 input parameters) Name: DrawCube Return type: void Description: Draw cube @@ -3707,14 +3784,14 @@ Function 433: DrawCube() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 434: DrawCubeV() (3 input parameters) +Function 443: DrawCubeV() (3 input parameters) Name: DrawCubeV Return type: void Description: Draw cube (Vector version) Param[1]: position (type: Vector3) Param[2]: size (type: Vector3) Param[3]: color (type: Color) -Function 435: DrawCubeWires() (5 input parameters) +Function 444: DrawCubeWires() (5 input parameters) Name: DrawCubeWires Return type: void Description: Draw cube wires @@ -3723,21 +3800,21 @@ Function 435: DrawCubeWires() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 436: DrawCubeWiresV() (3 input parameters) +Function 445: DrawCubeWiresV() (3 input parameters) Name: DrawCubeWiresV Return type: void Description: Draw cube wires (Vector version) Param[1]: position (type: Vector3) Param[2]: size (type: Vector3) Param[3]: color (type: Color) -Function 437: DrawSphere() (3 input parameters) +Function 446: DrawSphere() (3 input parameters) Name: DrawSphere Return type: void Description: Draw sphere Param[1]: centerPos (type: Vector3) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 438: DrawSphereEx() (5 input parameters) +Function 447: DrawSphereEx() (5 input parameters) Name: DrawSphereEx Return type: void Description: Draw sphere with extended parameters @@ -3746,7 +3823,7 @@ Function 438: DrawSphereEx() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 439: DrawSphereWires() (5 input parameters) +Function 448: DrawSphereWires() (5 input parameters) Name: DrawSphereWires Return type: void Description: Draw sphere wires @@ -3755,7 +3832,7 @@ Function 439: DrawSphereWires() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 440: DrawCylinder() (6 input parameters) +Function 449: DrawCylinder() (6 input parameters) Name: DrawCylinder Return type: void Description: Draw a cylinder/cone @@ -3765,7 +3842,7 @@ Function 440: DrawCylinder() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 441: DrawCylinderEx() (6 input parameters) +Function 450: DrawCylinderEx() (6 input parameters) Name: DrawCylinderEx Return type: void Description: Draw a cylinder with base at startPos and top at endPos @@ -3775,7 +3852,7 @@ Function 441: DrawCylinderEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 442: DrawCylinderWires() (6 input parameters) +Function 451: DrawCylinderWires() (6 input parameters) Name: DrawCylinderWires Return type: void Description: Draw a cylinder/cone wires @@ -3785,7 +3862,7 @@ Function 442: DrawCylinderWires() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 443: DrawCylinderWiresEx() (6 input parameters) +Function 452: DrawCylinderWiresEx() (6 input parameters) Name: DrawCylinderWiresEx Return type: void Description: Draw a cylinder wires with base at startPos and top at endPos @@ -3795,7 +3872,7 @@ Function 443: DrawCylinderWiresEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 444: DrawCapsule() (6 input parameters) +Function 453: DrawCapsule() (6 input parameters) Name: DrawCapsule Return type: void Description: Draw a capsule with the center of its sphere caps at startPos and endPos @@ -3805,7 +3882,7 @@ Function 444: DrawCapsule() (6 input parameters) Param[4]: slices (type: int) Param[5]: rings (type: int) Param[6]: color (type: Color) -Function 445: DrawCapsuleWires() (6 input parameters) +Function 454: DrawCapsuleWires() (6 input parameters) Name: DrawCapsuleWires Return type: void Description: Draw capsule wireframe with the center of its sphere caps at startPos and endPos @@ -3815,51 +3892,51 @@ Function 445: DrawCapsuleWires() (6 input parameters) Param[4]: slices (type: int) Param[5]: rings (type: int) Param[6]: color (type: Color) -Function 446: DrawPlane() (3 input parameters) +Function 455: DrawPlane() (3 input parameters) Name: DrawPlane Return type: void Description: Draw a plane XZ Param[1]: centerPos (type: Vector3) Param[2]: size (type: Vector2) Param[3]: color (type: Color) -Function 447: DrawRay() (2 input parameters) +Function 456: DrawRay() (2 input parameters) Name: DrawRay Return type: void Description: Draw a ray line Param[1]: ray (type: Ray) Param[2]: color (type: Color) -Function 448: DrawGrid() (2 input parameters) +Function 457: DrawGrid() (2 input parameters) Name: DrawGrid Return type: void Description: Draw a grid (centered at (0, 0, 0)) Param[1]: slices (type: int) Param[2]: spacing (type: float) -Function 449: LoadModel() (1 input parameters) +Function 458: LoadModel() (1 input parameters) Name: LoadModel Return type: Model Description: Load model from files (meshes and materials) Param[1]: fileName (type: const char *) -Function 450: LoadModelFromMesh() (1 input parameters) +Function 459: LoadModelFromMesh() (1 input parameters) Name: LoadModelFromMesh Return type: Model Description: Load model from generated mesh (default material) Param[1]: mesh (type: Mesh) -Function 451: IsModelReady() (1 input parameters) +Function 460: IsModelReady() (1 input parameters) Name: IsModelReady Return type: bool Description: Check if a model is ready Param[1]: model (type: Model) -Function 452: UnloadModel() (1 input parameters) +Function 461: UnloadModel() (1 input parameters) Name: UnloadModel Return type: void Description: Unload model (including meshes) from memory (RAM and/or VRAM) Param[1]: model (type: Model) -Function 453: GetModelBoundingBox() (1 input parameters) +Function 462: GetModelBoundingBox() (1 input parameters) Name: GetModelBoundingBox Return type: BoundingBox Description: Compute model bounding box limits (considers all meshes) Param[1]: model (type: Model) -Function 454: DrawModel() (4 input parameters) +Function 463: DrawModel() (4 input parameters) Name: DrawModel Return type: void Description: Draw a model (with texture if set) @@ -3867,7 +3944,7 @@ Function 454: DrawModel() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 455: DrawModelEx() (6 input parameters) +Function 464: DrawModelEx() (6 input parameters) Name: DrawModelEx Return type: void Description: Draw a model with extended parameters @@ -3877,7 +3954,7 @@ Function 455: DrawModelEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 456: DrawModelWires() (4 input parameters) +Function 465: DrawModelWires() (4 input parameters) Name: DrawModelWires Return type: void Description: Draw a model wires (with texture if set) @@ -3885,7 +3962,7 @@ Function 456: DrawModelWires() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 457: DrawModelWiresEx() (6 input parameters) +Function 466: DrawModelWiresEx() (6 input parameters) Name: DrawModelWiresEx Return type: void Description: Draw a model wires (with texture if set) with extended parameters @@ -3895,22 +3972,40 @@ Function 457: DrawModelWiresEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 458: DrawBoundingBox() (2 input parameters) +Function 467: DrawModelPoints() (4 input parameters) + Name: DrawModelPoints + Return type: void + Description: Draw a model as points + Param[1]: model (type: Model) + Param[2]: position (type: Vector3) + Param[3]: scale (type: float) + Param[4]: tint (type: Color) +Function 468: DrawModelPointsEx() (6 input parameters) + Name: DrawModelPointsEx + Return type: void + Description: Draw a model as points with extended parameters + Param[1]: model (type: Model) + Param[2]: position (type: Vector3) + Param[3]: rotationAxis (type: Vector3) + Param[4]: rotationAngle (type: float) + Param[5]: scale (type: Vector3) + Param[6]: tint (type: Color) +Function 469: DrawBoundingBox() (2 input parameters) Name: DrawBoundingBox Return type: void Description: Draw bounding box (wires) Param[1]: box (type: BoundingBox) Param[2]: color (type: Color) -Function 459: DrawBillboard() (5 input parameters) +Function 470: DrawBillboard() (5 input parameters) Name: DrawBillboard Return type: void Description: Draw a billboard texture Param[1]: camera (type: Camera) Param[2]: texture (type: Texture2D) Param[3]: position (type: Vector3) - Param[4]: size (type: float) + Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 460: DrawBillboardRec() (6 input parameters) +Function 471: DrawBillboardRec() (6 input parameters) Name: DrawBillboardRec Return type: void Description: Draw a billboard texture defined by source @@ -3920,7 +4015,7 @@ Function 460: DrawBillboardRec() (6 input parameters) Param[4]: position (type: Vector3) Param[5]: size (type: Vector2) Param[6]: tint (type: Color) -Function 461: DrawBillboardPro() (9 input parameters) +Function 472: DrawBillboardPro() (9 input parameters) Name: DrawBillboardPro Return type: void Description: Draw a billboard texture defined by source and rotation @@ -3933,13 +4028,13 @@ Function 461: DrawBillboardPro() (9 input parameters) Param[7]: origin (type: Vector2) Param[8]: rotation (type: float) Param[9]: tint (type: Color) -Function 462: UploadMesh() (2 input parameters) +Function 473: UploadMesh() (2 input parameters) Name: UploadMesh Return type: void Description: Upload mesh vertex data in GPU and provide VAO/VBO ids Param[1]: mesh (type: Mesh *) Param[2]: dynamic (type: bool) -Function 463: UpdateMeshBuffer() (5 input parameters) +Function 474: UpdateMeshBuffer() (5 input parameters) Name: UpdateMeshBuffer Return type: void Description: Update mesh vertex data in GPU for a specific buffer index @@ -3948,19 +4043,19 @@ Function 463: UpdateMeshBuffer() (5 input parameters) Param[3]: data (type: const void *) Param[4]: dataSize (type: int) Param[5]: offset (type: int) -Function 464: UnloadMesh() (1 input parameters) +Function 475: UnloadMesh() (1 input parameters) Name: UnloadMesh Return type: void Description: Unload mesh data from CPU and GPU Param[1]: mesh (type: Mesh) -Function 465: DrawMesh() (3 input parameters) +Function 476: DrawMesh() (3 input parameters) Name: DrawMesh Return type: void Description: Draw a 3d mesh with material and transform Param[1]: mesh (type: Mesh) Param[2]: material (type: Material) Param[3]: transform (type: Matrix) -Function 466: DrawMeshInstanced() (4 input parameters) +Function 477: DrawMeshInstanced() (4 input parameters) Name: DrawMeshInstanced Return type: void Description: Draw multiple mesh instances with material and different transforms @@ -3968,35 +4063,35 @@ Function 466: DrawMeshInstanced() (4 input parameters) Param[2]: material (type: Material) Param[3]: transforms (type: const Matrix *) Param[4]: instances (type: int) -Function 467: GetMeshBoundingBox() (1 input parameters) +Function 478: GetMeshBoundingBox() (1 input parameters) Name: GetMeshBoundingBox Return type: BoundingBox Description: Compute mesh bounding box limits Param[1]: mesh (type: Mesh) -Function 468: GenMeshTangents() (1 input parameters) +Function 479: GenMeshTangents() (1 input parameters) Name: GenMeshTangents Return type: void Description: Compute mesh tangents Param[1]: mesh (type: Mesh *) -Function 469: ExportMesh() (2 input parameters) +Function 480: ExportMesh() (2 input parameters) Name: ExportMesh Return type: bool Description: Export mesh data to file, returns true on success Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 470: ExportMeshAsCode() (2 input parameters) +Function 481: ExportMeshAsCode() (2 input parameters) Name: ExportMeshAsCode Return type: bool Description: Export mesh as code file (.h) defining multiple arrays of vertex attributes Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 471: GenMeshPoly() (2 input parameters) +Function 482: GenMeshPoly() (2 input parameters) Name: GenMeshPoly Return type: Mesh Description: Generate polygonal mesh Param[1]: sides (type: int) Param[2]: radius (type: float) -Function 472: GenMeshPlane() (4 input parameters) +Function 483: GenMeshPlane() (4 input parameters) Name: GenMeshPlane Return type: Mesh Description: Generate plane mesh (with subdivisions) @@ -4004,42 +4099,42 @@ Function 472: GenMeshPlane() (4 input parameters) Param[2]: length (type: float) Param[3]: resX (type: int) Param[4]: resZ (type: int) -Function 473: GenMeshCube() (3 input parameters) +Function 484: GenMeshCube() (3 input parameters) Name: GenMeshCube Return type: Mesh Description: Generate cuboid mesh Param[1]: width (type: float) Param[2]: height (type: float) Param[3]: length (type: float) -Function 474: GenMeshSphere() (3 input parameters) +Function 485: GenMeshSphere() (3 input parameters) Name: GenMeshSphere Return type: Mesh Description: Generate sphere mesh (standard sphere) Param[1]: radius (type: float) Param[2]: rings (type: int) Param[3]: slices (type: int) -Function 475: GenMeshHemiSphere() (3 input parameters) +Function 486: GenMeshHemiSphere() (3 input parameters) Name: GenMeshHemiSphere Return type: Mesh Description: Generate half-sphere mesh (no bottom cap) Param[1]: radius (type: float) Param[2]: rings (type: int) Param[3]: slices (type: int) -Function 476: GenMeshCylinder() (3 input parameters) +Function 487: GenMeshCylinder() (3 input parameters) Name: GenMeshCylinder Return type: Mesh Description: Generate cylinder mesh Param[1]: radius (type: float) Param[2]: height (type: float) Param[3]: slices (type: int) -Function 477: GenMeshCone() (3 input parameters) +Function 488: GenMeshCone() (3 input parameters) Name: GenMeshCone Return type: Mesh Description: Generate cone/pyramid mesh Param[1]: radius (type: float) Param[2]: height (type: float) Param[3]: slices (type: int) -Function 478: GenMeshTorus() (4 input parameters) +Function 489: GenMeshTorus() (4 input parameters) Name: GenMeshTorus Return type: Mesh Description: Generate torus mesh @@ -4047,7 +4142,7 @@ Function 478: GenMeshTorus() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 479: GenMeshKnot() (4 input parameters) +Function 490: GenMeshKnot() (4 input parameters) Name: GenMeshKnot Return type: Mesh Description: Generate trefoil knot mesh @@ -4055,84 +4150,91 @@ Function 479: GenMeshKnot() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 480: GenMeshHeightmap() (2 input parameters) +Function 491: GenMeshHeightmap() (2 input parameters) Name: GenMeshHeightmap Return type: Mesh Description: Generate heightmap mesh from image data Param[1]: heightmap (type: Image) Param[2]: size (type: Vector3) -Function 481: GenMeshCubicmap() (2 input parameters) +Function 492: GenMeshCubicmap() (2 input parameters) Name: GenMeshCubicmap Return type: Mesh Description: Generate cubes-based map mesh from image data Param[1]: cubicmap (type: Image) Param[2]: cubeSize (type: Vector3) -Function 482: LoadMaterials() (2 input parameters) +Function 493: LoadMaterials() (2 input parameters) Name: LoadMaterials Return type: Material * Description: Load materials from model file Param[1]: fileName (type: const char *) Param[2]: materialCount (type: int *) -Function 483: LoadMaterialDefault() (0 input parameters) +Function 494: LoadMaterialDefault() (0 input parameters) Name: LoadMaterialDefault Return type: Material Description: Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) No input parameters -Function 484: IsMaterialReady() (1 input parameters) +Function 495: IsMaterialReady() (1 input parameters) Name: IsMaterialReady Return type: bool Description: Check if a material is ready Param[1]: material (type: Material) -Function 485: UnloadMaterial() (1 input parameters) +Function 496: UnloadMaterial() (1 input parameters) Name: UnloadMaterial Return type: void Description: Unload material from GPU memory (VRAM) Param[1]: material (type: Material) -Function 486: SetMaterialTexture() (3 input parameters) +Function 497: SetMaterialTexture() (3 input parameters) Name: SetMaterialTexture Return type: void Description: Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) Param[1]: material (type: Material *) Param[2]: mapType (type: int) Param[3]: texture (type: Texture2D) -Function 487: SetModelMeshMaterial() (3 input parameters) +Function 498: SetModelMeshMaterial() (3 input parameters) Name: SetModelMeshMaterial Return type: void Description: Set material for a mesh Param[1]: model (type: Model *) Param[2]: meshId (type: int) Param[3]: materialId (type: int) -Function 488: LoadModelAnimations() (2 input parameters) +Function 499: LoadModelAnimations() (2 input parameters) Name: LoadModelAnimations Return type: ModelAnimation * Description: Load model animations from file Param[1]: fileName (type: const char *) Param[2]: animCount (type: int *) -Function 489: UpdateModelAnimation() (3 input parameters) +Function 500: UpdateModelAnimation() (3 input parameters) Name: UpdateModelAnimation Return type: void Description: Update model animation pose Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) Param[3]: frame (type: int) -Function 490: UnloadModelAnimation() (1 input parameters) +Function 501: UnloadModelAnimation() (1 input parameters) Name: UnloadModelAnimation Return type: void Description: Unload animation data Param[1]: anim (type: ModelAnimation) -Function 491: UnloadModelAnimations() (2 input parameters) +Function 502: UnloadModelAnimations() (2 input parameters) Name: UnloadModelAnimations Return type: void Description: Unload animation array data Param[1]: animations (type: ModelAnimation *) Param[2]: animCount (type: int) -Function 492: IsModelAnimationValid() (2 input parameters) +Function 503: IsModelAnimationValid() (2 input parameters) Name: IsModelAnimationValid Return type: bool Description: Check model animation skeleton match Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) -Function 493: CheckCollisionSpheres() (4 input parameters) +Function 504: UpdateModelAnimationBoneMatrices() (3 input parameters) + Name: UpdateModelAnimationBoneMatrices + Return type: void + Description: Update model animation mesh bone matrices (Note GPU skinning does not work on Mac) + Param[1]: model (type: Model) + Param[2]: anim (type: ModelAnimation) + Param[3]: frame (type: int) +Function 505: CheckCollisionSpheres() (4 input parameters) Name: CheckCollisionSpheres Return type: bool Description: Check collision between two spheres @@ -4140,40 +4242,40 @@ Function 493: CheckCollisionSpheres() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector3) Param[4]: radius2 (type: float) -Function 494: CheckCollisionBoxes() (2 input parameters) +Function 506: CheckCollisionBoxes() (2 input parameters) Name: CheckCollisionBoxes Return type: bool Description: Check collision between two bounding boxes Param[1]: box1 (type: BoundingBox) Param[2]: box2 (type: BoundingBox) -Function 495: CheckCollisionBoxSphere() (3 input parameters) +Function 507: CheckCollisionBoxSphere() (3 input parameters) Name: CheckCollisionBoxSphere Return type: bool Description: Check collision between box and sphere Param[1]: box (type: BoundingBox) Param[2]: center (type: Vector3) Param[3]: radius (type: float) -Function 496: GetRayCollisionSphere() (3 input parameters) +Function 508: GetRayCollisionSphere() (3 input parameters) Name: GetRayCollisionSphere Return type: RayCollision Description: Get collision info between ray and sphere Param[1]: ray (type: Ray) Param[2]: center (type: Vector3) Param[3]: radius (type: float) -Function 497: GetRayCollisionBox() (2 input parameters) +Function 509: GetRayCollisionBox() (2 input parameters) Name: GetRayCollisionBox Return type: RayCollision Description: Get collision info between ray and box Param[1]: ray (type: Ray) Param[2]: box (type: BoundingBox) -Function 498: GetRayCollisionMesh() (3 input parameters) +Function 510: GetRayCollisionMesh() (3 input parameters) Name: GetRayCollisionMesh Return type: RayCollision Description: Get collision info between ray and mesh Param[1]: ray (type: Ray) Param[2]: mesh (type: Mesh) Param[3]: transform (type: Matrix) -Function 499: GetRayCollisionTriangle() (4 input parameters) +Function 511: GetRayCollisionTriangle() (4 input parameters) Name: GetRayCollisionTriangle Return type: RayCollision Description: Get collision info between ray and triangle @@ -4181,7 +4283,7 @@ Function 499: GetRayCollisionTriangle() (4 input parameters) Param[2]: p1 (type: Vector3) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) -Function 500: GetRayCollisionQuad() (5 input parameters) +Function 512: GetRayCollisionQuad() (5 input parameters) Name: GetRayCollisionQuad Return type: RayCollision Description: Get collision info between ray and quad @@ -4190,158 +4292,158 @@ Function 500: GetRayCollisionQuad() (5 input parameters) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) Param[5]: p4 (type: Vector3) -Function 501: InitAudioDevice() (0 input parameters) +Function 513: InitAudioDevice() (0 input parameters) Name: InitAudioDevice Return type: void Description: Initialize audio device and context No input parameters -Function 502: CloseAudioDevice() (0 input parameters) +Function 514: CloseAudioDevice() (0 input parameters) Name: CloseAudioDevice Return type: void Description: Close the audio device and context No input parameters -Function 503: IsAudioDeviceReady() (0 input parameters) +Function 515: IsAudioDeviceReady() (0 input parameters) Name: IsAudioDeviceReady Return type: bool Description: Check if audio device has been initialized successfully No input parameters -Function 504: SetMasterVolume() (1 input parameters) +Function 516: SetMasterVolume() (1 input parameters) Name: SetMasterVolume Return type: void Description: Set master volume (listener) Param[1]: volume (type: float) -Function 505: GetMasterVolume() (0 input parameters) +Function 517: GetMasterVolume() (0 input parameters) Name: GetMasterVolume Return type: float Description: Get master volume (listener) No input parameters -Function 506: LoadWave() (1 input parameters) +Function 518: LoadWave() (1 input parameters) Name: LoadWave Return type: Wave Description: Load wave data from file Param[1]: fileName (type: const char *) -Function 507: LoadWaveFromMemory() (3 input parameters) +Function 519: LoadWaveFromMemory() (3 input parameters) Name: LoadWaveFromMemory Return type: Wave Description: Load wave from memory buffer, fileType refers to extension: i.e. '.wav' Param[1]: fileType (type: const char *) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 508: IsWaveReady() (1 input parameters) +Function 520: IsWaveReady() (1 input parameters) Name: IsWaveReady Return type: bool Description: Checks if wave data is ready Param[1]: wave (type: Wave) -Function 509: LoadSound() (1 input parameters) +Function 521: LoadSound() (1 input parameters) Name: LoadSound Return type: Sound Description: Load sound from file Param[1]: fileName (type: const char *) -Function 510: LoadSoundFromWave() (1 input parameters) +Function 522: LoadSoundFromWave() (1 input parameters) Name: LoadSoundFromWave Return type: Sound Description: Load sound from wave data Param[1]: wave (type: Wave) -Function 511: LoadSoundAlias() (1 input parameters) +Function 523: LoadSoundAlias() (1 input parameters) Name: LoadSoundAlias Return type: Sound Description: Create a new sound that shares the same sample data as the source sound, does not own the sound data Param[1]: source (type: Sound) -Function 512: IsSoundReady() (1 input parameters) +Function 524: IsSoundReady() (1 input parameters) Name: IsSoundReady Return type: bool Description: Checks if a sound is ready Param[1]: sound (type: Sound) -Function 513: UpdateSound() (3 input parameters) +Function 525: UpdateSound() (3 input parameters) Name: UpdateSound Return type: void Description: Update sound buffer with new data Param[1]: sound (type: Sound) Param[2]: data (type: const void *) Param[3]: sampleCount (type: int) -Function 514: UnloadWave() (1 input parameters) +Function 526: UnloadWave() (1 input parameters) Name: UnloadWave Return type: void Description: Unload wave data Param[1]: wave (type: Wave) -Function 515: UnloadSound() (1 input parameters) +Function 527: UnloadSound() (1 input parameters) Name: UnloadSound Return type: void Description: Unload sound Param[1]: sound (type: Sound) -Function 516: UnloadSoundAlias() (1 input parameters) +Function 528: UnloadSoundAlias() (1 input parameters) Name: UnloadSoundAlias Return type: void Description: Unload a sound alias (does not deallocate sample data) Param[1]: alias (type: Sound) -Function 517: ExportWave() (2 input parameters) +Function 529: ExportWave() (2 input parameters) Name: ExportWave Return type: bool Description: Export wave data to file, returns true on success Param[1]: wave (type: Wave) Param[2]: fileName (type: const char *) -Function 518: ExportWaveAsCode() (2 input parameters) +Function 530: ExportWaveAsCode() (2 input parameters) Name: ExportWaveAsCode Return type: bool Description: Export wave sample data to code (.h), returns true on success Param[1]: wave (type: Wave) Param[2]: fileName (type: const char *) -Function 519: PlaySound() (1 input parameters) +Function 531: PlaySound() (1 input parameters) Name: PlaySound Return type: void Description: Play a sound Param[1]: sound (type: Sound) -Function 520: StopSound() (1 input parameters) +Function 532: StopSound() (1 input parameters) Name: StopSound Return type: void Description: Stop playing a sound Param[1]: sound (type: Sound) -Function 521: PauseSound() (1 input parameters) +Function 533: PauseSound() (1 input parameters) Name: PauseSound Return type: void Description: Pause a sound Param[1]: sound (type: Sound) -Function 522: ResumeSound() (1 input parameters) +Function 534: ResumeSound() (1 input parameters) Name: ResumeSound Return type: void Description: Resume a paused sound Param[1]: sound (type: Sound) -Function 523: IsSoundPlaying() (1 input parameters) +Function 535: IsSoundPlaying() (1 input parameters) Name: IsSoundPlaying Return type: bool Description: Check if a sound is currently playing Param[1]: sound (type: Sound) -Function 524: SetSoundVolume() (2 input parameters) +Function 536: SetSoundVolume() (2 input parameters) Name: SetSoundVolume Return type: void Description: Set volume for a sound (1.0 is max level) Param[1]: sound (type: Sound) Param[2]: volume (type: float) -Function 525: SetSoundPitch() (2 input parameters) +Function 537: SetSoundPitch() (2 input parameters) Name: SetSoundPitch Return type: void Description: Set pitch for a sound (1.0 is base level) Param[1]: sound (type: Sound) Param[2]: pitch (type: float) -Function 526: SetSoundPan() (2 input parameters) +Function 538: SetSoundPan() (2 input parameters) Name: SetSoundPan Return type: void Description: Set pan for a sound (0.5 is center) Param[1]: sound (type: Sound) Param[2]: pan (type: float) -Function 527: WaveCopy() (1 input parameters) +Function 539: WaveCopy() (1 input parameters) Name: WaveCopy Return type: Wave Description: Copy a wave to a new wave Param[1]: wave (type: Wave) -Function 528: WaveCrop() (3 input parameters) +Function 540: WaveCrop() (3 input parameters) Name: WaveCrop Return type: void Description: Crop a wave to defined frames range Param[1]: wave (type: Wave *) Param[2]: initFrame (type: int) Param[3]: finalFrame (type: int) -Function 529: WaveFormat() (4 input parameters) +Function 541: WaveFormat() (4 input parameters) Name: WaveFormat Return type: void Description: Convert wave data to desired format @@ -4349,203 +4451,203 @@ Function 529: WaveFormat() (4 input parameters) Param[2]: sampleRate (type: int) Param[3]: sampleSize (type: int) Param[4]: channels (type: int) -Function 530: LoadWaveSamples() (1 input parameters) +Function 542: LoadWaveSamples() (1 input parameters) Name: LoadWaveSamples Return type: float * Description: Load samples data from wave as a 32bit float data array Param[1]: wave (type: Wave) -Function 531: UnloadWaveSamples() (1 input parameters) +Function 543: UnloadWaveSamples() (1 input parameters) Name: UnloadWaveSamples Return type: void Description: Unload samples data loaded with LoadWaveSamples() Param[1]: samples (type: float *) -Function 532: LoadMusicStream() (1 input parameters) +Function 544: LoadMusicStream() (1 input parameters) Name: LoadMusicStream Return type: Music Description: Load music stream from file Param[1]: fileName (type: const char *) -Function 533: LoadMusicStreamFromMemory() (3 input parameters) +Function 545: LoadMusicStreamFromMemory() (3 input parameters) Name: LoadMusicStreamFromMemory Return type: Music Description: Load music stream from data Param[1]: fileType (type: const char *) Param[2]: data (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 534: IsMusicReady() (1 input parameters) +Function 546: IsMusicReady() (1 input parameters) Name: IsMusicReady Return type: bool Description: Checks if a music stream is ready Param[1]: music (type: Music) -Function 535: UnloadMusicStream() (1 input parameters) +Function 547: UnloadMusicStream() (1 input parameters) Name: UnloadMusicStream Return type: void Description: Unload music stream Param[1]: music (type: Music) -Function 536: PlayMusicStream() (1 input parameters) +Function 548: PlayMusicStream() (1 input parameters) Name: PlayMusicStream Return type: void Description: Start music playing Param[1]: music (type: Music) -Function 537: IsMusicStreamPlaying() (1 input parameters) +Function 549: IsMusicStreamPlaying() (1 input parameters) Name: IsMusicStreamPlaying Return type: bool Description: Check if music is playing Param[1]: music (type: Music) -Function 538: UpdateMusicStream() (1 input parameters) +Function 550: UpdateMusicStream() (1 input parameters) Name: UpdateMusicStream Return type: void Description: Updates buffers for music streaming Param[1]: music (type: Music) -Function 539: StopMusicStream() (1 input parameters) +Function 551: StopMusicStream() (1 input parameters) Name: StopMusicStream Return type: void Description: Stop music playing Param[1]: music (type: Music) -Function 540: PauseMusicStream() (1 input parameters) +Function 552: PauseMusicStream() (1 input parameters) Name: PauseMusicStream Return type: void Description: Pause music playing Param[1]: music (type: Music) -Function 541: ResumeMusicStream() (1 input parameters) +Function 553: ResumeMusicStream() (1 input parameters) Name: ResumeMusicStream Return type: void Description: Resume playing paused music Param[1]: music (type: Music) -Function 542: SeekMusicStream() (2 input parameters) +Function 554: SeekMusicStream() (2 input parameters) Name: SeekMusicStream Return type: void Description: Seek music to a position (in seconds) Param[1]: music (type: Music) Param[2]: position (type: float) -Function 543: SetMusicVolume() (2 input parameters) +Function 555: SetMusicVolume() (2 input parameters) Name: SetMusicVolume Return type: void Description: Set volume for music (1.0 is max level) Param[1]: music (type: Music) Param[2]: volume (type: float) -Function 544: SetMusicPitch() (2 input parameters) +Function 556: SetMusicPitch() (2 input parameters) Name: SetMusicPitch Return type: void Description: Set pitch for a music (1.0 is base level) Param[1]: music (type: Music) Param[2]: pitch (type: float) -Function 545: SetMusicPan() (2 input parameters) +Function 557: SetMusicPan() (2 input parameters) Name: SetMusicPan Return type: void Description: Set pan for a music (0.5 is center) Param[1]: music (type: Music) Param[2]: pan (type: float) -Function 546: GetMusicTimeLength() (1 input parameters) +Function 558: GetMusicTimeLength() (1 input parameters) Name: GetMusicTimeLength Return type: float Description: Get music time length (in seconds) Param[1]: music (type: Music) -Function 547: GetMusicTimePlayed() (1 input parameters) +Function 559: GetMusicTimePlayed() (1 input parameters) Name: GetMusicTimePlayed Return type: float Description: Get current music time played (in seconds) Param[1]: music (type: Music) -Function 548: LoadAudioStream() (3 input parameters) +Function 560: LoadAudioStream() (3 input parameters) Name: LoadAudioStream Return type: AudioStream Description: Load audio stream (to stream raw audio pcm data) Param[1]: sampleRate (type: unsigned int) Param[2]: sampleSize (type: unsigned int) Param[3]: channels (type: unsigned int) -Function 549: IsAudioStreamReady() (1 input parameters) +Function 561: IsAudioStreamReady() (1 input parameters) Name: IsAudioStreamReady Return type: bool Description: Checks if an audio stream is ready Param[1]: stream (type: AudioStream) -Function 550: UnloadAudioStream() (1 input parameters) +Function 562: UnloadAudioStream() (1 input parameters) Name: UnloadAudioStream Return type: void Description: Unload audio stream and free memory Param[1]: stream (type: AudioStream) -Function 551: UpdateAudioStream() (3 input parameters) +Function 563: UpdateAudioStream() (3 input parameters) Name: UpdateAudioStream Return type: void Description: Update audio stream buffers with data Param[1]: stream (type: AudioStream) Param[2]: data (type: const void *) Param[3]: frameCount (type: int) -Function 552: IsAudioStreamProcessed() (1 input parameters) +Function 564: IsAudioStreamProcessed() (1 input parameters) Name: IsAudioStreamProcessed Return type: bool Description: Check if any audio stream buffers requires refill Param[1]: stream (type: AudioStream) -Function 553: PlayAudioStream() (1 input parameters) +Function 565: PlayAudioStream() (1 input parameters) Name: PlayAudioStream Return type: void Description: Play audio stream Param[1]: stream (type: AudioStream) -Function 554: PauseAudioStream() (1 input parameters) +Function 566: PauseAudioStream() (1 input parameters) Name: PauseAudioStream Return type: void Description: Pause audio stream Param[1]: stream (type: AudioStream) -Function 555: ResumeAudioStream() (1 input parameters) +Function 567: ResumeAudioStream() (1 input parameters) Name: ResumeAudioStream Return type: void Description: Resume audio stream Param[1]: stream (type: AudioStream) -Function 556: IsAudioStreamPlaying() (1 input parameters) +Function 568: IsAudioStreamPlaying() (1 input parameters) Name: IsAudioStreamPlaying Return type: bool Description: Check if audio stream is playing Param[1]: stream (type: AudioStream) -Function 557: StopAudioStream() (1 input parameters) +Function 569: StopAudioStream() (1 input parameters) Name: StopAudioStream Return type: void Description: Stop audio stream Param[1]: stream (type: AudioStream) -Function 558: SetAudioStreamVolume() (2 input parameters) +Function 570: SetAudioStreamVolume() (2 input parameters) Name: SetAudioStreamVolume Return type: void Description: Set volume for audio stream (1.0 is max level) Param[1]: stream (type: AudioStream) Param[2]: volume (type: float) -Function 559: SetAudioStreamPitch() (2 input parameters) +Function 571: SetAudioStreamPitch() (2 input parameters) Name: SetAudioStreamPitch Return type: void Description: Set pitch for audio stream (1.0 is base level) Param[1]: stream (type: AudioStream) Param[2]: pitch (type: float) -Function 560: SetAudioStreamPan() (2 input parameters) +Function 572: SetAudioStreamPan() (2 input parameters) Name: SetAudioStreamPan Return type: void Description: Set pan for audio stream (0.5 is centered) Param[1]: stream (type: AudioStream) Param[2]: pan (type: float) -Function 561: SetAudioStreamBufferSizeDefault() (1 input parameters) +Function 573: SetAudioStreamBufferSizeDefault() (1 input parameters) Name: SetAudioStreamBufferSizeDefault Return type: void Description: Default size for new audio streams Param[1]: size (type: int) -Function 562: SetAudioStreamCallback() (2 input parameters) +Function 574: SetAudioStreamCallback() (2 input parameters) Name: SetAudioStreamCallback Return type: void Description: Audio thread callback to request new data Param[1]: stream (type: AudioStream) Param[2]: callback (type: AudioCallback) -Function 563: AttachAudioStreamProcessor() (2 input parameters) +Function 575: AttachAudioStreamProcessor() (2 input parameters) Name: AttachAudioStreamProcessor Return type: void Description: Attach audio stream processor to stream, receives the samples as 'float' Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 564: DetachAudioStreamProcessor() (2 input parameters) +Function 576: DetachAudioStreamProcessor() (2 input parameters) Name: DetachAudioStreamProcessor Return type: void Description: Detach audio stream processor from stream Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 565: AttachAudioMixedProcessor() (1 input parameters) +Function 577: AttachAudioMixedProcessor() (1 input parameters) Name: AttachAudioMixedProcessor Return type: void Description: Attach audio stream processor to the entire audio pipeline, receives the samples as 'float' Param[1]: processor (type: AudioCallback) -Function 566: DetachAudioMixedProcessor() (1 input parameters) +Function 578: DetachAudioMixedProcessor() (1 input parameters) Name: DetachAudioMixedProcessor Return type: void Description: Detach audio stream processor from the entire audio pipeline diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index 130f22f75..895680f2c 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -3,9 +3,9 @@ - + - + @@ -160,7 +160,7 @@ - + @@ -172,8 +172,10 @@ - - + + + + @@ -220,7 +222,7 @@ - + @@ -505,7 +507,7 @@ - + @@ -532,6 +534,9 @@ + + + @@ -670,7 +675,7 @@ - + @@ -703,9 +708,9 @@ - + - + @@ -1069,6 +1074,9 @@ + + + @@ -1081,7 +1089,7 @@ - + @@ -1289,12 +1297,12 @@ - + - + @@ -1353,8 +1361,8 @@ - - + + @@ -1431,23 +1439,23 @@ - - + + - - + + - - - - + + + + @@ -1798,6 +1806,10 @@ + + + + @@ -1842,9 +1854,9 @@ - + - + @@ -1966,6 +1978,13 @@ + + + + + + + @@ -2017,6 +2036,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2173,6 +2227,11 @@ + + + + + @@ -2195,7 +2254,7 @@ - + @@ -2591,6 +2650,20 @@ + + + + + + + + + + + + + + @@ -2599,7 +2672,7 @@ - + @@ -2757,6 +2830,11 @@ + + + + + diff --git a/parser/raylib_parser.c b/parser/raylib_parser.c index 63f957284..94a715562 100644 --- a/parser/raylib_parser.c +++ b/parser/raylib_parser.c @@ -72,7 +72,7 @@ #define MAX_CALLBACKS_TO_PARSE 64 // Maximum number of callbacks to parse #define MAX_FUNCS_TO_PARSE 1024 // Maximum number of functions to parse -#define MAX_LINE_LENGTH 512 // Maximum length of one line (including comments) +#define MAX_LINE_LENGTH 1024 // Maximum length of one line (including comments) #define MAX_STRUCT_FIELDS 64 // Maximum number of struct fields #define MAX_ENUM_VALUES 512 // Maximum number of enum values @@ -139,7 +139,7 @@ typedef struct EnumInfo { // Function info data typedef struct FunctionInfo { char name[64]; // Function name - char desc[128]; // Function description (comment at the end) + char desc[512]; // Function description (comment at the end) char retType[32]; // Return value type int paramCount; // Number of function parameters char paramType[MAX_FUNCTION_PARAMETERS][32]; // Parameters type @@ -1100,7 +1100,7 @@ static void ShowCommandLineInfo(void) printf(" NOTE: If not specified, defaults to: raylib_api.txt\n\n"); printf(" -f, --format : Define output format for parser data.\n"); printf(" Supported types: DEFAULT, JSON, XML, LUA, CODE\n\n"); - printf(" -d, --define : Define functions specifiers (i.e. RLAPI for raylib.h, RMDEF for raymath.h, etc.)\n"); + printf(" -d, --define : Define functions specifiers (i.e. RLAPI for raylib.h, RMAPI for raymath.h, etc.)\n"); printf(" NOTE: If no specifier defined, defaults to: RLAPI\n\n"); printf(" -t, --truncate : Define string to truncate input after (i.e. \"RLGL IMPLEMENTATION\" for rlgl.h)\n"); printf(" NOTE: If not specified, the full input file is parsed.\n\n"); @@ -1110,7 +1110,7 @@ static void ShowCommandLineInfo(void) printf(" Process to generate \n\n"); printf(" > raylib_parser --output raylib_data.info --format XML\n"); printf(" Process to generate as XML text data\n\n"); - printf(" > raylib_parser --input raymath.h --output raymath_data.info --format XML\n"); + printf(" > raylib_parser --input raymath.h --output raymath_data.info --format XML --define RMAPI\n"); printf(" Process to generate as XML text data\n\n"); } diff --git a/projects/CMake/CMakeLists.txt b/projects/CMake/CMakeLists.txt index ee258d604..96e33f344 100644 --- a/projects/CMake/CMakeLists.txt +++ b/projects/CMake/CMakeLists.txt @@ -5,7 +5,7 @@ project(example) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Dependencies -set(RAYLIB_VERSION 5.0) +set(RAYLIB_VERSION 5.5) find_package(raylib ${RAYLIB_VERSION} QUIET) # QUIET or REQUIRED if (NOT raylib_FOUND) # If there's none, fetch and build raylib include(FetchContent) @@ -17,9 +17,8 @@ if (NOT raylib_FOUND) # If there's none, fetch and build raylib FetchContent_GetProperties(raylib) if (NOT raylib_POPULATED) # Have we downloaded raylib yet? set(FETCHCONTENT_QUIET NO) - FetchContent_Populate(raylib) + FetchContent_MakeAvailable(raylib) set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) # don't build the supplied examples - add_subdirectory(${raylib_SOURCE_DIR} ${raylib_BINARY_DIR}) endif() endif() @@ -31,8 +30,8 @@ target_link_libraries(${PROJECT_NAME} raylib) # Web Configurations if (${PLATFORM} STREQUAL "Web") - # Tell Emscripten to build an example.html file. - set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".html") + set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".html") # Tell Emscripten to build an example.html file. + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY -s GL_ENABLE_GET_PROC_ADDRESS=1") endif() # Checks if OSX and links appropriate frameworks (Only required on MacOS) diff --git a/projects/CMake/README.md b/projects/CMake/README.md index f7873c30f..fc4fe5542 100644 --- a/projects/CMake/README.md +++ b/projects/CMake/README.md @@ -22,6 +22,6 @@ Compiling for the web requires the [Emscripten SDK](https://emscripten.org/docs/ ``` bash mkdir build cd build -emcmake cmake .. -DPLATFORM=Web -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXE_LINKER_FLAGS="-s USE_GLFW=3" -DCMAKE_EXECUTABLE_SUFFIX=".html" +emcmake cmake .. -DPLATFORM=Web -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXECUTABLE_SUFFIX=".html" emmake make -``` \ No newline at end of file +``` diff --git a/projects/VS2022/examples/models_gpu_skinning.vcxproj b/projects/VS2022/examples/models_gpu_skinning.vcxproj new file mode 100644 index 000000000..bd596bed6 --- /dev/null +++ b/projects/VS2022/examples/models_gpu_skinning.vcxproj @@ -0,0 +1,387 @@ + + + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + Win32 + + + Release + x64 + + + + {8245DAD9-D402-4D5C-8F45-32229CD3B263} + Win32Proj + models_loading + 10.0 + models_gpu_skinning + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\models + WindowsLocalDebugger + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + 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) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + 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) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + 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) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + 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) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + 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) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + 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) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + 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) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + 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) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + \ No newline at end of file diff --git a/projects/VS2022/examples/models_loading_gltf.vcxproj b/projects/VS2022/examples/models_loading_gltf.vcxproj index 141fb9423..aba2e6843 100644 --- a/projects/VS2022/examples/models_loading_gltf.vcxproj +++ b/projects/VS2022/examples/models_loading_gltf.vcxproj @@ -376,6 +376,9 @@ + + + {e89d61ac-55de-4482-afd4-df7242ebc859} diff --git a/projects/VS2022/examples/shapes_splines_drawing.vcxproj b/projects/VS2022/examples/shapes_splines_drawing.vcxproj index 77b17a803..7be42c0b7 100644 --- a/projects/VS2022/examples/shapes_splines_drawing.vcxproj +++ b/projects/VS2022/examples/shapes_splines_drawing.vcxproj @@ -202,7 +202,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -219,7 +219,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) /FS %(AdditionalOptions) @@ -237,7 +237,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -258,7 +258,7 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) @@ -281,7 +281,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -303,7 +303,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -325,7 +325,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -353,7 +353,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index 294d0e84d..2b262bcfe 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -299,6 +299,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_splines_drawing", "e EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_top_down_lights", "examples\shapes_top_down_lights.vcxproj", "{703BE7BA-5B99-4F70-806D-3A259F6A991E}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_gpu_skinning", "examples\models_gpu_skinning.vcxproj", "{8245DAD9-D402-4D5C-8F45-32229CD3B263}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|x64 = Debug.DLL|x64 @@ -2531,6 +2533,22 @@ Global {703BE7BA-5B99-4F70-806D-3A259F6A991E}.Release|x64.Build.0 = Release|x64 {703BE7BA-5B99-4F70-806D-3A259F6A991E}.Release|x86.ActiveCfg = Release|Win32 {703BE7BA-5B99-4F70-806D-3A259F6A991E}.Release|x86.Build.0 = Release|Win32 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug|x64.ActiveCfg = Debug|x64 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug|x64.Build.0 = Debug|x64 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug|x86.ActiveCfg = Debug|Win32 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug|x86.Build.0 = Debug|Win32 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release|x64.ActiveCfg = Release|x64 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release|x64.Build.0 = Release|x64 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release|x86.ActiveCfg = Release|Win32 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2682,6 +2700,7 @@ Global {D8026C60-CCBC-45DF-9085-BF21569EB414} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} {DF25E545-00FF-4E64-844C-7DF98991F901} = {278D8859-20B1-428F-8448-064F46E1F021} {703BE7BA-5B99-4F70-806D-3A259F6A991E} = {278D8859-20B1-428F-8448-064F46E1F021} + {8245DAD9-D402-4D5C-8F45-32229CD3B263} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 387665705..9735e267f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ # Setup the project and settings project(raylib C) -set(PROJECT_VERSION 5.0.0) -set(API_VERSION 500) +set(PROJECT_VERSION 5.5.0) +set(API_VERSION 550) include(GNUInstallDirs) include(JoinPaths) @@ -29,6 +29,7 @@ set(raylib_public_headers # Sources to be compiled set(raylib_sources + raudio.c rcore.c rmodels.c rshapes.c @@ -47,14 +48,12 @@ endif () # Produces a variable LIBS_PRIVATE that will be used later include(LibraryConfigurations) -if (USE_AUDIO) +if (SUPPORT_MODULE_RAUDIO) MESSAGE(STATUS "Audio Backend: miniaudio") - list(APPEND raylib_sources raudio.c) else () - MESSAGE(STATUS "Audio Backend: None (-DUSE_AUDIO=OFF)") + MESSAGE(STATUS "Audio Backend: None (-DCUSTOMIZE_BUILD=ON -DSUPPORT_MODULE_RAUDIO=OFF)") endif () - add_library(raylib ${raylib_sources} ${raylib_public_headers}) if (NOT BUILD_SHARED_LIBS) @@ -69,7 +68,11 @@ else() endif() if (${PLATFORM} MATCHES "Web") - target_link_options(raylib PRIVATE "-sUSE_GLFW=3") + target_link_options(raylib PUBLIC "-sUSE_GLFW=3") + if(${GRAPHICS} MATCHES "GRAPHICS_API_OPENGL_ES3") + target_link_options(raylib PUBLIC "-sMIN_WEBGL_VERSION=2") + target_link_options(raylib PUBLIC "-sMAX_WEBGL_VERSION=2") + endif() endif() set_target_properties(raylib PROPERTIES diff --git a/src/Makefile b/src/Makefile index 19251b956..4740f1f01 100644 --- a/src/Makefile +++ b/src/Makefile @@ -4,7 +4,9 @@ # # This file supports building raylib library for the following platforms: # -# > PLATFORM_DESKTOP (GLFW backend): +# > PLATFORM_DESKTOP +# - Defaults to PLATFORM_DESKTOP_GLFW +# > PLATFORM_DESKTOP_GLFW (GLFW backend): # - Windows (Win32, Win64) # - Linux (X11/Wayland desktop mode) # - macOS/OSX (x64, arm64) @@ -55,12 +57,18 @@ # Define required environment variables #------------------------------------------------------------------------------------------------ -# Define target platform: PLATFORM_DESKTOP, PLATFORM_DRM, PLATFORM_ANDROID, PLATFORM_WEB +# Define target platform PLATFORM ?= PLATFORM_DESKTOP +ifeq ($(PLATFORM), PLATFORM_DESKTOP) + TARGET_PLATFORM = PLATFORM_DESKTOP_GLFW +else + TARGET_PLATFORM = $(PLATFORM) +endif + # Define required raylib variables -RAYLIB_VERSION = 5.0.0 -RAYLIB_API_VERSION = 500 +RAYLIB_VERSION = 5.5.0 +RAYLIB_API_VERSION = 550 # Define raylib source code path RAYLIB_SRC_PATH ?= ../src @@ -119,7 +127,7 @@ HOST_PLATFORM_OS ?= WINDOWS PLATFORM_OS ?= WINDOWS # Determine PLATFORM_OS when required -ifeq ($(PLATFORM),$(filter $(PLATFORM),PLATFORM_DESKTOP PLATFORM_DESKTOP_SDL PLATFORM_WEB PLATFORM_ANDROID PLATFORM_DESKTOP_RGFW)) +ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW PLATFORM_DESKTOP_SDL PLATFORM_DESKTOP_RGFW PLATFORM_WEB PLATFORM_ANDROID)) # No uname.exe on MinGW!, but OS=Windows_NT on Windows! # ifeq ($(UNAME),Msys) -> Windows ifeq ($(OS),Windows_NT) @@ -152,7 +160,7 @@ ifeq ($(PLATFORM),$(filter $(PLATFORM),PLATFORM_DESKTOP PLATFORM_DESKTOP_SDL PLA endif endif endif -ifeq ($(PLATFORM),PLATFORM_DRM) +ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) UNAMEOS = $(shell uname) ifeq ($(UNAMEOS),Linux) PLATFORM_OS = LINUX @@ -161,7 +169,7 @@ ifeq ($(PLATFORM),PLATFORM_DRM) PLATFORM_SHELL = sh endif endif -ifeq ($(PLATFORM),PLATFORM_WEB) +ifeq ($(TARGET_PLATFORM),PLATFORM_WEB) ifeq ($(PLATFORM_OS),LINUX) ifndef PLATFORM_SHELL PLATFORM_SHELL = sh @@ -169,7 +177,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB) endif endif -ifeq ($(PLATFORM),PLATFORM_WEB) +ifeq ($(TARGET_PLATFORM),PLATFORM_WEB) ifeq ($(PLATFORM_OS), WINDOWS) # Emscripten required variables EMSDK_PATH ?= C:/emsdk @@ -181,7 +189,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB) endif endif -ifeq ($(PLATFORM),PLATFORM_ANDROID) +ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID) # Android architecture # Starting at 2019 using arm64 is mandatory for published apps, # Starting on August 2020, minimum required target API is Android 10 (API level 29) @@ -221,7 +229,7 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID) endif # Define raylib graphics api depending on selected platform -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) # By default use OpenGL 3.3 on desktop platforms GRAPHICS ?= GRAPHICS_API_OPENGL_33 #GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1 @@ -229,28 +237,28 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) #GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3 #GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE) endif -ifeq ($(PLATFORM),PLATFORM_DESKTOP_RGFW) - # By default use OpenGL 3.3 on desktop platforms - GRAPHICS ?= GRAPHICS_API_OPENGL_33 - #GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1 - #GRAPHICS = GRAPHICS_API_OPENGL_21 # Uncomment to use OpenGL 2.1 - #GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3 - #GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE) -endif -ifeq ($(PLATFORM),PLATFORM_DESKTOP_SDL) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL) # By default use OpenGL 3.3 on desktop platform with SDL backend GRAPHICS ?= GRAPHICS_API_OPENGL_33 endif -ifeq ($(PLATFORM),PLATFORM_DRM) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW) + # By default use OpenGL 3.3 on desktop platforms + GRAPHICS ?= GRAPHICS_API_OPENGL_33 + #GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1 + #GRAPHICS = GRAPHICS_API_OPENGL_21 # Uncomment to use OpenGL 2.1 + #GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3 + #GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE) +endif +ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) # On DRM OpenGL ES 2.0 must be used GRAPHICS = GRAPHICS_API_OPENGL_ES2 endif -ifeq ($(PLATFORM),PLATFORM_WEB) +ifeq ($(TARGET_PLATFORM),PLATFORM_WEB) # On HTML5 OpenGL ES 2.0 is used, emscripten translates it to WebGL 1.0 GRAPHICS = GRAPHICS_API_OPENGL_ES2 #GRAPHICS = GRAPHICS_API_OPENGL_ES3 # Uncomment to use ES3/WebGL2 (preliminary support). endif -ifeq ($(PLATFORM),PLATFORM_ANDROID) +ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID) # By default use OpenGL ES 2.0 on Android GRAPHICS = GRAPHICS_API_OPENGL_ES2 endif @@ -260,7 +268,7 @@ endif CC = gcc AR = ar -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) ifeq ($(PLATFORM_OS),OSX) # OSX default compiler CC = clang @@ -271,7 +279,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) CC = clang endif endif -ifeq ($(PLATFORM),PLATFORM_DRM) +ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) ifeq ($(USE_RPI_CROSS_COMPILER),TRUE) # Define RPI cross-compiler #CC = armv6j-hardfloat-linux-gnueabi-gcc @@ -279,12 +287,12 @@ ifeq ($(PLATFORM),PLATFORM_DRM) AR = $(RPI_TOOLCHAIN)/bin/$(RPI_TOOLCHAIN_NAME)-ar endif endif -ifeq ($(PLATFORM),PLATFORM_WEB) +ifeq ($(TARGET_PLATFORM),PLATFORM_WEB) # HTML5 emscripten compiler CC = emcc AR = emar endif -ifeq ($(PLATFORM),PLATFORM_ANDROID) +ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID) # Android toolchain (must be provided for desired architecture and compiler) ifeq ($(ANDROID_ARCH),arm) CC = $(ANDROID_TOOLCHAIN)/bin/$(ANDROID_COMPILER_ARCH)-linux-androideabi$(ANDROID_API_VERSION)-clang @@ -316,13 +324,13 @@ endif # -D_GNU_SOURCE access to lots of nonstandard GNU/Linux extension functions # -Werror=pointer-arith catch unportable code that does direct arithmetic on void pointers # -fno-strict-aliasing jar_xm.h does shady stuff (breaks strict aliasing) -CFLAGS = -Wall -D_GNU_SOURCE -D$(PLATFORM) -D$(GRAPHICS) -Wno-missing-braces -Werror=pointer-arith -fno-strict-aliasing +CFLAGS = -Wall -D_GNU_SOURCE -D$(TARGET_PLATFORM) -D$(GRAPHICS) -Wno-missing-braces -Werror=pointer-arith -fno-strict-aliasing ifneq ($(RAYLIB_CONFIG_FLAGS), NONE) CFLAGS += -DEXTERNAL_CONFIG_FLAGS $(RAYLIB_CONFIG_FLAGS) endif -ifeq ($(PLATFORM), PLATFORM_WEB) +ifeq ($(TARGET_PLATFORM), PLATFORM_WEB) # NOTE: When using multi-threading in the user code, it requires -pthread enabled CFLAGS += -std=gnu99 else @@ -338,13 +346,13 @@ ifeq ($(RAYLIB_BUILD_MODE),DEBUG) endif ifeq ($(RAYLIB_BUILD_MODE),RELEASE) - ifeq ($(PLATFORM),PLATFORM_WEB) + ifeq ($(TARGET_PLATFORM),PLATFORM_WEB) CFLAGS += -Os endif - ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) CFLAGS += -O1 endif - ifeq ($(PLATFORM),PLATFORM_ANDROID) + ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID) CFLAGS += -O2 endif endif @@ -354,10 +362,10 @@ endif # -Wmissing-prototypes warn if a global function is defined without a previous prototype declaration # -Wstrict-prototypes warn if a function is declared or defined without specifying the argument types # -Werror=implicit-function-declaration catch function calls without prior declaration -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) CFLAGS += -Werror=implicit-function-declaration endif -ifeq ($(PLATFORM),PLATFORM_WEB) +ifeq ($(TARGET_PLATFORM),PLATFORM_WEB) # -Os # size optimization # -O2 # optimization level 2, if used, also set --memory-init-file 0 # -sUSE_GLFW=3 # Use glfw3 library (context/input management) -> Only for linker! @@ -375,7 +383,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB) endif #CFLAGS += -sGL_ENABLE_GET_PROC_ADDRESS endif -ifeq ($(PLATFORM),PLATFORM_ANDROID) +ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID) # Compiler flags for arquitecture ifeq ($(ANDROID_ARCH),arm) CFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 @@ -411,19 +419,18 @@ ifeq ($(RAYLIB_LIBTYPE),SHARED) endif endif -ifeq ($(PLATFORM),PLATFORM_DRM) +ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) # without EGL_NO_X11 eglplatform.h tears Xlib.h in which tears X.h in # which contains a conflicting type Font CFLAGS += -DEGL_NO_X11 CFLAGS += -Werror=implicit-function-declaration endif # Use Wayland display on Linux desktop -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) ifeq ($(PLATFORM_OS), LINUX) ifeq ($(GLFW_LINUX_ENABLE_X11),TRUE) CFLAGS += -D_GLFW_X11 endif - ifeq ($(GLFW_LINUX_ENABLE_WAYLAND),TRUE) CFLAGS += -D_GLFW_WAYLAND LDFLAGS += $(shell pkg-config wayland-client wayland-cursor wayland-egl xkbcommon --libs) @@ -457,26 +464,26 @@ CFLAGS += $(CUSTOM_CFLAGS) INCLUDE_PATHS = -I. # Define additional directories containing required header files -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) INCLUDE_PATHS += -Iexternal/glfw/include ifeq ($(PLATFORM_OS),BSD) - INCLUDE_PATHS += -I/usr/local/include + INCLUDE_PATHS += -I/usr/local/include -I/usr/pkg/include -I/usr/X11R7/include endif endif -ifeq ($(PLATFORM),PLATFORM_DESKTOP_SDL) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL) INCLUDE_PATHS += -I$(SDL_INCLUDE_PATH) endif -ifeq ($(PLATFORM),PLATFORM_WEB) +ifeq ($(TARGET_PLATFORM),PLATFORM_WEB) INCLUDE_PATHS += -Iexternal/glfw/include endif -ifeq ($(PLATFORM),PLATFORM_DRM) +ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) INCLUDE_PATHS += -I/usr/include/libdrm ifeq ($(USE_RPI_CROSSCOMPILER), TRUE) INCLUDE_PATHS += -I$(RPI_TOOLCHAIN_SYSROOT)/usr/include INCLUDE_PATHS += -I$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/include endif endif -ifeq ($(PLATFORM),PLATFORM_ANDROID) +ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID) NATIVE_APP_GLUE = $(ANDROID_NDK)/sources/android/native_app_glue # Include android_native_app_glue.h INCLUDE_PATHS += -I$(NATIVE_APP_GLUE) @@ -502,7 +509,7 @@ endif #------------------------------------------------------------------------------------------------ LDFLAGS = $(CUSTOM_LDFLAGS) -L. -L$(RAYLIB_RELEASE_PATH) -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) ifeq ($(PLATFORM_OS),WINDOWS) ifneq ($(CC), tcc) LDFLAGS += -Wl,--out-implib,$(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME)dll.a @@ -515,20 +522,20 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) LDFLAGS += -Wl,-soname,lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION) endif ifeq ($(PLATFORM_OS),BSD) - LDFLAGS += -Wl,-soname,lib$(RAYLIB_LIB_NAME).$(RAYLIB_API_VERSION).so -Lsrc -L/usr/local/lib + LDFLAGS += -Wl,-soname,lib$(RAYLIB_LIB_NAME).$(RAYLIB_API_VERSION).so -Lsrc -L/usr/local/lib -L/usr/pkg/lib -Wl,-R/usr/pkg/lib endif endif -ifeq ($(PLATFORM),PLATFORM_DESKTOP_SDL) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL) LDFLAGS += -Wl,-soname,lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION) LDFLAGS += -L$(SDL_LIBRARY_PATH) endif -ifeq ($(PLATFORM),PLATFORM_DRM) +ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) LDFLAGS += -Wl,-soname,lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION) ifeq ($(USE_RPI_CROSSCOMPILER), TRUE) LDFLAGS += -L$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/lib -L$(RPI_TOOLCHAIN_SYSROOT)/usr/lib endif endif -ifeq ($(PLATFORM),PLATFORM_ANDROID) +ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID) LDFLAGS += -Wl,-soname,libraylib.$(RAYLIB_API_VERSION).so -Wl,--exclude-libs,libatomic.a LDFLAGS += -Wl,--build-id -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings # Force linking of library module to define symbol @@ -542,7 +549,7 @@ endif # Define libraries required on linking: LDLIBS # NOTE: This is only required for dynamic library generation #------------------------------------------------------------------------------------------------ -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) ifeq ($(PLATFORM_OS),WINDOWS) ifeq ($(CC), tcc) LDLIBS = -lopengl32 -lgdi32 -lwinmm -lshell32 @@ -570,7 +577,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) LDLIBS = -lglfw endif endif -ifeq ($(PLATFORM),PLATFORM_DESKTOP_SDL) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL) ifeq ($(PLATFORM_OS),WINDOWS) LDLIBS = -static-libgcc -lopengl32 -lgdi32 endif @@ -582,16 +589,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP_SDL) endif LDLIBS += -lSDL2 -lSDL2main endif -ifeq ($(PLATFORM),PLATFORM_DRM) - LDLIBS = -lGLESv2 -lEGL -ldrm -lgbm -lpthread -lrt -lm -ldl - ifeq ($(RAYLIB_MODULE_AUDIO),TRUE) - LDLIBS += -latomic - endif -endif -ifeq ($(PLATFORM),PLATFORM_ANDROID) - LDLIBS = -llog -landroid -lEGL -lGLESv2 -lOpenSLES -lc -lm -endif -ifeq ($(PLATFORM),PLATFORM_DESKTOP_RGFW) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW) ifeq ($(PLATFORM_OS),WINDOWS) # Libraries for Windows desktop compilation LDLIBS = -lgdi32 -lwinmm -lopengl32 @@ -615,6 +613,15 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP_RGFW) LDLIBS += -lm -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo endif endif +ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) + LDLIBS = -lGLESv2 -lEGL -ldrm -lgbm -lpthread -lrt -lm -ldl + ifeq ($(RAYLIB_MODULE_AUDIO),TRUE) + LDLIBS += -latomic + endif +endif +ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID) + LDLIBS = -llog -landroid -lEGL -lGLESv2 -lOpenSLES -lc -lm +endif # Define source code object files required #------------------------------------------------------------------------------------------------ @@ -624,8 +631,7 @@ OBJS = rcore.o \ rtext.o \ utils.o - -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW) ifeq ($(USE_EXTERNAL_GLFW),FALSE) OBJS += rglfw.o endif @@ -640,7 +646,7 @@ ifeq ($(RAYLIB_MODULE_RAYGUI),TRUE) OBJS += raygui.o endif -ifeq ($(PLATFORM),PLATFORM_ANDROID) +ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID) OBJS += android_native_app_glue.o endif @@ -652,14 +658,14 @@ all: raylib # Compile raylib library # NOTE: Release directory is created if not exist raylib: $(OBJS) -ifeq ($(PLATFORM),PLATFORM_WEB) +ifeq ($(TARGET_PLATFORM),PLATFORM_WEB) # Compile raylib libray for web #$(CC) $(OBJS) -r -o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).bc $(AR) rcs $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).a $(OBJS) @echo "raylib library generated (lib$(RAYLIB_LIB_NAME).a)!" else ifeq ($(RAYLIB_LIBTYPE),SHARED) - ifeq ($(PLATFORM),$(filter $(PLATFORM),PLATFORM_DESKTOP PLATFORM_DESKTOP_SDL PLATFORM_DESKTOP_RGFW)) + ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW PLATFORM_DESKTOP_SDL PLATFORM_DESKTOP_RGFW)) ifeq ($(PLATFORM_OS),WINDOWS) # NOTE: Linking with provided resource file $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/$(RAYLIB_LIB_NAME).dll $(OBJS) $(RAYLIB_RES_FILE) $(LDFLAGS) $(LDLIBS) @@ -688,7 +694,7 @@ else cd $(RAYLIB_RELEASE_PATH) && ln -fs lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).so lib$(RAYLIB_LIB_NAME).so endif endif - ifeq ($(PLATFORM),PLATFORM_DRM) + ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) # Compile raylib shared library version $(RAYLIB_VERSION). # WARNING: you should type "make clean" before doing this target $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_VERSION) $(OBJS) $(LDFLAGS) $(LDLIBS) @@ -696,7 +702,7 @@ else cd $(RAYLIB_RELEASE_PATH) && ln -fsv lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_VERSION) lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION) cd $(RAYLIB_RELEASE_PATH) && ln -fsv lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION) lib$(RAYLIB_LIB_NAME).so endif - ifeq ($(PLATFORM),PLATFORM_ANDROID) + ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID) $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).so $(OBJS) $(LDFLAGS) $(LDLIBS) @echo "raylib shared library generated (lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).so)!" # WARNING: symbolic links creation on Windows should be done using mklink command, no ln available @@ -851,7 +857,7 @@ clean: clean_shell_$(PLATFORM_SHELL) clean_shell_sh: rm -fv *.o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).a $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).bc $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).so* raygui.c $(RAYLIB_RELEASE_PATH)/*-protocol.h $(RAYLIB_RELEASE_PATH)/*-protocol-code.h -ifeq ($(PLATFORM),PLATFORM_ANDROID) +ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID) rm -fv $(NATIVE_APP_GLUE)/android_native_app_glue.o endif diff --git a/src/build.zig b/src/build.zig index 35622a462..b08b909de 100644 --- a/src/build.zig +++ b/src/build.zig @@ -9,9 +9,14 @@ comptime { // get the flags a second time when adding raygui var raylib_flags_arr: std.ArrayListUnmanaged([]const u8) = .{}; +/// we're not inside the actual build script recognized by the +/// zig build system; use this type where one would otherwise +/// use `@This()` when inside the actual entrypoint file. +const BuildScript = @import("../build.zig"); + // This has been tested with zig version 0.12.0 pub fn addRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile { - const raylib_dep = b.dependency(options.raylib_dependency_name, .{ + const raylib_dep = b.dependencyFromBuildZig(BuildScript, .{ .target = target, .optimize = optimize, .raudio = options.raudio, @@ -23,6 +28,7 @@ pub fn addRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. .shared = options.shared, .linux_display_backend = options.linux_display_backend, .opengl_version = options.opengl_version, + .config = options.config, }); const raylib = raylib_dep.artifact("raylib"); @@ -34,6 +40,17 @@ pub fn addRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. return raylib; } +fn setDesktopPlatform(raylib: *std.Build.Step.Compile, platform: PlatformBackend) void { + raylib.defineCMacro("PLATFORM_DESKTOP", null); + + switch (platform) { + .glfw => raylib.defineCMacro("PLATFORM_DESKTOP_GLFW", null), + .rgfw => raylib.defineCMacro("PLATFORM_DESKTOP_RGFW", null), + .sdl => raylib.defineCMacro("PLATFORM_DESKTOP_SDL", null), + else => {} + } +} + fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile { raylib_flags_arr.clearRetainingCapacity(); @@ -47,6 +64,36 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. "-DGL_SILENCE_DEPRECATION=199309L", "-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/3674 }); + if (options.config) |config| { + const file = try std.fs.path.join(b.allocator, &.{ std.fs.path.dirname(@src().file) orelse ".", "config.h" }); + defer b.allocator.free(file); + const content = try std.fs.cwd().readFileAlloc(b.allocator, file, std.math.maxInt(usize)); + defer b.allocator.free(content); + + var lines = std.mem.splitScalar(u8, content, '\n'); + while (lines.next()) |line| { + if (!std.mem.containsAtLeast(u8, line, 1, "SUPPORT")) continue; + if (std.mem.startsWith(u8, line, "//")) continue; + + var flag = std.mem.trimLeft(u8, line, " \t"); // Trim whitespace + flag = flag["#define ".len - 1 ..]; // Remove #define + flag = std.mem.trimLeft(u8, flag, " \t"); // Trim whitespace + flag = flag[0..std.mem.indexOf(u8, flag, " ").?]; // Flag is only one word, so capture till space + flag = try std.fmt.allocPrint(b.allocator, "-D{s}", .{flag}); // Prepend with -D + + // If user specifies the flag skip it + if (std.mem.containsAtLeast(u8, config, 1, flag)) continue; + + // Append default value from config.h to compile flags + try raylib_flags_arr.append(b.allocator, flag); + } + + // Append config flags supplied by user to compile flags + try raylib_flags_arr.append(b.allocator, config); + + try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS"); + } + if (options.shared) { try raylib_flags_arr.appendSlice(b.allocator, shared_flags); } @@ -66,7 +113,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. raylib.linkLibC(); // No GLFW required on PLATFORM_DRM - if (!options.platform_drm) { + if (options.platform != .drm) { raylib.addIncludePath(b.path("src/external/glfw/include")); } @@ -100,10 +147,10 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. raylib.linkSystemLibrary("gdi32"); raylib.linkSystemLibrary("opengl32"); - raylib.defineCMacro("PLATFORM_DESKTOP", null); + setDesktopPlatform(raylib, options.platform); }, .linux => { - if (!options.platform_drm) { + if (options.platform != .drm) { try c_source_files.append("rglfw.c"); raylib.linkSystemLibrary("GL"); raylib.linkSystemLibrary("rt"); @@ -112,32 +159,36 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. raylib.addLibraryPath(.{ .cwd_relative = "/usr/lib" }); raylib.addIncludePath(.{ .cwd_relative = "/usr/include" }); - - switch (options.linux_display_backend) { - .X11 => { - raylib.defineCMacro("_GLFW_X11", null); - raylib.linkSystemLibrary("X11"); - }, - .Wayland => { - raylib.defineCMacro("_GLFW_WAYLAND", null); - raylib.linkSystemLibrary("wayland-client"); - raylib.linkSystemLibrary("wayland-cursor"); - raylib.linkSystemLibrary("wayland-egl"); - raylib.linkSystemLibrary("xkbcommon"); - raylib.addIncludePath(b.path("src")); - waylandGenerate(b, raylib, "wayland.xml", "wayland-client-protocol"); - waylandGenerate(b, raylib, "xdg-shell.xml", "xdg-shell-client-protocol"); - waylandGenerate(b, raylib, "xdg-decoration-unstable-v1.xml", "xdg-decoration-unstable-v1-client-protocol"); - waylandGenerate(b, raylib, "viewporter.xml", "viewporter-client-protocol"); - waylandGenerate(b, raylib, "relative-pointer-unstable-v1.xml", "relative-pointer-unstable-v1-client-protocol"); - waylandGenerate(b, raylib, "pointer-constraints-unstable-v1.xml", "pointer-constraints-unstable-v1-client-protocol"); - waylandGenerate(b, raylib, "fractional-scale-v1.xml", "fractional-scale-v1-client-protocol"); - waylandGenerate(b, raylib, "xdg-activation-v1.xml", "xdg-activation-v1-client-protocol"); - waylandGenerate(b, raylib, "idle-inhibit-unstable-v1.xml", "idle-inhibit-unstable-v1-client-protocol"); - }, + if (options.linux_display_backend == .X11 or options.linux_display_backend == .Both) { + raylib.defineCMacro("_GLFW_X11", null); + raylib.linkSystemLibrary("X11"); } - raylib.defineCMacro("PLATFORM_DESKTOP", null); + if (options.linux_display_backend == .Wayland or options.linux_display_backend == .Both) { + _ = b.findProgram(&.{"wayland-scanner"}, &.{}) catch { + std.log.err( + \\ Wayland may not be installed on the system. + \\ You can switch to X11 in your `build.zig` by changing `Options.linux_display_backend` + , .{}); + @panic("No Wayland"); + }; + raylib.defineCMacro("_GLFW_WAYLAND", null); + raylib.linkSystemLibrary("wayland-client"); + raylib.linkSystemLibrary("wayland-cursor"); + raylib.linkSystemLibrary("wayland-egl"); + raylib.linkSystemLibrary("xkbcommon"); + raylib.addIncludePath(b.path("src")); + waylandGenerate(b, raylib, "wayland.xml", "wayland-client-protocol"); + waylandGenerate(b, raylib, "xdg-shell.xml", "xdg-shell-client-protocol"); + waylandGenerate(b, raylib, "xdg-decoration-unstable-v1.xml", "xdg-decoration-unstable-v1-client-protocol"); + waylandGenerate(b, raylib, "viewporter.xml", "viewporter-client-protocol"); + waylandGenerate(b, raylib, "relative-pointer-unstable-v1.xml", "relative-pointer-unstable-v1-client-protocol"); + waylandGenerate(b, raylib, "pointer-constraints-unstable-v1.xml", "pointer-constraints-unstable-v1-client-protocol"); + waylandGenerate(b, raylib, "fractional-scale-v1.xml", "fractional-scale-v1-client-protocol"); + waylandGenerate(b, raylib, "xdg-activation-v1.xml", "xdg-activation-v1-client-protocol"); + waylandGenerate(b, raylib, "idle-inhibit-unstable-v1.xml", "idle-inhibit-unstable-v1-client-protocol"); + } + setDesktopPlatform(raylib, options.platform); } else { if (options.opengl_version == .auto) { raylib.linkSystemLibrary("GLESv2"); @@ -171,7 +222,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. raylib.linkSystemLibrary("Xxf86vm"); raylib.linkSystemLibrary("Xcursor"); - raylib.defineCMacro("PLATFORM_DESKTOP", null); + setDesktopPlatform(raylib, options.platform); }, .macos => { // On macos rglfw.c include Objective-C files. @@ -187,7 +238,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. raylib.linkFramework("AppKit"); raylib.linkFramework("IOKit"); - raylib.defineCMacro("PLATFORM_DESKTOP", null); + setDesktopPlatform(raylib, options.platform); }, .emscripten => { raylib.defineCMacro("PLATFORM_WEB", null); @@ -202,21 +253,16 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. const cache_include = std.fs.path.join(b.allocator, &.{ b.sysroot.?, "cache", "sysroot", "include" }) catch @panic("Out of memory"); defer b.allocator.free(cache_include); - if (comptime builtin.zig_version.minor > 12) { - var dir = std.fs.cwd().openDir(cache_include, std.fs.Dir.OpenDirOptions{ .access_sub_paths = true, .no_follow = true }) catch @panic("No emscripten cache. Generate it!"); - dir.close(); - raylib.addIncludePath(b.path(cache_include)); - } else { - var dir = std.fs.openDirAbsolute(cache_include, std.fs.Dir.OpenDirOptions{ .access_sub_paths = true, .no_follow = true }) catch @panic("No emscripten cache. Generate it!"); - dir.close(); - raylib.addIncludePath(.{ .path = cache_include }); - } + var dir = std.fs.openDirAbsolute(cache_include, std.fs.Dir.OpenDirOptions{ .access_sub_paths = true, .no_follow = true }) catch @panic("No emscripten cache. Generate it!"); + dir.close(); + raylib.addIncludePath(.{ .cwd_relative = cache_include }); }, else => { @panic("Unsupported OS"); }, } + raylib.addIncludePath(b.path("src")); raylib.root_module.addCSourceFiles(.{ .root = b.path("src"), .files = c_source_files.items, @@ -251,12 +297,12 @@ pub const Options = struct { rtext: bool = true, rtextures: bool = true, raygui: bool = false, - platform_drm: bool = false, + platform: PlatformBackend = .glfw, shared: bool = false, - linux_display_backend: LinuxDisplayBackend = .X11, + linux_display_backend: LinuxDisplayBackend = .Both, opengl_version: OpenglVersion = .auto, + config: ?[]const u8 = null, - raylib_dependency_name: []const u8 = "raylib", raygui_dependency_name: []const u8 = "raygui", }; @@ -271,11 +317,11 @@ pub const OpenglVersion = enum { pub fn toCMacroStr(self: @This()) []const u8 { switch (self) { - .auto => @panic("OpenglVersion.auto cannot be turned into a C macro string"), - .gl_1_1 => return "GRAPHICS_API_OPENGL_11", - .gl_2_1 => return "GRAPHICS_API_OPENGL_21", - .gl_3_3 => return "GRAPHICS_API_OPENGL_33", - .gl_4_3 => return "GRAPHICS_API_OPENGL_43", + .auto => @panic("OpenglVersion.auto cannot be turned into a C macro string"), + .gl_1_1 => return "GRAPHICS_API_OPENGL_11", + .gl_2_1 => return "GRAPHICS_API_OPENGL_21", + .gl_3_3 => return "GRAPHICS_API_OPENGL_33", + .gl_4_3 => return "GRAPHICS_API_OPENGL_43", .gles_2 => return "GRAPHICS_API_OPENGL_ES2", .gles_3 => return "GRAPHICS_API_OPENGL_ES3", } @@ -285,6 +331,14 @@ pub const OpenglVersion = enum { pub const LinuxDisplayBackend = enum { X11, Wayland, + Both, +}; + +pub const PlatformBackend = enum { + glfw, + rgfw, + sdl, + drm }; pub fn build(b: *std.Build) !void { @@ -300,7 +354,7 @@ pub fn build(b: *std.Build) !void { const defaults = Options{}; const options = Options{ - .platform_drm = b.option(bool, "platform_drm", "Compile raylib in native mode (no X11)") orelse defaults.platform_drm, + .platform = b.option(PlatformBackend, "platform", "Choose the platform backedn for desktop target") orelse defaults.platform, .raudio = b.option(bool, "raudio", "Compile with audio support") orelse defaults.raudio, .rmodels = b.option(bool, "rmodels", "Compile with models support") orelse defaults.rmodels, .rtext = b.option(bool, "rtext", "Compile with text support") orelse defaults.rtext, @@ -309,6 +363,7 @@ pub fn build(b: *std.Build) !void { .shared = b.option(bool, "shared", "Compile as shared library") orelse defaults.shared, .linux_display_backend = b.option(LinuxDisplayBackend, "linux_display_backend", "Linux display backend to use") orelse defaults.linux_display_backend, .opengl_version = b.option(OpenglVersion, "opengl_version", "OpenGL version to use") orelse defaults.opengl_version, + .config = b.option([]const u8, "config", "Compile with custom define macros overriding config.h") orelse null, }; const lib = try compileRaylib(b, target, optimize, options); diff --git a/src/config.h b/src/config.h index df17c2876..2fd9167f4 100644 --- a/src/config.h +++ b/src/config.h @@ -113,12 +113,22 @@ #define RL_CULL_DISTANCE_FAR 1000.0 // Default projection matrix far cull distance // Default shader vertex attribute locations -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6 + + +#define RL_SUPPORT_MESH_GPU_SKINNING // Remove this if your GPU does not support more than 8 VBOs + +#ifdef RL_SUPPORT_MESH_GPU_SKINNING +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 7 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8 +#endif + // Default shader vertex attribute names to set location points // NOTE: When a new shader is loaded, the following locations are tried to be set for convenience @@ -225,7 +235,12 @@ // rmodels: Configuration values //------------------------------------------------------------------------------------ #define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported + +#ifdef RL_SUPPORT_MESH_GPU_SKINNING +#define MAX_MESH_VERTEX_BUFFERS 9 // Maximum vertex buffers (VBO) per mesh +#else #define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh +#endif //------------------------------------------------------------------------------------ // Module: raudio - Configuration Flags diff --git a/src/external/RGFW.h b/src/external/RGFW.h index a0ca21cec..35e782d4a 100644 --- a/src/external/RGFW.h +++ b/src/external/RGFW.h @@ -37,7 +37,6 @@ This version doesn't work for desktops (I'm pretty sure) #define RGFW_OPENGL_ES2 - (optional) use OpenGL ES (version 2) #define RGFW_OPENGL_ES3 - (optional) use OpenGL ES (version 3) - #define RGFW_VULKAN - (optional) use vulkan for the rendering backend (rather than opengl) #define RGFW_DIRECTX - (optional) use directX for the rendering backend (rather than opengl) (windows only, defaults to opengl for unix) #define RGFW_NO_API - (optional) don't use any rendering API (no opengl, no vulkan, no directX) @@ -55,11 +54,16 @@ #define RGFW_MALLOC x - choose what function to use to allocate, by default the standard malloc is used #define RGFW_CALLOC x - choose what function to use to allocate (calloc), by default the standard calloc is used #define RGFW_FREE x - choose what function to use to allocated memory, by default the standard free is used + + #define RGFW_EXPORT - Use when building RGFW + #define RGFW_IMPORT - Use when linking with RGFW (not as a single-header) + + #define RGFW_STD_INT - force the use stdint.h (for systems that might not have stdint.h (msvc)) */ /* Credits : - EimaMei/Sacode : Much of the code for creating windows using winapi, Wrote the Silicon library, helped with MacOS Support + EimaMei/Sacode : Much of the code for creating windows using winapi, Wrote the Silicon library, helped with MacOS Support, siliapp.h -> referencing stb - This project is heavily inspired by the stb single header files @@ -72,38 +76,86 @@ Copyright (c) 2002-2006 Marcus Geelnard Copyright (c) 2006-2019 Camilla Löwy + + contributors : (feel free to put yourself here if you contribute) + krisvers -> code review + EimaMei (SaCode) -> code review + Code-Nycticebus -> bug fixes + Rob Rohan -> X11 bugs and missing features, MacOS/Cocoa fixing memory issues/bugs + AICDG (@THISISAGOODNAME) -> vulkan support (example) + @Easymode -> support, testing/debugging, bug fixes and reviews */ +#if _MSC_VER + #pragma comment(lib, "gdi32") + #pragma comment(lib, "shell32") + #pragma comment(lib, "opengl32") + #pragma comment(lib, "winmm") + #pragma comment(lib, "user32") +#endif + #ifndef RGFW_MALLOC -#include -#include -#define RGFW_MALLOC malloc -#define RGFW_CALLOC calloc -#define RGFW_FREE free + #include + + #ifndef __USE_POSIX199309 + #define __USE_POSIX199309 + #endif + + #include + #define RGFW_MALLOC malloc + #define RGFW_CALLOC calloc + #define RGFW_FREE free #endif #if !_MSC_VER -#ifndef inline -#ifndef __APPLE__ -#define inline __inline -#endif -#endif + #ifndef inline + #ifndef __APPLE__ + #define inline __inline + #endif + #endif #endif -#ifndef RGFWDEF -#ifdef __APPLE__ -#define RGFWDEF static inline -#else -#define RGFWDEF inline +#ifdef RGFW_WIN95 /* for windows 95 testing (not that it really works) */ + #define RGFW_NO_MONITOR + #define RGFW_NO_PASSTHROUGH #endif + +#if defined(RGFW_EXPORT) || defined(RGFW_IMPORT) + #if defined(_WIN32) + #if defined(__TINYC__) && (defined(RGFW_EXPORT) || defined(RGFW_IMPORT)) + #define __declspec(x) __attribute__((x)) + #endif + + #if defined(RGFW_EXPORT) + #define RGFWDEF __declspec(dllexport) + #else + #define RGFWDEF __declspec(dllimport) + #endif + #else + #if defined(RGFW_EXPORT) + #define RGFWDEF __attribute__((visibility("default"))) + #endif + #endif +#endif + +#ifndef RGFWDEF + #ifdef __clang__ + #define RGFWDEF static inline + #else + #define RGFWDEF inline + #endif +#endif + +#ifndef RGFW_ENUM + #define RGFW_ENUM(type, name) type name; enum #endif #ifndef RGFW_UNUSED -#define RGFW_UNUSED(x) if (x){} + #define RGFW_UNUSED(x) (void)(x); #endif -#ifdef __cplusplus -extern "C" { +#if defined(__cplusplus) && !defined(__EMSCRIPTEN__) + extern "C" { #endif /* makes sure the header file part is only defined once by default */ @@ -112,129 +164,145 @@ extern "C" { #define RGFW_HEADER #if !defined(u8) - #include + #if ((defined(_MSC_VER) || defined(__SYMBIAN32__)) && !defined(RGFW_STD_INT)) /* MSVC might not have stdint.h */ + typedef unsigned char u8; + typedef signed char i8; + typedef unsigned short u16; + typedef signed short i16; + typedef unsigned int u32; + typedef signed int i32; + typedef unsigned long u64; + typedef signed long i64; + #else /* use stdint standard types instead of c ""standard"" types */ + #include - typedef uint8_t u8; - typedef int8_t i8; - typedef uint16_t u16; - typedef int16_t i16; - typedef uint32_t u32; - typedef int32_t i32; - typedef uint64_t u64; - typedef int64_t i64; + typedef uint8_t u8; + typedef int8_t i8; + typedef uint16_t u16; + typedef int16_t i16; + typedef uint32_t u32; + typedef int32_t i32; + typedef uint64_t u64; + typedef int64_t i64; + #endif +#endif + +#if !defined(b8) /* RGFW bool type */ + typedef u8 b8; + typedef u32 b32; +#endif + +#define RGFW_TRUE 1 +#define RGFW_FALSE 0 + +/* thse OS macros looks better & are standardized */ +/* plus it helps with cross-compiling */ + +#ifdef __EMSCRIPTEN__ + #define RGFW_WEBASM + + #ifndef RGFW_NO_API + #define RGFW_OPENGL + #endif + + #ifdef RGFW_EGL + #undef RGFW_EGL + #endif + + #include + #include #endif #if defined(RGFW_X11) && defined(__APPLE__) -#define RGFW_MACOS_X11 -#undef __APPLE__ + #define RGFW_MACOS_X11 + #undef __APPLE__ #endif -#if defined(_WIN32) && !defined(RGFW_X11) /* (if you're using X11 on windows some how) */ +#if defined(_WIN32) && !defined(RGFW_X11) && !defined(RGFW_WEBASM) /* (if you're using X11 on windows some how) */ + #define RGFW_WINDOWS - /* this name looks better */ - /* plus it helps with cross-compiling because RGFW_X11 won't be accidently defined */ - -#define RGFW_WINDOWS + /* make sure the correct architecture is defined */ + #if defined(_WIN64) + #define _AMD64_ + #undef _X86_ + #else + #undef _AMD64_ + #ifndef _X86_ + #define _X86_ + #endif + #endif -#if defined(_WIN32) && !defined(WIN32) -#define WIN32 -#endif + #ifndef RGFW_NO_XINPUT + #ifdef __MINGW32__ /* try to find the right header */ + #include + #else + #include + #endif + #endif -#if defined(_WIN64) + #if defined(RGFW_DIRECTX) + #include + #include + #include + #include -#ifndef WIN64 -#define WIN64 -#endif + #ifndef __cplusplus + #define __uuidof(T) IID_##T + #endif + #endif -#define _AMD64_ -#undef _X86_ -#else -#undef _AMD64_ -#define _X86_ -#endif +#elif defined(RGFW_WAYLAND) + #if !defined(RGFW_NO_API) && (!defined(RGFW_BUFFER) || defined(RGFW_OPENGL)) + #define RGFW_EGL + #define RGFW_OPENGL + #include + #endif -#include - -#ifdef __MINGW32__ -#include -#else -#include -#endif - -#else -#if defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11) -#define RGFW_MACOS_X11 -#define RGFW_X11 -#include -#endif -#endif - -#if defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11) -#define RGFW_MACOS + #include +#elif (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)) && !defined(RGFW_WEBASM) + #define RGFW_MACOS_X11 + #define RGFW_X11 + #include +#elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11) && !defined(RGFW_WEBASM) + #define RGFW_MACOS #endif #if (defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3)) && !defined(RGFW_EGL) -#define RGFW_EGL -#endif -#if defined(RGFW_EGL) && defined(__APPLE__) - #warning EGL is not supported for Cocoa, switching back to the native opengl api -#undef RGFW_EGL + #define RGFW_EGL #endif -#if !defined(RGFW_OSMESA) && !defined(RGFW_EGL) && !defined(RGFW_OPENGL) && !defined (RGFW_VULKAN) && !defined(RGFW_DIRECTX) && !defined(RGFW_BUFFER) && !defined(RGFW_NO_API) -#define RGFW_OPENGL -#endif - -#ifdef RGFW_VULKAN -#ifndef RGFW_MAX_FRAMES_IN_FLIGHT -#define RGFW_MAX_FRAMES_IN_FLIGHT 2 -#endif - -#ifdef RGFW_X11 -#define VK_USE_PLATFORM_XLIB_KHR -#endif -#ifdef RGFW_WINDOWS -#define VK_USE_PLATFORM_WIN32_KHR -#endif -#ifdef RGFW_MACOS -#define VK_USE_PLATFORM_MACOS_MVK -#endif - -#include -#endif - -#if defined(RGFW_X11) && (defined(RGFW_OPENGL)) -#ifndef GLX_MESA_swap_control -#define GLX_MESA_swap_control -#endif -#include /* GLX defs, xlib.h, gl.h */ +#if !defined(RGFW_OSMESA) && !defined(RGFW_EGL) && !defined(RGFW_OPENGL) && !defined(RGFW_DIRECTX) && !defined(RGFW_BUFFER) && !defined(RGFW_NO_API) + #define RGFW_OPENGL #endif #ifdef RGFW_EGL -#include + #if defined(__APPLE__) + #warning EGL is not supported for Cocoa, switching back to the native opengl api + #undef RGFW_EGL + #endif + + #include +#elif defined(RGFW_OSMESA) + #ifndef __APPLE__ + #include + #else + #include + #endif #endif -#ifdef RGFW_OSMESA -#ifndef __APPLE__ -#include -#else -#include -#endif +#if defined(RGFW_OPENGL) && defined(RGFW_X11) + #ifndef GLX_MESA_swap_control + #define GLX_MESA_swap_control + #endif + #include /* GLX defs, xlib.h, gl.h */ #endif -#if defined(RGFW_DIRECTX) && defined(RGFW_WINDOWS) -#include -#include -#include -#include - -#ifndef __cplusplus -#define __uuidof(T) IID_##T -#endif +#ifndef RGFW_ALPHA + #define RGFW_ALPHA 128 /* alpha value for RGFW_TRANSPARENT_WINDOW (WINAPI ONLY, macOS + linux don't need this) */ #endif - /*! Optional arguments for making a windows */ -#define RGFW_TRANSPARENT_WINDOW (1L<<9) /*!< the window is transparent */ +/*! Optional arguments for making a windows */ +#define RGFW_TRANSPARENT_WINDOW (1L<<9) /*!< the window is transparent (only properly works on X11 and MacOS, although it's although for windows) */ #define RGFW_NO_BORDER (1L<<3) /*!< the window doesn't have border */ #define RGFW_NO_RESIZE (1L<<4) /*!< the window cannot be resized by the user */ #define RGFW_ALLOW_DND (1L<<5) /*!< the window supports drag and drop*/ @@ -244,59 +312,69 @@ extern "C" { #define RGFW_OPENGL_SOFTWARE (1L<<11) /*! use OpenGL software rendering */ #define RGFW_COCOA_MOVE_TO_RESOURCE_DIR (1L << 12) /* (cocoa only), move to resource folder */ #define RGFW_SCALE_TO_MONITOR (1L << 13) /* scale the window to the screen */ +#define RGFW_NO_INIT_API (1L << 2) /* DO not init an API (mostly for bindings, you should use `#define RGFW_NO_API` in C */ #define RGFW_NO_GPU_RENDER (1L<<14) /* don't render (using the GPU based API)*/ #define RGFW_NO_CPU_RENDER (1L<<15) /* don't render (using the CPU based buffer rendering)*/ +#define RGFW_WINDOW_HIDE (1L << 16)/* the window is hidden */ +typedef RGFW_ENUM(u8, RGFW_event_types) { + /*! event codes */ + RGFW_keyPressed = 1, /* a key has been pressed */ + RGFW_keyReleased, /*!< a key has been released*/ + /*! key event note + the code of the key pressed is stored in + RGFW_Event.keyCode + !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! -/*! event codes */ -#define RGFW_keyPressed 2 /* a key has been pressed */ -#define RGFW_keyReleased 3 /*!< a key has been released*/ -/*! key event note - the code of the key pressed is stored in - RGFW_Event.keyCode - !!Keycodes defined at the bottom of the header file!! + while a string version is stored in + RGFW_Event.KeyString - while a string version is stored in - RGFW_Event.KeyString + RGFW_Event.lockState holds the current lockState + this means if CapsLock, NumLock are active or not + */ + RGFW_mouseButtonPressed, /*!< a mouse button has been pressed (left,middle,right)*/ + RGFW_mouseButtonReleased, /*!< a mouse button has been released (left,middle,right)*/ + RGFW_mousePosChanged, /*!< the position of the mouse has been changed*/ + /*! mouse event note + the x and y of the mouse can be found in the vector, RGFW_Event.point - RGFW_Event.lockState holds the current lockState - this means if CapsLock, NumLock are active or not -*/ -#define RGFW_mouseButtonPressed 4 /*!< a mouse button has been pressed (left,middle,right)*/ -#define RGFW_mouseButtonReleased 5 /*!< a mouse button has been released (left,middle,right)*/ -#define RGFW_mousePosChanged 6 /*!< the position of the mouse has been changed*/ -/*! mouse event note - the x and y of the mouse can be found in the vector, RGFW_Event.point + RGFW_Event.button holds which mouse button was pressed + */ + RGFW_jsButtonPressed, /*!< a joystick button was pressed */ + RGFW_jsButtonReleased, /*!< a joystick button was released */ + RGFW_jsAxisMove, /*!< an axis of a joystick was moved*/ + /*! joystick event note + RGFW_Event.joystick holds which joystick was altered, if any + RGFW_Event.button holds which joystick button was pressed - RGFW_Event.button holds which mouse button was pressed -*/ -#define RGFW_jsButtonPressed 7 /*!< a joystick button was pressed */ -#define RGFW_jsButtonReleased 8 /*!< a joystick button was released */ -#define RGFW_jsAxisMove 9 /*!< an axis of a joystick was moved*/ -/*! joystick event note - RGFW_Event.joystick holds which joystick was altered, if any - RGFW_Event.button holds which joystick button was pressed + RGFW_Event.axis holds the data of all the axis + RGFW_Event.axisCount says how many axis there are + */ + RGFW_windowMoved, /*!< the window was moved (by the user) */ + RGFW_windowResized, /*!< the window was resized (by the user), [on webASM this means the browser was resized] */ + RGFW_focusIn, /*!< window is in focus now */ + RGFW_focusOut, /*!< window is out of focus now */ + RGFW_mouseEnter, /* mouse entered the window */ + RGFW_mouseLeave, /* mouse left the window */ + RGFW_windowRefresh, /* The window content needs to be refreshed */ - RGFW_Event.axis holds the data of all the axis - RGFW_Event.axisCount says how many axis there are -*/ -#define RGFW_windowAttribsChange 10 /*!< the window was moved or resized (by the user) */ -/* attribs change event note - The event data is sent straight to the window structure - with win->r.x, win->r.y, win->r.w and win->r.h -*/ -#define RGFW_quit 33 /*!< the user clicked the quit button*/ -#define RGFW_dnd 34 /*!< a file has been dropped into the window*/ -#define RGFW_dnd_init 35 /*!< the start of a dnd event, when the place where the file drop is known */ -/* dnd data note - The x and y coords of the drop are stored in the vector RGFW_Event.point + /* attribs change event note + The event data is sent straight to the window structure + with win->r.x, win->r.y, win->r.w and win->r.h + */ + RGFW_quit, /*!< the user clicked the quit button*/ + RGFW_dnd, /*!< a file has been dropped into the window*/ + RGFW_dnd_init /*!< the start of a dnd event, when the place where the file drop is known */ + /* dnd data note + The x and y coords of the drop are stored in the vector RGFW_Event.point - RGFW_Event.droppedFilesCount holds how many files were dropped + RGFW_Event.droppedFilesCount holds how many files were dropped - This is also the size of the array which stores all the dropped file string, - RGFW_Event.droppedFiles -*/ + This is also the size of the array which stores all the dropped file string, + RGFW_Event.droppedFiles + */ +}; /*! mouse button codes (RGFW_Event.button) */ #define RGFW_mouseLeft 1 /*!< left mouse button is pressed*/ @@ -318,370 +396,506 @@ extern "C" { #define RGFW_NUMLOCK (1L << 2) /*! joystick button codes (based on xbox/playstation), you may need to change these values per controller */ -#ifndef RGFW_JS_A - -#define RGFW_JS_A 0 /* or PS X button */ -#define RGFW_JS_B 1 /* or PS circle button */ -#define RGFW_JS_Y 2 /* or PS triangle button */ -#define RGFW_JS_X 3 /* or PS square button */ -#define RGFW_JS_START 9 /* start button */ -#define RGFW_JS_SELECT 8 /* select button */ -#define RGFW_JS_HOME 10 /* home button */ -#define RGFW_JS_UP 13 /* dpad up */ -#define RGFW_JS_DOWN 14 /* dpad down*/ -#define RGFW_JS_LEFT 15 /* dpad left */ -#define RGFW_JS_RIGHT 16 /* dpad right */ -#define RGFW_JS_L1 4 /* left bump */ -#define RGFW_JS_L2 5 /* left trigger*/ -#define RGFW_JS_R1 6 /* right bumper */ -#define RGFW_JS_R2 7 /* right trigger */ - +#ifndef RGFW_joystick_codes + typedef RGFW_ENUM(u8, RGFW_joystick_codes) { + RGFW_JS_A = 0, /*!< or PS X button */ + RGFW_JS_B = 1, /*!< or PS circle button */ + RGFW_JS_Y = 2, /*!< or PS triangle button */ + RGFW_JS_X = 3, /*!< or PS square button */ + RGFW_JS_START = 9, /*!< start button */ + RGFW_JS_SELECT = 8, /*!< select button */ + RGFW_JS_HOME = 10, /*!< home button */ + RGFW_JS_UP = 13, /*!< dpad up */ + RGFW_JS_DOWN = 14, /*!< dpad down*/ + RGFW_JS_LEFT = 15, /*!< dpad left */ + RGFW_JS_RIGHT = 16, /*!< dpad right */ + RGFW_JS_L1 = 4, /*!< left bump */ + RGFW_JS_L2 = 5, /*!< left trigger*/ + RGFW_JS_R1 = 6, /*!< right bumper */ + RGFW_JS_R2 = 7, /*!< right trigger */ + }; #endif -/* basic vector type, if there's not already a point/vector type of choice */ -#ifndef RGFW_vector -typedef struct { i32 x, y; } RGFW_vector; +/*! basic vector type, if there's not already a point/vector type of choice */ +#ifndef RGFW_point + typedef struct { i32 x, y; } RGFW_point; #endif - /* basic rect type, if there's not already a rect type of choice */ +/*! basic rect type, if there's not already a rect type of choice */ #ifndef RGFW_rect typedef struct { i32 x, y, w, h; } RGFW_rect; #endif - /* basic area type, if there's not already a area type of choice */ +/*! basic area type, if there's not already a area type of choice */ #ifndef RGFW_area typedef struct { u32 w, h; } RGFW_area; #endif -#define RGFW_VECTOR(x, y) (RGFW_vector){x, y} -#define RGFW_RECT(x, y, w, h) (RGFW_rect){x, y, w, h} -#define RGFW_AREA(w, h) (RGFW_area){w, h} +#ifndef __cplusplus +#define RGFW_POINT(x, y) (RGFW_point){(i32)(x), (i32)(y)} +#define RGFW_RECT(x, y, w, h) (RGFW_rect){(i32)(x), (i32)(y), (i32)(w), (i32)(h)} +#define RGFW_AREA(w, h) (RGFW_area){(u32)(w), (u32)(h)} +#else +#define RGFW_POINT(x, y) {(i32)(x), (i32)(y)} +#define RGFW_RECT(x, y, w, h) {(i32)(x), (i32)(y), (i32)(w), (i32)(h)} +#define RGFW_AREA(w, h) {(u32)(w), (u32)(h)} +#endif +#ifndef RGFW_NO_MONITOR + /*! structure for monitor data */ typedef struct RGFW_monitor { - char name[128]; /* monitor name */ - RGFW_rect rect; /* monitor Workarea */ - float scaleX, scaleY; /* monitor content scale*/ - float physW, physH; /* monitor physical size */ + char name[128]; /*!< monitor name */ + RGFW_rect rect; /*!< monitor Workarea */ + float scaleX, scaleY; /*!< monitor content scale*/ + float physW, physH; /*!< monitor physical size */ } RGFW_monitor; /* - NOTE : Monitor functions should be ran only as many times as needed (not in a loop) + NOTE : Monitor functions should be ran only as many times as needed (not in a loop) */ - /* get an array of all the monitors (max 6) */ + /*! get an array of all the monitors (max 6) */ RGFWDEF RGFW_monitor* RGFW_getMonitors(void); - /* get the primary monitor */ + /*! get the primary monitor */ RGFWDEF RGFW_monitor RGFW_getPrimaryMonitor(void); - - /* NOTE: some parts of the data can represent different things based on the event (read comments in RGFW_Event struct) */ - typedef struct RGFW_Event { -#ifdef RGFW_WINDOWS - char keyName[16]; /* key name of event*/ -#else - char* keyName; /*!< key name of event */ #endif - /*! drag and drop data */ - /* 260 max paths with a max length of 260 */ +/* NOTE: some parts of the data can represent different things based on the event (read comments in RGFW_Event struct) */ +/*! Event structure for checking/getting events */ +typedef struct RGFW_Event { + char keyName[16]; /*!< key name of event*/ + + /*! drag and drop data */ + /* 260 max paths with a max length of 260 */ #ifdef RGFW_ALLOC_DROPFILES - char** droppedFiles; + char** droppedFiles; #else - char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH]; /*!< dropped files*/ + char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH]; /*!< dropped files*/ #endif - u32 droppedFilesCount; /*!< house many files were dropped */ + u32 droppedFilesCount; /*!< house many files were dropped */ - u32 type; /*!< which event has been sent?*/ - RGFW_vector point; /*!< mouse x, y of event (or drop point) */ - u32 keyCode; /*!< keycode of event !!Keycodes defined at the bottom of the header file!! */ + u32 type; /*!< which event has been sent?*/ + RGFW_point point; /*!< mouse x, y of event (or drop point) */ + + u8 keyCode; /*!< keycode of event !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! */ + + b8 repeat; /*!< key press event repeated (the key is being held) */ + b8 inFocus; /*!< if the window is in focus or not (this is always true for MacOS windows due to the api being weird) */ - u32 fps; /*the current fps of the window [the fps is checked when events are checked]*/ - u64 frameTime, frameTime2; /* this is used for counting the fps */ + u8 lockState; + + u8 button; /* !< which mouse button was pressed */ + double scroll; /*!< the raw mouse scroll value */ - u8 inFocus; /*if the window is in focus or not*/ + u16 joystick; /*! which joystick this event applies to (if applicable to any) */ + u8 axisesCount; /*!< number of axises */ + RGFW_point axis[2]; /*!< x, y of axises (-100 to 100) */ - u8 lockState; + u64 frameTime, frameTime2; /*!< this is used for counting the fps */ +} RGFW_Event; - u16 joystick; /* which joystick this event applies to (if applicable to any) */ - - u8 button; /*!< which mouse button has been clicked (0) left (1) middle (2) right OR which joystick button was pressed*/ - double scroll; /* the raw mouse scroll value */ - - u8 axisesCount; /* number of axises */ - RGFW_vector axis[2]; /* x, y of axises (-100 to 100) */ - } RGFW_Event; /*!< Event structure for checking/getting events */ - - /* source data for the window (used by the APIs) */ - typedef struct RGFW_window_src { +/*! source data for the window (used by the APIs) */ +typedef struct RGFW_window_src { #ifdef RGFW_WINDOWS - HWND window; /*!< source window */ - HDC hdc; /*!< source HDC */ - u32 hOffset; /*!< height offset for window */ -#endif -#ifdef RGFW_X11 - Display* display; /*!< source display */ - Window window; /*!< source window */ - Cursor cursor; -#endif -#ifdef RGFW_MACOS - u32 display; - void* displayLink; - void* window; - u8 dndPassed; -#endif - -#if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) -#ifdef RGFW_MACOS - void* rSurf; /*!< source graphics context */ -#endif -#ifdef RGFW_WINDOWS - HGLRC rSurf; /*!< source graphics context */ -#endif -#ifdef RGFW_X11 - GLXContext rSurf; /*!< source graphics context */ -#endif -#else -#ifdef RGFW_VULKAN - VkSurfaceKHR rSurf; /*!< source graphics context */ - - /* vulkan data */ - VkSwapchainKHR swapchain; - u32 image_count; - VkImage* swapchain_images; - VkImageView* swapchain_image_views; -#endif - -#ifdef RGFW_OSMESA - OSMesaContext rSurf; -#endif -#endif - -#ifdef RGFW_WINDOWS - RGFW_area maxSize, minSize; -#if defined(RGFW_DIRECTX) + HWND window; /*!< source window */ + HDC hdc; /*!< source HDC */ + u32 hOffset; /*!< height offset for window */ + #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL) + HGLRC ctx; /*!< source graphics context */ + #elif defined(RGFW_OSMESA) + OSMesaContext ctx; + #elif defined(RGFW_DIRECTX) IDXGISwapChain* swapchain; ID3D11RenderTargetView* renderTargetView; ID3D11DepthStencilView* pDepthStencilView; -#endif -#endif + #elif defined(RGFW_EGL) + EGLSurface EGL_surface; + EGLDisplay EGL_display; + EGLContext EGL_context; + #endif -#if defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11) - void* view; /*apple viewpoint thingy*/ -#endif + #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + HDC hdcMem; + HBITMAP bitmap; + #endif + RGFW_area maxSize, minSize; /*!< for setting max/min resize (RGFW_WINDOWS) */ +#elif defined(RGFW_X11) + Display* display; /*!< source display */ + Window window; /*!< source window */ + #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL) + GLXContext ctx; /*!< source graphics context */ + #elif defined(RGFW_OSMESA) + OSMesaContext ctx; + #elif defined(RGFW_EGL) + EGLSurface EGL_surface; + EGLDisplay EGL_display; + EGLContext EGL_context; + #endif -#ifdef RGFW_EGL +#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + XImage* bitmap; + GC gc; +#endif +#elif defined(RGFW_WAYLAND) + struct wl_display* display; + struct wl_surface* surface; + struct wl_buffer* wl_buffer; + struct wl_keyboard* keyboard; + + struct xdg_surface* xdg_surface; + struct xdg_toplevel* xdg_toplevel; + struct zxdg_toplevel_decoration_v1* decoration; + RGFW_Event events[20]; + i32 eventLen; + size_t eventIndex; + #if defined(RGFW_EGL) + struct wl_egl_window* window; + EGLSurface EGL_surface; + EGLDisplay EGL_display; + EGLContext EGL_context; + #elif defined(RGFW_OSMESA) + OSMesaContext ctx; + #endif +#elif defined(RGFW_MACOS) + u32 display; + void* displayLink; + void* window; + b8 dndPassed; +#if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL) + void* ctx; /*!< source graphics context */ +#elif defined(RGFW_OSMESA) + OSMesaContext ctx; +#elif defined(RGFW_EGL) EGLSurface EGL_surface; EGLDisplay EGL_display; EGLContext EGL_context; #endif + void* view; /*apple viewpoint thingy*/ + #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) -#ifdef RGFW_WINDOWS - HBITMAP bitmap; -#endif -#ifdef RGFW_X11 - XImage* bitmap; -#endif -#ifdef RGFW_MACOS - void* bitmap; /* API's bitmap for storing or managing */ + void* bitmap; /*!< API's bitmap for storing or managing */ void* image; #endif -#if defined(RGFW_BUFFER) && defined(RGFW_WINDOWS) - HDC hdcMem; /* window stored in memory that winapi needs to render buffers */ -#endif +#elif defined(RGFW_WEBASM) + EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx; #endif +} RGFW_window_src; - u8 jsPressed[4][16]; /* if a key is currently pressed or not (per joystick) */ - i32 joysticks[4]; /* limit of 4 joysticks at a time */ - u16 joystickCount; /* the actual amount of joysticks */ - RGFW_area scale; /* window scaling */ - -#ifdef RGFW_MACOS - u8 cursorChanged; /* for steve jobs */ -#endif - - u32 winArgs; /* windows args (for RGFW to check) */ - /* - !< if dnd is enabled or on (based on window creating args) - cursorChanged - */ - } RGFW_window_src; - - typedef struct RGFW_window { - RGFW_window_src src; +typedef struct RGFW_window { + RGFW_window_src src; /*!< src window data */ #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - u8* buffer; /* buffer for non-GPU systems (OSMesa, basic software rendering) */ - /* when rendering using RGFW_BUFFER, the buffer is in the RGBA format */ + u8* buffer; /*!< buffer for non-GPU systems (OSMesa, basic software rendering) */ + /* when rendering using RGFW_BUFFER, the buffer is in the RGBA format */ #endif + void* userPtr; /* ptr for usr data */ + + RGFW_Event event; /*!< current event */ - RGFW_Event event; /*!< current event */ - - RGFW_rect r; /* the x, y, w and h of the struct */ - - u32 fpsCap; /*!< the fps cap of the window should run at (change this var to change the fps cap, 0 = no limit)*/ - /*[the fps is capped when events are checked]*/ - } RGFW_window; /*!< Window structure for managing the window */ + RGFW_rect r; /*!< the x, y, w and h of the struct */ + + RGFW_point _lastMousePoint; /*!< last cusor point (for raw mouse data) */ + + u32 _winArgs; /*!< windows args (for RGFW to check) */ +} RGFW_window; /*!< Window structure for managing the window */ #if defined(RGFW_X11) || defined(RGFW_MACOS) - typedef u64 RGFW_thread; /* thread type unix */ + typedef u64 RGFW_thread; /*!< thread type unix */ #else - typedef void* RGFW_thread; /* thread type for window */ + typedef void* RGFW_thread; /*!< thread type for window */ #endif - RGFW_window* RGFW_createWindow( - const char* name, /* name of the window */ - RGFW_rect rect, /* rect of window */ - u16 args /* extra arguments (NULL / (u16)0 means no args used)*/ - ); /*!< function to create a window struct */ +/** * @defgroup Window_management +* @{ */ - /* get the size of the screen to an area struct */ - RGFWDEF RGFW_area RGFW_getScreenSize(void); +/*! this has to be set before createWindow is called, else the fulscreen size is used */ +RGFWDEF void RGFW_setBufferSize(RGFW_area size); /*!< the buffer cannot be resized (by RGFW) */ - /* - this function checks an *individual* event (and updates window structure attributes) - this means, using this function without a while loop may cause event lag +RGFW_window* RGFW_createWindow( + const char* name, /* name of the window */ + RGFW_rect rect, /* rect of window */ + u16 args /* extra arguments (NULL / (u16)0 means no args used)*/ +); /*!< function to create a window struct */ - ex. +/*! get the size of the screen to an area struct */ +RGFWDEF RGFW_area RGFW_getScreenSize(void); - while (RGFW_window_checkEvent(win) != NULL) [this keeps checking events until it reaches the last one] - */ +/*! + this function checks an *individual* event (and updates window structure attributes) + this means, using this function without a while loop may cause event lag - RGFW_Event* RGFW_window_checkEvent(RGFW_window* win); /*!< check events (returns a pointer to win->event or NULL if there is no event)*/ + ex. - /*! window managment functions*/ - RGFWDEF void RGFW_window_close(RGFW_window* win); /*!< close the window and free leftover data */ + while (RGFW_window_checkEvent(win) != NULL) [this keeps checking events until it reaches the last one] - RGFWDEF void RGFW_window_move(RGFW_window* win, - RGFW_vector v/* new pos*/ - ); + this function is optional if you choose to use event callbacks, + although you still need some way to tell RGFW to process events eg. `RGFW_window_checkEvents` +*/ - /* move to a specific monitor */ - RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m); +RGFW_Event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/ - RGFWDEF void RGFW_window_resize(RGFW_window* win, - RGFW_area a/* new size*/ - ); +/*! + for RGFW_window_eventWait and RGFW_window_checkEvents + waitMS -> Allows th e function to keep checking for events even after `RGFW_window_checkEvent == NULL` + if waitMS == 0, the loop will not wait for events + if waitMS == a positive integer, the loop will wait that many miliseconds after there are no more events until it returns + if waitMS == a negative integer, the loop will not return until it gets another event +*/ +typedef RGFW_ENUM(i32, RGFW_eventWait) { + RGFW_NEXT = -1, + RGFW_NO_WAIT = 0 +}; - /* set the minimum size a user can shrink a window */ - RGFWDEF void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a); - /* set the minimum size a user can extend a window */ - RGFWDEF void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a); +/*! sleep until RGFW gets an event or the timer ends (defined by OS) */ +RGFWDEF void RGFW_window_eventWait(RGFW_window* win, i32 waitMS); - RGFWDEF void RGFW_window_maximize(RGFW_window* win); /* maximize the window size */ - RGFWDEF void RGFW_window_minimize(RGFW_window* win); /* minimize the window (in taskbar (per OS))*/ - RGFWDEF void RGFW_window_restore(RGFW_window* win); /* restore the window from minimized (per OS)*/ +/*! + check all the events until there are none left, + this should only be used if you're using callbacks only +*/ +RGFWDEF void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS); - RGFWDEF void RGFW_window_setName(RGFW_window* win, - char* name - ); +/*! + Tell RGFW_window_eventWait to stop waiting, to be ran from another thread +*/ +RGFWDEF void RGFW_stopCheckEvents(void); - void RGFW_window_setIcon(RGFW_window* win, /*!< source window */ - u8* icon /*!< icon bitmap */, - RGFW_area a /*!< width and height of the bitmap*/, - i32 channels /*!< how many channels the bitmap has (rgb : 3, rgba : 4) */ - ); /*!< image resized by default */ +/*! window managment functions*/ +RGFWDEF void RGFW_window_close(RGFW_window* win); /*!< close the window and free leftover data */ - /*!< sets mouse to bitmap (very simular to RGFW_window_setIcon), image NOT resized by default*/ - RGFWDEF void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels); +/*! moves window to a given point */ +RGFWDEF void RGFW_window_move(RGFW_window* win, + RGFW_point v/*!< new pos*/ +); - /*!< sets the mouse to a standard API cursor (based on RGFW_MOUSE, as seen at the end of the file) */ -#ifdef RGFW_MACOS - RGFWDEF void RGFW_window_setMouseStandard(RGFW_window* win, void* mouse); -#else - RGFWDEF void RGFW_window_setMouseStandard(RGFW_window* win, i32 mouse); +#ifndef RGFW_NO_MONITOR + /*! move to a specific monitor */ + RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m /* monitor */); #endif - RGFWDEF void RGFW_window_setMouseDefault(RGFW_window* win); /* sets the mouse to1` the default mouse image */ - /* - holds the mouse in place by moving the mouse back each time it moves - you can still use win->event.point to see how much it moved before it was put back in place +/*! resize window to a current size/area */ +RGFWDEF void RGFW_window_resize(RGFW_window* win, /*!< source window */ + RGFW_area a/*!< new size*/ +); - this is useful for a 3D camera - */ - RGFWDEF void RGFW_window_mouseHold(RGFW_window* win); - /* undo hold */ - RGFWDEF void RGFW_window_mouseUnhold(RGFW_window* win); +/*! set the minimum size a user can shrink a window to a given size/area */ +RGFWDEF void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a); +/*! set the minimum size a user can extend a window to a given size/area */ +RGFWDEF void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a); - /* hide the window */ - RGFWDEF void RGFW_window_hide(RGFW_window* win); - /* show the window */ - RGFWDEF void RGFW_window_show(RGFW_window* win); +RGFWDEF void RGFW_window_maximize(RGFW_window* win); /*!< maximize the window size */ +RGFWDEF void RGFW_window_minimize(RGFW_window* win); /*!< minimize the window (in taskbar (per OS))*/ +RGFWDEF void RGFW_window_restore(RGFW_window* win); /*!< restore the window from minimized (per OS)*/ - /* - makes it so `RGFW_window_shouldClose` returns true - by setting the window event.type to RGFW_quit - */ - RGFWDEF void RGFW_window_setShouldClose(RGFW_window* win); +/*! if the window should have a border or not (borderless) based on bool value of `border` */ +RGFWDEF void RGFW_window_setBorder(RGFW_window* win, b8 border); - /* where the mouse is on the screen */ - RGFWDEF RGFW_vector RGFW_getGlobalMousePoint(void); +/*! turn on / off dnd (RGFW_ALLOW_DND stil must be passed to the window)*/ +RGFWDEF void RGFW_window_setDND(RGFW_window* win, b8 allow); - /* show the mouse or hide the mouse*/ - RGFWDEF void RGFW_window_showMouse(RGFW_window* win, i8 show); - /* move the mouse to a set x, y pos*/ - RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, RGFW_vector v); +#ifndef RGFW_NO_PASSTHROUGH + /*!! turn on / off mouse passthrough */ + RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough); +#endif - /* if the window should close (RGFW_close was sent or escape was pressed) */ - RGFWDEF u8 RGFW_window_shouldClose(RGFW_window* win); - /* if window is fullscreen'd */ - RGFWDEF u8 RGFW_window_isFullscreen(RGFW_window* win); - /* if window is hidden */ - RGFWDEF u8 RGFW_window_isHidden(RGFW_window* win); - /* if window is minimized */ - RGFWDEF u8 RGFW_window_isMinimized(RGFW_window* win); - /* if window is maximized */ - RGFWDEF u8 RGFW_window_isMaximized(RGFW_window* win); +/*! rename window to a given string */ +RGFWDEF void RGFW_window_setName(RGFW_window* win, + char* name +); - /* - scale the window to the monitor, - this is run by default if the user uses the arg `RGFW_SCALE_TO_MONITOR` during window creation - */ - RGFWDEF void RGFW_window_scaleToMonitor(RGFW_window* win); - /* get the struct of the window's monitor */ - RGFWDEF RGFW_monitor RGFW_window_getMonitor(RGFW_window* win); +void RGFW_window_setIcon(RGFW_window* win, /*!< source window */ + u8* icon /*!< icon bitmap */, + RGFW_area a /*!< width and height of the bitmap*/, + i32 channels /*!< how many channels the bitmap has (rgb : 3, rgba : 4) */ +); /*!< image resized by default */ - /*!< make the window the current opengl drawing context */ - RGFWDEF void RGFW_window_makeCurrent(RGFW_window* win); +/*!< sets mouse to bitmap (very simular to RGFW_window_setIcon), image NOT resized by default*/ +RGFWDEF void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels); - /*error handling*/ - RGFWDEF u8 RGFW_Error(void); /* returns true if an error has occurred (doesn't print errors itself) */ +/*!< sets the mouse to a standard API cursor (based on RGFW_MOUSE, as seen at the end of the RGFW_HEADER part of this file) */ +RGFWDEF void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse); - /*!< if window == NULL, it checks if the key is pressed globally. Otherwise, it checks only if the key is pressed while the window in focus.*/ - RGFWDEF u8 RGFW_isPressedI(RGFW_window* win, u32 key); /*!< if key is pressed (key code)*/ +RGFWDEF void RGFW_window_setMouseDefault(RGFW_window* win); /*!< sets the mouse to the default mouse icon */ +/* + Locks cursor at the center of the window + win->event.point become raw mouse movement data - RGFWDEF u8 RGFW_wasPressedI(RGFW_window* win, u32 key); /*!< if key was pressed (checks prev keymap only) (key code)*/ + this is useful for a 3D camera +*/ +RGFWDEF void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area); +/*! stop holding the mouse and let it move freely */ +RGFWDEF void RGFW_window_mouseUnhold(RGFW_window* win); - RGFWDEF u8 RGFW_isHeldI(RGFW_window* win, u32 key); /*!< if key is held (key code)*/ - RGFWDEF u8 RGFW_isReleasedI(RGFW_window* win, u32 key); /*!< if key is released (key code)*/ +/*! hide the window */ +RGFWDEF void RGFW_window_hide(RGFW_window* win); +/*! show the window */ +RGFWDEF void RGFW_window_show(RGFW_window* win); - /* - !!Keycodes defined at the bottom of the header file!! - */ - /*!< converts a key code to it's key string */ - RGFWDEF char* RGFW_keyCodeTokeyStr(u64 key); - /*!< converts a string of a key to it's key code */ - RGFWDEF u32 RGFW_keyStrToKeyCode(char* key); - /*!< if key is pressed (key string) */ -#define RGFW_isPressedS(win, key) RGFW_isPressedI(win, RGFW_keyStrToKeyCode(key)) +/* + makes it so `RGFW_window_shouldClose` returns true + by setting the window event.type to RGFW_quit +*/ +RGFWDEF void RGFW_window_setShouldClose(RGFW_window* win); -/*! clipboard functions*/ - RGFWDEF char* RGFW_readClipboard(size_t* size); /*!< read clipboard data */ -#define RGFW_clipboardFree free /* the string returned from RGFW_readClipboard must be freed */ +/*! where the mouse is on the screen */ +RGFWDEF RGFW_point RGFW_getGlobalMousePoint(void); - RGFWDEF void RGFW_writeClipboard(const char* text, u32 textLen); /*!< write text to the clipboard */ +/*! where the mouse is on the window */ +RGFWDEF RGFW_point RGFW_window_getMousePoint(RGFW_window* win); - /* - convert a keyString to a char version - */ - RGFWDEF char RGFW_keystrToChar(const char*); - /* - ex. - "parenleft" -> '(' - "A" -> 'A', - "Return" -> "\n" - */ +/*! show the mouse or hide the mouse*/ +RGFWDEF void RGFW_window_showMouse(RGFW_window* win, i8 show); +/*! move the mouse to a set x, y pos*/ +RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v); + +/*! if the window should close (RGFW_close was sent or escape was pressed) */ +RGFWDEF b8 RGFW_window_shouldClose(RGFW_window* win); +/*! if window is fullscreen'd */ +RGFWDEF b8 RGFW_window_isFullscreen(RGFW_window* win); +/*! if window is hidden */ +RGFWDEF b8 RGFW_window_isHidden(RGFW_window* win); +/*! if window is minimized */ +RGFWDEF b8 RGFW_window_isMinimized(RGFW_window* win); +/*! if window is maximized */ +RGFWDEF b8 RGFW_window_isMaximized(RGFW_window* win); + +/** @} */ + +/** * @defgroup Monitor +* @{ */ + +#ifndef RGFW_NO_MONITOR +/* +scale the window to the monitor, +this is run by default if the user uses the arg `RGFW_SCALE_TO_MONITOR` during window creation +*/ +RGFWDEF void RGFW_window_scaleToMonitor(RGFW_window* win); +/*! get the struct of the window's monitor */ +RGFWDEF RGFW_monitor RGFW_window_getMonitor(RGFW_window* win); +#endif + +/** @} */ + +/** * @defgroup Input +* @{ */ + +/*error handling*/ +RGFWDEF b8 RGFW_Error(void); /*!< returns true if an error has occurred (doesn't print errors itself) */ + +/*! returns true if the key should be shifted */ +RGFWDEF b8 RGFW_shouldShift(u32 keycode, u8 lockState); + +/*! get char from RGFW keycode (using a LUT), uses shift'd version if shift = true */ +RGFWDEF char RGFW_keyCodeToChar(u32 keycode, b8 shift); +/*! get char from RGFW keycode (using a LUT), uses lockState for shouldShift) */ +RGFWDEF char RGFW_keyCodeToCharAuto(u32 keycode, u8 lockState); + +/*! if window == NULL, it checks if the key is pressed globally. Otherwise, it checks only if the key is pressed while the window in focus.*/ +RGFWDEF b8 RGFW_isPressed(RGFW_window* win, u8 key); /*!< if key is pressed (key code)*/ + +RGFWDEF b8 RGFW_wasPressed(RGFW_window* win, u8 key); /*!< if key was pressed (checks previous state only) (key code)*/ + +RGFWDEF b8 RGFW_isHeld(RGFW_window* win, u8 key); /*!< if key is held (key code)*/ +RGFWDEF b8 RGFW_isReleased(RGFW_window* win, u8 key); /*!< if key is released (key code)*/ + +/* if a key is pressed and then released, pretty much the same as RGFW_isReleased */ +RGFWDEF b8 RGFW_isClicked(RGFW_window* win, u8 key /*!< key code*/); + +/*! if a mouse button is pressed */ +RGFWDEF b8 RGFW_isMousePressed(RGFW_window* win, u8 button /*!< mouse button code */ ); +/*! if a mouse button is held */ +RGFWDEF b8 RGFW_isMouseHeld(RGFW_window* win, u8 button /*!< mouse button code */ ); +/*! if a mouse button was released */ +RGFWDEF b8 RGFW_isMouseReleased(RGFW_window* win, u8 button /*!< mouse button code */ ); +/*! if a mouse button was pressed (checks previous state only) */ +RGFWDEF b8 RGFW_wasMousePressed(RGFW_window* win, u8 button /*!< mouse button code */ ); +/** @} */ + +/** * @defgroup Clipboard +* @{ */ +RGFWDEF char* RGFW_readClipboard(size_t* size); /*!< read clipboard data */ +RGFWDEF void RGFW_clipboardFree(char* str); /*!< the string returned from RGFW_readClipboard must be freed */ + +RGFWDEF void RGFW_writeClipboard(const char* text, u32 textLen); /*!< write text to the clipboard */ +/** @} */ + +/** + + + Event callbacks, + these are completely optional, you can use the normal + RGFW_checkEvent() method if you prefer that + +* @defgroup Callbacks +* @{ +*/ + +/*! RGFW_windowMoved, the window and its new rect value */ +typedef void (* RGFW_windowmovefunc)(RGFW_window* win, RGFW_rect r); +/*! RGFW_windowResized, the window and its new rect value */ +typedef void (* RGFW_windowresizefunc)(RGFW_window* win, RGFW_rect r); +/*! RGFW_quit, the window that was closed */ +typedef void (* RGFW_windowquitfunc)(RGFW_window* win); +/*! RGFW_focusIn / RGFW_focusOut, the window who's focus has changed and if its inFocus */ +typedef void (* RGFW_focusfunc)(RGFW_window* win, b8 inFocus); +/*! RGFW_mouseEnter / RGFW_mouseLeave, the window that changed, the point of the mouse (enter only) and if the mouse has entered */ +typedef void (* RGFW_mouseNotifyfunc)(RGFW_window* win, RGFW_point point, b8 status); +/*! RGFW_mousePosChanged, the window that the move happened on and the new point of the mouse */ +typedef void (* RGFW_mouseposfunc)(RGFW_window* win, RGFW_point point); +/*! RGFW_dnd_init, the window, the point of the drop on the windows */ +typedef void (* RGFW_dndInitfunc)(RGFW_window* win, RGFW_point point); +/*! RGFW_windowRefresh, the window that needs to be refreshed */ +typedef void (* RGFW_windowrefreshfunc)(RGFW_window* win); +/*! RGFW_keyPressed / RGFW_keyReleased, the window that got the event, the keycode, the string version, the state of mod keys, if it was a press (else it's a release) */ +typedef void (* RGFW_keyfunc)(RGFW_window* win, u32 keycode, char keyName[16], u8 lockState, b8 pressed); +/*! RGFW_mouseButtonPressed / RGFW_mouseButtonReleased, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */ +typedef void (* RGFW_mousebuttonfunc)(RGFW_window* win, u8 button, double scroll, b8 pressed); +/*! RGFW_jsButtonPressed / RGFW_jsButtonReleased, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */ +typedef void (* RGFW_jsButtonfunc)(RGFW_window* win, u16 joystick, u8 button, b8 pressed); +/*! RGFW_jsAxisMove, the window that got the event, the joystick in question, the axis values and the amount of axises */ +typedef void (* RGFW_jsAxisfunc)(RGFW_window* win, u16 joystick, RGFW_point axis[2], u8 axisesCount); + + +/*! RGFW_dnd, the window that had the drop, the drop data and the amount files dropped returns previous callback function (if it was set) */ +#ifdef RGFW_ALLOC_DROPFILES + typedef void (* RGFW_dndfunc)(RGFW_window* win, char** droppedFiles, u32 droppedFilesCount); +#else + typedef void (* RGFW_dndfunc)(RGFW_window* win, char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH], u32 droppedFilesCount); +#endif +/*! set callback for a window move event returns previous callback function (if it was set) */ +RGFWDEF RGFW_windowmovefunc RGFW_setWindowMoveCallback(RGFW_windowmovefunc func); +/*! set callback for a window resize event returns previous callback function (if it was set) */ +RGFWDEF RGFW_windowresizefunc RGFW_setWindowResizeCallback(RGFW_windowresizefunc func); +/*! set callback for a window quit event returns previous callback function (if it was set) */ +RGFWDEF RGFW_windowquitfunc RGFW_setWindowQuitCallback(RGFW_windowquitfunc func); +/*! set callback for a mouse move event returns previous callback function (if it was set) */ +RGFWDEF RGFW_mouseposfunc RGFW_setMousePosCallback(RGFW_mouseposfunc func); +/*! set callback for a window refresh event returns previous callback function (if it was set) */ +RGFWDEF RGFW_windowrefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowrefreshfunc func); +/*! set callback for a window focus change event returns previous callback function (if it was set) */ +RGFWDEF RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func); +/*! set callback for a mouse notify event returns previous callback function (if it was set) */ +RGFWDEF RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallBack(RGFW_mouseNotifyfunc func); +/*! set callback for a drop event event returns previous callback function (if it was set) */ +RGFWDEF RGFW_dndfunc RGFW_setDndCallback(RGFW_dndfunc func); +/*! set callback for a start of a drop event returns previous callback function (if it was set) */ +RGFWDEF RGFW_dndInitfunc RGFW_setDndInitCallback(RGFW_dndInitfunc func); +/*! set callback for a key (press / release ) event returns previous callback function (if it was set) */ +RGFWDEF RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func); +/*! set callback for a mouse button (press / release ) event returns previous callback function (if it was set) */ +RGFWDEF RGFW_mousebuttonfunc RGFW_setMouseButtonCallback(RGFW_mousebuttonfunc func); +/*! set callback for a controller button (press / release ) event returns previous callback function (if it was set) */ +RGFWDEF RGFW_jsButtonfunc RGFW_setjsButtonCallback(RGFW_jsButtonfunc func); +/*! set callback for a joystick axis mov event returns previous callback function (if it was set) */ +RGFWDEF RGFW_jsAxisfunc RGFW_setjsAxisCallback(RGFW_jsAxisfunc func); + +/** @} */ + +/** * @defgroup Threads +* @{ */ #ifndef RGFW_NO_THREADS /*! threading functions*/ @@ -693,10 +907,10 @@ typedef struct { i32 x, y; } RGFW_vector; which is a good idea generally */ - #if defined(__unix__) || defined(__APPLE__) - typedef void* (* RGFW_threadFunc_ptr)(void*); + #if defined(__unix__) || defined(__APPLE__) || defined(RGFW_WEBASM) + typedef void* (* RGFW_threadFunc_ptr)(void*); #else - typedef DWORD (* RGFW_threadFunc_ptr)(void*); + typedef DWORD (__stdcall *RGFW_threadFunc_ptr) (LPVOID lpThreadParameter); #endif RGFWDEF RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args); /*!< create a thread*/ @@ -705,86 +919,58 @@ typedef struct { i32 x, y; } RGFW_vector; RGFWDEF void RGFW_setThreadPriority(RGFW_thread thread, u8 priority); /*!< sets the priority priority */ #endif - /*! gamepad/joystick functions (linux-only currently) */ +/** @} */ - /*! joystick count starts at 0*/ - /*!< register joystick to window based on a number (the number is based on when it was connected eg. /dev/js0)*/ - RGFWDEF u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber); - RGFWDEF u16 RGFW_registerJoystickF(RGFW_window* win, char* file); +/** * @defgroup joystick +* @{ */ - RGFWDEF u32 RGFW_isPressedJS(RGFW_window* win, u16 controller, u8 button); +/*! joystick count starts at 0*/ +/*!< register joystick to window based on a number (the number is based on when it was connected eg. /dev/js0)*/ +RGFWDEF u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber); +RGFWDEF u16 RGFW_registerJoystickF(RGFW_window* win, char* file); - /*! native opengl functions */ -#ifdef RGFW_OPENGL -/*! Get max OpenGL version */ - RGFWDEF u8* RGFW_getMaxGLVersion(void); - /* OpenGL init hints */ - RGFWDEF void RGFW_setGLStencil(i32 stencil); /* set stencil buffer bit size (8 by default) */ - RGFWDEF void RGFW_setGLSamples(i32 samples); /* set number of sampiling buffers (4 by default) */ - RGFWDEF void RGFW_setGLStereo(i32 stereo); /* use GL_STEREO (GL_FALSE by default) */ - RGFWDEF void RGFW_setGLAuxBuffers(i32 auxBuffers); /* number of aux buffers (0 by default) */ +RGFWDEF u32 RGFW_isPressedJS(RGFW_window* win, u16 controller, u8 button); - /*! Set OpenGL version hint */ - RGFWDEF void RGFW_setGLVersion(i32 major, i32 minor); - RGFWDEF void* RGFW_getProcAddress(const char* procname); /* get native opengl proc address */ -#endif - /* supports openGL, directX, OSMesa, EGL and software rendering */ - RGFWDEF void RGFW_window_swapBuffers(RGFW_window* win); /* swap the rendering buffer */ - RGFWDEF void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval); +/** @} */ - RGFWDEF void RGFW_window_setGPURender(RGFW_window* win, i8 set); +/** * @defgroup graphics_API +* @{ */ -#ifdef RGFW_VULKAN - typedef struct { - VkInstance instance; - VkPhysicalDevice physical_device; - VkDevice device; +/*!< make the window the current opengl drawing context - VkDebugUtilsMessengerEXT debugMessenger; + NOTE: + if you want to switch the graphics context's thread, + you have to run RGFW_window_makeCurrent(NULL); on the old thread + then RGFW_window_makeCurrent(valid_window) on the new thread +*/ +RGFWDEF void RGFW_window_makeCurrent(RGFW_window* win); - VkQueue graphics_queue; - VkQueue present_queue; +/*< updates fps / sets fps to cap (must by ran manually by the user at the end of a frame), returns current fps */ +RGFWDEF u32 RGFW_window_checkFPS(RGFW_window* win, u32 fpsCap); - VkFramebuffer* framebuffers; +/* supports openGL, directX, OSMesa, EGL and software rendering */ +RGFWDEF void RGFW_window_swapBuffers(RGFW_window* win); /*!< swap the rendering buffer */ +RGFWDEF void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval); - VkRenderPass render_pass; - VkPipelineLayout pipeline_layout; - VkPipeline graphics_pipeline; +RGFWDEF void RGFW_window_setGPURender(RGFW_window* win, i8 set); +RGFWDEF void RGFW_window_setCPURender(RGFW_window* win, i8 set); - VkCommandPool command_pool; - VkCommandBuffer* command_buffers; +/*! native API functions */ +#if defined(RGFW_OPENGL) || defined(RGFW_EGL) + /*! OpenGL init hints */ + RGFWDEF void RGFW_setGLStencil(i32 stencil); /*!< set stencil buffer bit size (8 by default) */ + RGFWDEF void RGFW_setGLSamples(i32 samples); /*!< set number of sampiling buffers (4 by default) */ + RGFWDEF void RGFW_setGLStereo(i32 stereo); /*!< use GL_STEREO (GL_FALSE by default) */ + RGFWDEF void RGFW_setGLAuxBuffers(i32 auxBuffers); /*!< number of aux buffers (0 by default) */ - VkSemaphore* available_semaphores; - VkSemaphore* finished_semaphore; - VkFence* in_flight_fences; - VkFence* image_in_flight; - size_t current_frame; - } RGFW_vulkanInfo; - - /*! initializes a vulkan rendering context for the RGFW window, - this outputs the vulkan surface into wwin->src.rSurf - other vulkan data is stored in the global instance of the RGFW_vulkanInfo structure which is returned - by the initVulkan() function - RGFW_VULKAN must be defined for this function to be defined - - */ - RGFWDEF RGFW_vulkanInfo* RGFW_initVulkan(RGFW_window* win); - RGFWDEF void RGFW_freeVulkan(void); - - RGFWDEF RGFW_vulkanInfo* RGFW_getVulkanInfo(void); - - RGFWDEF int RGFW_initData(RGFW_window* win); - RGFWDEF void RGFW_createSurface(VkInstance instance, RGFW_window* win); - int RGFW_deviceInitialization(RGFW_window* win); - int RGFW_createSwapchain(RGFW_window* win); - RGFWDEF int RGFW_createRenderPass(void); - int RGFW_createCommandPool(void); - int RGFW_createCommandBuffers(RGFW_window* win); - int RGFW_createSyncObjects(RGFW_window* win); - RGFWDEF int RGFW_createFramebuffers(RGFW_window* win); -#endif - -#ifdef RGFW_DIRECTX + /*! which profile to use for the opengl verion */ + typedef RGFW_ENUM(u8, RGFW_GL_profile) { RGFW_GL_CORE = 0, RGFW_GL_COMPATIBILITY }; + /*! Set OpenGL version hint (core or compatibility profile)*/ + RGFWDEF void RGFW_setGLVersion(RGFW_GL_profile profile, i32 major, i32 minor); + RGFWDEF void RGFW_setDoubleBuffer(b8 useDoubleBuffer); + RGFWDEF void* RGFW_getProcAddress(const char* procname); /*!< get native opengl proc address */ + RGFWDEF void RGFW_window_makeCurrent_OpenGL(RGFW_window* win); /*!< to be called by RGFW_window_makeCurrent */ +#elif defined(RGFW_DIRECTX) typedef struct { IDXGIFactory* pFactory; IDXGIAdapter* pAdapter; @@ -799,79 +985,219 @@ typedef struct { i32 x, y; } RGFW_vector; RGFWDEF RGFW_directXinfo* RGFW_getDirectXInfo(void); #endif - /*! Supporting functions */ - RGFWDEF void RGFW_window_checkFPS(RGFW_window* win); /*!< updates fps / sets fps to cap (ran by RGFW_window_checkEvent)*/ - RGFWDEF u64 RGFW_getTime(void); /* get time in seconds */ - RGFWDEF u64 RGFW_getTimeNS(void); /* get time in nanoseconds */ - RGFWDEF void RGFW_sleep(u64 microsecond); /* sleep for a set time */ +/** @} */ + +/** * @defgroup Supporting +* @{ */ +RGFWDEF u64 RGFW_getTime(void); /*!< get time in seconds */ +RGFWDEF u64 RGFW_getTimeNS(void); /*!< get time in nanoseconds */ +RGFWDEF void RGFW_sleep(u64 milisecond); /*!< sleep for a set time */ + +/*! + key codes and mouse icon enums +*/ + +typedef RGFW_ENUM(u8, RGFW_Key) { + RGFW_KEY_NULL = 0, + RGFW_Escape, + RGFW_F1, + RGFW_F2, + RGFW_F3, + RGFW_F4, + RGFW_F5, + RGFW_F6, + RGFW_F7, + RGFW_F8, + RGFW_F9, + RGFW_F10, + RGFW_F11, + RGFW_F12, + + RGFW_Backtick, + + RGFW_0, + RGFW_1, + RGFW_2, + RGFW_3, + RGFW_4, + RGFW_5, + RGFW_6, + RGFW_7, + RGFW_8, + RGFW_9, + + RGFW_Minus, + RGFW_Equals, + RGFW_BackSpace, + RGFW_Tab, + RGFW_CapsLock, + RGFW_ShiftL, + RGFW_ControlL, + RGFW_AltL, + RGFW_SuperL, + RGFW_ShiftR, + RGFW_ControlR, + RGFW_AltR, + RGFW_SuperR, + RGFW_Space, + + RGFW_a, + RGFW_b, + RGFW_c, + RGFW_d, + RGFW_e, + RGFW_f, + RGFW_g, + RGFW_h, + RGFW_i, + RGFW_j, + RGFW_k, + RGFW_l, + RGFW_m, + RGFW_n, + RGFW_o, + RGFW_p, + RGFW_q, + RGFW_r, + RGFW_s, + RGFW_t, + RGFW_u, + RGFW_v, + RGFW_w, + RGFW_x, + RGFW_y, + RGFW_z, + + RGFW_Period, + RGFW_Comma, + RGFW_Slash, + RGFW_Bracket, + RGFW_CloseBracket, + RGFW_Semicolon, + RGFW_Return, + RGFW_Quote, + RGFW_BackSlash, + + RGFW_Up, + RGFW_Down, + RGFW_Left, + RGFW_Right, + + RGFW_Delete, + RGFW_Insert, + RGFW_End, + RGFW_Home, + RGFW_PageUp, + RGFW_PageDown, + + RGFW_Numlock, + RGFW_KP_Slash, + RGFW_Multiply, + RGFW_KP_Minus, + RGFW_KP_1, + RGFW_KP_2, + RGFW_KP_3, + RGFW_KP_4, + RGFW_KP_5, + RGFW_KP_6, + RGFW_KP_7, + RGFW_KP_8, + RGFW_KP_9, + RGFW_KP_0, + RGFW_KP_Period, + RGFW_KP_Return, + + final_key, +}; + + +typedef RGFW_ENUM(u8, RGFW_mouseIcons) { + RGFW_MOUSE_NORMAL = 0, + RGFW_MOUSE_ARROW, + RGFW_MOUSE_IBEAM, + RGFW_MOUSE_CROSSHAIR, + RGFW_MOUSE_POINTING_HAND, + RGFW_MOUSE_RESIZE_EW, + RGFW_MOUSE_RESIZE_NS, + RGFW_MOUSE_RESIZE_NWSE, + RGFW_MOUSE_RESIZE_NESW, + RGFW_MOUSE_RESIZE_ALL, + RGFW_MOUSE_NOT_ALLOWED, +}; + +/** @} */ + #endif /* RGFW_HEADER */ - /* - Example to get you started : +/* +Example to get you started : - linux : gcc main.c -lX11 -lXcursor -lGL - windows : gcc main.c -lopengl32 -lshell32 -lgdi32 - macos : gcc main.c -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo +linux : gcc main.c -lX11 -lXcursor -lGL +windows : gcc main.c -lopengl32 -lshell32 -lgdi32 +macos : gcc main.c -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo +#define RGFW_IMPLEMENTATION +#include "RGFW.h" + +u8 icon[4 * 3 * 3] = {0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF}; + +int main() { + RGFW_window* win = RGFW_createWindow("name", RGFW_RECT(500, 500, 500, 500), (u64)0); + + RGFW_window_setIcon(win, icon, RGFW_AREA(3, 3), 4); + + for (;;) { + RGFW_window_checkEvent(win); // NOTE: checking events outside of a while loop may cause input lag + if (win->event.type == RGFW_quit || RGFW_isPressed(win, RGFW_Escape)) + break; + + RGFW_window_swapBuffers(win); + + glClearColor(0xFF, 0XFF, 0xFF, 0xFF); + glClear(GL_COLOR_BUFFER_BIT); + } + + RGFW_window_close(win); +} + + compiling : + + if you wish to compile the library all you have to do is create a new file with this in it + + rgfw.c #define RGFW_IMPLEMENTATION #include "RGFW.h" - u8 icon[4 * 3 * 3] = {0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF}; + then you can use gcc (or whatever compile you wish to use) to compile the library into object file - int main() { - RGFW_window* win = RGFW_createWindow("name", RGFW_RECT(500, 500, 500, 500), (u64)0); + ex. gcc -c RGFW.c -fPIC - RGFW_window_setIcon(win, icon, RGFW_AREA(3, 3), 4); + after you compile the library into an object file, you can also turn the object file into an static or shared library - for (;;) { - RGFW_window_checkEvent(win); // NOTE: checking events outside of a while loop may cause input lag - if (win->event.type == RGFW_quit || RGFW_isPressedI(win, RGFW_Escape)) - break; - - RGFW_window_swapBuffers(win); - - glClearColor(0xFF, 0XFF, 0xFF, 0xFF); - glClear(GL_COLOR_BUFFER_BIT); - } - - RGFW_window_close(win); - } - - compiling : - - if you wish to compile the library all you have to do is create a new file with this in it - - rgfw.c - #define RGFW_IMPLEMENTATION - #include "RGFW.h" - - then you can use gcc (or whatever compile you wish to use) to compile the library into object file - - ex. gcc -c RGFW.c -fPIC - - after you compile the library into an object file, you can also turn the object file into an static or shared library - - (commands ar and gcc can be replaced with whatever equivalent your system uses) - static : ar rcs RGFW.a RGFW.o - shared : - windows: - gcc -shared RGFW.o -lopengl32 -lshell32 -lgdi32 -o RGFW.dll - linux: - gcc -shared RGFW.o -lX11 -lXcursor -lGL -o RGFW.so - macos: - gcc -shared RGFW.o -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo - */ + (commands ar and gcc can be replaced with whatever equivalent your system uses) + static : ar rcs RGFW.a RGFW.o + shared : + windows: + gcc -shared RGFW.o -lopengl32 -lshell32 -lgdi32 -o RGFW.dll + linux: + gcc -shared RGFW.o -lX11 -lXcursor -lGL -o RGFW.so + macos: + gcc -shared RGFW.o -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo +*/ #ifdef RGFW_X11 -#define RGFW_OS_BASED_VALUE(l, w, m) l -#endif -#ifdef RGFW_WINDOWS -#define RGFW_OS_BASED_VALUE(l, w, m) w -#endif -#ifdef RGFW_MACOS -#define RGFW_OS_BASED_VALUE(l, w, m) m + #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) l +#elif defined(RGFW_WINDOWS) + #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) w +#elif defined(RGFW_MACOS) + #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) m +#elif defined(RGFW_WEBASM) + #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) h +#elif defined(RGFW_WAYLAND) + #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) ww #endif + #ifdef RGFW_IMPLEMENTATION #include @@ -879,416 +1205,358 @@ typedef struct { i32 x, y; } RGFW_vector; #include #include -#ifdef RGFW_WINDOWS +/* +RGFW_IMPLEMENTATION starts with generic RGFW defines -#include +This is the start of keycode data + Why not use macros instead of the numbers itself? + Windows -> Not all virtual keys are macros (VK_0 - VK_1, VK_a - VK_z) + Linux -> Only symcodes are values, (XK_0 - XK_1, XK_a - XK_z) are larger than 0xFF00, I can't find any way to work with them without making the array an unreasonable size + MacOS -> windows and linux already don't have keycodes as macros, so there's no point +*/ + + + +/* + the c++ compiler doesn't support setting up an array like, + we'll have to do it during runtime using a function & this messy setup +*/ +#ifndef __cplusplus +#define RGFW_NEXT , +#define RGFW_MAP +#else +#define RGFW_NEXT ; +#define RGFW_MAP RGFW_keycodes #endif -#ifdef RGFW_MACOS - /* - based on silicon.h - */ - -#ifndef GL_SILENCE_DEPRECATION -#define GL_SILENCE_DEPRECATION +#ifdef RGFW_WAYLAND +#include #endif -#include -#include -#include -#include +u8 RGFW_keycodes [RGFW_OS_BASED_VALUE(136, 337, 128, DOM_VK_WIN_OEM_CLEAR + 1, 130)] = { +#ifdef __cplusplus + 0 +}; +void RGFW_init_keys(void) { +#endif + RGFW_MAP [RGFW_OS_BASED_VALUE(49, 192, 50, DOM_VK_BACK_QUOTE, KEY_GRAVE)] = RGFW_Backtick RGFW_NEXT - typedef CGRect NSRect; - typedef CGPoint NSPoint; - typedef CGSize NSSize; + RGFW_MAP [RGFW_OS_BASED_VALUE(19, 0x30, 29, DOM_VK_0, KEY_0)] = RGFW_0 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(10, 0x31, 18, DOM_VK_1, KEY_1)] = RGFW_1 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(11, 0x32, 19, DOM_VK_2, KEY_2)] = RGFW_2 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(12, 0x33, 20, DOM_VK_3, KEY_3)] = RGFW_3 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(13, 0x34, 21, DOM_VK_4, KEY_4)] = RGFW_4 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(14, 0x35, 23, DOM_VK_5, KEY_5)] = RGFW_5 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(15, 0x36, 22, DOM_VK_6, KEY_6)] = RGFW_6 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(16, 0x37, 26, DOM_VK_7, KEY_7)] = RGFW_7 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(17, 0x38, 28, DOM_VK_8, KEY_8)] = RGFW_8 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(18, 0x39, 25, DOM_VK_9, KEY_9)] = RGFW_9, - typedef void NSBitmapImageRep; - typedef void NSCursor; - typedef void NSDraggingInfo; - typedef void NSWindow; - typedef void NSApplication; - typedef void NSScreen; - typedef void NSEvent; - typedef void NSString; - typedef void NSOpenGLContext; - typedef void NSPasteboard; - typedef void NSColor; - typedef void NSArray; - typedef void NSImageRep; - typedef void NSImage; - typedef void NSOpenGLView; + RGFW_MAP [RGFW_OS_BASED_VALUE(65, 0x20, 49, DOM_VK_SPACE, KEY_SPACE)] = RGFW_Space, + RGFW_MAP [RGFW_OS_BASED_VALUE(38, 0x41, 0, DOM_VK_A, KEY_A)] = RGFW_a RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(56, 0x42, 11, DOM_VK_B, KEY_B)] = RGFW_b RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(54, 0x43, 8, DOM_VK_C, KEY_C)] = RGFW_c RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(40, 0x44, 2, DOM_VK_D, KEY_D)] = RGFW_d RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(26, 0x45, 14, DOM_VK_E, KEY_E)] = RGFW_e RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(41, 0x46, 3, DOM_VK_F, KEY_F)] = RGFW_f RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(42, 0x47, 5, DOM_VK_G, KEY_G)] = RGFW_g RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(43, 0x48, 4, DOM_VK_H, KEY_H)] = RGFW_h RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(31, 0x49, 34, DOM_VK_I, KEY_I)] = RGFW_i RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(44, 0x4A, 38, DOM_VK_J, KEY_J)] = RGFW_j RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(45, 0x4B, 40, DOM_VK_K, KEY_K)] = RGFW_k RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(46, 0x4C, 37, DOM_VK_L, KEY_L)] = RGFW_l RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(58, 0x4D, 46, DOM_VK_M, KEY_M)] = RGFW_m RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(57, 0x4E, 45, DOM_VK_N, KEY_N)] = RGFW_n RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(32, 0x4F, 31, DOM_VK_O, KEY_O)] = RGFW_o RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(33, 0x50, 35, DOM_VK_P, KEY_P)] = RGFW_p RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(24, 0x51, 12, DOM_VK_Q, KEY_Q)] = RGFW_q RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(27, 0x52, 15, DOM_VK_R, KEY_R)] = RGFW_r RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(39, 0x53, 1, DOM_VK_S, KEY_S)] = RGFW_s RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(28, 0x54, 17, DOM_VK_T, KEY_T)] = RGFW_t RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(30, 0x55, 32, DOM_VK_U, KEY_U)] = RGFW_u RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(55, 0x56, 9, DOM_VK_V, KEY_V)] = RGFW_v RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(25, 0x57, 13, DOM_VK_W, KEY_W)] = RGFW_w RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(53, 0x58, 7, DOM_VK_X, KEY_X)] = RGFW_x RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(29, 0x59, 16, DOM_VK_Y, KEY_Y)] = RGFW_y RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(52, 0x5A, 6, DOM_VK_Z, KEY_Z)] = RGFW_z, - typedef const char* NSPasteboardType; - typedef unsigned long NSUInteger; - typedef long NSInteger; - typedef NSInteger NSModalResponse; + RGFW_MAP [RGFW_OS_BASED_VALUE(60, 190, 47, DOM_VK_PERIOD, KEY_DOT)] = RGFW_Period RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(59, 188, 43, DOM_VK_COMMA, KEY_COMMA)] = RGFW_Comma RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(61, 191, 44, DOM_VK_SLASH, KEY_SLASH)] = RGFW_Slash RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(34, 219, 33, DOM_VK_OPEN_BRACKET, KEY_LEFTBRACE)] = RGFW_Bracket RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(35, 221, 30, DOM_VK_CLOSE_BRACKET, KEY_RIGHTBRACE)] = RGFW_CloseBracket RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(47, 186, 41, DOM_VK_SEMICOLON, KEY_SEMICOLON)] = RGFW_Semicolon RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(48, 222, 39, DOM_VK_QUOTE, KEY_APOSTROPHE)] = RGFW_Quote RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(51, 322, 42, DOM_VK_BACK_SLASH, KEY_BACKSLASH)] = RGFW_BackSlash, + + RGFW_MAP [RGFW_OS_BASED_VALUE(36, 0x0D, 36, DOM_VK_RETURN, KEY_ENTER)] = RGFW_Return RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(119, 0x2E, 118, DOM_VK_DELETE, KEY_DELETE)] = RGFW_Delete RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(77, 0x90, 72, DOM_VK_NUM_LOCK, KEY_NUMLOCK)] = RGFW_Numlock RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(106, 0x6F, 82, DOM_VK_DIVIDE, KEY_KPSLASH)] = RGFW_KP_Slash RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(63, 0x6A, 76, DOM_VK_MULTIPLY, KEY_KPASTERISK)] = RGFW_Multiply RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(82, 0x6D, 67, DOM_VK_SUBTRACT, KEY_KPMINUS)] = RGFW_KP_Minus RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(87, 0x61, 84, DOM_VK_NUMPAD1, KEY_KP1)] = RGFW_KP_1 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(88, 0x62, 85, DOM_VK_NUMPAD2, KEY_KP2)] = RGFW_KP_2 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(89, 0x63, 86, DOM_VK_NUMPAD3, KEY_KP3)] = RGFW_KP_3 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(83, 0x64, 87, DOM_VK_NUMPAD4, KEY_KP4)] = RGFW_KP_4 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(84, 0x65, 88, DOM_VK_NUMPAD5, KEY_KP5)] = RGFW_KP_5 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(85, 0x66, 89, DOM_VK_NUMPAD6, KEY_KP6)] = RGFW_KP_6 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(79, 0x67, 90, DOM_VK_NUMPAD7, KEY_KP7)] = RGFW_KP_7 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(80, 0x68, 92, DOM_VK_NUMPAD8, KEY_KP8)] = RGFW_KP_8 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(81, 0x69, 93, DOM_VK_NUMPAD9, KEY_KP9)] = RGFW_KP_9 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(90, 0x60, 83, DOM_VK_NUMPAD0, KEY_KP0)] = RGFW_KP_0 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(91, 0x6E, 65, DOM_VK_DECIMAL, KEY_KPDOT)] = RGFW_KP_Period RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(104, 0x92, 77, 0, KEY_KPENTER)] = RGFW_KP_Return, + + RGFW_MAP [RGFW_OS_BASED_VALUE(20, 189, 27, DOM_VK_HYPHEN_MINUS, KEY_MINUS)] = RGFW_Minus RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(21, 187, 24, DOM_VK_EQUALS, KEY_EQUAL)] = RGFW_Equals RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(22, 8, 51, DOM_VK_BACK_SPACE, KEY_BACKSPACE)] = RGFW_BackSpace RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(23, 0x09, 48, DOM_VK_TAB, KEY_TAB)] = RGFW_Tab RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(66, 20, 57, DOM_VK_CAPS_LOCK, KEY_CAPSLOCK)] = RGFW_CapsLock RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(50, 0x10, 56, DOM_VK_SHIFT, KEY_LEFTSHIFT)] = RGFW_ShiftL RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(37, 0x11, 59, DOM_VK_CONTROL, KEY_LEFTCTRL)] = RGFW_ControlL RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(64,0x12, 58, DOM_VK_ALT, KEY_LEFTALT)] = RGFW_AltL RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(133, 0x5B, 55, DOM_VK_WIN, KEY_LEFTMETA)] = RGFW_SuperL, + + #if !defined(RGFW_WINDOWS) && !defined(RGFW_MACOS) && !defined(RGFW_WEBASM) + RGFW_MAP [RGFW_OS_BASED_VALUE(105, 0x11, 59, 0, KEY_RIGHTCTRL)] = RGFW_ControlR RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(135, 0xA4, 55, 0, KEY_RIGHTMETA)] = RGFW_SuperR, + RGFW_MAP [RGFW_OS_BASED_VALUE(62, 0x5C, 56, 0, KEY_RIGHTSHIFT)] = RGFW_ShiftR RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(108, 165, 58, 0, KEY_RIGHTALT)] = RGFW_AltR, + #endif -#ifdef __arm64__ - /* ARM just uses objc_msgSend */ -#define abi_objc_msgSend_stret objc_msgSend -#define abi_objc_msgSend_fpret objc_msgSend -#else /* __i386__ */ - /* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */ -#define abi_objc_msgSend_stret objc_msgSend_stret -#define abi_objc_msgSend_fpret objc_msgSend_fpret + RGFW_MAP [RGFW_OS_BASED_VALUE(67, 0x70, 127, DOM_VK_F1, KEY_F1)] = RGFW_F1 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(68, 0x71, 121, DOM_VK_F2, KEY_F2)] = RGFW_F2 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(69, 0x72, 100, DOM_VK_F3, KEY_F3)] = RGFW_F3 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(70, 0x73, 119, DOM_VK_F4, KEY_F4)] = RGFW_F4 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(71, 0x74, 97, DOM_VK_F5, KEY_F5)] = RGFW_F5 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(72, 0x75, 98, DOM_VK_F6, KEY_F6)] = RGFW_F6 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(73, 0x76, 99, DOM_VK_F7, KEY_F7)] = RGFW_F7 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(74, 0x77, 101, DOM_VK_F8, KEY_F8)] = RGFW_F8 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(75, 0x78, 102, DOM_VK_F9, KEY_F9)] = RGFW_F9 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(76, 0x79, 110, DOM_VK_F10, KEY_F10)] = RGFW_F10 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(95, 0x7A, 104, DOM_VK_F11, KEY_F11)] = RGFW_F11 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(96, 0x7B, 112, DOM_VK_F12, KEY_F12)] = RGFW_F12 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(111, 0x26, 126, DOM_VK_UP, KEY_UP)] = RGFW_Up RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(116, 0x28, 125, DOM_VK_DOWN, KEY_DOWN)] = RGFW_Down RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(113, 0x25, 123, DOM_VK_LEFT, KEY_LEFT)] = RGFW_Left RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(114, 0x27, 124, DOM_VK_RIGHT, KEY_RIGHT)] = RGFW_Right RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(118, 0x2D, 115, DOM_VK_INSERT, KEY_INSERT)] = RGFW_Insert RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(115, 0x23, 120, DOM_VK_END, KEY_END)] = RGFW_End RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(112, 336, 117, DOM_VK_PAGE_UP, KEY_PAGEUP)] = RGFW_PageUp RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(117, 325, 122, DOM_VK_PAGE_DOWN, KEY_PAGEDOWN)] = RGFW_PageDown RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(9, 0x1B, 53, DOM_VK_ESCAPE, KEY_ESC)] = RGFW_Escape RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(110, 0x24, 116, DOM_VK_HOME, KEY_HOME)] = RGFW_Home RGFW_NEXT +#ifndef __cplusplus +}; +#else +} #endif -#define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc")) -#define objc_msgSend_bool ((BOOL (*)(id, SEL))objc_msgSend) -#define objc_msgSend_void ((void (*)(id, SEL))objc_msgSend) -#define objc_msgSend_void_id ((void (*)(id, SEL, id))objc_msgSend) -#define objc_msgSend_uint ((NSUInteger (*)(id, SEL))objc_msgSend) -#define objc_msgSend_void_bool ((void (*)(id, SEL, BOOL))objc_msgSend) -#define objc_msgSend_void_SEL ((void (*)(id, SEL, SEL))objc_msgSend) -#define objc_msgSend_id ((id (*)(id, SEL))objc_msgSend) +#undef RGFW_NEXT +#undef RGFW_MAP -#define si_declare_single(class, name, func) \ - void class##_##name(class* obj) { \ - return objc_msgSend_void(obj, sel_registerName(func)); \ - } - - -#define loadFunc(funcName) \ - static void* func = NULL;\ - if (func == NULL) \ - func = sel_registerName(funcName); - - void NSRelease(id obj) { - loadFunc("release"); - objc_msgSend_void(obj, func); - } - -#define release NSRelease - - si_declare_single(NSApplication, finishLaunching, "finishLaunching") - si_declare_single(NSOpenGLContext, flushBuffer, "flushBuffer") - - NSString* NSString_stringWithUTF8String(const char* str) { - loadFunc("stringWithUTF8String:"); - - return ((id(*)(id, SEL, const char*))objc_msgSend) - ((id)objc_getClass("NSString"), func, str); - } - - const char* NSString_to_char(NSString* str) { - return ((const char* (*)(id, SEL)) objc_msgSend) (str, sel_registerName("UTF8String")); - } - - void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function) { - Class selected_class; - - if (strcmp(class_name, "NSView") == 0) { - selected_class = objc_getClass("ViewClass"); - } else if (strcmp(class_name, "NSWindow") == 0) { - selected_class = objc_getClass("WindowClass"); - } else { - selected_class = objc_getClass(class_name); - } - - class_addMethod(selected_class, sel_registerName(register_name), (IMP) function, 0); - } - - /* Header for the array. */ - typedef struct siArrayHeader { - size_t count; - /* TODO(EimaMei): Add a `type_width` later on. */ - } siArrayHeader; - - /* Gets the header of the siArray. */ -#define SI_ARRAY_HEADER(s) ((siArrayHeader*)s - 1) - - void* si_array_init_reserve(size_t sizeof_element, size_t count) { - siArrayHeader* ptr = malloc(sizeof(siArrayHeader) + (sizeof_element * count)); - void* array = ptr + sizeof(siArrayHeader); - - siArrayHeader* header = SI_ARRAY_HEADER(array); - header->count = count; - - return array; - } - -#define si_array_len(array) (SI_ARRAY_HEADER(array)->count) -#define si_func_to_SEL(class_name, function) si_impl_func_to_SEL_with_name(class_name, #function":", function) - /* Creates an Objective-C method (SEL) from a regular C function with the option to set the register name.*/ -#define si_func_to_SEL_with_name(class_name, register_name, function) si_impl_func_to_SEL_with_name(class_name, register_name":", function) - - NSRect NSMakeRect(double x, double y, double width, double height) { - NSRect r; - r.origin.x = x; - r.origin.y = y; - r.size.width = width; - r.size.height = height; - - return r; - } - - NSPoint NSMakePoint(double x, double y) { - NSPoint point; - point.x = x; - point.y = y; - return point; - } - - NSSize NSMakeSize(double w, double h) { - NSSize size; - size.width = w; - size.height = h; - return size; - } - - void* si_array_init(void* allocator, size_t sizeof_element, size_t count) { - void* array = si_array_init_reserve(sizeof_element, count); - memcpy(array, allocator, sizeof_element * count); - - return array; - } - - void si_array_free(void* array) { - if (array == NULL) - return; - - free(SI_ARRAY_HEADER(array)); - } - - unsigned char* NSBitmapImageRep_bitmapData(NSBitmapImageRep* imageRep) { - return ((unsigned char* (*)(id, SEL))objc_msgSend) - (imageRep, sel_registerName("bitmapData")); - } - -#define NS_ENUM(type, name) type name; enum - - typedef NS_ENUM(NSUInteger, NSBitmapFormat) { - NSBitmapFormatAlphaFirst = 1 << 0, // 0 means is alpha last (RGBA, CMYKA, etc.) - NSBitmapFormatAlphaNonpremultiplied = 1 << 1, // 0 means is premultiplied - NSBitmapFormatFloatingPointSamples = 1 << 2, // 0 is integer - - NSBitmapFormatSixteenBitLittleEndian API_AVAILABLE(macos(10.10)) = (1 << 8), - NSBitmapFormatThirtyTwoBitLittleEndian API_AVAILABLE(macos(10.10)) = (1 << 9), - NSBitmapFormatSixteenBitBigEndian API_AVAILABLE(macos(10.10)) = (1 << 10), - NSBitmapFormatThirtyTwoBitBigEndian API_AVAILABLE(macos(10.10)) = (1 << 11) - }; - - NSBitmapImageRep* NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits) { - void* func = sel_registerName("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:"); - - return (NSBitmapImageRep*) ((id(*)(id, SEL, unsigned char**, NSInteger, NSInteger, NSInteger, NSInteger, bool, bool, const char*, NSBitmapFormat, NSInteger, NSInteger))objc_msgSend) - (NSAlloc((id)objc_getClass("NSBitmapImageRep")), func, planes, width, height, bps, spp, alpha, isPlanar, NSString_stringWithUTF8String(colorSpaceName), bitmapFormat, rowBytes, pixelBits); - } - - NSColor* NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) { - void* nsclass = objc_getClass("NSColor"); - void* func = sel_registerName("colorWithSRGBRed:green:blue:alpha:"); - return ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend) - (nsclass, func, red, green, blue, alpha); - } - - NSCursor* NSCursor_initWithImage(NSImage* newImage, NSPoint aPoint) { - void* func = sel_registerName("initWithImage:hotSpot:"); - void* nsclass = objc_getClass("NSCursor"); - - return (NSCursor*) ((id(*)(id, SEL, id, NSPoint))objc_msgSend) - (NSAlloc(nsclass), func, newImage, aPoint); - } - - void NSImage_addRepresentation(NSImage* image, NSImageRep* imageRep) { - void* func = sel_registerName("addRepresentation:"); - objc_msgSend_void_id(image, func, imageRep); - } - - NSImage* NSImage_initWithSize(NSSize size) { - void* func = sel_registerName("initWithSize:"); - return ((id(*)(id, SEL, NSSize))objc_msgSend) - (NSAlloc((id)objc_getClass("NSImage")), func, size); - } -#define NS_OPENGL_ENUM_DEPRECATED(minVers, maxVers) API_AVAILABLE(macos(minVers)) - typedef NS_ENUM(NSInteger, NSOpenGLContextParameter) { - NSOpenGLContextParameterSwapInterval NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 222, /* 1 param. 0 -> Don't sync, 1 -> Sync to vertical retrace */ - NSOpenGLContextParameterSurfaceOrder NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 235, /* 1 param. 1 -> Above Window (default), -1 -> Below Window */ - NSOpenGLContextParameterSurfaceOpacity NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 236, /* 1 param. 1-> Surface is opaque (default), 0 -> non-opaque */ - NSOpenGLContextParameterSurfaceBackingSize NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 304, /* 2 params. Width/height of surface backing size */ - NSOpenGLContextParameterReclaimResources NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 308, /* 0 params. */ - NSOpenGLContextParameterCurrentRendererID NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 309, /* 1 param. Retrieves the current renderer ID */ - NSOpenGLContextParameterGPUVertexProcessing NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 310, /* 1 param. Currently processing vertices with GPU (get) */ - NSOpenGLContextParameterGPUFragmentProcessing NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 311, /* 1 param. Currently processing fragments with GPU (get) */ - NSOpenGLContextParameterHasDrawable NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 314, /* 1 param. Boolean returned if drawable is attached */ - NSOpenGLContextParameterMPSwapsInFlight NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 315, /* 1 param. Max number of swaps queued by the MP GL engine */ - - NSOpenGLContextParameterSwapRectangle API_DEPRECATED("", macos(10.0, 10.14)) = 200, /* 4 params. Set or get the swap rectangle {x, y, w, h} */ - NSOpenGLContextParameterSwapRectangleEnable API_DEPRECATED("", macos(10.0, 10.14)) = 201, /* Enable or disable the swap rectangle */ - NSOpenGLContextParameterRasterizationEnable API_DEPRECATED("", macos(10.0, 10.14)) = 221, /* Enable or disable all rasterization */ - NSOpenGLContextParameterStateValidation API_DEPRECATED("", macos(10.0, 10.14)) = 301, /* Validate state for multi-screen functionality */ - NSOpenGLContextParameterSurfaceSurfaceVolatile API_DEPRECATED("", macos(10.0, 10.14)) = 306, /* 1 param. Surface volatile state */ - }; - - - void NSOpenGLContext_setValues(NSOpenGLContext* context, const int* vals, NSOpenGLContextParameter param) { - void* func = sel_registerName("setValues:forParameter:"); - ((void (*)(id, SEL, const int*, NSOpenGLContextParameter))objc_msgSend) - (context, func, vals, param); - } - - void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs) { - void* func = sel_registerName("initWithAttributes:"); - return (void*) ((id(*)(id, SEL, const uint32_t*))objc_msgSend) - (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), func, attribs); - } - - NSOpenGLView* NSOpenGLView_initWithFrame(NSRect frameRect, uint32_t* format) { - void* func = sel_registerName("initWithFrame:pixelFormat:"); - return (NSOpenGLView*) ((id(*)(id, SEL, NSRect, uint32_t*))objc_msgSend) - (NSAlloc((id)objc_getClass("NSOpenGLView")), func, frameRect, format); - } - - void NSCursor_performSelector(NSCursor* cursor, void* selector) { - void* func = sel_registerName("performSelector:"); - objc_msgSend_void_SEL(cursor, func, selector); - } - - NSPasteboard* NSPasteboard_generalPasteboard(void) { - return (NSPasteboard*) objc_msgSend_id((id)objc_getClass("NSPasteboard"), sel_registerName("generalPasteboard")); - } - - NSString** cstrToNSStringArray(char** strs, size_t len) { - static NSString* nstrs[6]; - size_t i; - for (i = 0; i < len; i++) - nstrs[i] = NSString_stringWithUTF8String(strs[i]); - - return nstrs; - } - - const char* NSPasteboard_stringForType(NSPasteboard* pasteboard, NSPasteboardType dataType) { - void* func = sel_registerName("stringForType:"); - return (const char*) NSString_to_char(((id(*)(id, SEL, const char*))objc_msgSend)(pasteboard, func, NSString_stringWithUTF8String(dataType))); - } - - NSArray* c_array_to_NSArray(void* array, size_t len) { - SEL func = sel_registerName("initWithObjects:count:"); - void* nsclass = objc_getClass("NSArray"); - return ((id (*)(id, SEL, void*, NSUInteger))objc_msgSend) - (NSAlloc(nsclass), func, array, len); - } - - void NSregisterForDraggedTypes(void* view, NSPasteboardType* newTypes, size_t len) { - NSString** ntypes = cstrToNSStringArray((char**)newTypes, len); - - NSArray* array = c_array_to_NSArray(ntypes, len); - objc_msgSend_void_id(view, sel_registerName("registerForDraggedTypes:"), array); - NSRelease(array); - } - - NSInteger NSPasteBoard_declareTypes(NSPasteboard* pasteboard, NSPasteboardType* newTypes, size_t len, void* owner) { - NSString** ntypes = cstrToNSStringArray((char**)newTypes, len); - - void* func = sel_registerName("declareTypes:owner:"); - - NSArray* array = c_array_to_NSArray(ntypes, len); - - NSInteger output = ((NSInteger(*)(id, SEL, id, void*))objc_msgSend) - (pasteboard, func, array, owner); - NSRelease(array); - - return output; - } - - bool NSPasteBoard_setString(NSPasteboard* pasteboard, const char* stringToWrite, NSPasteboardType dataType) { - void* func = sel_registerName("setString:forType:"); - return ((bool (*)(id, SEL, id, NSPasteboardType))objc_msgSend) - (pasteboard, func, NSString_stringWithUTF8String(stringToWrite), NSString_stringWithUTF8String(dataType)); - } - - void NSRetain(id obj) { objc_msgSend_void(obj, sel_registerName("retain")); } - - typedef enum NSApplicationActivationPolicy { - NSApplicationActivationPolicyRegular, - NSApplicationActivationPolicyAccessory, - NSApplicationActivationPolicyProhibited - } NSApplicationActivationPolicy; - - typedef NS_ENUM(u32, NSBackingStoreType) { - NSBackingStoreRetained = 0, - NSBackingStoreNonretained = 1, - NSBackingStoreBuffered = 2 - }; - - typedef NS_ENUM(u32, NSWindowStyleMask) { - NSWindowStyleMaskBorderless = 0, - NSWindowStyleMaskTitled = 1 << 0, - NSWindowStyleMaskClosable = 1 << 1, - NSWindowStyleMaskMiniaturizable = 1 << 2, - NSWindowStyleMaskResizable = 1 << 3, - NSWindowStyleMaskTexturedBackground = 1 << 8, /* deprecated */ - NSWindowStyleMaskUnifiedTitleAndToolbar = 1 << 12, - NSWindowStyleMaskFullScreen = 1 << 14, - NSWindowStyleMaskFullSizeContentView = 1 << 15, - NSWindowStyleMaskUtilityWindow = 1 << 4, - NSWindowStyleMaskDocModalWindow = 1 << 6, - NSWindowStyleMaskNonactivatingPanel = 1 << 7, - NSWindowStyleMaskHUDWindow = 1 << 13 - }; - - typedef const char* NSPasteboardType; - NSPasteboardType const NSPasteboardTypeString = "public.utf8-plain-text"; // Replaces NSStringPboardType - - - - typedef NS_ENUM(i32, NSDragOperation) { - NSDragOperationNone = 0, - NSDragOperationCopy = 1, - NSDragOperationLink = 2, - NSDragOperationGeneric = 4, - NSDragOperationPrivate = 8, - NSDragOperationMove = 16, - NSDragOperationDelete = 32, - NSDragOperationEvery = ULONG_MAX, - - //NSDragOperationAll_Obsolete API_DEPRECATED("", macos(10.0,10.10)) = 15, // Use NSDragOperationEvery - //NSDragOperationAll API_DEPRECATED("", macos(10.0,10.10)) = NSDragOperationAll_Obsolete, // Use NSDragOperationEvery - }; - - - NSUInteger NSArray_count(NSArray* array) { - void* func = sel_registerName("count"); - return ((NSUInteger(*)(id, SEL))objc_msgSend)(array, func); - } - - void* NSArray_objectAtIndex(NSArray* array, NSUInteger index) { - void* func = sel_registerName("objectAtIndex:"); - return ((id(*)(id, SEL, NSUInteger))objc_msgSend)(array, func, index); - } - - const char** NSPasteboard_readObjectsForClasses(NSPasteboard* pasteboard, Class* classArray, size_t len, void* options) { - void* func = sel_registerName("readObjectsForClasses:options:"); - - NSArray* array = c_array_to_NSArray(classArray, len); - - NSArray* output = (NSArray*) ((id(*)(id, SEL, id, void*))objc_msgSend) - (pasteboard, func, array, options); - - NSRelease(array); - NSUInteger count = NSArray_count(output); - - const char** res = si_array_init_reserve(sizeof(const char*), count); - - void* path_func = sel_registerName("path"); - - for (NSUInteger i = 0; i < count; i++) { - void* url = NSArray_objectAtIndex(output, i); - NSString* url_str = ((id(*)(id, SEL))objc_msgSend)(url, path_func); - res[i] = NSString_to_char(url_str); - } - - return res; - } - - void* NSWindow_contentView(NSWindow* window) { - void* func = sel_registerName("contentView"); - return objc_msgSend_id(window, func); +typedef struct { + b8 current : 1; + b8 prev : 1; +} RGFW_keyState; + +RGFW_keyState RGFW_keyboard[final_key] = { {0, 0} }; + +RGFWDEF u32 RGFW_apiKeyCodeToRGFW(u32 keycode); + +u32 RGFW_apiKeyCodeToRGFW(u32 keycode) { + #ifdef __cplusplus + if (RGFW_OS_BASED_VALUE(49, 192, 50, DOM_VK_BACK_QUOTE, KEY_GRAVE) != RGFW_Backtick) { + RGFW_init_keys(); } + #endif + + /* make sure the key isn't out of bounds */ + if (keycode > sizeof(RGFW_keycodes) / sizeof(u8)) + return 0; + + return RGFW_keycodes[keycode]; +} + +RGFWDEF void RGFW_resetKey(void); +void RGFW_resetKey(void) { + size_t len = final_key; /*!< last_key == length */ + + size_t i; /*!< reset each previous state */ + for (i = 0; i < len; i++) + RGFW_keyboard[i].prev = 0; +} + +b8 RGFW_shouldShift(u32 keycode, u8 lockState) { + #define RGFW_xor(x, y) (( (x) && (!(y)) ) || ((y) && (!(x)) )) + b8 caps4caps = (lockState & RGFW_CAPSLOCK) && ((keycode >= RGFW_a) && (keycode <= RGFW_z)); + b8 shouldShift = RGFW_xor((RGFW_isPressed(NULL, RGFW_ShiftL) || RGFW_isPressed(NULL, RGFW_ShiftR)), caps4caps); + #undef RGFW_xor + + return shouldShift; +} + +char RGFW_keyCodeToChar(u32 keycode, b8 shift) { + static const char map[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '`', '0', '1', '2', '3', '4', '5', '6', '7', '8', + '9', '-', '=', 0, '\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '.', ',', '/', '[', ']', ';', '\n', '\'', '\\', + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/', '*', '-', '1', '2', '3', '3', '5', '6', '7', '8', '9', '0', '\n' + }; + + static const char mapCaps[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '~', ')', '!', '@', '#', '$', '%', '^', '&', '*', + '(', '_', '+', 0, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '>', '<', '?', '{', '}', ':', '\n', '"', '|', + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '?', '*', '-', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + if (shift == RGFW_FALSE) + return map[keycode]; + return mapCaps[keycode]; +} + +char RGFW_keyCodeToCharAuto(u32 keycode, u8 lockState) { return RGFW_keyCodeToChar(keycode, RGFW_shouldShift(keycode, lockState)); } + +/* + this is the end of keycode data +*/ + +/* joystick data */ +u8 RGFW_jsPressed[4][16]; /*!< if a key is currently pressed or not (per joystick) */ + +i32 RGFW_joysticks[4]; /*!< limit of 4 joysticks at a time */ +u16 RGFW_joystickCount; /*!< the actual amount of joysticks */ + +/* + event callback defines start here +*/ + + +/* + These exist to avoid the + if (func == NULL) check + for (allegedly) better performance +*/ +void RGFW_windowmovefuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } +void RGFW_windowresizefuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } +void RGFW_windowquitfuncEMPTY(RGFW_window* win) { RGFW_UNUSED(win); } +void RGFW_focusfuncEMPTY(RGFW_window* win, b8 inFocus) {RGFW_UNUSED(win); RGFW_UNUSED(inFocus);} +void RGFW_mouseNotifyfuncEMPTY(RGFW_window* win, RGFW_point point, b8 status) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(status);} +void RGFW_mouseposfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);} +void RGFW_dndInitfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);} +void RGFW_windowrefreshfuncEMPTY(RGFW_window* win) {RGFW_UNUSED(win); } +void RGFW_keyfuncEMPTY(RGFW_window* win, u32 keycode, char keyName[16], u8 lockState, b8 pressed) {RGFW_UNUSED(win); RGFW_UNUSED(keycode); RGFW_UNUSED(keyName); RGFW_UNUSED(lockState); RGFW_UNUSED(pressed);} +void RGFW_mousebuttonfuncEMPTY(RGFW_window* win, u8 button, double scroll, b8 pressed) {RGFW_UNUSED(win); RGFW_UNUSED(button); RGFW_UNUSED(scroll); RGFW_UNUSED(pressed);} +void RGFW_jsButtonfuncEMPTY(RGFW_window* win, u16 joystick, u8 button, b8 pressed){RGFW_UNUSED(win); RGFW_UNUSED(joystick); RGFW_UNUSED(button); RGFW_UNUSED(pressed); } +void RGFW_jsAxisfuncEMPTY(RGFW_window* win, u16 joystick, RGFW_point axis[2], u8 axisesCount){RGFW_UNUSED(win); RGFW_UNUSED(joystick); RGFW_UNUSED(axis); RGFW_UNUSED(axisesCount); } + +#ifdef RGFW_ALLOC_DROPFILES +void RGFW_dndfuncEMPTY(RGFW_window* win, char** droppedFiles, u32 droppedFilesCount) {RGFW_UNUSED(win); RGFW_UNUSED(droppedFiles); RGFW_UNUSED(droppedFilesCount);} +#else +void RGFW_dndfuncEMPTY(RGFW_window* win, char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH], u32 droppedFilesCount) {RGFW_UNUSED(win); RGFW_UNUSED(droppedFiles); RGFW_UNUSED(droppedFilesCount);} #endif +RGFW_windowmovefunc RGFW_windowMoveCallback = RGFW_windowmovefuncEMPTY; +RGFW_windowresizefunc RGFW_windowResizeCallback = RGFW_windowresizefuncEMPTY; +RGFW_windowquitfunc RGFW_windowQuitCallback = RGFW_windowquitfuncEMPTY; +RGFW_mouseposfunc RGFW_mousePosCallback = RGFW_mouseposfuncEMPTY; +RGFW_windowrefreshfunc RGFW_windowRefreshCallback = RGFW_windowrefreshfuncEMPTY; +RGFW_focusfunc RGFW_focusCallback = RGFW_focusfuncEMPTY; +RGFW_mouseNotifyfunc RGFW_mouseNotifyCallBack = RGFW_mouseNotifyfuncEMPTY; +RGFW_dndfunc RGFW_dndCallback = RGFW_dndfuncEMPTY; +RGFW_dndInitfunc RGFW_dndInitCallback = RGFW_dndInitfuncEMPTY; +RGFW_keyfunc RGFW_keyCallback = RGFW_keyfuncEMPTY; +RGFW_mousebuttonfunc RGFW_mouseButtonCallback = RGFW_mousebuttonfuncEMPTY; +RGFW_jsButtonfunc RGFW_jsButtonCallback = RGFW_jsButtonfuncEMPTY; +RGFW_jsAxisfunc RGFW_jsAxisCallback = RGFW_jsAxisfuncEMPTY; + +void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS) { + RGFW_window_eventWait(win, waitMS); + + while (RGFW_window_checkEvent(win) != NULL && RGFW_window_shouldClose(win) == 0) { + if (win->event.type == RGFW_quit) return; + } + + #ifdef RGFW_WEBASM /* webasm needs to run the sleep function for asyncify */ + RGFW_sleep(0); + #endif +} + +RGFW_windowmovefunc RGFW_setWindowMoveCallback(RGFW_windowmovefunc func) { + RGFW_windowmovefunc prev = (RGFW_windowMoveCallback == RGFW_windowmovefuncEMPTY) ? NULL : RGFW_windowMoveCallback; + RGFW_windowMoveCallback = func; + return prev; +} +RGFW_windowresizefunc RGFW_setWindowResizeCallback(RGFW_windowresizefunc func) { + RGFW_windowresizefunc prev = (RGFW_windowResizeCallback == RGFW_windowresizefuncEMPTY) ? NULL : RGFW_windowResizeCallback; + RGFW_windowResizeCallback = func; + return prev; +} +RGFW_windowquitfunc RGFW_setWindowQuitCallback(RGFW_windowquitfunc func) { + RGFW_windowquitfunc prev = (RGFW_windowQuitCallback == RGFW_windowquitfuncEMPTY) ? NULL : RGFW_windowQuitCallback; + RGFW_windowQuitCallback = func; + return prev; +} + +RGFW_mouseposfunc RGFW_setMousePosCallback(RGFW_mouseposfunc func) { + RGFW_mouseposfunc prev = (RGFW_mousePosCallback == RGFW_mouseposfuncEMPTY) ? NULL : RGFW_mousePosCallback; + RGFW_mousePosCallback = func; + return prev; +} +RGFW_windowrefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowrefreshfunc func) { + RGFW_windowrefreshfunc prev = (RGFW_windowRefreshCallback == RGFW_windowrefreshfuncEMPTY) ? NULL : RGFW_windowRefreshCallback; + RGFW_windowRefreshCallback = func; + return prev; +} +RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func) { + RGFW_focusfunc prev = (RGFW_focusCallback == RGFW_focusfuncEMPTY) ? NULL : RGFW_focusCallback; + RGFW_focusCallback = func; + return prev; +} + +RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallBack(RGFW_mouseNotifyfunc func) { + RGFW_mouseNotifyfunc prev = (RGFW_mouseNotifyCallBack == RGFW_mouseNotifyfuncEMPTY) ? NULL : RGFW_mouseNotifyCallBack; + RGFW_mouseNotifyCallBack = func; + return prev; +} +RGFW_dndfunc RGFW_setDndCallback(RGFW_dndfunc func) { + RGFW_dndfunc prev = (RGFW_dndCallback == RGFW_dndfuncEMPTY) ? NULL : RGFW_dndCallback; + RGFW_dndCallback = func; + return prev; +} +RGFW_dndInitfunc RGFW_setDndInitCallback(RGFW_dndInitfunc func) { + RGFW_dndInitfunc prev = (RGFW_dndInitCallback == RGFW_dndInitfuncEMPTY) ? NULL : RGFW_dndInitCallback; + RGFW_dndInitCallback = func; + return prev; +} +RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func) { + RGFW_keyfunc prev = (RGFW_keyCallback == RGFW_keyfuncEMPTY) ? NULL : RGFW_keyCallback; + RGFW_keyCallback = func; + return prev; +} +RGFW_mousebuttonfunc RGFW_setMouseButtonCallback(RGFW_mousebuttonfunc func) { + RGFW_mousebuttonfunc prev = (RGFW_mouseButtonCallback == RGFW_mousebuttonfuncEMPTY) ? NULL : RGFW_mouseButtonCallback; + RGFW_mouseButtonCallback = func; + return prev; +} +RGFW_jsButtonfunc RGFW_setjsButtonCallback(RGFW_jsButtonfunc func) { + RGFW_jsButtonfunc prev = (RGFW_jsButtonCallback == RGFW_jsButtonfuncEMPTY) ? NULL : RGFW_jsButtonCallback; + RGFW_jsButtonCallback = func; + return prev; +} +RGFW_jsAxisfunc RGFW_setjsAxisCallback(RGFW_jsAxisfunc func) { + RGFW_jsAxisfunc prev = (RGFW_jsAxisCallback == RGFW_jsAxisfuncEMPTY) ? NULL : RGFW_jsAxisCallback; + RGFW_jsAxisCallback = func; + return prev; +} +/* +no more event call back defines +*/ #define RGFW_ASSERT(check, str) {\ if (!(check)) { \ @@ -1297,18 +1565,229 @@ typedef struct { i32 x, y; } RGFW_vector; } \ } - u8 RGFW_error = 0; - u8 RGFW_Error() { return RGFW_error; } +b8 RGFW_error = 0; +b8 RGFW_Error(void) { return RGFW_error; } #define SET_ATTRIB(a, v) { \ assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ attribs[index++] = v; \ } + +RGFW_area RGFW_bufferSize = {0, 0}; +void RGFW_setBufferSize(RGFW_area size) { + RGFW_bufferSize = size; +} -#define ADD_ATTRIB(a) { \ - assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ - attribs[index++] = a; \ + +RGFWDEF RGFW_window* RGFW_window_basic_init(RGFW_rect rect, u16 args); + +/* do a basic initialization for RGFW_window, this is to standard it for each OS */ +RGFW_window* RGFW_window_basic_init(RGFW_rect rect, u16 args) { + RGFW_window* win = (RGFW_window*) RGFW_MALLOC(sizeof(RGFW_window)); /*!< make a new RGFW struct */ + + /* clear out dnd info */ +#ifdef RGFW_ALLOC_DROPFILES + win->event.droppedFiles = (char**) RGFW_MALLOC(sizeof(char*) * RGFW_MAX_DROPS); + u32 i; + for (i = 0; i < RGFW_MAX_DROPS; i++) + win->event.droppedFiles[i] = (char*) RGFW_CALLOC(RGFW_MAX_PATH, sizeof(char)); +#endif + + /* X11 requires us to have a display to get the screen size */ + #ifndef RGFW_X11 + RGFW_area screenR = RGFW_getScreenSize(); + #else + win->src.display = XOpenDisplay(NULL); + assert(win->src.display != NULL); + + Screen* scrn = DefaultScreenOfDisplay((Display*)win->src.display); + RGFW_area screenR = RGFW_AREA((u32)scrn->width, (u32)scrn->height); + #endif + + /* rect based the requested args */ + if (args & RGFW_FULLSCREEN) + rect = RGFW_RECT(0, 0, screenR.w, screenR.h); + + if (args & RGFW_CENTER) + rect = RGFW_RECT((screenR.w - rect.w) / 2, (screenR.h - rect.h) / 2, rect.w, rect.h); + + /* set and init the new window's data */ + win->r = rect; + win->event.inFocus = 1; + win->event.droppedFilesCount = 0; + RGFW_joystickCount = 0; + win->_winArgs = 0; + win->event.lockState = 0; + + return win; +} + +#ifndef RGFW_NO_MONITOR +void RGFW_window_scaleToMonitor(RGFW_window* win) { + RGFW_monitor monitor = RGFW_window_getMonitor(win); + + RGFW_window_resize(win, RGFW_AREA(((u32) monitor.scaleX) * win->r.w, ((u32) monitor.scaleX) * win->r.h)); +} +#endif + +RGFW_window* RGFW_root = NULL; + + +#define RGFW_HOLD_MOUSE (1L<<2) /*!< hold the moues still */ +#define RGFW_MOUSE_LEFT (1L<<3) /* if mouse left the window */ + +void RGFW_clipboardFree(char* str) { RGFW_FREE(str); } + +RGFW_keyState RGFW_mouseButtons[5] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} }; + +b8 RGFW_isMousePressed(RGFW_window* win, u8 button) { + assert(win != NULL); + return RGFW_mouseButtons[button].current && (win != NULL) && win->event.inFocus; +} +b8 RGFW_wasMousePressed(RGFW_window* win, u8 button) { + assert(win != NULL); + return RGFW_mouseButtons[button].prev && (win != NULL) && win->event.inFocus; +} +b8 RGFW_isMouseHeld(RGFW_window* win, u8 button) { + return (RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button)); +} +b8 RGFW_isMouseReleased(RGFW_window* win, u8 button) { + return (!RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button)); +} + +b8 RGFW_isPressed(RGFW_window* win, u8 key) { + return RGFW_keyboard[key].current && (win == NULL || win->event.inFocus); +} + +b8 RGFW_wasPressed(RGFW_window* win, u8 key) { + return RGFW_keyboard[key].prev && (win == NULL || win->event.inFocus); +} + +b8 RGFW_isHeld(RGFW_window* win, u8 key) { + return (RGFW_isPressed(win, key) && RGFW_wasPressed(win, key)); +} + +b8 RGFW_isClicked(RGFW_window* win, u8 key) { + return (RGFW_wasPressed(win, key) && !RGFW_isPressed(win, key)); +} + +b8 RGFW_isReleased(RGFW_window* win, u8 key) { + return (!RGFW_isPressed(win, key) && RGFW_wasPressed(win, key)); +} + +#if defined(RGFW_WINDOWS) && defined(RGFW_DIRECTX) /* defines for directX context*/ + RGFW_directXinfo RGFW_dxInfo; + RGFW_directXinfo* RGFW_getDirectXInfo(void) { return &RGFW_dxInfo; } +#endif + +void RGFW_window_makeCurrent(RGFW_window* win) { +#if defined(RGFW_WINDOWS) && defined(RGFW_DIRECTX) + if (win == NULL) + RGFW_dxInfo.pDeviceContext->lpVtbl->OMSetRenderTargets(RGFW_dxInfo.pDeviceContext, 1, NULL, NULL); + else + RGFW_dxInfo.pDeviceContext->lpVtbl->OMSetRenderTargets(RGFW_dxInfo.pDeviceContext, 1, &win->src.renderTargetView, NULL); +#elif defined(RGFW_OPENGL) + RGFW_window_makeCurrent_OpenGL(win); +#else + RGFW_UNUSED(win) +#endif +} + +void RGFW_window_setGPURender(RGFW_window* win, i8 set) { + if (!set && !(win->_winArgs & RGFW_NO_GPU_RENDER)) + win->_winArgs |= RGFW_NO_GPU_RENDER; + + else if (set && win->_winArgs & RGFW_NO_GPU_RENDER) + win->_winArgs ^= RGFW_NO_GPU_RENDER; +} + +void RGFW_window_setCPURender(RGFW_window* win, i8 set) { + if (!set && !(win->_winArgs & RGFW_NO_CPU_RENDER)) + win->_winArgs |= RGFW_NO_CPU_RENDER; + + else if (set && win->_winArgs & RGFW_NO_CPU_RENDER) + win->_winArgs ^= RGFW_NO_CPU_RENDER; +} + +void RGFW_window_maximize(RGFW_window* win) { + assert(win != NULL); + + RGFW_area screen = RGFW_getScreenSize(); + + RGFW_window_move(win, RGFW_POINT(0, 0)); + RGFW_window_resize(win, screen); +} + +b8 RGFW_window_shouldClose(RGFW_window* win) { + assert(win != NULL); + return (win->event.type == RGFW_quit || RGFW_isPressed(win, RGFW_Escape)); +} + +void RGFW_window_setShouldClose(RGFW_window* win) { win->event.type = RGFW_quit; RGFW_windowQuitCallback(win); } + +#ifndef RGFW_NO_MONITOR + void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m) { + RGFW_window_move(win, RGFW_POINT(m.rect.x + win->r.x, m.rect.y + win->r.y)); + } +#endif + +RGFWDEF void RGFW_captureCursor(RGFW_window* win, RGFW_rect); +RGFWDEF void RGFW_releaseCursor(RGFW_window* win); + +void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area) { + if ((win->_winArgs & RGFW_HOLD_MOUSE)) + return; + + + if (!area.w && !area.h) + area = RGFW_AREA(win->r.w / 2, win->r.h / 2); + + win->_winArgs |= RGFW_HOLD_MOUSE; + RGFW_captureCursor(win, win->r); + RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2))); +} + +void RGFW_window_mouseUnhold(RGFW_window* win) { + if ((win->_winArgs & RGFW_HOLD_MOUSE)) { + win->_winArgs ^= RGFW_HOLD_MOUSE; + + RGFW_releaseCursor(win); + } +} + +u32 RGFW_window_checkFPS(RGFW_window* win, u32 fpsCap) { + u64 deltaTime = RGFW_getTimeNS() - win->event.frameTime; + + u32 output_fps = 0; + u64 fps = round(1e+9 / deltaTime); + output_fps= fps; + + if (fpsCap && fps > fpsCap) { + u64 frameTimeNS = 1e+9 / fpsCap; + u64 sleepTimeMS = (frameTimeNS - deltaTime) / 1e6; + + if (sleepTimeMS > 0) { + RGFW_sleep(sleepTimeMS); + win->event.frameTime = 0; + } + } + + win->event.frameTime = RGFW_getTimeNS(); + + if (fpsCap == 0) + return (u32) output_fps; + + deltaTime = RGFW_getTimeNS() - win->event.frameTime2; + output_fps = round(1e+9 / deltaTime); + win->event.frameTime2 = RGFW_getTimeNS(); + + return output_fps; +} + +u32 RGFW_isPressedJS(RGFW_window* win, u16 c, u8 button) { + RGFW_UNUSED(win); + return RGFW_jsPressed[c][button]; } #if defined(RGFW_X11) || defined(RGFW_WINDOWS) @@ -1321,760 +1800,71 @@ typedef struct { i32 x, y; } RGFW_vector; } #endif - #ifdef RGFW_WINDOWS - __declspec(dllimport) u32 __stdcall timeBeginPeriod(u32 uPeriod); - #endif +RGFWDEF void RGFW_updateLockState(RGFW_window* win, b8 capital, b8 numlock); +void RGFW_updateLockState(RGFW_window* win, b8 capital, b8 numlock) { + if (capital && !(win->event.lockState & RGFW_CAPSLOCK)) + win->event.lockState |= RGFW_CAPSLOCK; + else if (!capital && (win->event.lockState & RGFW_CAPSLOCK)) + win->event.lockState ^= RGFW_CAPSLOCK; + + if (numlock && !(win->event.lockState & RGFW_NUMLOCK)) + win->event.lockState |= RGFW_NUMLOCK; + else if (!numlock && (win->event.lockState & RGFW_NUMLOCK)) + win->event.lockState ^= RGFW_NUMLOCK; +} - RGFWDEF RGFW_window* RGFW_window_basic_init(RGFW_rect rect, u16 args); - RGFWDEF void RGFW_init_buffer(RGFW_window* win); +#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WEBASM) || defined(RGFW_WAYLAND) + struct timespec; - RGFW_window* RGFW_window_basic_init(RGFW_rect rect, u16 args) { - RGFW_window* win = (RGFW_window*) RGFW_MALLOC(sizeof(RGFW_window)); /* make a new RGFW struct */ + int nanosleep(const struct timespec* duration, struct timespec* rem); + int clock_gettime(clockid_t clk_id, struct timespec* tp); + int setenv(const char *name, const char *value, int overwrite); - #ifdef RGFW_WINDOWS - timeBeginPeriod(1); - #endif - -#ifdef RGFW_ALLOC_DROPFILES - win->event.droppedFiles = (char**) RGFW_MALLOC(sizeof(char*) * RGFW_MAX_DROPS); - u32 i; - for (i = 0; i < RGFW_MAX_DROPS; i++) - win->event.droppedFiles[i] = (char*) RGFW_CALLOC(RGFW_MAX_PATH, sizeof(char)); -#endif + void RGFW_window_setDND(RGFW_window* win, b8 allow) { + if (allow && !(win->_winArgs & RGFW_ALLOW_DND)) + win->_winArgs |= RGFW_ALLOW_DND; -#ifdef RGFW_X11 - /* open X11 display */ - /* this is done here so the screen size can be accessed */ - win->src.display = XOpenDisplay(NULL); - assert(win->src.display != NULL); -#endif - - #ifndef RGFW_X11 - RGFW_area screenR = RGFW_getScreenSize(); - #else - win->src.display = XOpenDisplay(NULL); - assert(win->src.display != NULL); - - Screen* scrn = DefaultScreenOfDisplay((Display*)win->src.display); - RGFW_area screenR = RGFW_AREA(scrn->width, scrn->height); - #endif - - if (args & RGFW_FULLSCREEN) - rect = RGFW_RECT(0, 0, screenR.w, screenR.h); - - if (args & RGFW_CENTER) - rect = RGFW_RECT((screenR.w - rect.w) / 2, (screenR.h - rect.h) / 2, rect.w, rect.h); - - /* set and init the new window's data */ - win->r = rect; - win->fpsCap = 0; - win->event.inFocus = 1; - win->event.droppedFilesCount = 0; - win->src.joystickCount = 0; -#ifdef RGFW_X11 - win->src.cursor = 0; -#endif -#ifdef RGFW_MACOS - RGFW_window_setMouseDefault(win); -#endif -#ifdef RGFW_WINDOWS - win->src.maxSize = RGFW_AREA(0, 0); - win->src.minSize = RGFW_AREA(0, 0); -#endif - win->src.winArgs = 0; - - return win; + else if (!allow && (win->_winArgs & RGFW_ALLOW_DND)) + win->_winArgs ^= RGFW_ALLOW_DND; } - - void RGFW_window_scaleToMonitor(RGFW_window* win) { - RGFW_monitor monitor = RGFW_window_getMonitor(win); - - RGFW_window_resize(win, RGFW_AREA(((u32) monitor.scaleX) * win->r.w, ((u32) monitor.scaleX) * win->r.h)); - } - - void RGFW_init_buffer(RGFW_window* win) { -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - RGFW_area area = RGFW_getScreenSize(); -#if !(defined(RGFW_WINDOWS)) || defined(RGFW_OSMESA) - win->buffer = RGFW_MALLOC(area.w * area.h * 4); #endif -#ifdef RGFW_OSMESA - win->src.rSurf = OSMesaCreateContext(OSMESA_RGBA, NULL); - OSMesaMakeCurrent(win->src.rSurf, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h); -#endif -#ifdef RGFW_X11 - win->src.bitmap = XCreateImage( - win->src.display, DefaultVisual(win->src.display, XDefaultScreen(win->src.display)), - DefaultDepth(win->src.display, XDefaultScreen(win->src.display)), - ZPixmap, 0, NULL, area.w, area.h, - 32, 0 - ); -#endif -#ifdef RGFW_WINDOWS - BITMAPV5HEADER bi = { 0 }; - ZeroMemory(&bi, sizeof(bi)); - bi.bV5Size = sizeof(bi); - bi.bV5Width = area.w; - bi.bV5Height = -((LONG) area.h); - bi.bV5Planes = 1; - bi.bV5BitCount = 32; - bi.bV5Compression = BI_BITFIELDS; - bi.bV5BlueMask = 0x00ff0000; - bi.bV5GreenMask = 0x0000ff00; - bi.bV5RedMask = 0x000000ff; - bi.bV5AlphaMask = 0xff000000; +/* + graphics API specific code (end of generic code) + starts here +*/ - win->src.bitmap = CreateDIBSection(win->src.hdc, - (BITMAPINFO*) &bi, - DIB_RGB_COLORS, - (void**) &win->buffer, - NULL, - (DWORD) 0); - win->src.hdcMem = CreateCompatibleDC(win->src.hdc); -#endif -#else -RGFW_UNUSED(win); /* if buffer rendering is not being used */ -#endif - } +/* + OpenGL defines start here (Normal, EGL, OSMesa) +*/ #if defined(RGFW_OPENGL) || defined(RGFW_EGL) || defined(RGFW_OSMESA) -#ifndef __APPLE__ -#include -#else -#include -#endif -#endif - -#ifdef RGFW_VULKAN - RGFW_vulkanInfo RGFW_vulkan_info; - - RGFW_vulkanInfo* RGFW_initVulkan(RGFW_window* win) { - assert(win != NULL); - - if ( - RGFW_initData(win) || - RGFW_deviceInitialization(win) || - RGFW_createSwapchain(win) - ) - return NULL; - - u32 graphics_family_index = 0; - u32 present_family_index = 0; - - vkGetDeviceQueue(RGFW_vulkan_info.device, graphics_family_index, 0, &RGFW_vulkan_info.graphics_queue); - vkGetDeviceQueue(RGFW_vulkan_info.device, present_family_index, 0, &RGFW_vulkan_info.present_queue); - - if ( - RGFW_createRenderPass() || - RGFW_createFramebuffers(win) || - RGFW_createCommandPool() || - RGFW_createCommandBuffers(win) || - RGFW_createSyncObjects(win) - ) - return NULL; - - return &RGFW_vulkan_info; - } - - int RGFW_initData(RGFW_window* win) { - assert(win != NULL); - - win->src.swapchain = VK_NULL_HANDLE; - win->src.image_count = 0; - RGFW_vulkan_info.current_frame = 0; - - return 0; - } - - void RGFW_createSurface(VkInstance instance, RGFW_window* win) { - assert(win != NULL); - assert(instance); - - win->src.rSurf = VK_NULL_HANDLE; - -#ifdef RGFW_X11 - VkXlibSurfaceCreateInfoKHR x11 = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, 0, 0, (Display*) win->src.display, (Window) win->src.window }; - - vkCreateXlibSurfaceKHR(RGFW_vulkan_info.instance, &x11, NULL, &win->src.rSurf); -#endif -#ifdef RGFW_WINDOWS - VkWin32SurfaceCreateInfoKHR win32 = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, 0, 0, GetModuleHandle(NULL), win->src.window }; - - vkCreateWin32SurfaceKHR(RGFW_vulkan_info.instance, &win32, NULL, &win->src.rSurf); -#endif -#if defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11) - VkMacOSSurfaceCreateFlagsMVK macos = { VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, 0, 0, win->src.display, win->src.window }; - - vkCreateMacOSSurfaceMVK(RGFW_vulkan_info.instance, &macos, NULL, &win->src.rSurf); -#endif - } - - RGFW_vulkanInfo* RGFW_getVulkanInfo(void) { - return &RGFW_vulkan_info; - } - - int RGFW_deviceInitialization(RGFW_window* win) { - assert(win != NULL); - - VkApplicationInfo appInfo = { 0 }; - appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.pApplicationName = "RGFW app"; - appInfo.apiVersion = VK_MAKE_VERSION(1, 0, 0); - - char* extension = -#ifdef RGFW_WINDOWS - "VK_KHR_win32_surface"; -#elif defined(RGFW_X11) - VK_KHR_XLIB_SURFACE_EXTENSION_NAME; -#elif defined(RGFW_MACOS) - "VK_MVK_macos_surface"; -#else - NULL; -#endif - - VkInstanceCreateInfo instance_create_info = { 0 }; - instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - instance_create_info.pApplicationInfo = &appInfo; - instance_create_info.enabledExtensionCount = extension ? 2 : 0, - instance_create_info.ppEnabledExtensionNames = (const char* [2]){ - VK_KHR_SURFACE_EXTENSION_NAME, - extension - }; - - if (vkCreateInstance(&instance_create_info, NULL, &RGFW_vulkan_info.instance) != VK_SUCCESS) { - fprintf(stderr, "failed to create instance!\n"); - return -1; - } - - - RGFW_createSurface(RGFW_vulkan_info.instance, win); - - u32 deviceCount = 0; - vkEnumeratePhysicalDevices(RGFW_vulkan_info.instance, &deviceCount, NULL); - VkPhysicalDevice* devices = (VkPhysicalDevice*) malloc(sizeof(VkPhysicalDevice) * deviceCount); - vkEnumeratePhysicalDevices(RGFW_vulkan_info.instance, &deviceCount, devices); - - RGFW_vulkan_info.physical_device = devices[0]; - - u32 queue_family_count = 0; - vkGetPhysicalDeviceQueueFamilyProperties(RGFW_vulkan_info.physical_device, &queue_family_count, NULL); - VkQueueFamilyProperties* queueFamilies = (VkQueueFamilyProperties*) malloc(sizeof(VkQueueFamilyProperties) * queue_family_count); - vkGetPhysicalDeviceQueueFamilyProperties(RGFW_vulkan_info.physical_device, &queue_family_count, queueFamilies); - - float queuePriority = 1.0f; - - VkPhysicalDeviceFeatures device_features = { 0 }; - - VkDeviceCreateInfo device_create_info = { 0 }; - device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - VkDeviceQueueCreateInfo queue_create_infos[2] = { - {0}, - {0}, - }; - queue_create_infos[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queue_create_infos[0].queueCount = 1; - queue_create_infos[0].pQueuePriorities = &queuePriority; - queue_create_infos[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queue_create_infos[1].queueCount = 1; - queue_create_infos[1].pQueuePriorities = &queuePriority; - device_create_info.queueCreateInfoCount = 2; - device_create_info.pQueueCreateInfos = queue_create_infos; - - device_create_info.enabledExtensionCount = 1; - - const char* device_extensions[] = { - VK_KHR_SWAPCHAIN_EXTENSION_NAME - }; - - device_create_info.ppEnabledExtensionNames = device_extensions; - device_create_info.pEnabledFeatures = &device_features; - - if (vkCreateDevice(RGFW_vulkan_info.physical_device, &device_create_info, NULL, &RGFW_vulkan_info.device) != VK_SUCCESS) { - fprintf(stderr, "failed to create logical device!\n"); - return -1; - } - - return 0; - } - - int RGFW_createSwapchain(RGFW_window* win) { - assert(win != NULL); - - VkSurfaceFormatKHR surfaceFormat = { VK_FORMAT_B8G8R8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }; - VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; - - VkSurfaceCapabilitiesKHR capabilities = { 0 }; - vkGetPhysicalDeviceSurfaceCapabilitiesKHR(RGFW_vulkan_info.physical_device, win->src.rSurf, &capabilities); - - win->src.image_count = capabilities.minImageCount + 1; - if (capabilities.maxImageCount > 0 && win->src.image_count > capabilities.maxImageCount) { - win->src.image_count = capabilities.maxImageCount; - } - - VkSwapchainCreateInfoKHR swapchain_create_info = { 0 }; - swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swapchain_create_info.surface = win->src.rSurf; - swapchain_create_info.minImageCount = win->src.image_count; - swapchain_create_info.imageFormat = surfaceFormat.format; - swapchain_create_info.imageColorSpace = surfaceFormat.colorSpace; - swapchain_create_info.imageExtent = (VkExtent2D){ win->r.w, win->r.h }; - swapchain_create_info.imageArrayLayers = 1; - swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - swapchain_create_info.queueFamilyIndexCount = 2; - swapchain_create_info.preTransform = capabilities.currentTransform; - swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - swapchain_create_info.presentMode = presentMode; - swapchain_create_info.clipped = VK_TRUE; - swapchain_create_info.oldSwapchain = VK_NULL_HANDLE; - - if (vkCreateSwapchainKHR(RGFW_vulkan_info.device, &swapchain_create_info, NULL, &win->src.swapchain) != VK_SUCCESS) { - fprintf(stderr, "failed to create swap chain!\n"); - return -1; - } - - u32 imageCount; - vkGetSwapchainImagesKHR(RGFW_vulkan_info.device, win->src.swapchain, &imageCount, NULL); - win->src.swapchain_images = (VkImage*) malloc(sizeof(VkImage) * imageCount); - vkGetSwapchainImagesKHR(RGFW_vulkan_info.device, win->src.swapchain, &imageCount, win->src.swapchain_images); - - win->src.swapchain_image_views = (VkImageView*) malloc(sizeof(VkImageView) * imageCount); - for (u32 i = 0; i < imageCount; i++) { - VkImageViewCreateInfo image_view_cre_infos = { 0 }; - image_view_cre_infos.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - image_view_cre_infos.image = win->src.swapchain_images[i]; - image_view_cre_infos.viewType = VK_IMAGE_VIEW_TYPE_2D; - image_view_cre_infos.format = VK_FORMAT_B8G8R8A8_SRGB; - image_view_cre_infos.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - image_view_cre_infos.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - image_view_cre_infos.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - image_view_cre_infos.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - image_view_cre_infos.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - image_view_cre_infos.subresourceRange.baseMipLevel = 0; - image_view_cre_infos.subresourceRange.levelCount = 1; - image_view_cre_infos.subresourceRange.baseArrayLayer = 0; - image_view_cre_infos.subresourceRange.layerCount = 1; - if (vkCreateImageView(RGFW_vulkan_info.device, &image_view_cre_infos, NULL, &win->src.swapchain_image_views[i]) != VK_SUCCESS) { - fprintf(stderr, "failed to create image views!"); - return -1; - } - } - - return 0; - } - - int RGFW_createRenderPass(void) { - VkAttachmentDescription color_attachment = { 0 }; - color_attachment.format = VK_FORMAT_B8G8R8A8_SRGB; - color_attachment.samples = VK_SAMPLE_COUNT_1_BIT; - color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - - VkAttachmentReference color_attachment_ref = { 0 }; - color_attachment_ref.attachment = 0; - color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpass = { 0 }; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &color_attachment_ref; - - VkSubpassDependency dependency = { 0 }; - dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - dependency.dstSubpass = 0; - dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.srcAccessMask = 0; - dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - - VkRenderPassCreateInfo render_pass_info = { 0 }; - render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - render_pass_info.attachmentCount = 1; - render_pass_info.pAttachments = &color_attachment; - render_pass_info.subpassCount = 1; - render_pass_info.pSubpasses = &subpass; - render_pass_info.dependencyCount = 1; - render_pass_info.pDependencies = &dependency; - - if (vkCreateRenderPass(RGFW_vulkan_info.device, &render_pass_info, NULL, &RGFW_vulkan_info.render_pass) != VK_SUCCESS) { - fprintf(stderr, "failed to create render pass\n"); - return -1; // failed to create render pass! - } - return 0; - } - - int RGFW_createCommandPool(void) { - VkCommandPoolCreateInfo pool_info = { 0 }; - pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - pool_info.queueFamilyIndex = 0; - - if (vkCreateCommandPool(RGFW_vulkan_info.device, &pool_info, NULL, &RGFW_vulkan_info.command_pool) != VK_SUCCESS) { - fprintf(stderr, "failed to create command pool\n"); - return -1; // failed to create command pool - } - return 0; - } - - int RGFW_createCommandBuffers(RGFW_window* win) { - assert(win != NULL); - - RGFW_vulkan_info.command_buffers = (VkCommandBuffer*) malloc(sizeof(VkCommandBuffer) * win->src.image_count); - - VkCommandBufferAllocateInfo allocInfo = { 0 }; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.commandPool = RGFW_vulkan_info.command_pool; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandBufferCount = (u32) win->src.image_count; - - if (vkAllocateCommandBuffers(RGFW_vulkan_info.device, &allocInfo, RGFW_vulkan_info.command_buffers) != VK_SUCCESS) { - return -1; // failed to allocate command buffers; - } - - return 0; - } - - int RGFW_createSyncObjects(RGFW_window* win) { - assert(win != NULL); - - RGFW_vulkan_info.available_semaphores = (VkSemaphore*) malloc(sizeof(VkSemaphore) * RGFW_MAX_FRAMES_IN_FLIGHT); - RGFW_vulkan_info.finished_semaphore = (VkSemaphore*) malloc(sizeof(VkSemaphore) * RGFW_MAX_FRAMES_IN_FLIGHT); - RGFW_vulkan_info.in_flight_fences = (VkFence*) malloc(sizeof(VkFence) * RGFW_MAX_FRAMES_IN_FLIGHT); - RGFW_vulkan_info.image_in_flight = (VkFence*) malloc(sizeof(VkFence) * win->src.image_count); - - VkSemaphoreCreateInfo semaphore_info = { 0 }; - semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - - VkFenceCreateInfo fence_info = { 0 }; - fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; - - for (size_t i = 0; i < RGFW_MAX_FRAMES_IN_FLIGHT; i++) { - if (vkCreateSemaphore(RGFW_vulkan_info.device, &semaphore_info, NULL, &RGFW_vulkan_info.available_semaphores[i]) != VK_SUCCESS || - vkCreateSemaphore(RGFW_vulkan_info.device, &semaphore_info, NULL, &RGFW_vulkan_info.finished_semaphore[i]) != VK_SUCCESS || - vkCreateFence(RGFW_vulkan_info.device, &fence_info, NULL, &RGFW_vulkan_info.in_flight_fences[i]) != VK_SUCCESS) { - fprintf(stderr, "failed to create sync objects\n"); - return -1; // failed to create synchronization objects for a frame - } - } - - for (size_t i = 0; i < win->src.image_count; i++) { - RGFW_vulkan_info.image_in_flight[i] = VK_NULL_HANDLE; - } - - return 0; - } - - int RGFW_createFramebuffers(RGFW_window* win) { - assert(win != NULL); - - RGFW_vulkan_info.framebuffers = (VkFramebuffer*) malloc(sizeof(VkFramebuffer) * win->src.image_count); - - for (size_t i = 0; i < win->src.image_count; i++) { - VkImageView attachments[] = { win->src.swapchain_image_views[i] }; - - VkFramebufferCreateInfo framebuffer_info = { 0 }; - framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebuffer_info.renderPass = RGFW_vulkan_info.render_pass; - framebuffer_info.attachmentCount = 1; - framebuffer_info.pAttachments = attachments; - framebuffer_info.width = win->r.w; - framebuffer_info.height = win->r.h; - framebuffer_info.layers = 1; - - if (vkCreateFramebuffer(RGFW_vulkan_info.device, &framebuffer_info, NULL, &RGFW_vulkan_info.framebuffers[i]) != VK_SUCCESS) { - return -1; // failed to create framebuffer - } - } - return 0; - } - - void RGFW_freeVulkan(void) { - vkDeviceWaitIdle(RGFW_vulkan_info.device); - - for (size_t i = 0; i < RGFW_MAX_FRAMES_IN_FLIGHT; i++) { - vkDestroySemaphore(RGFW_vulkan_info.device, RGFW_vulkan_info.finished_semaphore[i], NULL); - vkDestroySemaphore(RGFW_vulkan_info.device, RGFW_vulkan_info.available_semaphores[i], NULL); - vkDestroyFence(RGFW_vulkan_info.device, RGFW_vulkan_info.in_flight_fences[i], NULL); - } - - vkDestroyCommandPool(RGFW_vulkan_info.device, RGFW_vulkan_info.command_pool, NULL); - - vkDestroyPipeline(RGFW_vulkan_info.device, RGFW_vulkan_info.graphics_pipeline, NULL); - vkDestroyPipelineLayout(RGFW_vulkan_info.device, RGFW_vulkan_info.pipeline_layout, NULL); - vkDestroyRenderPass(RGFW_vulkan_info.device, RGFW_vulkan_info.render_pass, NULL); - -#ifdef RGFW_DEBUG - PFN_vkDestroyDebugUtilsMessengerEXT func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(RGFW_vulkan_info.instance, "vkDestroyDebugUtilsMessengerEXT"); - if (func != NULL) { - func(RGFW_vulkan_info.instance, RGFW_vulkan_info.debugMessenger, NULL); - } -#endif - - vkDestroyDevice(RGFW_vulkan_info.device, NULL); - vkDestroyInstance(RGFW_vulkan_info.instance, NULL); - - free(RGFW_vulkan_info.framebuffers); - free(RGFW_vulkan_info.command_buffers); - free(RGFW_vulkan_info.available_semaphores); - free(RGFW_vulkan_info.finished_semaphore); - free(RGFW_vulkan_info.in_flight_fences); - free(RGFW_vulkan_info.image_in_flight); - } - -#endif /* RGFW_VULKAN */ - - RGFW_window* RGFW_root = NULL; - -#ifdef RGFW_X11 -#include -#ifndef RGFW_NO_X11_CURSOR -#include -#endif -#include - -#ifndef RGFW_NO_DPI -#include -#include -#endif -#endif - -#define RGFW_MOUSE_CHANGED (1L<<1) /*!< mouse change (for winargs)*/ -#define RGFW_HOLD_MOUSE (1L<<2) /*!< hold the moues still */ - -#ifdef RGFW_WINDOWS -#include -#include -#include -#include -#include -#include -#endif - -#if defined(RGFW_MACOS) - u8 RGFW_keyBoard[128] = { 0 }; - u8 RGFW_keyBoard_prev[128]; -#endif - - u8 RGFW_isHeldI(RGFW_window* win, u32 key) { - return (RGFW_isPressedI(win, key) && RGFW_wasPressedI(win, key)); - } - - u8 RGFW_isReleasedI(RGFW_window* win, u32 key) { - return (!RGFW_isPressedI(win, key) && RGFW_wasPressedI(win, key)); - } - - char* RGFW_keyCodeTokeyStr(u64 key) { -#if defined(RGFW_MACOS) - static char* keyStrs[128] = { "a", "s", "d", "f", "h", "g", "z", "x", "c", "v", "0", "b", "q", "w", "e", "r", "y", "t", "1", "2", "3", "4", "6", "5", "Equals", "9", "7", "Minus", "8", "0", "CloseBracket", "o", "u", "Bracket", "i", "p", "Return", "l", "j", "Apostrophe", "k", "Semicolon", "BackSlash", "Comma", "Slash", "n", "m", "Period", "Tab", "Space", "Backtick", "BackSpace", "0", "Escape", "0", "Super", "Shift", "CapsLock", "Alt", "Control", "0", "0", "0", "0", "0", "KP_Period", "0", "KP_Minus", "0", "0", "0", "0", "Numlock", "0", "0", "0", "KP_Multiply", "KP_Return", "0", "0", "0", "0", "KP_Slash", "KP_0", "KP_1", "KP_2", "KP_3", "KP_4", "KP_5", "KP_6", "KP_7", "0", "KP_8", "KP_9", "0", "0", "0", "F5", "F6", "F7", "F3", "F8", "F9", "0", "F11", "0", "F13", "0", "F14", "0", "F10", "0", "F12", "0", "F15", "Insert", "Home", "PageUp", "Delete", "F4", "End", "F2", "PageDown", "Left", "Right", "Down", "Up", "F1" }; - - return keyStrs[key]; -#endif -#ifdef RGFW_X11 - return XKeysymToString(key); -#endif -#ifdef RGFW_WINDOWS - static char keyName[16]; - GetKeyNameTextA((LONG) key, keyName, 16); - - if ((!(GetKeyState(VK_CAPITAL) & 0x0001) && !(GetKeyState(VK_SHIFT) & 0x8000)) || - ((GetKeyState(VK_CAPITAL) & 0x0001) && (GetKeyState(VK_SHIFT) & 0x8000))) { - CharLowerBuffA(keyName, 16); - } - - return keyName; -#endif - } - - u32 RGFW_keyStrToKeyCode(char* key) { -#if defined(RGFW_MACOS) - static char* keyStrs[128] = { "a", "s", "d", "f", "h", "g", "z", "x", "c", "v", "0", "b", "q", "w", "e", "r", "y", "t", "1", "2", "3", "4", "6", "5", "Equals", "9", "7", "Minus", "8", "0", "CloseBracket", "o", "u", "Bracket", "i", "p", "Return", "l", "j", "Apostrophe", "k", "Semicolon", "BackSlash", "Comma", "Slash", "n", "m", "Period", "Tab", "Space", "Backtick", "BackSpace", "0", "Escape", "0", "Super", "Shift", "CapsLock", "Alt", "Control", "0", "0", "0", "0", "0", "KP_Period", "0", "KP_Minus", "0", "0", "0", "0", "Numlock", "0", "0", "0", "KP_Multiply", "KP_Return", "0", "0", "0", "0", "KP_Slash", "KP_0", "KP_1", "KP_2", "KP_3", "KP_4", "KP_5", "KP_6", "KP_7", "0", "KP_8", "KP_9", "0", "0", "0", "F5", "F6", "F7", "F3", "F8", "F9", "0", "F11", "0", "F13", "0", "F14", "0", "F10", "0", "F12", "0", "F15", "Insert", "Home", "PageUp", "Delete", "F4", "End", "F2", "PageDown", "Left", "Right", "Down", "Up", "F1" }; - - key--; - while (key++) { - u32 i; - for (i = 0; i < 128; i++) { - if (*keyStrs[i] == '\1') - continue; - - if (*keyStrs[i] != *key) { - keyStrs[i] = "\1"; - continue; - } - - if (*keyStrs[i] == '\0' && *key == '\0') - return i; - - else - keyStrs[i]++; - } - - if (*key == '\0') - break; - } - -#endif -#ifdef RGFW_X11 - if (strcmp(key, "Space") == 0) key = (char*) "space"; - - return XStringToKeysym(key); -#endif -#ifdef RGFW_WINDOWS - if (key[1]) { - struct { char* key; i32 code; } keyStrs[] = { - {"Super_L", VK_LWIN}, - {"Super_R", VK_RWIN}, - {"Space", VK_SPACE}, - {"Return", VK_RETURN}, - {"Caps_Lock", VK_CAPITAL}, - {"Tab", VK_TAB}, - {"Right", VK_RIGHT}, - {"Left", VK_LEFT}, - {"Up", VK_UP}, - {"Down", VK_DOWN}, - {"ShiftL", VK_LSHIFT}, - {"ShiftR", VK_RSHIFT}, - {"ControlL", VK_RCONTROL}, - {"ControlR", VK_RCONTROL} - }; - - - while (key++) { - u32 i; - for (i = 0; i < 14; i++) { - if (*keyStrs[i].key != '\0' && *keyStrs[i].key != '\1') - keyStrs[i].key++; - - if (*keyStrs[i].key != *key) { - keyStrs[i].key = "\1"; - continue; - } - - if (*keyStrs[i].key == '\0' && *key == '\0') - return keyStrs[i].code; - } - - if (*key == '\0') - break; - } - } - - i32 vKey = VkKeyScan(key[0]); - - return vKey; -#endif /* RGFW_WINDOWS */ - - return 0; - } - - - char RGFW_keystrToChar(const char* str) { - if (str[1] == 0) - return str[0]; - - static const char* map[] = { - "asciitilde", "`", - "grave", "~", - "exclam", "!", - "at", "@", - "numbersign", "#", - "dollar", "$", - "percent", "%%", - "asciicircum", "^", - "ampersand", "&", - "asterisk", "*", - "parenleft", "(", - "parenright", ")", - "underscore", "_", - "minus", "-", - "plus", "+", - "equal", "=", - "braceleft", "{", - "bracketleft", "[", - "bracketright", "]", - "braceright", "}", - "colon", ":", - "semicolon", ";", - "quotedbl", "\"", - "apostrophe", "'", - "bar", "|", - "backslash", "\'", - "less", "<", - "comma", ",", - "greater", ">", - "period", ".", - "question", "?", - "slash", "/", - "space", " ", - "Return", "\n", - "Enter", "\n", - "enter", "\n", - }; - - u8 i = 0; - for (i = 0; i < (sizeof(map) / sizeof(char*)); i += 2) - if (strcmp(map[i], str) == 0) - return *map[i + 1]; - - return '\0'; - } - -#ifndef M_PI -#define M_PI 3.14159265358979323846 /* pi */ -#endif - - typedef struct RGFW_Timespec { - time_t tv_sec; /* Seconds. */ - u32 tv_nsec; /* Nanoseconds. */ - } RGFW_Timespec; /*time struct for fps functions*/ - -#ifndef RGFW_WINDOWS - u32 RGFW_isPressedJS(RGFW_window* win, u16 c, u8 button) { return win->src.jsPressed[c][button]; } -#else - - typedef u64 (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*); - PFN_XInputGetState XInputGetStateSRC = NULL; - #define XInputGetState XInputGetStateSRC - static HMODULE RGFW_XInput_dll = NULL; - - u32 RGFW_isPressedJS(RGFW_window* win, u16 c, u8 button) { - RGFW_UNUSED(win) - - XINPUT_STATE state; - if (XInputGetState == NULL || XInputGetState(c, &state) == ERROR_DEVICE_NOT_CONNECTED) - return 0; - - if (button == RGFW_JS_A) return state.Gamepad.wButtons & XINPUT_GAMEPAD_A; - else if (button == RGFW_JS_B) return state.Gamepad.wButtons & XINPUT_GAMEPAD_B; - else if (button == RGFW_JS_Y) return state.Gamepad.wButtons & XINPUT_GAMEPAD_Y; - else if (button == RGFW_JS_X) return state.Gamepad.wButtons & XINPUT_GAMEPAD_X; - else if (button == RGFW_JS_START) return state.Gamepad.wButtons & XINPUT_GAMEPAD_START; - else if (button == RGFW_JS_SELECT) return state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK; - else if (button == RGFW_JS_UP) return state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP; - else if (button == RGFW_JS_DOWN) return state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN; - else if (button == RGFW_JS_LEFT) return state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT; - else if (button == RGFW_JS_RIGHT) return state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT; - else if (button == RGFW_JS_L1) return state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER; - else if (button == RGFW_JS_R1) return state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER; - else if (button == RGFW_JS_L2 && state.Gamepad.bLeftTrigger) return 1; - else if (button == RGFW_JS_R2 && state.Gamepad.bRightTrigger) return 1; - - return 0; - } -#endif - -#if defined(RGFW_OPENGL) || defined(RGFW_EGL) + #ifdef RGFW_WINDOWS + #define WIN32_LEAN_AND_MEAN + #define OEMRESOURCE + #include + #endif + + #if !defined(__APPLE__) && !defined(RGFW_NO_GL_HEADER) + #include + #elif defined(__APPLE__) + #ifndef GL_SILENCE_DEPRECATION + #define GL_SILENCE_DEPRECATION + #endif + #include + #include + #endif + +/* EGL, normal OpenGL only */ +#if !defined(RGFW_OSMESA) i32 RGFW_majorVersion = 0, RGFW_minorVersion = 0; + b8 RGFW_profile = RGFW_GL_CORE; #ifndef RGFW_EGL - i32 RGFW_STENCIL = 8, RGFW_SAMPLES = 4, RGFW_STEREO = GL_FALSE, RGFW_AUX_BUFFERS = 0; + i32 RGFW_STENCIL = 8, RGFW_SAMPLES = 4, RGFW_STEREO = 0, RGFW_AUX_BUFFERS = 0, RGFW_DOUBLE_BUFFER = 1; #else - i32 RGFW_STENCIL = 0, RGFW_SAMPLES = 0, RGFW_STEREO = GL_FALSE, RGFW_AUX_BUFFERS = 0; + i32 RGFW_STENCIL = 0, RGFW_SAMPLES = 0, RGFW_STEREO = 0, RGFW_AUX_BUFFERS = 0, RGFW_DOUBLE_BUFFER = 1; #endif @@ -2082,75 +1872,67 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ void RGFW_setGLSamples(i32 samples) { RGFW_SAMPLES = samples; } void RGFW_setGLStereo(i32 stereo) { RGFW_STEREO = stereo; } void RGFW_setGLAuxBuffers(i32 auxBuffers) { RGFW_AUX_BUFFERS = auxBuffers; } + void RGFW_setDoubleBuffer(b8 useDoubleBuffer) { RGFW_DOUBLE_BUFFER = useDoubleBuffer; } - void RGFW_setGLVersion(i32 major, i32 minor) { + void RGFW_setGLVersion(b8 profile, i32 major, i32 minor) { + RGFW_profile = profile; RGFW_majorVersion = major; RGFW_minorVersion = minor; } - u8* RGFW_getMaxGLVersion(void) { - RGFW_window* dummy = RGFW_createWindow("dummy", RGFW_RECT(0, 0, 1, 1), 0); - - const char* versionStr = (const char*) glGetString(GL_VERSION); - - static u8 version[2]; - version[0] = versionStr[0] - '0', - version[1] = versionStr[2] - '0'; - - RGFW_window_close(dummy); - - return version; - } - +/* OPENGL normal only (no EGL / OSMesa) */ #ifndef RGFW_EGL -#define RGFW_GL_RENDER_TYPE RGFW_OS_BASED_VALUE(GLX_X_VISUAL_TYPE, 0x2003, 73) -#define RGFW_GL_ALPHA_SIZE RGFW_OS_BASED_VALUE(GLX_ALPHA_SIZE, 0x201b, 11) -#define RGFW_GL_DEPTH_SIZE RGFW_OS_BASED_VALUE(GLX_DEPTH_SIZE, 0x2022, 12) -#define RGFW_GL_DOUBLEBUFFER RGFW_OS_BASED_VALUE(GLX_DOUBLEBUFFER, 0x2011, 5) -#define RGFW_GL_STENCIL_SIZE RGFW_OS_BASED_VALUE(GLX_STENCIL_SIZE, 0x2023, 13) -#define RGFW_GL_SAMPLES RGFW_OS_BASED_VALUE(GLX_SAMPLES, 0x2042, 55) -#define RGFW_GL_STEREO RGFW_OS_BASED_VALUE(GLX_STEREO, 0x2012, 6) -#define RGFW_GL_AUX_BUFFERS RGFW_OS_BASED_VALUE(GLX_AUX_BUFFERS, 0x2024, 7) +#define RGFW_GL_RENDER_TYPE RGFW_OS_BASED_VALUE(GLX_X_VISUAL_TYPE, 0x2003, 73, 0, 0) + #define RGFW_GL_ALPHA_SIZE RGFW_OS_BASED_VALUE(GLX_ALPHA_SIZE, 0x201b, 11, 0, 0) + #define RGFW_GL_DEPTH_SIZE RGFW_OS_BASED_VALUE(GLX_DEPTH_SIZE, 0x2022, 12, 0, 0) + #define RGFW_GL_DOUBLEBUFFER RGFW_OS_BASED_VALUE(GLX_DOUBLEBUFFER, 0x2011, 5, 0, 0) + #define RGFW_GL_STENCIL_SIZE RGFW_OS_BASED_VALUE(GLX_STENCIL_SIZE, 0x2023, 13, 0, 0) + #define RGFW_GL_SAMPLES RGFW_OS_BASED_VALUE(GLX_SAMPLES, 0x2042, 55, 0, 0) + #define RGFW_GL_STEREO RGFW_OS_BASED_VALUE(GLX_STEREO, 0x2012, 6, 0, 0) + #define RGFW_GL_AUX_BUFFERS RGFW_OS_BASED_VALUE(GLX_AUX_BUFFERS, 0x2024, 7, 0, 0) #if defined(RGFW_X11) || defined(RGFW_WINDOWS) -#define RGFW_GL_DRAW RGFW_OS_BASED_VALUE(GLX_X_RENDERABLE, 0x2001, 0) -#define RGFW_GL_DRAW_TYPE RGFW_OS_BASED_VALUE(GLX_RENDER_TYPE, 0x2013, 0) -#define RGFW_GL_USE_OPENGL RGFW_OS_BASED_VALUE(GLX_USE_GL, 0x2010, 0) -#define RGFW_GL_FULL_FORMAT RGFW_OS_BASED_VALUE(GLX_TRUE_COLOR, 0x2027, 0) -#define RGFW_GL_RED_SIZE RGFW_OS_BASED_VALUE(GLX_RED_SIZE, 0x2015, 0) -#define RGFW_GL_GREEN_SIZE RGFW_OS_BASED_VALUE(GLX_GREEN_SIZE, 0x2017, 0) -#define RGFW_GL_BLUE_SIZE RGFW_OS_BASED_VALUE(GLX_BLUE_SIZE, 0x2019, 0) -#define RGFW_GL_USE_RGBA RGFW_OS_BASED_VALUE(GLX_RGBA_BIT, 0x202B, 0) + #define RGFW_GL_DRAW RGFW_OS_BASED_VALUE(GLX_X_RENDERABLE, 0x2001, 0, 0, 0) + #define RGFW_GL_DRAW_TYPE RGFW_OS_BASED_VALUE(GLX_RENDER_TYPE, 0x2013, 0, 0, 0) + #define RGFW_GL_FULL_FORMAT RGFW_OS_BASED_VALUE(GLX_TRUE_COLOR, 0x2027, 0, 0, 0) + #define RGFW_GL_RED_SIZE RGFW_OS_BASED_VALUE(GLX_RED_SIZE, 0x2015, 0, 0, 0) + #define RGFW_GL_GREEN_SIZE RGFW_OS_BASED_VALUE(GLX_GREEN_SIZE, 0x2017, 0, 0, 0) + #define RGFW_GL_BLUE_SIZE RGFW_OS_BASED_VALUE(GLX_BLUE_SIZE, 0x2019, 0, 0, 0) + #define RGFW_GL_USE_RGBA RGFW_OS_BASED_VALUE(GLX_RGBA_BIT, 0x202B, 0, 0, 0) #endif #ifdef RGFW_WINDOWS -#define WGL_COLOR_BITS_ARB 0x2014 -#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 -#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 -#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#define WGL_SAMPLE_BUFFERS_ARB 0x2041 -#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9 -#endif + #define WGL_SUPPORT_OPENGL_ARB 0x2010 + #define WGL_COLOR_BITS_ARB 0x2014 + #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 + #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 + #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 + #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 + #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 + #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 + #define WGL_SAMPLE_BUFFERS_ARB 0x2041 + #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9 + #define WGL_PIXEL_TYPE_ARB 0x2013 + #define WGL_TYPE_RGBA_ARB 0x202B - static u32* RGFW_initAttribs(u32 useSoftware) { + #define WGL_TRANSPARENT_ARB 0x200A +#endif + +/* The window'ing api needs to know how to render the data we (or opengl) give it + MacOS and Windows do this using a structure called a "pixel format" + X11 calls it a "Visual" + This function returns the attributes for the format we want */ + static u32* RGFW_initFormatAttribs(u32 useSoftware) { RGFW_UNUSED(useSoftware); static u32 attribs[] = { - #ifndef RGFW_MACOS + #if defined(RGFW_X11) || defined(RGFW_WINDOWS) RGFW_GL_RENDER_TYPE, RGFW_GL_FULL_FORMAT, #endif RGFW_GL_ALPHA_SIZE , 8, RGFW_GL_DEPTH_SIZE , 24, - RGFW_GL_DOUBLEBUFFER , - #ifndef RGFW_MACOS - 1, - #endif - #if defined(RGFW_X11) || defined(RGFW_WINDOWS) - RGFW_GL_USE_OPENGL, 1, RGFW_GL_DRAW, 1, RGFW_GL_RED_SIZE , 8, RGFW_GL_GREEN_SIZE , 8, @@ -2160,7 +1942,7 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ #ifdef RGFW_X11 GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, - #endif + #endif #ifdef RGFW_MACOS 72, @@ -2168,6 +1950,8 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ #endif #ifdef RGFW_WINDOWS + WGL_SUPPORT_OPENGL_ARB, 1, + WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, WGL_COLOR_BITS_ARB, 32, #endif @@ -2182,8 +1966,10 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ attribs[index + 1] = attVal;\ index += 2;\ } - - RGFW_GL_ADD_ATTRIB(RGFW_GL_STENCIL_SIZE, RGFW_STENCIL); + + RGFW_GL_ADD_ATTRIB(RGFW_GL_DOUBLEBUFFER, 1); + + RGFW_GL_ADD_ATTRIB(RGFW_GL_STENCIL_SIZE, RGFW_STENCIL); RGFW_GL_ADD_ATTRIB(RGFW_GL_STEREO, RGFW_STEREO); RGFW_GL_ADD_ATTRIB(RGFW_GL_AUX_BUFFERS, RGFW_AUX_BUFFERS); @@ -2201,13 +1987,15 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ #endif #ifdef RGFW_MACOS + /* macOS has the surface attribs and the opengl attribs connected for some reason + maybe this is to give macOS more control to limit openGL/the opengl version? */ + attribs[index] = 99; attribs[index + 1] = 0x1000; if (RGFW_majorVersion >= 4 || RGFW_majorVersion >= 3) { attribs[index + 1] = (u32) ((RGFW_majorVersion >= 4) ? 0x4100 : 0x3200); } - #endif RGFW_GL_ADD_ATTRIB(0, 0); @@ -2215,7 +2003,8 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ return attribs; } -#else +/* EGL only (no OSMesa nor normal OPENGL) */ +#elif defined(RGFW_EGL) #include @@ -2325,18 +2114,29 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ #else 2, #endif - EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE + EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE }; size_t index = 4; RGFW_GL_ADD_ATTRIB(EGL_STENCIL_SIZE, RGFW_STENCIL); RGFW_GL_ADD_ATTRIB(EGL_SAMPLES, RGFW_SAMPLES); + if (RGFW_DOUBLE_BUFFER) + RGFW_GL_ADD_ATTRIB(EGL_RENDER_BUFFER, EGL_BACK_BUFFER); + if (RGFW_majorVersion) { attribs[1] = RGFW_majorVersion; - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT); + RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MAJOR_VERSION, RGFW_majorVersion); RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MINOR_VERSION, RGFW_minorVersion); + + if (RGFW_profile == RGFW_GL_CORE) { + RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT); + } + else { + RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT); + } + } #if defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3) @@ -2344,13 +2144,20 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ #else eglBindAPI(EGL_OPENGL_API); #endif - - win->src.EGL_context = eglCreateContext(win->src.EGL_display, config, EGL_NO_CONTEXT, attribs); + + win->src.EGL_context = eglCreateContext(win->src.EGL_display, config, EGL_NO_CONTEXT, attribs); + + if (win->src.EGL_context == NULL) + fprintf(stderr, "failed to create an EGL opengl context\n"); eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context); eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); } + void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { + eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context); + } + #ifdef RGFW_APPLE void* RGFWnsglFramework = NULL; #elif defined(RGFW_WINDOWS) @@ -2374,15 +2181,126 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ eglTerminate(win->src.EGL_display); } + + void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { + assert(win != NULL); + + eglSwapInterval(win->src.EGL_display, swapInterval); + } #endif /* RGFW_EGL */ -#endif /* RGFW_GL stuff? */ - /* - This is where OS specific stuff starts - */ +/* + end of RGFW_EGL defines +*/ + +/* OPENGL Normal / EGL defines only (no OS MESA) Ends here */ + +#elif defined(RGFW_OSMESA) /* OSmesa only */ +RGFWDEF void RGFW_OSMesa_reorganize(void); + +/* reorganize buffer for osmesa */ +void RGFW_OSMesa_reorganize(void) { + u8* row = (u8*) RGFW_MALLOC(win->r.w * 3); + + i32 half_height = win->r.h / 2; + i32 stride = win->r.w * 3; + + i32 y; + for (y = 0; y < half_height; ++y) { + i32 top_offset = y * stride; + i32 bottom_offset = (win->r.h - y - 1) * stride; + memcpy(row, win->buffer + top_offset, stride); + memcpy(win->buffer + top_offset, win->buffer + bottom_offset, stride); + memcpy(win->buffer + bottom_offset, row, stride); + } + + RGFW_FREE(row); +} +#endif /* RGFW_OSMesa */ + +#endif /* RGFW_GL (OpenGL, EGL, OSMesa )*/ + +/* +This is where OS specific stuff starts +*/ + + +#if defined(RGFW_WAYLAND) || defined(RGFW_X11) + int RGFW_eventWait_forceStop[] = {0, 0, 0}; /* for wait events */ + + #ifdef __linux__ + #include + #include + #include + + RGFW_Event* RGFW_linux_updateJoystick(RGFW_window* win) { + static int xAxis = 0, yAxis = 0; + u8 i; + for (i = 0; i < RGFW_joystickCount; i++) { + struct js_event e; + + + if (RGFW_joysticks[i] == 0) + continue; + + i32 flags = fcntl(RGFW_joysticks[i], F_GETFL, 0); + fcntl(RGFW_joysticks[i], F_SETFL, flags | O_NONBLOCK); + + ssize_t bytes; + while ((bytes = read(RGFW_joysticks[i], &e, sizeof(e))) > 0) { + switch (e.type) { + case JS_EVENT_BUTTON: + win->event.type = e.value ? RGFW_jsButtonPressed : RGFW_jsButtonReleased; + win->event.button = e.number; + RGFW_jsPressed[i][e.number] = e.value; + RGFW_jsButtonCallback(win, i, e.number, e.value); + return &win->event; + case JS_EVENT_AXIS: + ioctl(RGFW_joysticks[i], JSIOCGAXES, &win->event.axisesCount); + + if ((e.number == 0 || e.number % 2) && e.number != 1) + xAxis = e.value; + else + yAxis = e.value; + + win->event.axis[e.number / 2].x = xAxis; + win->event.axis[e.number / 2].y = yAxis; + win->event.type = RGFW_jsAxisMove; + win->event.joystick = i; + RGFW_jsAxisCallback(win, i, win->event.axis, win->event.axisesCount); + return &win->event; + + default: break; + } + } + } + + return NULL; + } + + #endif +#endif + +/* + + +Start of Linux / Unix defines + + +*/ #ifdef RGFW_X11 +#ifndef RGFW_NO_X11_CURSOR +#include +#endif +#include + +#ifndef RGFW_NO_DPI +#include +#include +#endif + #include #include #include @@ -2390,14 +2308,19 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ #include /* for converting keycode to string */ #include /* for hiding */ +#include +#include +#include #include /* for data limits (mainly used in drag and drop functions) */ -#include +#include + #ifdef __linux__ #include #endif + u8 RGFW_mouseIconSrc[] = { XC_arrow, XC_left_ptr, XC_xterm, XC_crosshair, XC_hand2, XC_sb_h_double_arrow, XC_sb_v_double_arrow, XC_bottom_left_corner, XC_bottom_right_corner, XC_fleur, XC_X_cursor}; /*atoms needed for drag and drop*/ Atom XdndAware, XdndTypeList, XdndSelection, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, XdndFinished, XdndActionCopy, XdndActionMove, XdndActionLink, XdndActionAsk, XdndActionPrivate; @@ -2412,6 +2335,14 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ typedef GLXContext(*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); #endif +#if !defined(RGFW_NO_X11_XI_PRELOAD) + typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int); + PFN_XISelectEvents XISelectEventsSrc = NULL; + #define XISelectEvents XISelectEventsSrc + + void* X11Xihandle = NULL; +#endif + #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) PFN_XcursorImageLoadCursor XcursorImageLoadCursorSrc = NULL; PFN_XcursorImageCreate XcursorImageCreateSrc = NULL; @@ -2430,6 +2361,85 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ void* RGFW_getProcAddress(const char* procname) { return (void*) glXGetProcAddress((GLubyte*) procname); } #endif + RGFWDEF void RGFW_init_buffer(RGFW_window* win, XVisualInfo* vi); + void RGFW_init_buffer(RGFW_window* win, XVisualInfo* vi) { +#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0) + RGFW_bufferSize = RGFW_getScreenSize(); + + win->buffer = (u8*)RGFW_MALLOC(RGFW_bufferSize.w * RGFW_bufferSize.h * 4); + + #ifdef RGFW_OSMESA + win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); + OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h); + #endif + + win->src.bitmap = XCreateImage( + win->src.display, XDefaultVisual(win->src.display, vi->screen), + vi->depth, + ZPixmap, 0, NULL, RGFW_bufferSize.w, RGFW_bufferSize.h, + 32, 0 + ); + + win->src.gc = XCreateGC(win->src.display, win->src.window, 0, NULL); + + #else + RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ + RGFW_UNUSED(vi) + #endif + } + + + + void RGFW_window_setBorder(RGFW_window* win, u8 border) { + static Atom _MOTIF_WM_HINTS = 0; + if (_MOTIF_WM_HINTS == 0 ) + _MOTIF_WM_HINTS = XInternAtom(win->src.display, "_MOTIF_WM_HINTS", False); + + struct __x11WindowHints { + unsigned long flags, functions, decorations, status; + long input_mode; + } hints; + hints.flags = (1L << 1); + hints.decorations = border; + + XChangeProperty( + win->src.display, win->src.window, + _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, + 32, PropModeReplace, (u8*)&hints, 5 + ); + } + + void RGFW_releaseCursor(RGFW_window* win) { + XUngrabPointer(win->src.display, CurrentTime); + + /* disable raw input */ + unsigned char mask[] = { 0 }; + XIEventMask em; + em.deviceid = XIAllMasterDevices; + em.mask_len = sizeof(mask); + em.mask = mask; + + XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1); + } + + void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { + /* enable raw input */ + unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; + XISetMask(mask, XI_RawMotion); + + XIEventMask em; + em.deviceid = XIAllMasterDevices; + em.mask_len = sizeof(mask); + em.mask = mask; + + XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1); + + XGrabPointer(win->src.display, win->src.window, True, PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); + + RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (i32)(r.w / 2), win->r.y + (i32)(r.h / 2))); + } + RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) { #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) if (X11Cursorhandle == NULL) { @@ -2447,38 +2457,53 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ } #endif - XInitThreads(); /* init X11 threading*/ +#if !defined(RGFW_NO_X11_XI_PRELOAD) + if (X11Xihandle == NULL) { +#if defined(__CYGWIN__) + X11Xihandle = dlopen("libXi-6.so", RTLD_LAZY | RTLD_LOCAL); +#elif defined(__OpenBSD__) || defined(__NetBSD__) + X11Xihandle = dlopen("libXi.so", RTLD_LAZY | RTLD_LOCAL); +#else + X11Xihandle = dlopen("libXi.so.6", RTLD_LAZY | RTLD_LOCAL); +#endif + + XISelectEventsSrc = (PFN_XISelectEvents) dlsym(X11Xihandle, "XISelectEvents"); + } +#endif + + XInitThreads(); /*!< init X11 threading*/ if (args & RGFW_OPENGL_SOFTWARE) setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1); RGFW_window* win = RGFW_window_basic_init(rect, args); - u64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask; /* X11 events accepted*/ + u64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | ExposureMask; /*!< X11 events accepted*/ #ifdef RGFW_OPENGL - u32* visual_attribs = RGFW_initAttribs(args & RGFW_OPENGL_SOFTWARE); + u32* visual_attribs = RGFW_initFormatAttribs(args & RGFW_OPENGL_SOFTWARE); i32 fbcount; GLXFBConfig* fbc = glXChooseFBConfig((Display*) win->src.display, DefaultScreen(win->src.display), (i32*) visual_attribs, &fbcount); i32 best_fbc = -1; if (fbcount == 0) { - printf("Failed to find any valid GLX configs\n"); + printf("Failed to find any valid GLX visual configs\n"); return NULL; } u32 i; for (i = 0; i < (u32)fbcount; i++) { XVisualInfo* vi = glXGetVisualFromFBConfig((Display*) win->src.display, fbc[i]); - if (vi == NULL) + if (vi == NULL) continue; - + XFree(vi); i32 samp_buf, samples; glXGetFBConfigAttrib((Display*) win->src.display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf); glXGetFBConfigAttrib((Display*) win->src.display, fbc[i], GLX_SAMPLES, &samples); + if ((best_fbc < 0 || samp_buf) && (samples == RGFW_SAMPLES || best_fbc == -1)) { best_fbc = i; } @@ -2493,48 +2518,67 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ /* Get a visual */ XVisualInfo* vi = glXGetVisualFromFBConfig((Display*) win->src.display, bestFbc); - + XFree(fbc); - - u32 valuemask = CWBorderPixel | CWColormap; + + if (args & RGFW_TRANSPARENT_WINDOW) { + XMatchVisualInfo((Display*) win->src.display, DefaultScreen((Display*) win->src.display), 32, TrueColor, vi); /*!< for RGBA backgrounds*/ + } + #else - XVisualInfo* vi = (XVisualInfo*) malloc(sizeof(XVisualInfo)); - vi->screen = DefaultScreen((Display*) win->src.display); - vi->visual = DefaultVisual((Display*) win->src.display, vi->screen); + XVisualInfo viNorm; - vi->depth = 0; - u32 valuemask = 0; + viNorm.visual = DefaultVisual((Display*) win->src.display, DefaultScreen((Display*) win->src.display)); + + viNorm.depth = 0; + XVisualInfo* vi = &viNorm; + + XMatchVisualInfo((Display*) win->src.display, DefaultScreen((Display*) win->src.display), 32, TrueColor, vi); /*!< for RGBA backgrounds*/ #endif - /* make X window attrubutes*/ XSetWindowAttributes swa; Colormap cmap; swa.colormap = cmap = XCreateColormap((Display*) win->src.display, - RootWindow(win->src.display, vi->screen), + DefaultRootWindow(win->src.display), vi->visual, AllocNone); swa.background_pixmap = None; swa.border_pixel = 0; swa.event_mask = event_mask; + + swa.background_pixel = 0; /* create the window*/ - win->src.window = XCreateWindow((Display*) win->src.display, RootWindow((Display*) win->src.display, vi->screen), win->r.x, win->r.y, win->r.w, win->r.h, + win->src.window = XCreateWindow((Display*) win->src.display, DefaultRootWindow((Display*) win->src.display), win->r.x, win->r.y, win->r.w, win->r.h, 0, vi->depth, InputOutput, vi->visual, - valuemask | CWEventMask, &swa); - + CWColormap | CWBorderPixel | CWBackPixel | CWEventMask, &swa); XFreeColors((Display*) win->src.display, cmap, NULL, 0, 0); - if (args & RGFW_TRANSPARENT_WINDOW) - XMatchVisualInfo((Display*) win->src.display, DefaultScreen((Display*) win->src.display), 32, TrueColor, vi); /* for RGBA backgrounds*/ + #ifdef RGFW_OPENGL XFree(vi); + #endif -#ifdef RGFW_OPENGL + // In your .desktop app, if you set the property + // StartupWMClass=RGFW that will assoicate the launcher icon + // with your application - robrohan + XClassHint *hint = XAllocClassHint(); + assert(hint != NULL); + hint->res_class = (char*)"RGFW"; + hint->res_name = (char*)name; // just use the window name as the app name + XSetClassHint((Display*) win->src.display, win->src.window, hint); + XFree(hint); + + if ((args & RGFW_NO_INIT_API) == 0) { +#ifdef RGFW_OPENGL /* This is the second part of setting up opengl. This is where we ask OpenGL for a specific version. */ i32 context_attribs[7] = { 0, 0, 0, 0, 0, 0, 0 }; context_attribs[0] = GLX_CONTEXT_PROFILE_MASK_ARB; - context_attribs[1] = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; - + if (RGFW_profile == RGFW_GL_CORE) + context_attribs[1] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; + else + context_attribs[1] = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + if (RGFW_majorVersion || RGFW_minorVersion) { context_attribs[2] = GLX_CONTEXT_MAJOR_VERSION_ARB; context_attribs[3] = RGFW_majorVersion; @@ -2549,21 +2593,21 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ GLXContext ctx = NULL; if (RGFW_root != NULL) - ctx = RGFW_root->src.rSurf; + ctx = RGFW_root->src.ctx; - win->src.rSurf = glXCreateContextAttribsARB((Display*) win->src.display, bestFbc, ctx, True, context_attribs); + win->src.ctx = glXCreateContextAttribsARB((Display*) win->src.display, bestFbc, ctx, True, context_attribs); #endif if (RGFW_root == NULL) RGFW_root = win; - RGFW_init_buffer(win); - -#ifdef RGFW_VULKAN - RGFW_initVulkan(win); -#endif + RGFW_init_buffer(win, vi); + } + + #ifndef RGFW_NO_MONITOR if (args & RGFW_SCALE_TO_MONITOR) RGFW_window_scaleToMonitor(win); + #endif if (args & RGFW_NO_RESIZE) { /* make it so the user can't resize the window*/ XSizeHints* sh = XAllocSizeHints(); @@ -2576,39 +2620,31 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ } if (args & RGFW_NO_BORDER) { - /* Atom vars for no-border*/ - static Atom window_type = 0; - static Atom value = 0; - - if (window_type == 0) { - window_type = XInternAtom((Display*) win->src.display, "_NET_WM_WINDOW_TYPE", False); - value = XInternAtom((Display*) win->src.display, "_NET_WM_WINDOW_TYPE_DOCK", False); - } - - XChangeProperty((Display*) win->src.display, (Drawable) win->src.window, window_type, XA_ATOM, 32, PropModeReplace, (u8*) &value, 1); /* toggle border*/ + RGFW_window_setBorder(win, 0); } - XSelectInput((Display*) win->src.display, (Drawable) win->src.window, event_mask); /* tell X11 what events we want*/ + XSelectInput((Display*) win->src.display, (Drawable) win->src.window, event_mask); /*!< tell X11 what events we want*/ /* make it so the user can't close the window until the program does*/ if (wm_delete_window == 0) - wm_delete_window = XInternAtom((Display*) win->src.display, "WM_DELETE_WINDOW", 1); + wm_delete_window = XInternAtom((Display*) win->src.display, "WM_DELETE_WINDOW", False); XSetWMProtocols((Display*) win->src.display, (Drawable) win->src.window, &wm_delete_window, 1); /* connect the context to the window*/ #ifdef RGFW_OPENGL - glXMakeCurrent((Display*) win->src.display, (Drawable) win->src.window, (GLXContext) win->src.rSurf); + if ((args & RGFW_NO_INIT_API) == 0) + glXMakeCurrent((Display*) win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx); #endif /* set the background*/ - XStoreName((Display*) win->src.display, (Drawable) win->src.window, name); /* set the name*/ + XStoreName((Display*) win->src.display, (Drawable) win->src.window, name); /*!< set the name*/ XMapWindow((Display*) win->src.display, (Drawable) win->src.window); /* draw the window*/ - XMoveWindow((Display*) win->src.display, (Drawable) win->src.window, win->r.x, win->r.y); /* move the window to it's proper cords*/ + XMoveWindow((Display*) win->src.display, (Drawable) win->src.window, win->r.x, win->r.y); /*!< move the window to it's proper cords*/ if (args & RGFW_ALLOW_DND) { /* init drag and drop atoms and turn on drag and drop for this window */ - win->src.winArgs |= RGFW_ALLOW_DND; + win->_winArgs |= RGFW_ALLOW_DND; XdndAware = XInternAtom((Display*) win->src.display, "XdndAware", False); XdndTypeList = XInternAtom((Display*) win->src.display, "XdndTypeList", False); @@ -2632,11 +2668,12 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ XChangeProperty((Display*) win->src.display, (Window) win->src.window, XdndAware, 4, 32, - PropModeReplace, (u8*) &version, 1); /* turns on drag and drop */ + PropModeReplace, (u8*) &version, 1); /*!< turns on drag and drop */ } #ifdef RGFW_EGL - RGFW_createOpenGLContext(win); + if ((args & RGFW_NO_INIT_API) == 0) + RGFW_createOpenGLContext(win); #endif RGFW_window_setMouseDefault(win); @@ -2653,15 +2690,28 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ return RGFW_AREA(scrn->width, scrn->height); } - RGFW_vector RGFW_getGlobalMousePoint(void) { + RGFW_point RGFW_getGlobalMousePoint(void) { assert(RGFW_root != NULL); - RGFW_vector RGFWMouse; + RGFW_point RGFWMouse; i32 x, y; u32 z; Window window1, window2; - XQueryPointer((Display*) RGFW_root->src.display, XDefaultRootWindow((Display*) RGFW_root->src.display), &window1, &window2, &x, &RGFWMouse.x, &RGFWMouse.y, &y, &z); + XQueryPointer((Display*) RGFW_root->src.display, XDefaultRootWindow((Display*) RGFW_root->src.display), &window1, &window2, &RGFWMouse.x, &RGFWMouse.y, &x, &y, &z); + + return RGFWMouse; + } + + RGFW_point RGFW_window_getMousePoint(RGFW_window* win) { + assert(win != NULL); + + RGFW_point RGFWMouse; + + i32 x, y; + u32 z; + Window window1, window2; + XQueryPointer((Display*) win->src.display, win->src.window, &window1, &window2, &x, &y, &RGFWMouse.x, &RGFWMouse.y, &z); return RGFWMouse; } @@ -2669,64 +2719,37 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ typedef struct XDND { long source, version; i32 format; - } XDND; /* data structure for xdnd events */ + } XDND; /*!< data structure for xdnd events */ XDND xdnd; int xAxis = 0, yAxis = 0; - char RGFW_keyboard[32]; - char RGFW_keyboard_prev[32]; - RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) { assert(win != NULL); + + if (win->event.type == 0) + RGFW_resetKey(); + + if (win->event.type == RGFW_quit) { + return NULL; + } + win->event.type = 0; #ifdef __linux__ - { - u8 i; - for (i = 0; i < win->src.joystickCount; i++) { - struct js_event e; - - - if (!win->src.joysticks[i]) - continue; - - i32 flags = fcntl(win->src.joysticks[i], F_GETFL, 0); - fcntl(win->src.joysticks[i], F_SETFL, flags | O_NONBLOCK); - - ssize_t bytes; - while ((bytes = read(win->src.joysticks[i], &e, sizeof(e))) > 0) { - switch (e.type) { - case JS_EVENT_BUTTON: - win->event.type = e.value ? RGFW_jsButtonPressed : RGFW_jsButtonReleased; - win->event.button = e.number; - win->src.jsPressed[i][e.number] = e.value; - return &win->event; - case JS_EVENT_AXIS: - ioctl(win->src.joysticks[i], JSIOCGAXES, &win->event.axisesCount); - - if ((e.number == 0 || e.number % 2) && e.number != 1) - xAxis = e.value; - else - yAxis = e.value; - - win->event.axis[e.number / 2].x = xAxis; - win->event.axis[e.number / 2].y = yAxis; - win->event.type = RGFW_jsAxisMove; - win->event.joystick = e.number / 2; - return &win->event; - - default: break; - } - } - } - } + RGFW_Event* event = RGFW_linux_updateJoystick(win); + if (event != NULL) + return event; #endif - XEvent E; /* raw X11 event */ + XPending(win->src.display); + + XEvent E; /*!< raw X11 event */ /* if there is no unread qued events, get a new one */ - if (XEventsQueued((Display*) win->src.display, QueuedAlready) + XEventsQueued((Display*) win->src.display, QueuedAfterReading) && win->event.type != RGFW_quit) + if ((QLength(win->src.display) || XEventsQueued((Display*) win->src.display, QueuedAlready) + XEventsQueued((Display*) win->src.display, QueuedAfterReading)) + && win->event.type != RGFW_quit + ) XNextEvent((Display*) win->src.display, &E); else { return NULL; @@ -2738,67 +2761,127 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ switch (E.type) { case KeyPress: - case KeyRelease: + case KeyRelease: { + win->event.repeat = RGFW_FALSE; /* check if it's a real key release */ if (E.type == KeyRelease && XEventsQueued((Display*) win->src.display, QueuedAfterReading)) { /* get next event if there is one*/ XEvent NE; XPeekEvent((Display*) win->src.display, &NE); if (E.xkey.time == NE.xkey.time && E.xkey.keycode == NE.xkey.keycode) /* check if the current and next are both the same*/ - break; + win->event.repeat = RGFW_TRUE; } /* set event key data */ - win->event.keyCode = XkbKeycodeToKeysym((Display*) win->src.display, E.xkey.keycode, 0, E.xkey.state & ShiftMask ? 1 : 0); - win->event.keyName = XKeysymToString(win->event.keyCode); /* convert to string */ + KeySym sym = (KeySym)XkbKeycodeToKeysym((Display*) win->src.display, E.xkey.keycode, 0, E.xkey.state & ShiftMask ? 1 : 0); + win->event.keyCode = RGFW_apiKeyCodeToRGFW(E.xkey.keycode); + + char* str = (char*)XKeysymToString(sym); + if (str != NULL) + strncpy(win->event.keyName, str, 16); - if (RGFW_isPressedI(win, win->event.keyCode)) - RGFW_keyboard_prev[E.xkey.keycode >> 3] |= (1 << (E.xkey.keycode & 7)); - else - RGFW_keyboard_prev[E.xkey.keycode >> 3] |= 0; + win->event.keyName[15] = '\0'; + RGFW_keyboard[win->event.keyCode].prev = RGFW_isPressed(win, win->event.keyCode); + /* get keystate data */ win->event.type = (E.type == KeyPress) ? RGFW_keyPressed : RGFW_keyReleased; - if (win->event.type == RGFW_keyReleased) { - if (win->event.keyCode == XK_Caps_Lock && win->event.lockState & RGFW_CAPSLOCK) - win->event.lockState ^= RGFW_CAPSLOCK; - else if (win->event.keyCode == XK_Caps_Lock) - win->event.lockState |= RGFW_CAPSLOCK; + XKeyboardState keystate; + XGetKeyboardControl((Display*) win->src.display, &keystate); - else if (win->event.keyCode == XK_Num_Lock && win->event.lockState & RGFW_NUMLOCK) - win->event.lockState ^= RGFW_NUMLOCK; - else if (win->event.keyCode == XK_Num_Lock) - win->event.lockState |= RGFW_NUMLOCK; - } - - XQueryKeymap(win->src.display, RGFW_keyboard); /* query the keymap */ + RGFW_updateLockState(win, (keystate.led_mask & 1), (keystate.led_mask & 2)); + RGFW_keyboard[win->event.keyCode].current = (E.type == KeyPress); + RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, (E.type == KeyPress)); break; - + } case ButtonPress: case ButtonRelease: - win->event.type = (E.type == ButtonPress) ? RGFW_mouseButtonPressed : RGFW_mouseButtonReleased; - - if (win->event.button == RGFW_mouseScrollUp) { - win->event.scroll = 1; - } - else if (win->event.button == RGFW_mouseScrollDown) { - win->event.scroll = -1; + win->event.type = RGFW_mouseButtonPressed + (E.type == ButtonRelease); // the events match + + switch(win->event.button) { + case RGFW_mouseScrollUp: + win->event.scroll = 1; + break; + case RGFW_mouseScrollDown: + win->event.scroll = -1; + break; + default: break; } win->event.button = E.xbutton.button; + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + + if (win->event.repeat == RGFW_FALSE) + win->event.repeat = RGFW_isPressed(win, win->event.keyCode); + + RGFW_mouseButtons[win->event.button].current = (E.type == ButtonPress); + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, (E.type == ButtonPress)); break; - case MotionNotify: + case MotionNotify: win->event.point.x = E.xmotion.x; win->event.point.y = E.xmotion.y; + + if ((win->_winArgs & RGFW_HOLD_MOUSE)) { + win->event.point.y = E.xmotion.y; + + win->event.point.x = win->_lastMousePoint.x - abs(win->event.point.x); + win->event.point.y = win->_lastMousePoint.y - abs(win->event.point.y); + } + + win->_lastMousePoint = RGFW_POINT(E.xmotion.x, E.xmotion.y); + win->event.type = RGFW_mousePosChanged; + RGFW_mousePosCallback(win, win->event.point); + break; + + case GenericEvent: { + /* MotionNotify is used for mouse events if the mouse isn't held */ + if (!(win->_winArgs & RGFW_HOLD_MOUSE)) { + XFreeEventData(win->src.display, &E.xcookie); + break; + } + + XGetEventData(win->src.display, &E.xcookie); + if (E.xcookie.evtype == XI_RawMotion) { + XIRawEvent *raw = (XIRawEvent *)E.xcookie.data; + if (raw->valuators.mask_len == 0) { + XFreeEventData(win->src.display, &E.xcookie); + break; + } + + double deltaX = 0.0f; + double deltaY = 0.0f; + + /* check if relative motion data exists where we think it does */ + if (XIMaskIsSet(raw->valuators.mask, 0) != 0) + deltaX += raw->raw_values[0]; + if (XIMaskIsSet(raw->valuators.mask, 1) != 0) + deltaY += raw->raw_values[1]; + + win->event.point = RGFW_POINT((i32)deltaX, (i32)deltaY); + + RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2))); + + win->event.type = RGFW_mousePosChanged; + RGFW_mousePosCallback(win, win->event.point); + } + + XFreeEventData(win->src.display, &E.xcookie); + break; + } + + case Expose: + win->event.type = RGFW_windowRefresh; + RGFW_windowRefreshCallback(win); break; case ClientMessage: /* if the client closed the window*/ if (E.xclient.data.l[0] == (i64) wm_delete_window) { win->event.type = RGFW_quit; + RGFW_windowQuitCallback(win); break; } @@ -2814,13 +2897,14 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ much of this event (drag and drop code) is source from glfw */ - if ((win->src.winArgs & RGFW_ALLOW_DND) == 0) + if ((win->_winArgs & RGFW_ALLOW_DND) == 0) break; - u8 formFree = 0; if (E.xclient.message_type == XdndEnter) { - u64 count; - Atom* formats = (Atom*) 0; + unsigned long count; + Atom* formats; + Atom real_formats[6]; + Bool list = E.xclient.data.l[1] & 1; xdnd.source = E.xclient.data.l[0]; @@ -2833,7 +2917,7 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ if (list) { Atom actualType; i32 actualFormat; - u64 bytesAfter; + unsigned long bytesAfter; XGetWindowProperty((Display*) win->src.display, xdnd.source, @@ -2844,25 +2928,24 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ 4, &actualType, &actualFormat, - (unsigned long*) &count, - (unsigned long*) &bytesAfter, + &count, + &bytesAfter, (u8**) &formats); } else { - formats = (Atom*) RGFW_MALLOC(E.xclient.data.l[2] + E.xclient.data.l[3] + E.xclient.data.l[4]); - formFree = 1; - count = 0; if (E.xclient.data.l[2] != None) - formats[count++] = E.xclient.data.l[2]; + real_formats[count++] = E.xclient.data.l[2]; if (E.xclient.data.l[3] != None) - formats[count++] = E.xclient.data.l[3]; + real_formats[count++] = E.xclient.data.l[3]; if (E.xclient.data.l[4] != None) - formats[count++] = E.xclient.data.l[4]; + real_formats[count++] = E.xclient.data.l[4]; + + formats = real_formats; } u32 i; - for (i = 0; i < count; i++) { + for (i = 0; i < (u32)count; i++) { char* name = XGetAtomName((Display*) win->src.display, formats[i]); char* links[2] = { (char*) (const char*) "text/uri-list", (char*) (const char*) "text/plain" }; @@ -2886,14 +2969,8 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ } } - if (list && formats) { + if (list) { XFree(formats); - formats = (Atom*) 0; - } else if (formFree && formats != (Atom*) 0) { - RGFW_FREE(formats); - - formats = (Atom*) 0; - formFree = 1; } break; @@ -2969,18 +3046,20 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ False, NoEventMask, &reply); XFlush((Display*) win->src.display); } + + RGFW_dndInitCallback(win, win->event.point); break; - case SelectionNotify: + case SelectionNotify: { /* this is only for checking for xdnd drops */ - if (E.xselection.property != XdndSelection || !(win->src.winArgs | RGFW_ALLOW_DND)) + if (E.xselection.property != XdndSelection || !(win->_winArgs | RGFW_ALLOW_DND)) break; char* data; - u64 result; + unsigned long result; Atom actualType; i32 actualFormat; - u64 bytesAfter; + unsigned long bytesAfter; XGetWindowProperty((Display*) win->src.display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (u8**) &data); @@ -2993,7 +3072,7 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ Copyright (c) 2006-2019 Camilla Löwy */ - const char* prefix = "file://"; + const char* prefix = (const char*)"file://"; char* line; @@ -3038,8 +3117,8 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ index++; line++; } - - strcpy(win->event.droppedFiles[win->event.droppedFilesCount - 1], path); + path[index] = '\0'; + strncpy(win->event.droppedFiles[win->event.droppedFilesCount - 1], path, index + 1); } if (data) @@ -3058,49 +3137,60 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ XFlush((Display*) win->src.display); } + RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount); break; - + } case FocusIn: win->event.inFocus = 1; - - XKeyboardState keystate; - XGetKeyboardControl((Display*) win->src.display, &keystate); - win->event.lockState = keystate.led_mask; + win->event.type = RGFW_focusIn; + RGFW_focusCallback(win, 1); + break; break; case FocusOut: win->event.inFocus = 0; - RGFW_window_setMouseDefault(win); + win->event.type = RGFW_focusOut; + RGFW_focusCallback(win, 0); break; - case ConfigureNotify: { -#ifndef RGFW_NO_X11_WINDOW_ATTRIB - XWindowAttributes a; - XGetWindowAttributes((Display*) win->src.display, (Window) win->src.window, &a); - win->r = RGFW_RECT(E.xconfigure.x, E.xconfigure.y, E.xconfigure.width, E.xconfigure.height); -#endif + + case EnterNotify: { + win->event.type = RGFW_mouseEnter; + win->event.point.x = E.xcrossing.x; + win->event.point.y = E.xcrossing.y; + RGFW_mouseNotifyCallBack(win, win->event.point, 1); + break; + } - win->event.type = RGFW_windowAttribsChange; + case LeaveNotify: { + win->event.type = RGFW_mouseLeave; + RGFW_mouseNotifyCallBack(win, win->event.point, 0); break; } + + case ConfigureNotify: { + /* detect resize */ + if (E.xconfigure.width != win->r.w || E.xconfigure.height != win->r.h) { + win->event.type = RGFW_windowResized; + win->r = RGFW_RECT(win->r.x, win->r.y, E.xconfigure.width, E.xconfigure.height); + RGFW_windowResizeCallback(win, win->r); + break; + } + + /* detect move */ + if (E.xconfigure.x != win->r.x || E.xconfigure.y != win->r.y) { + win->event.type = RGFW_windowMoved; + win->r = RGFW_RECT(E.xconfigure.x, E.xconfigure.y, win->r.w, win->r.h); + RGFW_windowMoveCallback(win, win->r); + break; + } + + break; + } default: { break; } } - if (win->event.inFocus && (win->src.winArgs & RGFW_MOUSE_CHANGED)) { - XDefineCursor((Display*) win->src.display, (Window) win->src.window, (Cursor) win->src.cursor); - - win->src.winArgs &= ~RGFW_MOUSE_CHANGED; - } - - if (win->src.winArgs & RGFW_HOLD_MOUSE && win->event.inFocus && win->event.type == RGFW_mousePosChanged) { - RGFW_window_moveMouse(win, RGFW_VECTOR(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2))); - - if (XEventsQueued((Display*) win->src.display, QueuedAfterReading) <= 1) - XSync(win->src.display, True); - } - - XFlush((Display*) win->src.display); if (win->event.type) @@ -3109,79 +3199,7 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ return NULL; } - void RGFW_window_close(RGFW_window* win) { - assert(win != NULL); - -#ifdef RGFW_VULKAN - for (u32 i = 0; i < win->src.image_count; i++) { - vkDestroyImageView(RGFW_vulkan_info.device, win->src.swapchain_image_views[i], NULL); - } - - vkDestroySwapchainKHR(RGFW_vulkan_info.device, win->src.swapchain, NULL); - vkDestroySurfaceKHR(RGFW_vulkan_info.instance, win->src.rSurf, NULL); - free(win->src.swapchain_image_views); - free(win->src.swapchain_images); -#endif - -#ifdef RGFW_EGL - RGFW_closeEGL(win); -#endif - - XFreeCursor((Display*) win->src.display, (Cursor) win->src.cursor); - -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - if (win->buffer != NULL) { - XDestroyImage((XImage*) win->src.bitmap); - } -#endif - - if ((Display*) win->src.display) { -#ifdef RGFW_OPENGL - glXDestroyContext((Display*) win->src.display, win->src.rSurf); -#endif - - if (win == RGFW_root) - RGFW_root = NULL; - - if ((Drawable) win->src.window) - XDestroyWindow((Display*) win->src.display, (Drawable) win->src.window); /* close the window*/ - - if (win->src.display) - XCloseDisplay((Display*) win->src.display); /* kill the display*/ - } - -#ifdef RGFW_ALLOC_DROPFILES - { - u32 i; - for (i = 0; i < RGFW_MAX_DROPS; i++) - RGFW_FREE(win->event.droppedFiles[i]); - - - RGFW_FREE(win->event.droppedFiles); - } -#endif - - RGFW_windowsOpen--; -#if !defined(RGFW_NO_X11_CURSOR_PRELOAD) && !defined(RGFW_NO_X11_CURSOR) - if (X11Cursorhandle != NULL && RGFW_windowsOpen <= 0) { - dlclose(X11Cursorhandle); - - X11Cursorhandle = NULL; - } -#endif - - /* set cleared display / window to NULL for error checking */ - win->src.display = (Display*) 0; - win->src.window = (Window) 0; - - u8 i; - for (i = 0; i < win->src.joystickCount; i++) - close(win->src.joysticks[i]); - - RGFW_FREE(win); /* free collected window data */ - } - - void RGFW_window_move(RGFW_window* win, RGFW_vector v) { + void RGFW_window_move(RGFW_window* win, RGFW_point v) { assert(win != NULL); win->r.x = v.x; win->r.y = v.y; @@ -3201,13 +3219,16 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { assert(win != NULL); + if (a.w == 0 && a.h == 0) + return; + XSizeHints hints; long flags; XGetWMNormalHints(win->src.display, (Window) win->src.window, &hints, &flags); hints.flags |= PMinSize; - + hints.min_width = a.w; hints.min_height = a.h; @@ -3217,6 +3238,9 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { assert(win != NULL); + if (a.w == 0 && a.h == 0) + return; + XSizeHints hints; long flags; @@ -3243,13 +3267,51 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ XMapWindow(win->src.display, (Window) win->src.window); XFlush(win->src.display); - } + } void RGFW_window_setName(RGFW_window* win, char* name) { assert(win != NULL); XStoreName((Display*) win->src.display, (Window) win->src.window, name); } + + void* RGFW_libxshape = NULL; + + #ifndef RGFW_NO_PASSTHROUGH + void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) { + assert(win != NULL); + + #if defined(__CYGWIN__) + RGFW_libxshape = dlopen("libXext-6.so", RTLD_LAZY | RTLD_LOCAL); + #elif defined(__OpenBSD__) || defined(__NetBSD__) + RGFW_libxshape = dlopen("libXext.so", RTLD_LAZY | RTLD_LOCAL); + #else + RGFW_libxshape = dlopen("libXext.so.6", RTLD_LAZY | RTLD_LOCAL); + #endif + + typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int); + static PFN_XShapeCombineMask XShapeCombineMask; + + typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int); + static PFN_XShapeCombineRegion XShapeCombineRegion; + + if (XShapeCombineMask != NULL) + XShapeCombineMask = (PFN_XShapeCombineMask) dlsym(RGFW_libxshape, "XShapeCombineMask"); + + if (XShapeCombineRegion != NULL) + XShapeCombineRegion = (PFN_XShapeCombineRegion) dlsym(RGFW_libxshape, "XShapeCombineMask"); + + if (passthrough) { + Region region = XCreateRegion(); + XShapeCombineRegion(win->src.display, win->src.window, ShapeInput, 0, 0, region, ShapeSet); + XDestroyRegion(region); + + return; + } + + XShapeCombineMask(win->src.display, win->src.window, ShapeInput, 0, 0, None, ShapeSet); + } + #endif /* the majority function is sourced from GLFW @@ -3302,10 +3364,6 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ assert(win != NULL); #ifndef RGFW_NO_X11_CURSOR - /* free the previous cursor */ - if (win->src.cursor) - XFreeCursor((Display*) win->src.display, (Cursor) win->src.cursor); - XcursorImage* native = XcursorImageCreate(a.w, a.h); native->xhot = 0; native->yhot = 0; @@ -3322,16 +3380,17 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ *target = (alpha << 24) | (((source[0] * alpha) / 255) << 16) | (((source[1] * alpha) / 255) << 8) | (((source[2] * alpha) / 255) << 0); } - win->src.winArgs |= RGFW_MOUSE_CHANGED; - win->src.cursor = XcursorImageLoadCursor((Display*) win->src.display, native); + Cursor cursor = XcursorImageLoadCursor((Display*) win->src.display, native); + XDefineCursor((Display*) win->src.display, (Window) win->src.window, (Cursor) cursor); + XFreeCursor((Display*) win->src.display, (Cursor) cursor); XcursorImageDestroy(native); #else RGFW_UNUSED(image) RGFW_UNUSED(a.w) RGFW_UNUSED(channels) #endif } - void RGFW_window_moveMouse(RGFW_window* win, RGFW_vector v) { + void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { assert(win != NULL); XEvent event; @@ -3344,8 +3403,7 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ if (event.xbutton.x == v.x && event.xbutton.y == v.y) return; - XWarpPointer(win->src.display, None, None, 0, 0, 0, 0, -event.xbutton.x, -event.xbutton.y); - XWarpPointer(win->src.display, None, None, 0, 0, 0, 0, v.x, v.y); + XWarpPointer(win->src.display, None, win->src.window, 0, 0, 0, 0, (int) v.x - win->r.x, (int) v.y - win->r.y); } RGFWDEF void RGFW_window_disableMouse(RGFW_window* win) { @@ -3353,18 +3411,21 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ } void RGFW_window_setMouseDefault(RGFW_window* win) { - RGFW_window_setMouseStandard(win, XC_left_ptr); + RGFW_window_setMouseStandard(win, RGFW_MOUSE_ARROW); } - void RGFW_window_setMouseStandard(RGFW_window* win, i32 mouse) { + void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { assert(win != NULL); + + if (mouse > (sizeof(RGFW_mouseIconSrc) / sizeof(u8))) + return; + + mouse = RGFW_mouseIconSrc[mouse]; - /* free the previous cursor */ - if (win->src.cursor) - XFreeCursor((Display*) win->src.display, (Cursor) win->src.cursor); + Cursor cursor = XCreateFontCursor((Display*) win->src.display, mouse); + XDefineCursor((Display*) win->src.display, (Window) win->src.window, (Cursor) cursor); - win->src.winArgs |= RGFW_MOUSE_CHANGED; - win->src.cursor = XCreateFontCursor((Display*) win->src.display, mouse); + XFreeCursor((Display*) win->src.display, (Cursor) cursor); } void RGFW_window_hide(RGFW_window* win) { @@ -3407,7 +3468,9 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ &format, &sizeN, &N, (unsigned char**) &data); if (target == UTF8 || target == XA_STRING) { - s = strndup(data, sizeN); + s = (char*)RGFW_MALLOC(sizeof(char) * sizeN); + strncpy(s, data, sizeN); + s[sizeN] = '\0'; XFree(data); } @@ -3417,7 +3480,7 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ *size = sizeN; return s; - } + } /* almost all of this function is sourced from GLFW @@ -3440,28 +3503,26 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ ATOM_PAIR = XInternAtom((Display*) RGFW_root->src.display, "ATOM_PAIR", False); CLIPBOARD_MANAGER = XInternAtom((Display*) RGFW_root->src.display, "CLIPBOARD_MANAGER", False); } - + XSetSelectionOwner((Display*) RGFW_root->src.display, CLIPBOARD, (Window) RGFW_root->src.window, CurrentTime); XConvertSelection((Display*) RGFW_root->src.display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, (Window) RGFW_root->src.window, CurrentTime); - for (;;) { XEvent event; XNextEvent((Display*) RGFW_root->src.display, &event); - if (event.type != SelectionRequest) - return; + if (event.type != SelectionRequest) { + break; + } const XSelectionRequestEvent* request = &event.xselectionrequest; XEvent reply = { SelectionNotify }; + reply.xselection.property = 0; - char* selectionString = NULL; const Atom formats[] = { UTF8_STRING, XA_STRING }; const i32 formatCount = sizeof(formats) / sizeof(formats[0]); - - selectionString = (char*) text; - + if (request->target == TARGETS) { const Atom targets[] = { TARGETS, MULTIPLE, @@ -3481,17 +3542,16 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ } if (request->target == MULTIPLE) { + Atom* targets = NULL; - Atom* targets; - - Atom actualType; - i32 actualFormat; - u64 count, bytesAfter; + Atom actualType = 0; + int actualFormat = 0; + unsigned long count = 0, bytesAfter = 0; XGetWindowProperty((Display*) RGFW_root->src.display, request->requestor, request->property, 0, LONG_MAX, False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets); - u64 i; - for (i = 0; i < count; i += 2) { + unsigned long i; + for (i = 0; i < (u32)count; i += 2) { i32 j; for (j = 0; j < formatCount; j++) { @@ -3507,10 +3567,12 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ targets[i], 8, PropModeReplace, - (u8*) selectionString, + (u8*) text, textLen); - } else + XFlush(RGFW_root->src.display); + } else { targets[i + 1] = None; + } } XChangeProperty((Display*) RGFW_root->src.display, @@ -3522,6 +3584,7 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ (u8*) targets, count); + XFlush(RGFW_root->src.display); XFree(targets); reply.xselection.property = request->property; @@ -3534,49 +3597,10 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ reply.xselection.time = request->time; XSendEvent((Display*) RGFW_root->src.display, request->requestor, False, 0, &reply); + XFlush(RGFW_root->src.display); } } - u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber) { - assert(win != NULL); - -#ifdef __linux__ - char file[15]; - sprintf(file, "/dev/input/js%i", jsNumber); - - return RGFW_registerJoystickF(win, file); -#endif - } - - u16 RGFW_registerJoystickF(RGFW_window* win, char* file) { - assert(win != NULL); - -#ifdef __linux__ - - i32 js = open(file, O_RDONLY); - - if (js && win->src.joystickCount < 4) { - win->src.joystickCount++; - - win->src.joysticks[win->src.joystickCount - 1] = open(file, O_RDONLY); - - u8 i; - for (i = 0; i < 16; i++) - win->src.jsPressed[win->src.joystickCount - 1][i] = 0; - - } - - else { -#ifdef RGFW_PRINT_ERRORS - RGFW_error = 1; - fprintf(stderr, "Error RGFW_registerJoystickF : Cannot open file %s\n", file); -#endif - } - - return win->src.joystickCount - 1; -#endif - } - u8 RGFW_window_isFullscreen(RGFW_window* win) { assert(win != NULL); @@ -3611,7 +3635,7 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ Atom actual_type; i32 actual_format; - u64 nitems, bytes_after; + unsigned long nitems, bytes_after; unsigned char* prop_data; i16 status = XGetWindowProperty(win->src.display, (Window) win->src.window, prop, 0, 2, False, @@ -3644,7 +3668,7 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ Atom actual_type; i32 actual_format; - u64 nitems, bytes_after; + unsigned long nitems, bytes_after; unsigned char* prop_data; i16 status = XGetWindowProperty(win->src.display, (Window) win->src.window, net_wm_state, 0, 1024, False, @@ -3690,7 +3714,7 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ XrmValue value; char* type = NULL; - if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && strcmp(type, "String") == 0) + if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && strncmp(type, "String", 7) == 0) xdpi = ydpi = atof(value.addr); XrmDestroyDatabase(db); #endif @@ -3708,7 +3732,7 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ monitor.physW = (monitor.rect.w * 25.4f / 96.f); monitor.physH = (monitor.rect.h * 25.4f / 96.f); - strcpy(monitor.name, DisplayString(display)); + strncpy(monitor.name, DisplayString(display), 128); XGetSystemContentScale(display, &monitor.scaleX, &monitor.scaleY); @@ -3777,36 +3801,1228 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { return RGFW_XCreateMonitor(DefaultScreen(win->src.display)); } - - u8 RGFW_isPressedI(RGFW_window* win, u32 key) { - Display* d; - if (win == (RGFW_window*) 0) - d = RGFW_root->src.display; - else if (!win->event.inFocus) - return 0; + + #ifdef RGFW_OPENGL + void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { + if (win == NULL) + glXMakeCurrent((Display*) NULL, (Drawable)NULL, (GLXContext) NULL); else - d = (Display*) win->src.display; - - KeyCode kc2 = XKeysymToKeycode(d, key); /* convert the key to a keycode */ - return (RGFW_keyboard[kc2 >> 3] & (1 << (kc2 & 7))); /* check if the key is pressed */ + glXMakeCurrent((Display*) win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx); + } + #endif + + + void RGFW_window_swapBuffers(RGFW_window* win) { + assert(win != NULL); + + /* clear the window*/ + if (!(win->_winArgs & RGFW_NO_CPU_RENDER)) { +#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + #ifdef RGFW_OSMESA + RGFW_OSMesa_reorganize(); + #endif + RGFW_area area = RGFW_bufferSize; + +#ifndef RGFW_X11_DONT_CONVERT_BGR + win->src.bitmap->data = (char*) win->buffer; + u32 x, y; + for (y = 0; y < (u32)win->r.h; y++) { + for (x = 0; x < (u32)win->r.w; x++) { + u32 index = (y * 4 * area.w) + x * 4; + + u8 red = win->src.bitmap->data[index]; + win->src.bitmap->data[index] = win->buffer[index + 2]; + win->src.bitmap->data[index + 2] = red; + + } + } +#endif + XPutImage(win->src.display, (Window) win->src.window, win->src.gc, win->src.bitmap, 0, 0, 0, 0, RGFW_bufferSize.w, RGFW_bufferSize.h); +#endif + } + + if (!(win->_winArgs & RGFW_NO_GPU_RENDER)) { + #ifdef RGFW_EGL + eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); + #elif defined(RGFW_OPENGL) + glXSwapBuffers((Display*) win->src.display, (Window) win->src.window); + #endif + } } - u8 RGFW_wasPressedI(RGFW_window* win, u32 key) { - Display* d; - if (win == (RGFW_window*) 0) - d = RGFW_root->src.display; - else if (!win->event.inFocus) - return 0; - else - d = (Display*) win->src.display; - - KeyCode kc2 = XKeysymToKeycode(d, key); /* convert the key to a keycode */ - return !!(RGFW_keyboard_prev[kc2 >> 3] & (1 << (kc2 & 7))); /* check if the key is pressed */ - } + #if !defined(RGFW_EGL) + void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { + assert(win != NULL); + #if defined(RGFW_OPENGL) + ((PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddress((GLubyte*) "glXSwapIntervalEXT"))((Display*) win->src.display, (Window) win->src.window, swapInterval); + #else + RGFW_UNUSED(swapInterval); + #endif + } + #endif + + + void RGFW_window_close(RGFW_window* win) { + /* ungrab pointer if it was grabbed */ + if (win->_winArgs & RGFW_HOLD_MOUSE) + XUngrabPointer(win->src.display, CurrentTime); + + assert(win != NULL); +#ifdef RGFW_EGL + RGFW_closeEGL(win); #endif +#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + if (win->buffer != NULL) { + XDestroyImage((XImage*) win->src.bitmap); + XFreeGC(win->src.display, win->src.gc); + } +#endif + + if ((Display*) win->src.display) { +#ifdef RGFW_OPENGL + glXDestroyContext((Display*) win->src.display, win->src.ctx); +#endif + + if (win == RGFW_root) + RGFW_root = NULL; + + if ((Drawable) win->src.window) + XDestroyWindow((Display*) win->src.display, (Drawable) win->src.window); /*!< close the window*/ + + XCloseDisplay((Display*) win->src.display); /*!< kill the display*/ + } + +#ifdef RGFW_ALLOC_DROPFILES + { + u32 i; + for (i = 0; i < RGFW_MAX_DROPS; i++) + RGFW_FREE(win->event.droppedFiles[i]); + + + RGFW_FREE(win->event.droppedFiles); + } +#endif + + RGFW_windowsOpen--; +#if !defined(RGFW_NO_X11_CURSOR_PRELOAD) && !defined(RGFW_NO_X11_CURSOR) + if (X11Cursorhandle != NULL && RGFW_windowsOpen <= 0) { + dlclose(X11Cursorhandle); + + X11Cursorhandle = NULL; + } +#endif +#if !defined(RGFW_NO_X11_XI_PRELOAD) + if (X11Xihandle != NULL && RGFW_windowsOpen <= 0) { + dlclose(X11Xihandle); + + X11Xihandle = NULL; + } +#endif + + if (RGFW_libxshape != NULL && RGFW_windowsOpen <= 0) { + dlclose(RGFW_libxshape); + RGFW_libxshape = NULL; + } + + if (RGFW_windowsOpen <= 0) { + if (RGFW_eventWait_forceStop[0] || RGFW_eventWait_forceStop[1]){ + close(RGFW_eventWait_forceStop[0]); + close(RGFW_eventWait_forceStop[1]); + } + + u8 i; + for (i = 0; i < RGFW_joystickCount; i++) + close(RGFW_joysticks[i]); + } + + /* set cleared display / window to NULL for error checking */ + win->src.display = (Display*) 0; + win->src.window = (Window) 0; + + RGFW_FREE(win); /*!< free collected window data */ + } + + +/* + End of X11 linux / unix defines +*/ + +#endif /* RGFW_X11 */ + + +/* wayland or X11 defines*/ +#if defined(RGFW_WAYLAND) || defined(RGFW_X11) +#include +#include +#include + u16 RGFW_registerJoystickF(RGFW_window* win, char* file) { + assert(win != NULL); + +#ifdef __linux__ + + i32 js = open(file, O_RDONLY); + + if (js && RGFW_joystickCount < 4) { + RGFW_joystickCount++; + + RGFW_joysticks[RGFW_joystickCount - 1] = open(file, O_RDONLY); + + u8 i; + for (i = 0; i < 16; i++) + RGFW_jsPressed[RGFW_joystickCount - 1][i] = 0; + + } + + else { +#ifdef RGFW_PRINT_ERRORS + RGFW_error = 1; + fprintf(stderr, "Error RGFW_registerJoystickF : Cannot open file %s\n", file); +#endif + } + + return RGFW_joystickCount - 1; +#endif + } + + u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber) { + assert(win != NULL); + +#ifdef __linux__ + char file[15]; + sprintf(file, "/dev/input/js%i", jsNumber); + + return RGFW_registerJoystickF(win, file); +#endif + } + + void RGFW_stopCheckEvents(void) { + RGFW_eventWait_forceStop[2] = 1; + while (1) { + const char byte = 0; + const ssize_t result = write(RGFW_eventWait_forceStop[1], &byte, 1); + if (result == 1 || result == -1) + break; + } + } + + void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { + if (waitMS == 0) + return; + + u8 i; + + if (RGFW_eventWait_forceStop[0] == 0 || RGFW_eventWait_forceStop[1] == 0) { + if (pipe(RGFW_eventWait_forceStop) != -1) { + fcntl(RGFW_eventWait_forceStop[0], F_GETFL, 0); + fcntl(RGFW_eventWait_forceStop[0], F_GETFD, 0); + fcntl(RGFW_eventWait_forceStop[1], F_GETFL, 0); + fcntl(RGFW_eventWait_forceStop[1], F_GETFD, 0); + } + } + + struct pollfd fds[] = { + #ifdef RGFW_WAYLAND + { wl_display_get_fd(win->src.display), POLLIN, 0 }, + #else + { ConnectionNumber(win->src.display), POLLIN, 0 }, + #endif + { RGFW_eventWait_forceStop[0], POLLIN, 0 }, + #ifdef __linux__ /* blank space for 4 joystick files*/ + { -1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0} + #endif + }; + + u8 index = 2; + + #if defined(__linux__) + for (i = 0; i < RGFW_joystickCount; i++) { + if (RGFW_joysticks[i] == 0) + continue; + + fds[index].fd = RGFW_joysticks[i]; + index++; + } + #endif + + + u64 start = RGFW_getTimeNS(); + + #ifdef RGFW_WAYLAND + while (wl_display_dispatch(win->src.display) <= 0 && waitMS >= -1) { + #else + while (XPending(win->src.display) == 0 && waitMS >= -1) { + #endif + if (poll(fds, index, waitMS) <= 0) + break; + + if (waitMS > 0) { + waitMS -= (RGFW_getTimeNS() - start) / 1e+6; + } + } + + /* drain any data in the stop request */ + if (RGFW_eventWait_forceStop[2]) { + char data[64]; + (void)!read(RGFW_eventWait_forceStop[0], data, sizeof(data)); + + RGFW_eventWait_forceStop[2] = 0; + } + } + + u64 RGFW_getTimeNS(void) { + struct timespec ts = { 0 }; + clock_gettime(1, &ts); + unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; + + return nanoSeconds; + } + + u64 RGFW_getTime(void) { + struct timespec ts = { 0 }; + clock_gettime(1, &ts); + unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; + + return (double)(nanoSeconds) * 1e-9; + } +#endif /* end of wayland or X11 time defines*/ + + +/* + + Start of Wayland defines + + +*/ + +#ifdef RGFW_WAYLAND +/* +Wayland TODO: +- fix RGFW_keyPressed lock state + + RGFW_windowMoved, the window was moved (by the user) + RGFW_windowResized the window was resized (by the user), [on webASM this means the browser was resized] + RGFW_windowRefresh The window content needs to be refreshed + + RGFW_dnd a file has been dropped into the window + RGFW_dnd_init + +- window args: + #define RGFW_NO_RESIZE the window cannot be resized by the user + #define RGFW_ALLOW_DND the window supports drag and drop + #define RGFW_SCALE_TO_MONITOR scale the window to the screen + +- other missing functions functions ("TODO wayland") (~30 functions) +- fix buffer rendering weird behavior +*/ + #include + #include + #include + #include + #include + #include + #include + #include + +RGFW_window* RGFW_key_win = NULL; + +void RGFW_eventPipe_push(RGFW_window* win, RGFW_Event event) { + if (win == NULL) { + win = RGFW_key_win; + + if (win == NULL) return; + } + + if (win->src.eventLen >= (i32)(sizeof(win->src.events) / sizeof(win->src.events[0]))) + return; + + win->src.events[win->src.eventLen] = event; + win->src.eventLen += 1; +} + +RGFW_Event RGFW_eventPipe_pop(RGFW_window* win) { + RGFW_Event ev; + ev.type = 0; + + if (win->src.eventLen > -1) + win->src.eventLen -= 1; + + if (win->src.eventLen >= 0) + ev = win->src.events[win->src.eventLen]; + else { + printf("H2\n"); + } + + return ev; +} + +/* wayland global garbage (wayland bad, X11 is fine (ish) (not really)) */ +#include "xdg-shell.h" +#include "xdg-decoration-unstable-v1.h" + +struct xdg_wm_base *xdg_wm_base; +struct wl_compositor* RGFW_compositor = NULL; +struct wl_shm* shm = NULL; +struct wl_shell* RGFW_shell = NULL; +static struct wl_seat *seat = NULL; +static struct xkb_context *xkb_context; +static struct xkb_keymap *keymap = NULL; +static struct xkb_state *xkb_state = NULL; +enum zxdg_toplevel_decoration_v1_mode client_preferred_mode, RGFW_current_mode; +static struct zxdg_decoration_manager_v1 *decoration_manager = NULL; + +struct wl_cursor_theme* RGFW_wl_cursor_theme = NULL; +struct wl_surface* RGFW_cursor_surface = NULL; +struct wl_cursor_image* RGFW_cursor_image = NULL; + +static void xdg_wm_base_ping_handler(void *data, + struct xdg_wm_base *wm_base, uint32_t serial) +{ + RGFW_UNUSED(data); + xdg_wm_base_pong(wm_base, serial); +} + +static const struct xdg_wm_base_listener xdg_wm_base_listener = { + .ping = xdg_wm_base_ping_handler, +}; + +b8 RGFW_wl_configured = 0; + +static void xdg_surface_configure_handler(void *data, + struct xdg_surface *xdg_surface, uint32_t serial) +{ + RGFW_UNUSED(data); + xdg_surface_ack_configure(xdg_surface, serial); + #ifdef RGFW_DEBUG + printf("Surface configured\n"); + #endif + RGFW_wl_configured = 1; +} + +static const struct xdg_surface_listener xdg_surface_listener = { + .configure = xdg_surface_configure_handler, +}; + +static void xdg_toplevel_configure_handler(void *data, + struct xdg_toplevel *toplevel, int32_t width, int32_t height, + struct wl_array *states) +{ + RGFW_UNUSED(data); RGFW_UNUSED(toplevel); RGFW_UNUSED(states) + fprintf(stderr, "XDG toplevel configure: %dx%d\n", width, height); +} + +static void xdg_toplevel_close_handler(void *data, + struct xdg_toplevel *toplevel) +{ + RGFW_UNUSED(data); + RGFW_window* win = (RGFW_window*)xdg_toplevel_get_user_data(toplevel); + if (win == NULL) + win = RGFW_key_win; + + RGFW_Event ev; + ev.type = RGFW_quit; + + RGFW_eventPipe_push(win, ev); + + RGFW_windowQuitCallback(win); +} + +static void shm_format_handler(void *data, + struct wl_shm *shm, uint32_t format) +{ + RGFW_UNUSED(data); RGFW_UNUSED(shm); + fprintf(stderr, "Format %d\n", format); +} + +static const struct wl_shm_listener shm_listener = { + .format = shm_format_handler, +}; + +static const struct xdg_toplevel_listener xdg_toplevel_listener = { + .configure = xdg_toplevel_configure_handler, + .close = xdg_toplevel_close_handler, +}; + +RGFW_window* RGFW_mouse_win = NULL; + +static void pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { + RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface_x); RGFW_UNUSED(surface_y); + RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); + RGFW_mouse_win = win; + + RGFW_Event ev; + ev.type = RGFW_mouseEnter; + ev.point = win->event.point; + + RGFW_eventPipe_push(win, ev); + + RGFW_mouseNotifyCallBack(win, win->event.point, RGFW_TRUE); +} +static void pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) { + RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface); + RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); + if (RGFW_mouse_win == win) + RGFW_mouse_win = NULL; + + RGFW_Event ev; + ev.type = RGFW_mouseLeave; + ev.point = win->event.point; + RGFW_eventPipe_push(win, ev); + + RGFW_mouseNotifyCallBack(win, win->event.point, RGFW_FALSE); +} +static void pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y) { + RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(x); RGFW_UNUSED(y); + + assert(RGFW_mouse_win != NULL); + + RGFW_Event ev; + ev.type = RGFW_mousePosChanged; + ev.point = RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y)); + RGFW_eventPipe_push(RGFW_mouse_win, ev); + + RGFW_mousePosCallback(RGFW_mouse_win, RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y))); +} +static void pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { + RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(serial); + assert(RGFW_mouse_win != NULL); + + u32 b = (button - 0x110) + 1; + + /* flip right and middle button codes */ + if (b == 2) b = 3; + else if (b == 3) b = 2; + + RGFW_mouseButtons[b].prev = RGFW_mouseButtons[b].current; + RGFW_mouseButtons[b].current = state; + + RGFW_Event ev; + ev.type = RGFW_mouseButtonPressed + state; + ev.button = b; + RGFW_eventPipe_push(RGFW_mouse_win, ev); + + RGFW_mouseButtonCallback(RGFW_mouse_win, b, 0, state); +} +static void pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { + RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(axis); + assert(RGFW_mouse_win != NULL); + + double scroll = wl_fixed_to_double(value); + + RGFW_Event ev; + ev.type = RGFW_mouseButtonPressed; + ev.button = RGFW_mouseScrollUp + (scroll < 0); + RGFW_eventPipe_push(RGFW_mouse_win, ev); + + RGFW_mouseButtonCallback(RGFW_mouse_win, RGFW_mouseScrollUp + (scroll < 0), scroll, 1); +} + +void RGFW_doNothing(void) { } +static struct wl_pointer_listener pointer_listener = (struct wl_pointer_listener){&pointer_enter, &pointer_leave, &pointer_motion, &pointer_button, &pointer_axis, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing}; + +static void keyboard_keymap (void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) { + RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(format); + + char *keymap_string = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0); + xkb_keymap_unref (keymap); + keymap = xkb_keymap_new_from_string (xkb_context, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + + munmap (keymap_string, size); + close (fd); + xkb_state_unref (xkb_state); + xkb_state = xkb_state_new (keymap); +} +static void keyboard_enter (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { + RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(keys); + + RGFW_key_win = (RGFW_window*)wl_surface_get_user_data(surface); + + RGFW_Event ev; + ev.type = RGFW_focusIn; + ev.inFocus = RGFW_TRUE; + RGFW_key_win->event.inFocus = RGFW_TRUE; + + RGFW_eventPipe_push((RGFW_window*)RGFW_mouse_win, ev); + + RGFW_focusCallback(RGFW_key_win, RGFW_TRUE); +} +static void keyboard_leave (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) { + RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); + + RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); + if (RGFW_key_win == win) + RGFW_key_win = NULL; + + RGFW_Event ev; + ev.type = RGFW_focusOut; + ev.inFocus = RGFW_FALSE; + win->event.inFocus = RGFW_FALSE; + RGFW_eventPipe_push(win, ev); + + RGFW_focusCallback(win, RGFW_FALSE); +} +static void keyboard_key (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { + RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time); + + assert(RGFW_key_win != NULL); + + xkb_keysym_t keysym = xkb_state_key_get_one_sym (xkb_state, key+8); + char name[16]; + xkb_keysym_get_name(keysym, name, 16); + + u32 RGFW_key = RGFW_apiKeyCodeToRGFW(key); + RGFW_keyboard[RGFW_key].prev = RGFW_keyboard[RGFW_key].current; + RGFW_keyboard[RGFW_key].current = state; + RGFW_Event ev; + ev.type = RGFW_keyPressed + state; + ev.keyCode = RGFW_key; + strcpy(ev.keyName, name); + ev.repeat = RGFW_isHeld(RGFW_key_win, RGFW_key); + RGFW_eventPipe_push(RGFW_key_win, ev); + + RGFW_updateLockState(RGFW_key_win, xkb_keymap_mod_get_index(keymap, "Lock"), xkb_keymap_mod_get_index(keymap, "Mod2")); + + RGFW_keyCallback(RGFW_key_win, RGFW_key, name, RGFW_key_win->event.lockState, state); +} +static void keyboard_modifiers (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { + RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time); + xkb_state_update_mask (xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group); +} +static struct wl_keyboard_listener keyboard_listener = {&keyboard_keymap, &keyboard_enter, &keyboard_leave, &keyboard_key, &keyboard_modifiers, (void*)&RGFW_doNothing}; + +static void seat_capabilities (void *data, struct wl_seat *seat, uint32_t capabilities) { + RGFW_UNUSED(data); + + if (capabilities & WL_SEAT_CAPABILITY_POINTER) { + struct wl_pointer *pointer = wl_seat_get_pointer (seat); + wl_pointer_add_listener (pointer, &pointer_listener, NULL); + } + if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { + struct wl_keyboard *keyboard = wl_seat_get_keyboard (seat); + wl_keyboard_add_listener (keyboard, &keyboard_listener, NULL); + } +} +static struct wl_seat_listener seat_listener = {&seat_capabilities, (void*)&RGFW_doNothing}; + +static void wl_global_registry_handler(void *data, + struct wl_registry *registry, uint32_t id, const char *interface, + uint32_t version) +{ + RGFW_UNUSED(data); RGFW_UNUSED(version); + + if (strcmp(interface, "wl_compositor") == 0) { + RGFW_compositor = wl_registry_bind(registry, + id, &wl_compositor_interface, 4); + } else if (strcmp(interface, "xdg_wm_base") == 0) { + xdg_wm_base = wl_registry_bind(registry, + id, &xdg_wm_base_interface, 1); + } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) { + decoration_manager = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1); + } else if (strcmp(interface, "wl_shm") == 0) { + shm = wl_registry_bind(registry, + id, &wl_shm_interface, 1); + wl_shm_add_listener(shm, &shm_listener, NULL); + } else if (strcmp(interface,"wl_seat") == 0) { + seat = wl_registry_bind(registry, id, &wl_seat_interface, 1); + wl_seat_add_listener(seat, &seat_listener, NULL); + } + + else { + #ifdef RGFW_DEBUG + printf("did not register %s\n", interface); + return; + #endif + } + + #ifdef RGFW_DEBUG + printf("registered %s\n", interface); + #endif +} + +static void wl_global_registry_remove(void *data, struct wl_registry *registry, uint32_t name) { RGFW_UNUSED(data); RGFW_UNUSED(registry); RGFW_UNUSED(name); } +static const struct wl_registry_listener registry_listener = { + .global = wl_global_registry_handler, + .global_remove = wl_global_registry_remove, +}; + +static const char *get_mode_name(enum zxdg_toplevel_decoration_v1_mode mode) { + switch (mode) { + case ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE: + return "client-side decorations"; + case ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE: + return "server-side decorations"; + } + abort(); +} + + +static void decoration_handle_configure(void *data, + struct zxdg_toplevel_decoration_v1 *decoration, + enum zxdg_toplevel_decoration_v1_mode mode) { + RGFW_UNUSED(data); RGFW_UNUSED(decoration); + printf("Using %s\n", get_mode_name(mode)); + RGFW_current_mode = mode; +} + +static const struct zxdg_toplevel_decoration_v1_listener decoration_listener = { + .configure = decoration_handle_configure, +}; + +static void randname(char *buf) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + long r = ts.tv_nsec; + for (int i = 0; i < 6; ++i) { + buf[i] = 'A'+(r&15)+(r&16)*2; + r >>= 5; + } +} + +static int anonymous_shm_open(void) { + char name[] = "/RGFW-wayland-XXXXXX"; + int retries = 100; + + do { + randname(name + strlen(name) - 6); + + --retries; + // shm_open guarantees that O_CLOEXEC is set + int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd >= 0) { + shm_unlink(name); + return fd; + } + } while (retries > 0 && errno == EEXIST); + + return -1; +} + +int create_shm_file(off_t size) { + int fd = anonymous_shm_open(); + if (fd < 0) { + return fd; + } + + if (ftruncate(fd, size) < 0) { + close(fd); + return -1; + } + + return fd; +} + +static void wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) { + #ifdef RGFW_BUFFER + RGFW_window* win = (RGFW_window*)data; + if ((win->_winArgs & RGFW_NO_CPU_RENDER)) + return; + + #ifndef RGFW_X11_DONT_CONVERT_BGR + u32 x, y; + for (y = 0; y < (u32)win->r.h; y++) { + for (x = 0; x < (u32)win->r.w; x++) { + u32 index = (y * 4 * win->r.w) + x * 4; + + u8 red = win->buffer[index]; + win->buffer[index] = win->buffer[index + 2]; + win->buffer[index + 2] = red; + + } + } + #endif + + wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0); + wl_surface_damage_buffer(win->src.surface, 0, 0, win->r.w, win->r.h); + wl_surface_commit(win->src.surface); + #endif +} + +static const struct wl_callback_listener wl_surface_frame_listener = { + .done = wl_surface_frame_done, +}; + + + /* normal wayland RGFW stuff */ + + RGFW_area RGFW_getScreenSize(void) { + RGFW_area area = {}; + + if (RGFW_root != NULL) + /* this isn't right but it's here for buffers */ + area = RGFW_AREA(RGFW_root->r.w, RGFW_root->r.h); + + /* TODO wayland */ + return area; + } + + void RGFW_releaseCursor(RGFW_window* win) { + RGFW_UNUSED(win); + } + + void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { + RGFW_UNUSED(win); RGFW_UNUSED(r); + + /* TODO wayland */ + } + + + RGFWDEF void RGFW_init_buffer(RGFW_window* win); + void RGFW_init_buffer(RGFW_window* win) { + #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + size_t size = win->r.w * win->r.h * 4; + int fd = create_shm_file(size); + if (fd < 0) { + fprintf(stderr, "Failed to create a buffer. size: %ld\n", size); + exit(1); + } + + win->buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (win->buffer == MAP_FAILED) { + fprintf(stderr, "mmap failed!\n"); + close(fd); + exit(1); + } + + struct wl_shm_pool* pool = wl_shm_create_pool(shm, fd, size); + win->src.wl_buffer = wl_shm_pool_create_buffer(pool, 0, win->r.w, win->r.h, win->r.w * 4, + WL_SHM_FORMAT_ARGB8888); + wl_shm_pool_destroy(pool); + + close(fd); + + wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0); + wl_surface_commit(win->src.surface); + + u8 color[] = {0x00, 0x00, 0x00, 0xFF}; + + size_t i; + for (i = 0; i < size; i += 4) { + memcpy(&win->buffer[i], color, 4); + } + + #if defined(RGFW_OSMESA) + win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); + OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h); + #endif + #else + RGFW_UNUSED(win); + #endif + } + + + RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) { + RGFW_window* win = RGFW_window_basic_init(rect, args); + + fprintf(stderr, "Warning: RGFW Wayland support is experimental\n"); + + win->src.display = wl_display_connect(NULL); + if (win->src.display == NULL) { + #ifdef RGFW_DEBUG + fprintf(stderr, "Failed to load Wayland display\n"); + #endif + return NULL; + } + + struct wl_registry *registry = wl_display_get_registry(win->src.display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + + wl_display_dispatch(win->src.display); + wl_display_roundtrip(win->src.display); + + if (RGFW_compositor == NULL) { + #ifdef RGFW_DEBUG + fprintf(stderr, "Can't find compositor.\n"); + #endif + + return NULL; + } + + if (RGFW_wl_cursor_theme == NULL) { + RGFW_wl_cursor_theme = wl_cursor_theme_load(NULL, 24, shm); + RGFW_cursor_surface = wl_compositor_create_surface(RGFW_compositor); + + struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, "left_ptr"); + RGFW_cursor_image = cursor->images[0]; + struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image); + + wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0); + wl_surface_commit(RGFW_cursor_surface); + } + + if (RGFW_root == NULL) + xdg_wm_base_add_listener(xdg_wm_base, &xdg_wm_base_listener, NULL); + + xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + + win->src.surface = wl_compositor_create_surface(RGFW_compositor); + wl_surface_set_user_data(win->src.surface, win); + + win->src.xdg_surface = xdg_wm_base_get_xdg_surface(xdg_wm_base, win->src.surface); + xdg_surface_add_listener(win->src.xdg_surface, &xdg_surface_listener, NULL); + + xdg_wm_base_set_user_data(xdg_wm_base, win); + + win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface); + xdg_toplevel_set_user_data(win->src.xdg_toplevel, win); + xdg_toplevel_set_title(win->src.xdg_toplevel, name); + xdg_toplevel_add_listener(win->src.xdg_toplevel, &xdg_toplevel_listener, NULL); + + xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->r.w, win->r.h); + + if (!(args & RGFW_NO_BORDER)) { + win->src.decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( + decoration_manager, win->src.xdg_toplevel); + } + + + if (args & RGFW_OPENGL_SOFTWARE) + setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1); + + wl_display_roundtrip(win->src.display); + + wl_surface_commit(win->src.surface); + + /* wait for the surface to be configured */ + while (wl_display_dispatch(win->src.display) != -1 && !RGFW_wl_configured) { } + + + #ifdef RGFW_OPENGL + if ((args & RGFW_NO_INIT_API) == 0) { + win->src.window = wl_egl_window_create(win->src.surface, win->r.w, win->r.h); + RGFW_createOpenGLContext(win); + } + #endif + + RGFW_init_buffer(win); + + struct wl_callback* callback = wl_surface_frame(win->src.surface); + wl_callback_add_listener(callback, &wl_surface_frame_listener, win); + wl_surface_commit(win->src.surface); + + if (args & RGFW_HIDE_MOUSE) { + RGFW_window_showMouse(win, 0); + } + + if (RGFW_root == NULL) { + RGFW_root = win; + } + + win->src.eventIndex = 0; + win->src.eventLen = 0; + + return win; + } + + RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) { + if (win->_winArgs & RGFW_WINDOW_HIDE) + return NULL; + + if (win->src.eventIndex == 0) { + if (wl_display_roundtrip(win->src.display) == -1) { + return NULL; + } + RGFW_resetKey(); + } + + #ifdef __linux__ + RGFW_Event* event = RGFW_linux_updateJoystick(win); + if (event != NULL) + return event; + #endif + + if (win->src.eventLen == 0) { + return NULL; + } + + RGFW_Event ev = RGFW_eventPipe_pop(win); + + if (ev.type == 0 || win->event.type == RGFW_quit) { + return NULL; + } + + ev.frameTime = win->event.frameTime; + ev.frameTime2 = win->event.frameTime2; + ev.inFocus = win->event.inFocus; + win->event = ev; + + return &win->event; + } + + + void RGFW_window_resize(RGFW_window* win, RGFW_area a) { + RGFW_UNUSED(win); RGFW_UNUSED(a); + + /* TODO wayland */ + } + + void RGFW_window_move(RGFW_window* win, RGFW_point v) { + RGFW_UNUSED(win); RGFW_UNUSED(v); + + /* TODO wayland */ + } + + void RGFW_window_setIcon(RGFW_window* win, u8* src, RGFW_area a, i32 channels) { + RGFW_UNUSED(win); RGFW_UNUSED(src); RGFW_UNUSED(a); RGFW_UNUSED(channels) + /* TODO wayland */ + } + + void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { + RGFW_UNUSED(win); RGFW_UNUSED(v); + + /* TODO wayland */ + } + + void RGFW_window_showMouse(RGFW_window* win, i8 show) { + RGFW_UNUSED(win); + + if (show) { + + } + else { + + } + + /* TODO wayland */ + } + + b8 RGFW_window_isMaximized(RGFW_window* win) { + RGFW_UNUSED(win); + /* TODO wayland */ + return 0; + } + + b8 RGFW_window_isMinimized(RGFW_window* win) { + RGFW_UNUSED(win); + /* TODO wayland */ + return 0; + } + + b8 RGFW_window_isHidden(RGFW_window* win) { + RGFW_UNUSED(win); + /* TODO wayland */ + return 0; + } + + b8 RGFW_window_isFullscreen(RGFW_window* win) { + RGFW_UNUSED(win); + /* TODO wayland */ + return 0; + } + + RGFW_point RGFW_window_getMousePoint(RGFW_window* win) { + RGFW_UNUSED(win); + /* TODO wayland */ + return RGFW_POINT(0, 0); + } + + RGFW_point RGFW_getGlobalMousePoint(void) { + /* TODO wayland */ + return RGFW_POINT(0, 0); + } + + void RGFW_window_show(RGFW_window* win) { + //wl_surface_attach(win->src.surface, win->rc., 0, 0); + wl_surface_commit(win->src.surface); + + if (win->_winArgs & RGFW_WINDOW_HIDE) + win->_winArgs ^= RGFW_WINDOW_HIDE; + } + + void RGFW_window_hide(RGFW_window* win) { + wl_surface_attach(win->src.surface, NULL, 0, 0); + wl_surface_commit(win->src.surface); + win->_winArgs |= RGFW_WINDOW_HIDE; + } + + void RGFW_window_setMouseDefault(RGFW_window* win) { + RGFW_UNUSED(win); + + RGFW_window_setMouseStandard(win, RGFW_MOUSE_NORMAL); + } + + void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { + RGFW_UNUSED(win); + + static const char* iconStrings[] = { "left_ptr", "left_ptr", "text", "cross", "pointer", "e-resize", "n-resize", "nw-resize", "ne-resize", "all-resize", "not-allowed" }; + + struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, iconStrings[mouse]); + RGFW_cursor_image = cursor->images[0]; + struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image); + + wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0); + wl_surface_commit(RGFW_cursor_surface); + } + + void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) { + RGFW_UNUSED(win); RGFW_UNUSED(image); RGFW_UNUSED(a); RGFW_UNUSED(channels) + //struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, iconStrings[mouse]); + //RGFW_cursor_image = image; + struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image); + + wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0); + wl_surface_commit(RGFW_cursor_surface); + } + + void RGFW_window_setName(RGFW_window* win, char* name) { + xdg_toplevel_set_title(win->src.xdg_toplevel, name); + } + + void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) { + RGFW_UNUSED(win); RGFW_UNUSED(passthrough); + + /* TODO wayland */ + } + + void RGFW_window_setBorder(RGFW_window* win, b8 border) { + RGFW_UNUSED(win); RGFW_UNUSED(border); + + /* TODO wayland */ + } + + void RGFW_window_restore(RGFW_window* win) { + RGFW_UNUSED(win); + + /* TODO wayland */ + } + + void RGFW_window_minimize(RGFW_window* win) { + RGFW_UNUSED(win); + + /* TODO wayland */ + } + + void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { + RGFW_UNUSED(win); RGFW_UNUSED(a); + + /* TODO wayland */ + } + + void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { + RGFW_UNUSED(win); RGFW_UNUSED(a); + + /* TODO wayland */ + } + + RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { + RGFW_monitor m = {}; + RGFW_UNUSED(win); + RGFW_UNUSED(m); + /* TODO wayland */ + + return m; + } + + + #ifndef RGFW_EGL + void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); } + #endif + + void RGFW_window_swapBuffers(RGFW_window* win) { + assert(win != NULL); + + /* clear the window*/ + #ifdef RGFW_BUFFER + wl_surface_frame_done(win, NULL, 0); + if (!(win->_winArgs & RGFW_NO_GPU_RENDER)) + #endif + { + #ifdef RGFW_OPENGL + eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); + #endif + } + + wl_display_flush(win->src.display); + } + + void RGFW_window_close(RGFW_window* win) { + #ifdef RGFW_EGL + RGFW_closeEGL(win); + #endif + + if (RGFW_root == win) { + RGFW_root = NULL; + } + + xdg_toplevel_destroy(win->src.xdg_toplevel); + xdg_surface_destroy(win->src.xdg_surface); + wl_surface_destroy(win->src.surface); + + #ifdef RGFW_BUFFER + wl_buffer_destroy(win->src.wl_buffer); + #endif + + wl_display_disconnect(win->src.display); + RGFW_FREE(win); + } + + RGFW_monitor RGFW_getPrimaryMonitor(void) { + /* TODO wayland */ + + return (RGFW_monitor){}; + } + + RGFW_monitor* RGFW_getMonitors(void) { + /* TODO wayland */ + + return NULL; + } + + void RGFW_writeClipboard(const char* text, u32 textLen) { + RGFW_UNUSED(text); RGFW_UNUSED(textLen); + + /* TODO wayland */ + } + + char* RGFW_readClipboard(size_t* size) { + RGFW_UNUSED(size); + + /* TODO wayland */ + + return NULL; + } +#endif /* RGFW_WAYLAND */ + +/* + End of Wayland defines +*/ + + +/* + + Start of Windows defines + + +*/ + #ifdef RGFW_WINDOWS + #define WIN32_LEAN_AND_MEAN + #define OEMRESOURCE + #include + + __declspec(dllimport) int __stdcall WideCharToMultiByte( UINT CodePage, DWORD dwFlags, const WCHAR* lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar); + + #include + #include + #include + #include + #include + #include + + #ifndef RGFW_NO_XINPUT + typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*); + PFN_XInputGetState XInputGetStateSRC = NULL; + #define XInputGetState XInputGetStateSRC + + typedef DWORD (WINAPI * PFN_XInputGetKeystroke)(DWORD, DWORD, PXINPUT_KEYSTROKE); + PFN_XInputGetKeystroke XInputGetKeystrokeSRC = NULL; + #define XInputGetKeystroke XInputGetKeystrokeSRC + + static HMODULE RGFW_XInput_dll = NULL; + #endif + + u32 RGFW_mouseIconSrc[] = {OCR_NORMAL, OCR_NORMAL, OCR_IBEAM, OCR_CROSS, OCR_HAND, OCR_SIZEWE, OCR_SIZENS, OCR_SIZENWSE, OCR_SIZENESW, OCR_SIZEALL, OCR_NO}; + char* createUTF8FromWideStringWin32(const WCHAR* source); #define GL_FRONT 0x0404 @@ -3834,31 +5050,20 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ #define wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc - -#if defined(RGFW_DIRECTX) - RGFW_directXinfo RGFW_dxInfo; - - RGFW_directXinfo* RGFW_getDirectXInfo(void) { return &RGFW_dxInfo; } -#endif - void* RGFWjoystickApi = NULL; /* these two wgl functions need to be preloaded */ - typedef long long int (WINAPI* wglCreateContextAttribsARB_type)(HDC hdc, HGLRC hShareContext, - const int* attribList); - wglCreateContextAttribsARB_type wglCreateContextAttribsARB = NULL; + typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hglrc, const int *attribList); + PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; /* defines for creating ARB attributes */ #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define WGL_TRANSPARENT_ARB 0x200A #define WGL_DRAW_TO_WINDOW_ARB 0x2001 #define WGL_ACCELERATION_ARB 0x2003 #define WGL_NO_ACCELERATION_ARB 0x2025 -#define WGL_SUPPORT_OPENGL_ARB 0x2010 #define WGL_DOUBLE_BUFFER_ARB 0x2011 -#define WGL_PIXEL_TYPE_ARB 0x2013 #define WGL_COLOR_BITS_ARB 0x2014 #define WGL_RED_BITS_ARB 0x2015 #define WGL_RED_SHIFT_ARB 0x2016 @@ -3879,7 +5084,6 @@ RGFW_UNUSED(win); /* if buffer rendering is not being used */ #define WGL_DEPTH_BITS_ARB 0x2022 #define WGL_STENCIL_BITS_ARB 0x2023 #define WGL_FULL_ACCELERATION_ARB 0x2027 -#define WGL_TYPE_RGBA_ARB 0x202B #define WGL_CONTEXT_FLAGS_ARB 0x2094 #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 @@ -3924,7 +5128,7 @@ static HMODULE wglinstance = NULL; return (void*) GetProcAddress(wglinstance, procname); } - typedef u64 (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats); + typedef HRESULT (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats); static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL; #endif @@ -3949,11 +5153,14 @@ static HMODULE wglinstance = NULL; #ifndef RGFW_NO_DPI static HMODULE RGFW_Shcore_dll = NULL; - typedef u64 (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*); + typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*); PFN_GetDpiForMonitor GetDpiForMonitorSRC = NULL; #define GetDpiForMonitor GetDpiForMonitorSRC #endif + __declspec(dllimport) u32 __stdcall timeBeginPeriod(u32 uPeriod); + + #ifndef RGFW_NO_XINPUT void RGFW_loadXInput(void) { u32 i; static const char* names[] = { @@ -3968,22 +5175,85 @@ static HMODULE wglinstance = NULL; RGFW_XInput_dll = LoadLibraryA(names[i]); if (RGFW_XInput_dll) { - XInputGetStateSRC = (PFN_XInputGetState)GetProcAddress(RGFW_XInput_dll, "XInputGetState"); + XInputGetStateSRC = (PFN_XInputGetState)(void*)GetProcAddress(RGFW_XInput_dll, "XInputGetState"); if (XInputGetStateSRC == NULL) printf("Failed to load XInputGetState"); } } } + #endif + + RGFWDEF void RGFW_init_buffer(RGFW_window* win); + void RGFW_init_buffer(RGFW_window* win) { +#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0) + RGFW_bufferSize = RGFW_getScreenSize(); + + BITMAPV5HEADER bi = { 0 }; + ZeroMemory(&bi, sizeof(bi)); + bi.bV5Size = sizeof(bi); + bi.bV5Width = RGFW_bufferSize.w; + bi.bV5Height = -((LONG) RGFW_bufferSize.h); + bi.bV5Planes = 1; + bi.bV5BitCount = 32; + bi.bV5Compression = BI_BITFIELDS; + bi.bV5BlueMask = 0x00ff0000; + bi.bV5GreenMask = 0x0000ff00; + bi.bV5RedMask = 0x000000ff; + bi.bV5AlphaMask = 0xff000000; + + win->src.bitmap = CreateDIBSection(win->src.hdc, + (BITMAPINFO*) &bi, + DIB_RGB_COLORS, + (void**) &win->buffer, + NULL, + (DWORD) 0); + + win->src.hdcMem = CreateCompatibleDC(win->src.hdc); + + #if defined(RGFW_OSMESA) + win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); + OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h); + #endif +#else +RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ +#endif + } + + void RGFW_window_setDND(RGFW_window* win, b8 allow) { + DragAcceptFiles(win->src.window, allow); + } + + void RGFW_releaseCursor(RGFW_window* win) { + ClipCursor(NULL); + const RAWINPUTDEVICE id = { 0x01, 0x02, RIDEV_REMOVE, NULL }; + RegisterRawInputDevices(&id, 1, sizeof(id)); + } + + void RGFW_captureCursor(RGFW_window* win, RGFW_rect rect) { + RGFW_UNUSED(win) + + RECT clipRect; + GetClientRect(win->src.window, &clipRect); + ClientToScreen(win->src.window, (POINT*) &clipRect.left); + ClientToScreen(win->src.window, (POINT*) &clipRect.right); + ClipCursor(&clipRect); + + const RAWINPUTDEVICE id = { 0x01, 0x02, 0, win->src.window }; + RegisterRawInputDevices(&id, 1, sizeof(id)); + } RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) { + #ifndef RGFW_NO_XINPUT if (RGFW_XInput_dll == NULL) RGFW_loadXInput(); - + #endif + #ifndef RGFW_NO_DPI if (RGFW_Shcore_dll == NULL) { RGFW_Shcore_dll = LoadLibraryA("shcore.dll"); - GetDpiForMonitorSRC = (PFN_GetDpiForMonitor)GetProcAddress(RGFW_Shcore_dll, "GetDpiForMonitor"); + GetDpiForMonitorSRC = (PFN_GetDpiForMonitor)(void*)GetProcAddress(RGFW_Shcore_dll, "GetDpiForMonitor"); } #endif @@ -3998,7 +5268,7 @@ static HMODULE wglinstance = NULL; wglGetCurrentContextSRC = (PFN_wglGetCurrentContext) GetProcAddress(wglinstance, "wglGetCurrentContext"); #endif } - + if (name[0] == 0) name = (char*) " "; RGFW_eventWindow.r = RGFW_RECT(-1, -1, -1, -1); @@ -4006,13 +5276,18 @@ static HMODULE wglinstance = NULL; RGFW_window* win = RGFW_window_basic_init(rect, args); - if (RGFW_root == NULL) { - RGFW_root = win; - } - + win->src.maxSize = RGFW_AREA(0, 0); + win->src.minSize = RGFW_AREA(0, 0); + + HINSTANCE inh = GetModuleHandleA(NULL); - WNDCLASSA Class = { 0 }; /* Setup the Window class. */ + #ifndef __cplusplus + WNDCLASSA Class = { 0 }; /*!< Setup the Window class. */ + #else + WNDCLASSA Class = { }; + #endif + Class.lpszClassName = name; Class.hInstance = inh; Class.hCursor = LoadCursor(NULL, IDC_ARROW); @@ -4025,7 +5300,7 @@ static HMODULE wglinstance = NULL; RECT windowRect, clientRect; if (!(args & RGFW_NO_BORDER)) { - window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_VISIBLE | WS_MINIMIZEBOX; + window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX; if (!(args & RGFW_NO_RESIZE)) window_style |= WS_SIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME; @@ -4040,15 +5315,13 @@ static HMODULE wglinstance = NULL; win->src.hOffset = (windowRect.bottom - windowRect.top) - (clientRect.bottom - clientRect.top); win->src.window = CreateWindowA(Class.lpszClassName, name, window_style, win->r.x, win->r.y, win->r.w, win->r.h + win->src.hOffset, 0, 0, inh, 0); - if (args & RGFW_TRANSPARENT_WINDOW) { - SetWindowLongA(win->src.window, GWL_EXSTYLE, GetWindowLongA(win->src.window, GWL_EXSTYLE) | WS_EX_LAYERED); - } if (args & RGFW_ALLOW_DND) { - win->src.winArgs |= RGFW_ALLOW_DND; - DragAcceptFiles(win->src.window, TRUE); + win->_winArgs |= RGFW_ALLOW_DND; + RGFW_window_setDND(win, 1); } win->src.hdc = GetDC(win->src.window); + if ((args & RGFW_NO_INIT_API) == 0) { #ifdef RGFW_DIRECTX assert(FAILED(CreateDXGIFactory(&__uuidof(IDXGIFactory), (void**) &RGFW_dxInfo.pFactory)) == 0); @@ -4112,17 +5385,26 @@ static HMODULE wglinstance = NULL; #ifdef RGFW_OPENGL HDC dummy_dc = GetDC(dummyWin); - - PIXELFORMATDESCRIPTOR pfd = { - .nSize = sizeof(pfd), - .nVersion = 1, - .iPixelType = PFD_TYPE_RGBA, - .dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, - .cColorBits = 32, - .cAlphaBits = 8, - .iLayerType = PFD_MAIN_PLANE, - .cDepthBits = 24, - .cStencilBits = 8, + + u32 pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; + + //if (RGFW_DOUBLE_BUFFER) + pfd_flags |= PFD_DOUBLEBUFFER; + + PIXELFORMATDESCRIPTOR pfd = { + sizeof(pfd), + 1, /* version */ + pfd_flags, + PFD_TYPE_RGBA, /* ipixel type */ + 24, /* color bits */ + 0, 0, 0, 0, 0, 0, + 8, /* alpha bits */ + 0, 0, 0, 0, 0, 0, + 32, /* depth bits */ + 8, /* stencil bits */ + 0, + PFD_MAIN_PLANE, /* Layer type */ + 0, 0, 0, 0 }; int pixel_format = ChoosePixelFormat(dummy_dc, &pfd); @@ -4132,48 +5414,48 @@ static HMODULE wglinstance = NULL; wglMakeCurrent(dummy_dc, dummy_context); if (wglChoosePixelFormatARB == NULL) { - wglCreateContextAttribsARB = (wglCreateContextAttribsARB_type) wglGetProcAddress("wglCreateContextAttribsARB"); - wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC) wglGetProcAddress("wglChoosePixelFormatARB"); + wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) (void*) wglGetProcAddress("wglCreateContextAttribsARB"); + wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC) (void*)wglGetProcAddress("wglChoosePixelFormatARB"); } wglMakeCurrent(dummy_dc, 0); wglDeleteContext(dummy_context); ReleaseDC(dummyWin, dummy_dc); - + + /* try to create the pixel format we want for opengl and then try to create an opengl context for the specified version */ if (wglCreateContextAttribsARB != NULL) { - PIXELFORMATDESCRIPTOR pfd = (PIXELFORMATDESCRIPTOR){ sizeof(pfd), 1, PFD_TYPE_RGBA, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, 32, 8, PFD_MAIN_PLANE, 24, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd), 1, pfd_flags, PFD_TYPE_RGBA, 32, 8, PFD_MAIN_PLANE, 24, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; if (args & RGFW_OPENGL_SOFTWARE) pfd.dwFlags |= PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED; if (wglChoosePixelFormatARB != NULL) { - i32* pixel_format_attribs = (i32*)RGFW_initAttribs(args & RGFW_OPENGL_SOFTWARE); + i32* pixel_format_attribs = (i32*)RGFW_initFormatAttribs(args & RGFW_OPENGL_SOFTWARE); int pixel_format; UINT num_formats; wglChoosePixelFormatARB(win->src.hdc, pixel_format_attribs, 0, 1, &pixel_format, &num_formats); if (!num_formats) { - printf("Failed to set the OpenGL 3.3 pixel format.\n"); + printf("Failed to create a pixel format for WGL.\n"); } DescribePixelFormat(win->src.hdc, pixel_format, sizeof(pfd), &pfd); if (!SetPixelFormat(win->src.hdc, pixel_format, &pfd)) { - printf("Failed to set the OpenGL 3.3 pixel format.\n"); + printf("Failed to set the WGL pixel format.\n"); } } - + + /* create opengl/WGL context for the specified version */ u32 index = 0; i32 attribs[40]; - SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB); - - if (RGFW_majorVersion || RGFW_minorVersion) { - SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, RGFW_majorVersion); - SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, RGFW_minorVersion); + if (RGFW_profile == RGFW_GL_CORE) { + SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB); } - - SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB); - + else { + SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB); + } + if (RGFW_majorVersion || RGFW_minorVersion) { SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, RGFW_majorVersion); SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, RGFW_minorVersion); @@ -4181,19 +5463,19 @@ static HMODULE wglinstance = NULL; SET_ATTRIB(0, 0); - win->src.rSurf = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs); - } else { + win->src.ctx = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs); + } else { /* fall back to a default context (probably opengl 2 or something) */ fprintf(stderr, "Failed to create an accelerated OpenGL Context\n"); int pixel_format = ChoosePixelFormat(win->src.hdc, &pfd); SetPixelFormat(win->src.hdc, pixel_format, &pfd); - win->src.rSurf = wglCreateContext(win->src.hdc); + win->src.ctx = wglCreateContext(win->src.hdc); } - wglMakeCurrent(win->src.hdc, win->src.rSurf); - wglShareLists(RGFW_root->src.rSurf, win->src.rSurf); + wglMakeCurrent(win->src.hdc, win->src.ctx); #endif + } #ifdef RGFW_OSMESA #ifdef RGFW_LINK_OSM ESA @@ -4204,43 +5486,85 @@ static HMODULE wglinstance = NULL; #endif #ifdef RGFW_OPENGL - ReleaseDC(win->src.window, win->src.hdc); - win->src.hdc = GetDC(win->src.window); - wglMakeCurrent(win->src.hdc, win->src.rSurf); + if ((args & RGFW_NO_INIT_API) == 0) { + ReleaseDC(win->src.window, win->src.hdc); + win->src.hdc = GetDC(win->src.window); + wglMakeCurrent(win->src.hdc, win->src.ctx); + } #endif DestroyWindow(dummyWin); RGFW_init_buffer(win); -#ifdef RGFW_VULKAN - RGFW_initVulkan(win); -#endif + #ifndef RGFW_NO_MONITOR if (args & RGFW_SCALE_TO_MONITOR) RGFW_window_scaleToMonitor(win); + #endif #ifdef RGFW_EGL - RGFW_createOpenGLContext(win); + if ((args & RGFW_NO_INIT_API) == 0) + RGFW_createOpenGLContext(win); #endif if (args & RGFW_HIDE_MOUSE) RGFW_window_showMouse(win, 0); + if (args & RGFW_TRANSPARENT_WINDOW) { + SetWindowLong(win->src.window, GWL_EXSTYLE, GetWindowLong(win->src.window, GWL_EXSTYLE) | WS_EX_LAYERED); + SetLayeredWindowAttributes(win->src.window, RGB(255, 255, 255), RGFW_ALPHA, LWA_ALPHA); + } + ShowWindow(win->src.window, SW_SHOWNORMAL); + + if (RGFW_root == NULL) + RGFW_root = win; + + #ifdef RGFW_OPENGL + else + wglShareLists(RGFW_root->src.ctx, win->src.ctx); + #endif return win; } + void RGFW_window_setBorder(RGFW_window* win, u8 border) { + DWORD style = GetWindowLong(win->src.window, GWL_STYLE); + + if (border == 0) { + SetWindowLong(win->src.window, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW); + SetWindowPos( + win->src.window, HWND_TOP, 0, 0, 0, 0, + SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE + ); + } + else { + SetWindowLong(win->src.window, GWL_STYLE, style | WS_OVERLAPPEDWINDOW); + SetWindowPos( + win->src.window, HWND_TOP, 0, 0, 0, 0, + SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE + ); + } + } + RGFW_area RGFW_getScreenSize(void) { return RGFW_AREA(GetDeviceCaps(GetDC(NULL), HORZRES), GetDeviceCaps(GetDC(NULL), VERTRES)); } - RGFW_vector RGFW_getGlobalMousePoint(void) { + RGFW_point RGFW_getGlobalMousePoint(void) { POINT p; GetCursorPos(&p); - return RGFW_VECTOR(p.x, p.y); + return RGFW_POINT(p.x, p.y); + } + + RGFW_point RGFW_window_getMousePoint(RGFW_window* win) { + POINT p; + GetCursorPos(&p); + ScreenToClient(win->src.window, &p); + + return RGFW_POINT(p.x, p.y); } void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { @@ -4266,98 +5590,57 @@ static HMODULE wglinstance = NULL; ShowWindow(win->src.window, SW_RESTORE); } - static i32 RGFW_checkXInput(RGFW_Event* e) { - static WORD buttons[4]; - static BYTE triggers[4][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} }; + u8 RGFW_xinput2RGFW[] = { + RGFW_JS_A, /* or PS X button */ + RGFW_JS_B, /* or PS circle button */ + RGFW_JS_X, /* or PS square button */ + RGFW_JS_Y, /* or PS triangle button */ + RGFW_JS_R1, /* right bumper */ + RGFW_JS_L1, /* left bump */ + RGFW_JS_L2, /* left trigger*/ + RGFW_JS_R2, /* right trigger */ + 0, 0, 0, 0, 0, 0, 0, 0, + RGFW_JS_UP, /* dpad up */ + RGFW_JS_DOWN, /* dpad down*/ + RGFW_JS_LEFT, /* dpad left */ + RGFW_JS_RIGHT, /* dpad right */ + RGFW_JS_START, /* start button */ + RGFW_JS_SELECT/* select button */ + }; + + static i32 RGFW_checkXInput(RGFW_window* win, RGFW_Event* e) { + RGFW_UNUSED(win) + size_t i; for (i = 0; i < 4; i++) { + XINPUT_KEYSTROKE keystroke; + + if (XInputGetKeystroke == NULL) + return 0; + + DWORD result = XInputGetKeystroke((DWORD)i, 0, &keystroke); + + if ((keystroke.Flags & XINPUT_KEYSTROKE_REPEAT) == 0 && result != ERROR_EMPTY) { + if (result != ERROR_SUCCESS) + return 0; + + if (keystroke.VirtualKey > VK_PAD_BACK) + continue; + + // RGFW_jsButtonPressed + 1 = RGFW_jsButtonReleased + e->type = RGFW_jsButtonPressed + !(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN); + e->button = RGFW_xinput2RGFW[keystroke.VirtualKey - 0x5800]; + RGFW_jsPressed[i][e->button] = !(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN); + + return 1; + } + XINPUT_STATE state; if (XInputGetState == NULL || XInputGetState((DWORD) i, &state) == ERROR_DEVICE_NOT_CONNECTED ) return 0; - - e->button = 0; - if (state.Gamepad.wButtons & XINPUT_GAMEPAD_A && !(buttons[i] & XINPUT_GAMEPAD_A)) { - e->button = RGFW_JS_A; - e->type = RGFW_jsButtonPressed; - buttons[i] = state.Gamepad.wButtons; - return 1; - } else if (state.Gamepad.wButtons & XINPUT_GAMEPAD_B && !(buttons[i] & XINPUT_GAMEPAD_B)) - e->button = RGFW_JS_B; - else if (state.Gamepad.wButtons & XINPUT_GAMEPAD_Y && !(buttons[i] & XINPUT_GAMEPAD_Y)) - e->button = RGFW_JS_Y; - else if (state.Gamepad.wButtons & XINPUT_GAMEPAD_X && !(buttons[i] & XINPUT_GAMEPAD_X)) - e->button = RGFW_JS_X; - else if (state.Gamepad.wButtons & XINPUT_GAMEPAD_START && !(buttons[i] & XINPUT_GAMEPAD_START)) - e->button = RGFW_JS_START; - else if (state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK && !(buttons[i] & XINPUT_GAMEPAD_BACK)) - e->button = RGFW_JS_SELECT; - else if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP && !(buttons[i] & XINPUT_GAMEPAD_DPAD_UP)) - e->button = RGFW_JS_UP; - else if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN && !(buttons[i] & XINPUT_GAMEPAD_DPAD_DOWN)) - e->button = RGFW_JS_DOWN; - else if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT && !(buttons[i] & XINPUT_GAMEPAD_DPAD_LEFT)) - e->button = RGFW_JS_LEFT; - else if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT && !(buttons[i] & XINPUT_GAMEPAD_DPAD_RIGHT)) - e->button = RGFW_JS_RIGHT; - else if (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER && !(buttons[i] & XINPUT_GAMEPAD_LEFT_SHOULDER)) - e->button = RGFW_JS_L1; - else if (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER && !(buttons[i] & XINPUT_GAMEPAD_RIGHT_SHOULDER)) - e->button = RGFW_JS_R1; - else if (state.Gamepad.bLeftTrigger && triggers[i][0] == 0) - e->button = RGFW_JS_L2; - else if (state.Gamepad.bRightTrigger && triggers[i][1] == 0) - e->button = RGFW_JS_R2; - - triggers[i][0] = state.Gamepad.bLeftTrigger; - triggers[i][1] = state.Gamepad.bRightTrigger; - - if (e->button) { - buttons[i] = state.Gamepad.wButtons; - e->type = RGFW_jsButtonPressed; - return 1; - } - - if (!(state.Gamepad.wButtons & XINPUT_GAMEPAD_A) && (buttons[i] & XINPUT_GAMEPAD_A)) { - e->button = RGFW_JS_A; - e->type = RGFW_jsButtonReleased; - buttons[i] = state.Gamepad.wButtons; - return 1; - } else if (!(state.Gamepad.wButtons & XINPUT_GAMEPAD_B) && (buttons[i] & XINPUT_GAMEPAD_B)) - e->button = RGFW_JS_B; - else if (!(state.Gamepad.wButtons & XINPUT_GAMEPAD_Y) && (buttons[i] & XINPUT_GAMEPAD_Y)) - e->button = RGFW_JS_Y; - else if (!(state.Gamepad.wButtons & XINPUT_GAMEPAD_X) && (buttons[i] & XINPUT_GAMEPAD_X)) - e->button = RGFW_JS_X; - else if (!(state.Gamepad.wButtons & XINPUT_GAMEPAD_START) && (buttons[i] & XINPUT_GAMEPAD_START)) - e->button = RGFW_JS_START; - else if (!(state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) && (buttons[i] & XINPUT_GAMEPAD_BACK)) - e->button = RGFW_JS_SELECT; - else if (!(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) && (buttons[i] & XINPUT_GAMEPAD_DPAD_UP)) - e->button = RGFW_JS_UP; - else if (!(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) && (buttons[i] & XINPUT_GAMEPAD_DPAD_DOWN)) - e->button = RGFW_JS_DOWN; - else if (!(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) && (buttons[i] & XINPUT_GAMEPAD_DPAD_LEFT)) - e->button = RGFW_JS_LEFT; - else if (!(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) && (buttons[i] & XINPUT_GAMEPAD_DPAD_RIGHT)) - e->button = RGFW_JS_RIGHT; - else if (!(state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) && (buttons[i] & XINPUT_GAMEPAD_LEFT_SHOULDER)) - e->button = RGFW_JS_L1; - else if (!(state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) && (buttons[i] & XINPUT_GAMEPAD_RIGHT_SHOULDER)) - e->button = RGFW_JS_R1; - else if (state.Gamepad.bLeftTrigger == 0 && triggers[i][0] != 0) - e->button = RGFW_JS_L2; - else if (state.Gamepad.bRightTrigger == 0 && triggers[i][1] != 0) - e->button = RGFW_JS_R2; - - buttons[i] = state.Gamepad.wButtons; - - if (e->button) { - e->type = RGFW_jsButtonReleased; - return 1; - } #define INPUT_DEADZONE ( 0.24f * (float)(0x7FFF) ) // Default to 24% of the +/- 32767 range. This is a reasonable default value but can be altered if needed. if ((state.Gamepad.sThumbLX < INPUT_DEADZONE && @@ -4379,8 +5662,8 @@ static HMODULE wglinstance = NULL; } e->axisesCount = 2; - RGFW_vector axis1 = RGFW_VECTOR(state.Gamepad.sThumbLX, state.Gamepad.sThumbLY); - RGFW_vector axis2 = RGFW_VECTOR(state.Gamepad.sThumbRX, state.Gamepad.sThumbRY); + RGFW_point axis1 = RGFW_POINT(state.Gamepad.sThumbLX, state.Gamepad.sThumbLY); + RGFW_point axis2 = RGFW_POINT(state.Gamepad.sThumbRX, state.Gamepad.sThumbRY); if (axis1.x != e->axis[0].x || axis1.y != e->axis[0].y || axis2.x != e->axis[1].x || axis2.y != e->axis[1].y) { e->type = RGFW_jsAxisMove; @@ -4398,103 +5681,236 @@ static HMODULE wglinstance = NULL; return 0; } - BYTE RGFW_keyBoard[256]; - BYTE RGFW_keyBoard_prev[256]; + void RGFW_stopCheckEvents(void) { + PostMessageW(RGFW_root->src.window, WM_NULL, 0, 0); + } + + void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { + RGFW_UNUSED(win); + + MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (waitMS * 1e3), QS_ALLINPUT); + } RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) { assert(win != NULL); + if (win->event.type == RGFW_quit) { + return NULL; + } + MSG msg; if (RGFW_eventWindow.src.window == win->src.window) { if (RGFW_eventWindow.r.x != -1) { win->r.x = RGFW_eventWindow.r.x; win->r.y = RGFW_eventWindow.r.y; + win->event.type = RGFW_windowMoved; + RGFW_windowMoveCallback(win, win->r); } if (RGFW_eventWindow.r.w != -1) { win->r.w = RGFW_eventWindow.r.w; win->r.h = RGFW_eventWindow.r.h; + win->event.type = RGFW_windowResized; + RGFW_windowResizeCallback(win, win->r); } - win->event.type = RGFW_windowAttribsChange; - RGFW_eventWindow.src.window = NULL; RGFW_eventWindow.r = RGFW_RECT(-1, -1, -1, -1); return &win->event; } + + static HDROP drop; + + if (win->event.type == RGFW_dnd_init) { + if (win->event.droppedFilesCount) { + u32 i; + for (i = 0; i < win->event.droppedFilesCount; i++) + win->event.droppedFiles[i][0] = '\0'; + } + + win->event.droppedFilesCount = 0; + win->event.droppedFilesCount = DragQueryFileW(drop, 0xffffffff, NULL, 0); + //win->event.droppedFiles = (char**)RGFW_CALLOC(win->event.droppedFilesCount, sizeof(char*)); + + u32 i; + for (i = 0; i < win->event.droppedFilesCount; i++) { + const UINT length = DragQueryFileW(drop, i, NULL, 0); + WCHAR* buffer = (WCHAR*) RGFW_CALLOC((size_t) length + 1, sizeof(WCHAR)); + + DragQueryFileW(drop, i, buffer, length + 1); + strncpy(win->event.droppedFiles[i], createUTF8FromWideStringWin32(buffer), RGFW_MAX_PATH); + win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0'; + RGFW_FREE(buffer); + } + + DragFinish(drop); + RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount); + + win->event.type = RGFW_dnd; + return &win->event; + } + win->event.inFocus = (GetForegroundWindow() == win->src.window); - if (RGFW_checkXInput(&win->event)) + if (RGFW_checkXInput(win, &win->event)) return &win->event; - if (win->event.type == RGFW_quit) - return NULL; - static BYTE keyboardState[256]; if (PeekMessageA(&msg, win->src.window, 0u, 0u, PM_REMOVE)) { switch (msg.message) { case WM_CLOSE: case WM_QUIT: + RGFW_windowQuitCallback(win); win->event.type = RGFW_quit; break; - case WM_KEYUP: - win->event.keyCode = (u32) msg.wParam; - if (RGFW_isPressedI(win, win->event.keyCode)) - RGFW_keyBoard_prev[win->event.keyCode] |= 0x80; - else - RGFW_keyBoard_prev[win->event.keyCode] = 0; + case WM_ACTIVATE: + win->event.inFocus = (LOWORD(msg.wParam) == WA_INACTIVE); - strncpy(win->event.keyName, RGFW_keyCodeTokeyStr(msg.lParam), 16); - if (RGFW_isPressedI(win, VK_SHIFT)) { + if (win->event.inFocus) { + win->event.type = RGFW_focusIn; + RGFW_focusCallback(win, 1); + } + else { + win->event.type = RGFW_focusOut; + RGFW_focusCallback(win, 0); + } + + break; + + case WM_PAINT: + win->event.type = RGFW_windowRefresh; + RGFW_windowRefreshCallback(win); + break; + + case WM_MOUSELEAVE: + win->event.type = RGFW_mouseLeave; + win->_winArgs |= RGFW_MOUSE_LEFT; + RGFW_mouseNotifyCallBack(win, win->event.point, 0); + break; + + case WM_KEYUP: { + win->event.keyCode = RGFW_apiKeyCodeToRGFW((u32) msg.wParam); + + RGFW_keyboard[win->event.keyCode].prev = RGFW_isPressed(win, win->event.keyCode); + + static char keyName[16]; + + { + GetKeyNameTextA((LONG) msg.lParam, keyName, 16); + + if ((!(GetKeyState(VK_CAPITAL) & 0x0001) && !(GetKeyState(VK_SHIFT) & 0x8000)) || + ((GetKeyState(VK_CAPITAL) & 0x0001) && (GetKeyState(VK_SHIFT) & 0x8000))) { + CharLowerBuffA(keyName, 16); + } + } + + RGFW_updateLockState(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001)); + + strncpy(win->event.keyName, keyName, 16); + + if (RGFW_isPressed(win, RGFW_ShiftL)) { ToAscii((UINT) msg.wParam, MapVirtualKey((UINT) msg.wParam, MAPVK_VK_TO_CHAR), keyboardState, (LPWORD) win->event.keyName, 0); } win->event.type = RGFW_keyReleased; - GetKeyboardState(RGFW_keyBoard); + RGFW_keyboard[win->event.keyCode].current = 0; + RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 0); break; + } + case WM_KEYDOWN: { + win->event.keyCode = RGFW_apiKeyCodeToRGFW((u32) msg.wParam); - case WM_KEYDOWN: - win->event.keyCode = (u32) msg.wParam; + RGFW_keyboard[win->event.keyCode].prev = RGFW_isPressed(win, win->event.keyCode); - if (RGFW_isPressedI(win, win->event.keyCode)) - RGFW_keyBoard_prev[win->event.keyCode] |= 0x80; - else - RGFW_keyBoard_prev[win->event.keyCode] = 0; + static char keyName[16]; + + { + GetKeyNameTextA((LONG) msg.lParam, keyName, 16); - strncpy(win->event.keyName, RGFW_keyCodeTokeyStr(msg.lParam), 16); - if (RGFW_isPressedI(win, VK_SHIFT) & 0x8000) { + if ((!(GetKeyState(VK_CAPITAL) & 0x0001) && !(GetKeyState(VK_SHIFT) & 0x8000)) || + ((GetKeyState(VK_CAPITAL) & 0x0001) && (GetKeyState(VK_SHIFT) & 0x8000))) { + CharLowerBuffA(keyName, 16); + } + } + + RGFW_updateLockState(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001)); + + strncpy(win->event.keyName, keyName, 16); + + if (RGFW_isPressed(win, RGFW_ShiftL) & 0x8000) { ToAscii((UINT) msg.wParam, MapVirtualKey((UINT) msg.wParam, MAPVK_VK_TO_CHAR), keyboardState, (LPWORD) win->event.keyName, 0); } win->event.type = RGFW_keyPressed; - GetKeyboardState(RGFW_keyBoard); + win->event.repeat = RGFW_isPressed(win, win->event.keyCode); + RGFW_keyboard[win->event.keyCode].current = 1; + RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 1); break; + } case WM_MOUSEMOVE: - win->event.point.x = GET_X_LPARAM(msg.lParam); - win->event.point.y = GET_Y_LPARAM(msg.lParam); + if ((win->_winArgs & RGFW_HOLD_MOUSE)) + break; win->event.type = RGFW_mousePosChanged; + + win->event.point.x = GET_X_LPARAM(msg.lParam); + win->event.point.y = GET_Y_LPARAM(msg.lParam); + + RGFW_mousePosCallback(win, win->event.point); + + if (win->_winArgs & RGFW_MOUSE_LEFT) { + win->_winArgs ^= RGFW_MOUSE_LEFT; + win->event.type = RGFW_mouseEnter; + RGFW_mouseNotifyCallBack(win, win->event.point, 1); + } + break; + case WM_INPUT: { + if (!(win->_winArgs & RGFW_HOLD_MOUSE)) + break; + + unsigned size = sizeof(RAWINPUT); + static RAWINPUT raw[sizeof(RAWINPUT)]; + GetRawInputData((HRAWINPUT)msg.lParam, RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER)); + + if (raw->header.dwType != RIM_TYPEMOUSE || (raw->data.mouse.lLastX == 0 && raw->data.mouse.lLastY == 0) ) + break; + + win->event.type = RGFW_mousePosChanged; + win->event.point.x = raw->data.mouse.lLastX; + win->event.point.y = raw->data.mouse.lLastY; + break; + } + case WM_LBUTTONDOWN: win->event.button = RGFW_mouseLeft; + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 1; win->event.type = RGFW_mouseButtonPressed; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); break; case WM_RBUTTONDOWN: win->event.button = RGFW_mouseRight; win->event.type = RGFW_mouseButtonPressed; + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 1; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); break; case WM_MBUTTONDOWN: win->event.button = RGFW_mouseMiddle; win->event.type = RGFW_mouseButtonPressed; + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 1; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); break; case WM_MOUSEWHEEL: @@ -4503,45 +5919,49 @@ static HMODULE wglinstance = NULL; else win->event.button = RGFW_mouseScrollDown; + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 1; + win->event.scroll = (SHORT) HIWORD(msg.wParam) / (double) WHEEL_DELTA; win->event.type = RGFW_mouseButtonPressed; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); break; case WM_LBUTTONUP: + win->event.button = RGFW_mouseLeft; win->event.type = RGFW_mouseButtonReleased; + + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 0; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); break; case WM_RBUTTONUP: win->event.button = RGFW_mouseRight; win->event.type = RGFW_mouseButtonReleased; + + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 0; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); break; case WM_MBUTTONUP: win->event.button = RGFW_mouseMiddle; win->event.type = RGFW_mouseButtonReleased; + + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 0; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); break; /* much of this event is source from glfw */ - case WM_DROPFILES: { + case WM_DROPFILES: { + win->event.type = RGFW_dnd_init; - if (win->event.droppedFilesCount) { - u32 i; - for (i = 0; i < win->event.droppedFilesCount; i++) - win->event.droppedFiles[i][0] = '\0'; - } - - win->event.droppedFilesCount = 0; - - win->event.type = RGFW_dnd; - - HDROP drop = (HDROP) msg.wParam; + drop = (HDROP) msg.wParam; POINT pt; - u32 i; - - win->event.droppedFilesCount = DragQueryFileW(drop, 0xffffffff, NULL, 0); - //win->event.droppedFiles = (char**)RGFW_CALLOC(win->event.droppedFilesCount, sizeof(char*)); /* Move the mouse to the position of the drop */ DragQueryPoint(drop, &pt); @@ -4549,19 +5969,9 @@ static HMODULE wglinstance = NULL; win->event.point.x = pt.x; win->event.point.y = pt.y; - for (i = 0; i < win->event.droppedFilesCount; i++) { - const UINT length = DragQueryFileW(drop, i, NULL, 0); - WCHAR* buffer = (WCHAR*) RGFW_CALLOC((size_t) length + 1, sizeof(WCHAR)); - - DragQueryFileW(drop, i, buffer, length + 1); - strcpy(win->event.droppedFiles[i], createUTF8FromWideStringWin32(buffer)); - - RGFW_FREE(buffer); - } - - DragFinish(drop); + RGFW_dndInitCallback(win, win->event.point); } - break; + break; case WM_GETMINMAXINFO: { if (win->src.maxSize.w == 0 && win->src.maxSize.h == 0) @@ -4586,24 +5996,10 @@ static HMODULE wglinstance = NULL; else win->event.type = 0; - RGFW_vector mouse = RGFW_getGlobalMousePoint(); - if (win->src.winArgs & RGFW_HOLD_MOUSE && win->event.inFocus && - (mouse.x != win->r.x + (win->r.w / 2) || mouse.y != win->r.y + (win->r.h / 2))) { - RGFW_window_moveMouse(win, RGFW_VECTOR(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2))); - } - - win->event.lockState = 0; - - if ((GetKeyState(VK_CAPITAL) & 0x0001) != 0) - win->event.lockState |= RGFW_CAPSLOCK; - if ((GetKeyState(VK_NUMLOCK) & 0x0001) != 0) - win->event.lockState |= RGFW_NUMLOCK; - if ((GetKeyState(VK_SCROLL) & 0x0001) != 0) - win->event.lockState |= 3; - - - if (!IsWindow(win->src.window)) + if (!IsWindow(win->src.window)) { win->event.type = RGFW_quit; + RGFW_windowQuitCallback(win); + } if (win->event.type) return &win->event; @@ -4614,7 +6010,11 @@ static HMODULE wglinstance = NULL; u8 RGFW_window_isFullscreen(RGFW_window* win) { assert(win != NULL); + #ifndef __cplusplus WINDOWPLACEMENT placement = { 0 }; + #else + WINDOWPLACEMENT placement = { }; + #endif GetWindowPlacement(win->src.window, &placement); return placement.showCmd == SW_SHOWMAXIMIZED; } @@ -4628,7 +6028,11 @@ static HMODULE wglinstance = NULL; u8 RGFW_window_isMinimized(RGFW_window* win) { assert(win != NULL); + #ifndef __cplusplus WINDOWPLACEMENT placement = { 0 }; + #else + WINDOWPLACEMENT placement = { }; + #endif GetWindowPlacement(win->src.window, &placement); return placement.showCmd == SW_SHOWMINIMIZED; } @@ -4636,7 +6040,11 @@ static HMODULE wglinstance = NULL; u8 RGFW_window_isMaximized(RGFW_window* win) { assert(win != NULL); + #ifndef __cplusplus WINDOWPLACEMENT placement = { 0 }; + #else + WINDOWPLACEMENT placement = { }; + #endif GetWindowPlacement(win->src.window, &placement); return placement.showCmd == SW_SHOWMAXIMIZED; } @@ -4653,7 +6061,8 @@ static HMODULE wglinstance = NULL; info->iIndex++; return TRUE; } - + + #ifndef RGFW_NO_MONITOR RGFW_monitor win32CreateMonitor(HMONITOR src) { RGFW_monitor monitor; MONITORINFO monitorInfo; @@ -4675,7 +6084,7 @@ static HMODULE wglinstance = NULL; for (deviceIndex = 0; EnumDisplayDevicesA(0, (DWORD) deviceIndex, &dd, 0); deviceIndex++) { char* deviceName = dd.DeviceName; if (EnumDisplayDevicesA(deviceName, info.iIndex, &dd, 0)) { - strcpy(monitor.name, dd.DeviceString); /* copy the monitor's name */ + strncpy(monitor.name, dd.DeviceString, 128); /*!< copy the monitor's name */ break; } } @@ -4687,6 +6096,10 @@ static HMODULE wglinstance = NULL; monitor.rect.h = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top; #ifndef RGFW_NO_DPI + #ifndef USER_DEFAULT_SCREEN_DPI + #define USER_DEFAULT_SCREEN_DPI 96 + #endif + if (GetDpiForMonitor != NULL) { u32 x, y; GetDpiForMonitor(src, MDT_ANGULAR_DPI, &x, &y); @@ -4707,7 +6120,10 @@ static HMODULE wglinstance = NULL; return monitor; } + #endif /* RGFW_NO_MONITOR */ + + #ifndef RGFW_NO_MONITOR RGFW_monitor RGFW_monitors[6]; BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { RGFW_UNUSED(hdcMonitor) @@ -4725,8 +6141,12 @@ static HMODULE wglinstance = NULL; } RGFW_monitor RGFW_getPrimaryMonitor(void) { + #ifdef __cplusplus + return win32CreateMonitor(MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY)); + #else return win32CreateMonitor(MonitorFromPoint((POINT) { 0, 0 }, MONITOR_DEFAULTTOPRIMARY)); - } + #endif + } RGFW_monitor* RGFW_getMonitors(void) { RGFW_mInfo info; @@ -4740,26 +6160,7 @@ static HMODULE wglinstance = NULL; HMONITOR src = MonitorFromWindow(win->src.window, MONITOR_DEFAULTTOPRIMARY); return win32CreateMonitor(src); } - - u8 RGFW_isPressedI(RGFW_window* win, u32 key) { - if (win != NULL && !win->event.inFocus) - return 0; - - if (RGFW_keyBoard[key] & 0x80) - return 1; - - return 0; - } - - u8 RGFW_wasPressedI(RGFW_window* win, u32 key) { - if (win != NULL && !win->event.inFocus) - return 0; - - if (RGFW_keyBoard_prev[key] & 0x80) - return 1; - - return 0; - } + #endif HICON RGFW_loadHandleImage(RGFW_window* win, u8* src, RGFW_area a, BOOL icon) { assert(win != NULL); @@ -4831,13 +6232,16 @@ static HMODULE wglinstance = NULL; } void RGFW_window_setMouseDefault(RGFW_window* win) { - RGFW_window_setMouseStandard(win, 32512); + RGFW_window_setMouseStandard(win, RGFW_MOUSE_ARROW); } - void RGFW_window_setMouseStandard(RGFW_window* win, i32 mouse) { + void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { assert(win != NULL); - char* icon = MAKEINTRESOURCEA(mouse); + if (mouse > (sizeof(RGFW_mouseIconSrc) / sizeof(u32))) + return; + + char* icon = MAKEINTRESOURCEA(RGFW_mouseIconSrc[mouse]); SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) LoadCursorA(NULL, icon)); SetCursor(LoadCursorA(NULL, icon)); @@ -4854,21 +6258,6 @@ static HMODULE wglinstance = NULL; void RGFW_window_close(RGFW_window* win) { assert(win != NULL); -#ifdef RGFW_VULKAN - for (u32 i = 0; i < win->src.image_count; i++) { - vkDestroyFramebuffer(RGFW_vulkan_info.device, RGFW_vulkan_info.framebuffers[i], NULL); - } - - for (u32 i = 0; i < win->src.image_count; i++) { - vkDestroyImageView(RGFW_vulkan_info.device, win->src.swapchain_image_views[i], NULL); - } - - vkDestroySwapchainKHR(RGFW_vulkan_info.device, win->src.swapchain, NULL); - vkDestroySurfaceKHR(RGFW_vulkan_info.instance, win->src.rSurf, NULL); - free(win->src.swapchain_image_views); - free(win->src.swapchain_images); -#endif - #ifdef RGFW_EGL RGFW_closeEGL(win); #endif @@ -4913,10 +6302,10 @@ static HMODULE wglinstance = NULL; #endif #ifdef RGFW_OPENGL - wglDeleteContext((HGLRC) win->src.rSurf); /* delete opengl context */ + wglDeleteContext((HGLRC) win->src.ctx); /*!< delete opengl context */ #endif - DeleteDC(win->src.hdc); /* delete device context */ - DestroyWindow(win->src.window); /* delete window */ + DeleteDC(win->src.hdc); /*!< delete device context */ + DestroyWindow(win->src.window); /*!< delete window */ #if defined(RGFW_OSMESA) if (win->buffer != NULL) @@ -4937,7 +6326,7 @@ static HMODULE wglinstance = NULL; RGFW_FREE(win); } - void RGFW_window_move(RGFW_window* win, RGFW_vector v) { + void RGFW_window_move(RGFW_window* win, RGFW_point v) { assert(win != NULL); win->r.x = v.x; @@ -4960,9 +6349,45 @@ static HMODULE wglinstance = NULL; SetWindowTextA(win->src.window, name); } + /* sourced from GLFW */ + #ifndef RGFW_NO_PASSTHROUGH + void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) { + assert(win != NULL); + + COLORREF key = 0; + BYTE alpha = 0; + DWORD flags = 0; + DWORD exStyle = GetWindowLongW(win->src.window, GWL_EXSTYLE); + + if (exStyle & WS_EX_LAYERED) + GetLayeredWindowAttributes(win->src.window, &key, &alpha, &flags); + + if (passthrough) + exStyle |= (WS_EX_TRANSPARENT | WS_EX_LAYERED); + else + { + exStyle &= ~WS_EX_TRANSPARENT; + // NOTE: Window opacity also needs the layered window style so do not + // remove it if the window is alpha blended + if (exStyle & WS_EX_LAYERED) + { + if (!(flags & LWA_ALPHA)) + exStyle &= ~WS_EX_LAYERED; + } + } + + SetWindowLongW(win->src.window, GWL_EXSTYLE, exStyle); + + if (passthrough) { + SetLayeredWindowAttributes(win->src.window, key, alpha, flags); + } + } + #endif + /* much of this function is sourced from GLFW */ void RGFW_window_setIcon(RGFW_window* win, u8* src, RGFW_area a, i32 channels) { assert(win != NULL); + #ifndef RGFW_WIN95 RGFW_UNUSED(channels) HICON handle = RGFW_loadHandleImage(win, src, a, TRUE); @@ -4970,6 +6395,11 @@ static HMODULE wglinstance = NULL; SetClassLongPtrA(win->src.window, GCLP_HICON, (LPARAM) handle); DestroyIcon(handle); + #else + RGFW_UNUSED(src) + RGFW_UNUSED(a) + RGFW_UNUSED(channels) + #endif } char* RGFW_readClipboard(size_t* size) { @@ -4995,12 +6425,14 @@ static HMODULE wglinstance = NULL; if (textLen == 0) return (char*) ""; - text = (char*) malloc((textLen * sizeof(char)) + 1); + text = (char*) RGFW_MALLOC((textLen * sizeof(char)) + 1); wcstombs(text, wstr, (textLen) +1); if (size != NULL) *size = textLen + 1; + + text[textLen] = '\0'; } /* Release the clipboard data */ @@ -5049,15 +6481,81 @@ static HMODULE wglinstance = NULL; assert(win != NULL); RGFW_UNUSED(file) - return win->src.joystickCount - 1; + return RGFW_joystickCount - 1; } - void RGFW_window_moveMouse(RGFW_window* win, RGFW_vector p) { + void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) { assert(win != NULL); SetCursorPos(p.x, p.y); } + #ifdef RGFW_OPENGL + void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { + if (win == NULL) + wglMakeCurrent(NULL, NULL); + else + wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx); + } + #endif + + #ifndef RGFW_EGL + void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { + assert(win != NULL); + + #if defined(RGFW_OPENGL) + typedef BOOL(APIENTRY* PFNWGLSWAPINTERVALEXTPROC)(int interval); + static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; + static void* loadSwapFunc = (void*) 1; + + if (loadSwapFunc == NULL) { + fprintf(stderr, "wglSwapIntervalEXT not supported\n"); + return; + } + + if (wglSwapIntervalEXT == NULL) { + loadSwapFunc = (void*) wglGetProcAddress("wglSwapIntervalEXT"); + wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) loadSwapFunc; + } + + if (wglSwapIntervalEXT(swapInterval) == FALSE) + fprintf(stderr, "Failed to set swap interval\n"); + #else + RGFW_UNUSED(swapInterval); + #endif + + } + #endif + + void RGFW_window_swapBuffers(RGFW_window* win) { + //assert(win != NULL); + /* clear the window*/ + + if (!(win->_winArgs & RGFW_NO_CPU_RENDER)) { +#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + #ifdef RGFW_OSMESA + RGFW_OSMesa_reorganize(); + #endif + + HGDIOBJ oldbmp = SelectObject(win->src.hdcMem, win->src.bitmap); + BitBlt(win->src.hdc, 0, 0, win->r.w, win->r.h, win->src.hdcMem, 0, 0, SRCCOPY); + SelectObject(win->src.hdcMem, oldbmp); +#endif + } + + if (!(win->_winArgs & RGFW_NO_GPU_RENDER)) { + #ifdef RGFW_EGL + eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); + #elif defined(RGFW_OPENGL) + SwapBuffers(win->src.hdc); + #endif + + #if defined(RGFW_WINDOWS) && defined(RGFW_DIRECTX) + win->src.swapchain->lpVtbl->Present(win->src.swapchain, 0, 0); + #endif + } + } + char* createUTF8FromWideStringWin32(const WCHAR* source) { char* target; i32 size; @@ -5076,6 +6574,37 @@ static HMODULE wglinstance = NULL; return target; } + + static inline LARGE_INTEGER RGFW_win32_initTimer(void) { + static LARGE_INTEGER frequency = {{0, 0}}; + if (frequency.QuadPart == 0) { + timeBeginPeriod(1); + QueryPerformanceFrequency(&frequency); + } + + return frequency; + } + + u64 RGFW_getTimeNS(void) { + LARGE_INTEGER frequency = RGFW_win32_initTimer(); + + LARGE_INTEGER counter; + QueryPerformanceCounter(&counter); + + return (u64) ((counter.QuadPart * 1e9) / frequency.QuadPart); + } + + u64 RGFW_getTime(void) { + LARGE_INTEGER frequency = RGFW_win32_initTimer(); + + LARGE_INTEGER counter; + QueryPerformanceCounter(&counter); + return (u64) (counter.QuadPart / (double) frequency.QuadPart); + } + + void RGFW_sleep(u64 ms) { + Sleep(ms); + } #ifndef RGFW_NO_THREADS RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) { return CreateThread(NULL, 0, ptr, args, 0, NULL); } @@ -5083,9 +6612,374 @@ static HMODULE wglinstance = NULL; void RGFW_joinThread(RGFW_thread thread) { WaitForSingleObject((HANDLE) thread, INFINITE); } void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { SetThreadPriority((HANDLE) thread, priority); } #endif -#endif +#endif /* RGFW_WINDOWS */ + +/* + End of Windows defines +*/ + + + +/* + + Start of MacOS defines + + +*/ #if defined(RGFW_MACOS) + /* + based on silicon.h + start of cocoa wrapper + */ + +#include +#include +#include +#include +#include + + typedef CGRect NSRect; + typedef CGPoint NSPoint; + typedef CGSize NSSize; + + typedef void NSBitmapImageRep; + typedef void NSCursor; + typedef void NSDraggingInfo; + typedef void NSWindow; + typedef void NSApplication; + typedef void NSScreen; + typedef void NSEvent; + typedef void NSString; + typedef void NSOpenGLContext; + typedef void NSPasteboard; + typedef void NSColor; + typedef void NSArray; + typedef void NSImageRep; + typedef void NSImage; + typedef void NSOpenGLView; + + + typedef const char* NSPasteboardType; + typedef unsigned long NSUInteger; + typedef long NSInteger; + typedef NSInteger NSModalResponse; + +#ifdef __arm64__ + /* ARM just uses objc_msgSend */ +#define abi_objc_msgSend_stret objc_msgSend +#define abi_objc_msgSend_fpret objc_msgSend +#else /* __i386__ */ + /* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */ +#define abi_objc_msgSend_stret objc_msgSend_stret +#define abi_objc_msgSend_fpret objc_msgSend_fpret +#endif + +#define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc")) +#define objc_msgSend_bool ((BOOL (*)(id, SEL))objc_msgSend) +#define objc_msgSend_void ((void (*)(id, SEL))objc_msgSend) +#define objc_msgSend_void_id ((void (*)(id, SEL, id))objc_msgSend) +#define objc_msgSend_uint ((NSUInteger (*)(id, SEL))objc_msgSend) +#define objc_msgSend_void_bool ((void (*)(id, SEL, BOOL))objc_msgSend) +#define objc_msgSend_bool_void ((BOOL (*)(id, SEL))objc_msgSend) +#define objc_msgSend_void_SEL ((void (*)(id, SEL, SEL))objc_msgSend) +#define objc_msgSend_id ((id (*)(id, SEL))objc_msgSend) +#define objc_msgSend_id_id ((id (*)(id, SEL, id))objc_msgSend) +#define objc_msgSend_id_bool ((BOOL (*)(id, SEL, id))objc_msgSend) +#define objc_msgSend_int ((id (*)(id, SEL, int))objc_msgSend) +#define objc_msgSend_arr ((id (*)(id, SEL, int))objc_msgSend) +#define objc_msgSend_ptr ((id (*)(id, SEL, void*))objc_msgSend) +#define objc_msgSend_class ((id (*)(Class, SEL))objc_msgSend) +#define objc_msgSend_class_char ((id (*)(Class, SEL, char*))objc_msgSend) + + NSApplication* NSApp = NULL; + + void NSRelease(id obj) { + objc_msgSend_void(obj, sel_registerName("release")); + } + + #define release NSRelease + + NSString* NSString_stringWithUTF8String(const char* str) { + return ((id(*)(id, SEL, const char*))objc_msgSend) + ((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), str); + } + + const char* NSString_to_char(NSString* str) { + return ((const char* (*)(id, SEL)) objc_msgSend) (str, sel_registerName("UTF8String")); + } + + void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function) { + Class selected_class; + + if (strcmp(class_name, "NSView") == 0) { + selected_class = objc_getClass("ViewClass"); + } else if (strcmp(class_name, "NSWindow") == 0) { + selected_class = objc_getClass("WindowClass"); + } else { + selected_class = objc_getClass(class_name); + } + + class_addMethod(selected_class, sel_registerName(register_name), (IMP) function, 0); + } + + /* Header for the array. */ + typedef struct siArrayHeader { + size_t count; + /* TODO(EimaMei): Add a `type_width` later on. */ + } siArrayHeader; + + /* Gets the header of the siArray. */ +#define SI_ARRAY_HEADER(s) ((siArrayHeader*)s - 1) + + void* si_array_init_reserve(size_t sizeof_element, size_t count) { + siArrayHeader* ptr = malloc(sizeof(siArrayHeader) + (sizeof_element * count)); + void* array = ptr + sizeof(siArrayHeader); + + siArrayHeader* header = SI_ARRAY_HEADER(array); + header->count = count; + + return array; + } + +#define si_array_len(array) (SI_ARRAY_HEADER(array)->count) +#define si_func_to_SEL(class_name, function) si_impl_func_to_SEL_with_name(class_name, #function":", function) + /* Creates an Objective-C method (SEL) from a regular C function with the option to set the register name.*/ +#define si_func_to_SEL_with_name(class_name, register_name, function) si_impl_func_to_SEL_with_name(class_name, register_name":", function) + + unsigned char* NSBitmapImageRep_bitmapData(NSBitmapImageRep* imageRep) { + return ((unsigned char* (*)(id, SEL))objc_msgSend) + (imageRep, sel_registerName("bitmapData")); + } + +#define NS_ENUM(type, name) type name; enum + + typedef NS_ENUM(NSUInteger, NSBitmapFormat) { + NSBitmapFormatAlphaFirst = 1 << 0, // 0 means is alpha last (RGBA, CMYKA, etc.) + NSBitmapFormatAlphaNonpremultiplied = 1 << 1, // 0 means is premultiplied + NSBitmapFormatFloatingPointSamples = 1 << 2, // 0 is integer + + NSBitmapFormatSixteenBitLittleEndian API_AVAILABLE(macos(10.10)) = (1 << 8), + NSBitmapFormatThirtyTwoBitLittleEndian API_AVAILABLE(macos(10.10)) = (1 << 9), + NSBitmapFormatSixteenBitBigEndian API_AVAILABLE(macos(10.10)) = (1 << 10), + NSBitmapFormatThirtyTwoBitBigEndian API_AVAILABLE(macos(10.10)) = (1 << 11) + }; + + NSBitmapImageRep* NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits) { + void* func = sel_registerName("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:"); + + return (NSBitmapImageRep*) ((id(*)(id, SEL, unsigned char**, NSInteger, NSInteger, NSInteger, NSInteger, bool, bool, const char*, NSBitmapFormat, NSInteger, NSInteger))objc_msgSend) + (NSAlloc((id)objc_getClass("NSBitmapImageRep")), func, planes, width, height, bps, spp, alpha, isPlanar, NSString_stringWithUTF8String(colorSpaceName), bitmapFormat, rowBytes, pixelBits); + } + + NSColor* NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) { + void* nsclass = objc_getClass("NSColor"); + void* func = sel_registerName("colorWithSRGBRed:green:blue:alpha:"); + return ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend) + (nsclass, func, red, green, blue, alpha); + } + + NSCursor* NSCursor_initWithImage(NSImage* newImage, NSPoint aPoint) { + void* func = sel_registerName("initWithImage:hotSpot:"); + void* nsclass = objc_getClass("NSCursor"); + + return (NSCursor*) ((id(*)(id, SEL, id, NSPoint))objc_msgSend) + (NSAlloc(nsclass), func, newImage, aPoint); + } + + void NSImage_addRepresentation(NSImage* image, NSImageRep* imageRep) { + void* func = sel_registerName("addRepresentation:"); + objc_msgSend_void_id(image, func, imageRep); + } + + NSImage* NSImage_initWithSize(NSSize size) { + void* func = sel_registerName("initWithSize:"); + return ((id(*)(id, SEL, NSSize))objc_msgSend) + (NSAlloc((id)objc_getClass("NSImage")), func, size); + } +#define NS_OPENGL_ENUM_DEPRECATED(minVers, maxVers) API_AVAILABLE(macos(minVers)) + typedef NS_ENUM(NSInteger, NSOpenGLContextParameter) { + NSOpenGLContextParameterSwapInterval NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 222, /* 1 param. 0 -> Don't sync, 1 -> Sync to vertical retrace */ + NSOpenGLContextParametectxaceOrder NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 235, /* 1 param. 1 -> Above Window (default), -1 -> Below Window */ + NSOpenGLContextParametectxaceOpacity NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 236, /* 1 param. 1-> Surface is opaque (default), 0 -> non-opaque */ + NSOpenGLContextParametectxaceBackingSize NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 304, /* 2 params. Width/height of surface backing size */ + NSOpenGLContextParameterReclaimResources NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 308, /* 0 params. */ + NSOpenGLContextParameterCurrentRendererID NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 309, /* 1 param. Retrieves the current renderer ID */ + NSOpenGLContextParameterGPUVertexProcessing NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 310, /* 1 param. Currently processing vertices with GPU (get) */ + NSOpenGLContextParameterGPUFragmentProcessing NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 311, /* 1 param. Currently processing fragments with GPU (get) */ + NSOpenGLContextParameterHasDrawable NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 314, /* 1 param. Boolean returned if drawable is attached */ + NSOpenGLContextParameterMPSwapsInFlight NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 315, /* 1 param. Max number of swaps queued by the MP GL engine */ + + NSOpenGLContextParameterSwapRectangle API_DEPRECATED("", macos(10.0, 10.14)) = 200, /* 4 params. Set or get the swap rectangle {x, y, w, h} */ + NSOpenGLContextParameterSwapRectangleEnable API_DEPRECATED("", macos(10.0, 10.14)) = 201, /* Enable or disable the swap rectangle */ + NSOpenGLContextParameterRasterizationEnable API_DEPRECATED("", macos(10.0, 10.14)) = 221, /* Enable or disable all rasterization */ + NSOpenGLContextParameterStateValidation API_DEPRECATED("", macos(10.0, 10.14)) = 301, /* Validate state for multi-screen functionality */ + NSOpenGLContextParametectxaceSurfaceVolatile API_DEPRECATED("", macos(10.0, 10.14)) = 306, /* 1 param. Surface volatile state */ + }; + + + void NSOpenGLContext_setValues(NSOpenGLContext* context, const int* vals, NSOpenGLContextParameter param) { + void* func = sel_registerName("setValues:forParameter:"); + ((void (*)(id, SEL, const int*, NSOpenGLContextParameter))objc_msgSend) + (context, func, vals, param); + } + + void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs) { + void* func = sel_registerName("initWithAttributes:"); + return (void*) ((id(*)(id, SEL, const uint32_t*))objc_msgSend) + (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), func, attribs); + } + + NSOpenGLView* NSOpenGLView_initWithFrame(NSRect frameRect, uint32_t* format) { + void* func = sel_registerName("initWithFrame:pixelFormat:"); + return (NSOpenGLView*) ((id(*)(id, SEL, NSRect, uint32_t*))objc_msgSend) + (NSAlloc((id)objc_getClass("NSOpenGLView")), func, frameRect, format); + } + + void NSCursor_performSelector(NSCursor* cursor, void* selector) { + void* func = sel_registerName("performSelector:"); + objc_msgSend_void_SEL(cursor, func, selector); + } + + NSPasteboard* NSPasteboard_generalPasteboard(void) { + return (NSPasteboard*) objc_msgSend_id((id)objc_getClass("NSPasteboard"), sel_registerName("generalPasteboard")); + } + + NSString** cstrToNSStringArray(char** strs, size_t len) { + static NSString* nstrs[6]; + size_t i; + for (i = 0; i < len; i++) + nstrs[i] = NSString_stringWithUTF8String(strs[i]); + + return nstrs; + } + + const char* NSPasteboard_stringForType(NSPasteboard* pasteboard, NSPasteboardType dataType) { + void* func = sel_registerName("stringForType:"); + return (const char*) NSString_to_char(((id(*)(id, SEL, const char*))objc_msgSend)(pasteboard, func, NSString_stringWithUTF8String(dataType))); + } + + NSArray* c_array_to_NSArray(void* array, size_t len) { + SEL func = sel_registerName("initWithObjects:count:"); + void* nsclass = objc_getClass("NSArray"); + return ((id (*)(id, SEL, void*, NSUInteger))objc_msgSend) + (NSAlloc(nsclass), func, array, len); + } + + void NSregisterForDraggedTypes(void* view, NSPasteboardType* newTypes, size_t len) { + NSString** ntypes = cstrToNSStringArray((char**)newTypes, len); + + NSArray* array = c_array_to_NSArray(ntypes, len); + objc_msgSend_void_id(view, sel_registerName("registerForDraggedTypes:"), array); + NSRelease(array); + } + + NSInteger NSPasteBoard_declareTypes(NSPasteboard* pasteboard, NSPasteboardType* newTypes, size_t len, void* owner) { + NSString** ntypes = cstrToNSStringArray((char**)newTypes, len); + + void* func = sel_registerName("declareTypes:owner:"); + + NSArray* array = c_array_to_NSArray(ntypes, len); + + NSInteger output = ((NSInteger(*)(id, SEL, id, void*))objc_msgSend) + (pasteboard, func, array, owner); + NSRelease(array); + + return output; + } + + bool NSPasteBoard_setString(NSPasteboard* pasteboard, const char* stringToWrite, NSPasteboardType dataType) { + void* func = sel_registerName("setString:forType:"); + return ((bool (*)(id, SEL, id, NSPasteboardType))objc_msgSend) + (pasteboard, func, NSString_stringWithUTF8String(stringToWrite), NSString_stringWithUTF8String(dataType)); + } + + void NSRetain(id obj) { objc_msgSend_void(obj, sel_registerName("retain")); } + + typedef enum NSApplicationActivationPolicy { + NSApplicationActivationPolicyRegular, + NSApplicationActivationPolicyAccessory, + NSApplicationActivationPolicyProhibited + } NSApplicationActivationPolicy; + + typedef NS_ENUM(u32, NSBackingStoreType) { + NSBackingStoreRetained = 0, + NSBackingStoreNonretained = 1, + NSBackingStoreBuffered = 2 + }; + + typedef NS_ENUM(u32, NSWindowStyleMask) { + NSWindowStyleMaskBorderless = 0, + NSWindowStyleMaskTitled = 1 << 0, + NSWindowStyleMaskClosable = 1 << 1, + NSWindowStyleMaskMiniaturizable = 1 << 2, + NSWindowStyleMaskResizable = 1 << 3, + NSWindowStyleMaskTexturedBackground = 1 << 8, /* deprecated */ + NSWindowStyleMaskUnifiedTitleAndToolbar = 1 << 12, + NSWindowStyleMaskFullScreen = 1 << 14, + NSWindowStyleMaskFullSizeContentView = 1 << 15, + NSWindowStyleMaskUtilityWindow = 1 << 4, + NSWindowStyleMaskDocModalWindow = 1 << 6, + NSWindowStyleMaskNonactivatingPanel = 1 << 7, + NSWindowStyleMaskHUDWindow = 1 << 13 + }; + + NSPasteboardType const NSPasteboardTypeString = "public.utf8-plain-text"; // Replaces NSStringPboardType + + + typedef NS_ENUM(i32, NSDragOperation) { + NSDragOperationNone = 0, + NSDragOperationCopy = 1, + NSDragOperationLink = 2, + NSDragOperationGeneric = 4, + NSDragOperationPrivate = 8, + NSDragOperationMove = 16, + NSDragOperationDelete = 32, + NSDragOperationEvery = ULONG_MAX, + + //NSDragOperationAll_Obsolete API_DEPRECATED("", macos(10.0,10.10)) = 15, // Use NSDragOperationEvery + //NSDragOperationAll API_DEPRECATED("", macos(10.0,10.10)) = NSDragOperationAll_Obsolete, // Use NSDragOperationEvery + }; + + void* NSArray_objectAtIndex(NSArray* array, NSUInteger index) { + void* func = sel_registerName("objectAtIndex:"); + return ((id(*)(id, SEL, NSUInteger))objc_msgSend)(array, func, index); + } + + const char** NSPasteboard_readObjectsForClasses(NSPasteboard* pasteboard, Class* classArray, size_t len, void* options) { + void* func = sel_registerName("readObjectsForClasses:options:"); + + NSArray* array = c_array_to_NSArray(classArray, len); + + NSArray* output = (NSArray*) ((id(*)(id, SEL, id, void*))objc_msgSend) + (pasteboard, func, array, options); + + NSRelease(array); + NSUInteger count = ((NSUInteger(*)(id, SEL))objc_msgSend)(output, sel_registerName("count")); + + const char** res = si_array_init_reserve(sizeof(const char*), count); + + void* path_func = sel_registerName("path"); + + for (NSUInteger i = 0; i < count; i++) { + void* url = NSArray_objectAtIndex(output, i); + NSString* url_str = ((id(*)(id, SEL))objc_msgSend)(url, path_func); + res[i] = NSString_to_char(url_str); + } + + return res; + } + + void* NSWindow_contentView(NSWindow* window) { + void* func = sel_registerName("contentView"); + return objc_msgSend_id(window, func); + } + + /* + End of cocoa wrapper + */ + + char* RGFW_mouseIconSrc[] = {"arrowCursor", "arrowCursor", "IBeamCursor", "crosshairCursor", "pointingHandCursor", "resizeLeftRightCursor", "resizeUpDownCursor", "_windowResizeNorthWestSouthEastCursor", "_windowResizeNorthEastSouthWestCursor", "closedHandCursor", "operationNotAllowedCursor"}; void* RGFWnsglFramework = NULL; @@ -5109,20 +7003,18 @@ static HMODULE wglinstance = NULL; return kCVReturnSuccess; } - RGFW_window* RGFW_windows[10]; - u32 RGFW_windows_size = 0; - id NSWindow_delegate(RGFW_window* win) { return (id) objc_msgSend_id(win->src.window, sel_registerName("delegate")); } u32 RGFW_OnClose(void* self) { - u32 i; - for (i = 0; i < RGFW_windows_size; i++) - if (RGFW_windows[i] && NSWindow_delegate(RGFW_windows[i]) == self) { - RGFW_windows[i]->event.type = RGFW_quit; - return true; - } + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void*)&win); + if (win == NULL) + return true; + + win->event.type = RGFW_quit; + RGFW_windowQuitCallback(win); return true; } @@ -5133,13 +7025,43 @@ static HMODULE wglinstance = NULL; NSDragOperation draggingEntered(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); + return NSDragOperationCopy; } NSDragOperation draggingUpdated(id self, SEL sel, id sender) { - RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); + RGFW_UNUSED(sel); + + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void*)&win); + if (win == NULL) + return 0; + + if (!(win->_winArgs & RGFW_ALLOW_DND)) { + return 0; + } + + win->event.type = RGFW_dnd_init; + win->src.dndPassed = 0; + + NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation")); + + win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); + RGFW_dndInitCallback(win, win->event.point); + return NSDragOperationCopy; } - bool prepareForDragOperation(void) { return true; } + bool prepareForDragOperation(id self) { + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void*)&win); + if (win == NULL) + return true; + + if (!(win->_winArgs & RGFW_ALLOW_DND)) { + return false; + } + + return true; + } void RGFW__osxDraggingEnded(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); return; } @@ -5147,44 +7069,58 @@ static HMODULE wglinstance = NULL; bool performDragOperation(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); - NSWindow* window = objc_msgSend_id(sender, sel_registerName("draggingDestinationWindow")); - u32 i; - bool found = false; + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void*)&win); - for (i = 0; i < RGFW_windows_size; i++) - if (RGFW_windows[i]->src.window == window) { - found = true; - break; - } + if (win == NULL) + return false; - if (!found) - i = 0; + // NSPasteboard* pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard")); - Class array[] = { objc_getClass("NSURL"), NULL }; - NSPasteboard* pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard")); + ///////////////////////////// + id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard")); + + // Get the types of data available on the pasteboard + id types = objc_msgSend_id(pasteBoard, sel_registerName("types")); + + // Get the string type for file URLs + id fileURLsType = objc_msgSend_class_char(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "NSFilenamesPboardType"); + + // Check if the pasteboard contains file URLs + if (objc_msgSend_id_bool(types, sel_registerName("containsObject:"), fileURLsType) == 0) { + #ifdef RGFW_DEBUG + printf("No files found on the pasteboard.\n"); + #endif + + return 0; + } + + id fileURLs = objc_msgSend_id_id(pasteBoard, sel_registerName("propertyListForType:"), fileURLsType); + int count = ((int (*)(id, SEL))objc_msgSend)(fileURLs, sel_registerName("count")); + + if (count == 0) + return 0; + + for (int i = 0; i < count; i++) { + id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i); + const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("UTF8String")); + // printf("File: %s\n", filePath); + strncpy(win->event.droppedFiles[i], filePath, RGFW_MAX_PATH); + win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0'; + } + win->event.droppedFilesCount = count; + + win->event.type = RGFW_dnd; + win->src.dndPassed = 0; - char** droppedFiles = (char**) NSPasteboard_readObjectsForClasses(pasteBoard, array, 1, NULL); - - RGFW_windows[i]->event.droppedFilesCount = si_array_len(droppedFiles); - - u32 y; - - for (y = 0; y < RGFW_windows[i]->event.droppedFilesCount; y++) - strcpy(RGFW_windows[i]->event.droppedFiles[y], droppedFiles[y]); - - RGFW_windows[i]->event.type = RGFW_dnd; - RGFW_windows[i]->src.dndPassed = false; - NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation")); - - RGFW_windows[i]->event.point.x = (i32)p.x; - RGFW_windows[i]->event.point.x = (i32)p.y; - return true; + win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); + + RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount); + + return false; } - - NSApplication* NSApp = NULL; - static void NSMoveToResourceDir(void) { /* sourced from glfw */ char resourcesPath[255]; @@ -5215,41 +7151,62 @@ static HMODULE wglinstance = NULL; NSSize RGFW__osxWindowResize(void* self, SEL sel, NSSize frameSize) { RGFW_UNUSED(sel); - u32 i; - for (i = 0; i < RGFW_windows_size; i++) { - if (RGFW_windows[i] && NSWindow_delegate(RGFW_windows[i]) == self) { - RGFW_windows[i]->r.w = frameSize.width; - RGFW_windows[i]->r.h = frameSize.height; - RGFW_windows[i]->event.type = RGFW_windowAttribsChange; - - return frameSize; - } - } - + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void*)&win); + if (win == NULL) + return frameSize; + + win->r.w = frameSize.width; + win->r.h = frameSize.height; + win->event.type = RGFW_windowResized; + RGFW_windowResizeCallback(win, win->r); return frameSize; } void RGFW__osxWindowMove(void* self, SEL sel) { RGFW_UNUSED(sel); - u32 i; - for (i = 0; i < RGFW_windows_size; i++) { - if (RGFW_windows[i] && NSWindow_delegate(RGFW_windows[i]) == self) { - NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)(RGFW_windows[i]->src.window, sel_registerName("frame")); - RGFW_windows[i]->r.x = (i32) frame.origin.x; - RGFW_windows[i]->r.y = (i32) frame.origin.y; + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void*)&win); + if (win == NULL) + return; + + NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)(win->src.window, sel_registerName("frame")); + win->r.x = (i32) frame.origin.x; + win->r.y = (i32) frame.origin.y; - RGFW_windows[i]->event.type = RGFW_windowAttribsChange; - return; - } - } + win->event.type = RGFW_windowMoved; + RGFW_windowMoveCallback(win, win->r); } - #ifdef __cplusplus - #define APPKIT_EXTERN extern "C" - #else - #define APPKIT_EXTERN extern - #endif + void RGFW__osxUpdateLayer(void* self, SEL sel) { + RGFW_UNUSED(sel); + + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void*)&win); + if (win == NULL) + return; + + win->event.type = RGFW_windowRefresh; + RGFW_windowRefreshCallback(win); + } + + RGFWDEF void RGFW_init_buffer(RGFW_window* win); + void RGFW_init_buffer(RGFW_window* win) { + #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0) + RGFW_bufferSize = RGFW_getScreenSize(); + + win->buffer = RGFW_MALLOC(RGFW_bufferSize.w * RGFW_bufferSize.h * 4); + + #ifdef RGFW_OSMESA + win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); + OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h); + #endif + #else + RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ + #endif + } NSPasteboardType const NSPasteboardTypeURL = "public.url"; NSPasteboardType const NSPasteboardTypeFileURL = "public.file-url"; @@ -5266,6 +7223,10 @@ static HMODULE wglinstance = NULL; si_func_to_SEL("NSWindow", acceptsFirstResponder); si_func_to_SEL("NSWindow", performKeyEquivalent); + // RR Create an autorelease pool + id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); + pool = objc_msgSend_id(pool, sel_registerName("init")); + if (NSApp == NULL) { NSApp = objc_msgSend_id((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication")); @@ -5274,6 +7235,8 @@ static HMODULE wglinstance = NULL; } RGFW_window* win = RGFW_window_basic_init(rect, args); + + RGFW_window_setMouseDefault(win); NSRect windowRect; windowRect.origin.x = win->r.x; @@ -5301,31 +7264,34 @@ static HMODULE wglinstance = NULL; objc_msgSend_void_id(win->src.window, sel_registerName("setTitle:"), str); #ifdef RGFW_OPENGL - void* attrs = RGFW_initAttribs(args & RGFW_OPENGL_SOFTWARE); + if ((args & RGFW_NO_INIT_API) == 0) { + void* attrs = RGFW_initFormatAttribs(args & RGFW_OPENGL_SOFTWARE); void* format = NSOpenGLPixelFormat_initWithAttributes(attrs); if (format == NULL) { - printf("Failed to load pixel format "); + printf("Failed to load pixel format for OpenGL\n"); - void* attrs = RGFW_initAttribs(1); + void* attrs = RGFW_initFormatAttribs(1); format = NSOpenGLPixelFormat_initWithAttributes(attrs); if (format == NULL) printf("and loading software rendering OpenGL failed\n"); else printf("Switching to software rendering\n"); } - - win->src.view = NSOpenGLView_initWithFrame(NSMakeRect(0, 0, win->r.w, win->r.h), format); + + /* the pixel format can be passed directly to opengl context creation to create a context + this is because the format also includes information about the opengl version (which may be a bad thing) */ + win->src.view = NSOpenGLView_initWithFrame((NSRect){{0, 0}, {win->r.w, win->r.h}}, format); objc_msgSend_void(win->src.view, sel_registerName("prepareOpenGL")); - win->src.rSurf = objc_msgSend_id(win->src.view, sel_registerName("openGLContext")); - -#else - NSRect contentRect = NSMakeRect(0, 0, win->r.w, win->r.h); + win->src.ctx = objc_msgSend_id(win->src.view, sel_registerName("openGLContext")); + } else +#endif + { + NSRect contentRect = (NSRect){{0, 0}, {win->r.w, win->r.h}}; win->src.view = ((id(*)(id, SEL, NSRect))objc_msgSend) (NSAlloc((id)objc_getClass("NSView")), sel_registerName("initWithFrame:"), contentRect); -#endif - + } void* contentView = NSWindow_contentView(win->src.window); objc_msgSend_void_bool(contentView, sel_registerName("setWantsLayer:"), true); @@ -5333,21 +7299,22 @@ static HMODULE wglinstance = NULL; objc_msgSend_void_id(win->src.window, sel_registerName("setContentView:"), win->src.view); #ifdef RGFW_OPENGL - objc_msgSend_void(win->src.rSurf, sel_registerName("makeCurrentContext")); + if ((args & RGFW_NO_INIT_API) == 0) + objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext")); #endif if (args & RGFW_TRANSPARENT_WINDOW) { #ifdef RGFW_OPENGL + if ((args & RGFW_NO_INIT_API) == 0) { i32 opacity = 0; - NSOpenGLContext_setValues(win->src.rSurf, &opacity, 304); + #define NSOpenGLCPSurfaceOpacity 236 + NSOpenGLContext_setValues(win->src.ctx, &opacity, NSOpenGLCPSurfaceOpacity); + } #endif objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false); objc_msgSend_void_id(win->src.window, sel_registerName("setBackgroundColor:"), NSColor_colorWithSRGB(0, 0, 0, 0)); - - ((void (*)(id, SEL, CGFloat))objc_msgSend) - (win->src.window, sel_registerName("setAlphaValue:"), 0x00); } win->src.display = CGMainDisplayID(); @@ -5357,12 +7324,10 @@ static HMODULE wglinstance = NULL; RGFW_init_buffer(win); -#ifdef RGFW_VULKAN - RGFW_initVulkan(win); -#endif - + #ifndef RGFW_NO_MONITOR if (args & RGFW_SCALE_TO_MONITOR) RGFW_window_scaleToMonitor(win); + #endif if (args & RGFW_HIDE_MOUSE) RGFW_window_showMouse(win, 0); @@ -5371,9 +7336,15 @@ static HMODULE wglinstance = NULL; NSMoveToResourceDir(); Class delegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0); - + + class_addIvar( + delegateClass, "RGFW_window", + sizeof(RGFW_window*), rint(log2(sizeof(RGFW_window*))), + "L" + ); class_addMethod(delegateClass, sel_registerName("windowWillResize:toSize:"), (IMP) RGFW__osxWindowResize, "{NSSize=ff}@:{NSSize=ff}"); + class_addMethod(delegateClass, sel_registerName("updateLayer:"), (IMP) RGFW__osxUpdateLayer, ""); class_addMethod(delegateClass, sel_registerName("windowWillMove:"), (IMP) RGFW__osxWindowMove, ""); class_addMethod(delegateClass, sel_registerName("windowDidMove:"), (IMP) RGFW__osxWindowMove, ""); class_addMethod(delegateClass, sel_registerName("draggingEntered:"), (IMP)draggingEntered, "l@:@"); @@ -5390,13 +7361,14 @@ static HMODULE wglinstance = NULL; objc_msgSend_void_id(win->src.window, sel_registerName("setDelegate:"), delegate); if (args & RGFW_ALLOW_DND) { - win->src.winArgs |= RGFW_ALLOW_DND; + win->_winArgs |= RGFW_ALLOW_DND; NSPasteboardType types[] = {NSPasteboardTypeURL, NSPasteboardTypeFileURL, NSPasteboardTypeString}; NSregisterForDraggedTypes(win->src.window, types, 3); } // Show the window + objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true); ((id(*)(id, SEL, SEL))objc_msgSend)(win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL); objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true); @@ -5408,16 +7380,7 @@ static HMODULE wglinstance = NULL; objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow")); - NSApplication_finishLaunching(NSApp); - - RGFW_windows_size++; - - size_t i; - for (i = 0; i < RGFW_windows_size; i++) - if (!RGFW_windows[i]) { - RGFW_windows[i] = win; - break; - } + objc_msgSend_void(NSApp, sel_registerName("finishLaunching")); if (RGFW_root == NULL) RGFW_root = win; @@ -5428,6 +7391,19 @@ static HMODULE wglinstance = NULL; return win; } + void RGFW_window_setBorder(RGFW_window* win, u8 border) { + NSBackingStoreType storeType = NSWindowStyleMaskBorderless; + if (!border) { + storeType = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable; + } + if (!(win->_winArgs & RGFW_NO_RESIZE)) { + storeType |= NSWindowStyleMaskResizable; + } + + ((void (*)(id, SEL, NSBackingStoreType))objc_msgSend)(win->src.window, sel_registerName("setStyleMask:"), storeType); + + objc_msgSend_void_bool(win->src.window, sel_registerName("setHasShadow:"), border); + } RGFW_area RGFW_getScreenSize(void) { static CGDirectDisplayID display = 0; @@ -5438,14 +7414,20 @@ static HMODULE wglinstance = NULL; return RGFW_AREA(CGDisplayPixelsWide(display), CGDisplayPixelsHigh(display)); } - RGFW_vector RGFW_getGlobalMousePoint(void) { + RGFW_point RGFW_getGlobalMousePoint(void) { assert(RGFW_root != NULL); CGEventRef e = CGEventCreate(NULL); CGPoint point = CGEventGetLocation(e); CFRelease(e); - return RGFW_VECTOR((u32) point.x, (u32) point.y); /* the point is loaded during event checks */ + return RGFW_POINT((u32) point.x, (u32) point.y); /*!< the point is loaded during event checks */ + } + + RGFW_point RGFW_window_getMousePoint(RGFW_window* win) { + NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(win->src.window, sel_registerName("mouseLocationOutsideOfEventStream")); + + return RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); } u32 RGFW_keysPressed[10]; /*10 keys at a time*/ @@ -5539,40 +7521,84 @@ static HMODULE wglinstance = NULL; NSEventModifierFlagShift = 1 << 17, NSEventModifierFlagControl = 1 << 18, NSEventModifierFlagOption = 1 << 19, - NSEventModifierFlagCommand = 1 << 20 + NSEventModifierFlagCommand = 1 << 20, + NSEventModifierFlagNumericPad = 1 << 21 } NSEventModifierFlags; + void RGFW_stopCheckEvents(void) { + id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); + eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); + + NSEvent* e = (NSEvent*) ((id(*)(id, SEL, NSEventType, NSPoint, NSEventModifierFlags, void*, NSInteger, void**, short, NSInteger, NSInteger))objc_msgSend) + (NSApp, sel_registerName("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"), + NSEventTypeApplicationDefined, (NSPoint){0, 0}, 0, 0, 0, NULL, 0, 0, 0); + + ((void (*)(id, SEL, id, bool))objc_msgSend) + (NSApp, sel_registerName("postEvent:atStart:"), e, 1); + + objc_msgSend_bool_void(eventPool, sel_registerName("drain")); + } + + void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { + RGFW_UNUSED(win); + + id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); + eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); + + void* date = (void*) ((id(*)(Class, SEL, double))objc_msgSend) + (objc_getClass("NSDate"), sel_registerName("dateWithTimeIntervalSinceNow:"), waitMS); + + NSEvent* e = (NSEvent*) ((id(*)(id, SEL, NSEventMask, void*, NSString*, bool))objc_msgSend) + (NSApp, sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"), + ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); + + + if (e) { + objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); + } + + objc_msgSend_bool_void(eventPool, sel_registerName("drain")); + } + RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) { assert(win != NULL); - + if (win->event.type == RGFW_quit) - return &win->event; - - if (win->event.type == RGFW_dnd && win->src.dndPassed == 0) { + return NULL; + + if ((win->event.type == RGFW_dnd || win->event.type == RGFW_dnd_init) && win->src.dndPassed == 0) { win->src.dndPassed = 1; return &win->event; } + id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); + eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); + static void* eventFunc = NULL; - if (eventFunc == NULL) + if (eventFunc == NULL) eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"); - - if (win->event.type == RGFW_windowAttribsChange && win->event.keyCode != 120) { + + if ((win->event.type == RGFW_windowMoved || win->event.type == RGFW_windowResized || win->event.type == RGFW_windowRefresh) && win->event.keyCode != 120) { win->event.keyCode = 120; + objc_msgSend_bool_void(eventPool, sel_registerName("drain")); return &win->event; } + void* date = NULL; + NSEvent* e = (NSEvent*) ((id(*)(id, SEL, NSEventMask, void*, NSString*, bool))objc_msgSend) - (NSApp, eventFunc, ULONG_MAX, NULL, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); + (NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); - - if (e == NULL) + if (e == NULL) { + objc_msgSend_bool_void(eventPool, sel_registerName("drain")); return NULL; - + } + if (objc_msgSend_id(e, sel_registerName("window")) != win->src.window) { ((void (*)(id, SEL, id, bool))objc_msgSend) (NSApp, sel_registerName("postEvent:atStart:"), e, 0); - + + objc_msgSend_bool_void(eventPool, sel_registerName("drain")); return NULL; } @@ -5584,94 +7610,88 @@ static HMODULE wglinstance = NULL; win->event.droppedFilesCount = 0; win->event.type = 0; - - win->event.inFocus = (bool) objc_msgSend_bool(win->src.window, sel_registerName("isKeyWindow")); - + switch (objc_msgSend_uint(e, sel_registerName("type"))) { - case NSEventTypeKeyDown: - win->event.keyCode = (u16) objc_msgSend_uint(e, sel_registerName("keyCode")); - RGFW_keyBoard_prev[win->event.keyCode] = RGFW_keyBoard[win->event.keyCode]; + case NSEventTypeMouseEntered: { + win->event.type = RGFW_mouseEnter; + NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow")); + + win->event.point = RGFW_POINT((i32) p.x, (i32) (win->r.h - p.y)); + RGFW_mouseNotifyCallBack(win, win->event.point, 1); + break; + } + + case NSEventTypeMouseExited: + win->event.type = RGFW_mouseLeave; + RGFW_mouseNotifyCallBack(win, win->event.point, 0); + break; + + case NSEventTypeKeyDown: { + u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode")); + win->event.keyCode = RGFW_apiKeyCodeToRGFW(key); + RGFW_keyboard[win->event.keyCode].prev = RGFW_keyboard[win->event.keyCode].current; win->event.type = RGFW_keyPressed; - win->event.keyName = (char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("characters"))); + char* str = (char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("characters"))); + strncpy(win->event.keyName, str, 16); + win->event.repeat = RGFW_isPressed(win, win->event.keyCode); + RGFW_keyboard[win->event.keyCode].current = 1; - RGFW_keyBoard[win->event.keyCode] = 1; + RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 1); break; + } - case NSEventTypeKeyUp: - win->event.keyCode = (u16) objc_msgSend_uint(e, sel_registerName("keyCode")); + case NSEventTypeKeyUp: { + u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode")); + win->event.keyCode = RGFW_apiKeyCodeToRGFW(key);; - RGFW_keyBoard_prev[win->event.keyCode] = RGFW_keyBoard[win->event.keyCode]; + RGFW_keyboard[win->event.keyCode].prev = RGFW_keyboard[win->event.keyCode].current; win->event.type = RGFW_keyReleased; - win->event.keyName = (char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("characters"))); + char* str = (char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("characters"))); + strncpy(win->event.keyName, str, 16); - RGFW_keyBoard[win->event.keyCode] = 0; + RGFW_keyboard[win->event.keyCode].current = 0; + RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 0); break; + } case NSEventTypeFlagsChanged: { u32 flags = objc_msgSend_uint(e, sel_registerName("modifierFlags")); - memcpy(RGFW_keyBoard_prev + 55, RGFW_keyBoard + 55, 5); + RGFW_updateLockState(win, ((u32)(flags & NSEventModifierFlagCapsLock) % 255), ((flags & NSEventModifierFlagNumericPad) % 255)); + + u8 i; + for (i = 0; i < 9; i++) + RGFW_keyboard[i + RGFW_CapsLock].prev = 0; + + for (i = 0; i < 5; i++) { + u32 shift = (1 << (i + 16)); + u32 key = i + RGFW_CapsLock; - if ((flags & NSEventModifierFlagCapsLock) && !RGFW_wasPressedI(win, 57)) { - RGFW_keyBoard[57] = 1; - win->event.type = RGFW_keyPressed; - win->event.keyCode = 57; - break; - } if (!(flags & NSEventModifierFlagCapsLock) && RGFW_wasPressedI(win, 57)) { - RGFW_keyBoard[57] = 0; - win->event.type = RGFW_keyReleased; - win->event.keyCode = 57; - break; + if ((flags & shift) && !RGFW_wasPressed(win, key)) { + RGFW_keyboard[key].current = 1; + + if (key != RGFW_CapsLock) + RGFW_keyboard[key+ 4].current = 1; + + win->event.type = RGFW_keyPressed; + win->event.keyCode = key; + break; + } + + if (!(flags & shift) && RGFW_wasPressed(win, key)) { + RGFW_keyboard[key].current = 0; + + if (key != RGFW_CapsLock) + RGFW_keyboard[key + 4].current = 0; + + win->event.type = RGFW_keyReleased; + win->event.keyCode = key; + break; + } } - if ((flags & NSEventModifierFlagOption) && !RGFW_wasPressedI(win, 58)) { - RGFW_keyBoard[58] = 1; - win->event.type = RGFW_keyPressed; - win->event.keyCode = 58; - break; - } if (!(flags & NSEventModifierFlagOption) && RGFW_wasPressedI(win, 58)) { - RGFW_keyBoard[58] = 0; - win->event.type = RGFW_keyReleased; - win->event.keyCode = 58; - break; - } - - if ((flags & NSEventModifierFlagControl) && !RGFW_wasPressedI(win, 59)) { - RGFW_keyBoard[59] = 1; - win->event.type = RGFW_keyPressed; - win->event.keyCode = 59; - break; - } if (!(flags & NSEventModifierFlagControl) && RGFW_wasPressedI(win, 59)) { - RGFW_keyBoard[59] = 0; - win->event.type = RGFW_keyReleased; - win->event.keyCode = 59; - break; - } - - if ((flags & NSEventModifierFlagCommand) && !RGFW_wasPressedI(win, 55)) { - RGFW_keyBoard[55] = 1; - win->event.type = RGFW_keyPressed; - win->event.keyCode = 55; - break; - } if (!(flags & NSEventModifierFlagCommand) && RGFW_wasPressedI(win, 55)) { - RGFW_keyBoard[55] = 0; - win->event.type = RGFW_keyReleased; - win->event.keyCode = 55; - break; - } - - if ((flags & NSEventModifierFlagShift) && !RGFW_wasPressedI(win, 56)) { - RGFW_keyBoard[56] = 1; - win->event.type = RGFW_keyPressed; - win->event.keyCode = 56; - break; - } if (!(flags & NSEventModifierFlagShift) && RGFW_wasPressedI(win, 56)) { - RGFW_keyBoard[56] = 0; - win->event.type = RGFW_keyReleased; - win->event.keyCode = 56; - break; - } + RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, win->event.type == RGFW_keyPressed); break; } @@ -5681,78 +7701,105 @@ static HMODULE wglinstance = NULL; case NSEventTypeMouseMoved: win->event.type = RGFW_mousePosChanged; NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow")); + win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); - win->event.point = RGFW_VECTOR((u32) p.x, (u32) (win->r.h - p.y)); - - if (win->src.winArgs & RGFW_HOLD_MOUSE) { - RGFW_vector mouse = RGFW_getGlobalMousePoint(); - if ((mouse.x != win->r.x + (win->r.w / 2) || mouse.y != win->r.y + (win->r.h / 2))) { - RGFW_window_moveMouse(win, RGFW_VECTOR(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2))); - } + if ((win->_winArgs & RGFW_HOLD_MOUSE)) { + p.x = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaX")); + p.y = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY")); + + win->event.point = RGFW_POINT((i32)p.x, (i32)p.y); } + + RGFW_mousePosCallback(win, win->event.point); break; case NSEventTypeLeftMouseDown: win->event.button = RGFW_mouseLeft; win->event.type = RGFW_mouseButtonPressed; + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 1; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); break; case NSEventTypeOtherMouseDown: win->event.button = RGFW_mouseMiddle; win->event.type = RGFW_mouseButtonPressed; + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 1; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); break; case NSEventTypeRightMouseDown: win->event.button = RGFW_mouseRight; win->event.type = RGFW_mouseButtonPressed; + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 1; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); break; case NSEventTypeLeftMouseUp: win->event.button = RGFW_mouseLeft; win->event.type = RGFW_mouseButtonReleased; + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 0; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); break; case NSEventTypeOtherMouseUp: win->event.button = RGFW_mouseMiddle; + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 0; win->event.type = RGFW_mouseButtonReleased; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); + break; + + case NSEventTypeRightMouseUp: + win->event.button = RGFW_mouseRight; + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 0; + win->event.type = RGFW_mouseButtonReleased; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); break; case NSEventTypeScrollWheel: { double deltaY = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY")); - if (deltaY > 0) + if (deltaY > 0) { win->event.button = RGFW_mouseScrollUp; - - else if (deltaY < 0) + } + else if (deltaY < 0) { win->event.button = RGFW_mouseScrollDown; + } + + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 1; win->event.scroll = deltaY; - win->event.type = RGFW_mouseButtonReleased; + win->event.type = RGFW_mouseButtonPressed; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); break; } - case NSEventTypeRightMouseUp: - win->event.button = RGFW_mouseRight; - win->event.type = RGFW_mouseButtonReleased; - break; default: break; } objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); - + ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); + + objc_msgSend_bool_void(eventPool, sel_registerName("drain")); return &win->event; } - void RGFW_window_move(RGFW_window* win, RGFW_vector v) { + void RGFW_window_move(RGFW_window* win, RGFW_point v) { assert(win != NULL); win->r.x = v.x; win->r.y = v.y; ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend) - (win->src.window, sel_registerName("setFrame:display:animate:"), NSMakeRect(win->r.x, win->r.y, win->r.w, win->r.h), true, true); + (win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true); } void RGFW_window_resize(RGFW_window* win, RGFW_area a) { @@ -5761,7 +7808,7 @@ static HMODULE wglinstance = NULL; win->r.w = a.w; win->r.h = a.h; ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend) - (win->src.window, sel_registerName("setFrame:display:animate:"), NSMakeRect(win->r.x, win->r.y, win->r.w, win->r.h), true, true); + (win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true); } void RGFW_window_minimize(RGFW_window* win) { @@ -5783,14 +7830,26 @@ static HMODULE wglinstance = NULL; objc_msgSend_void_id(win->src.window, sel_registerName("setTitle:"), str); } + #ifndef RGFW_NO_PASSTHROUGH + void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) { + objc_msgSend_void_bool(win->src.window, sel_registerName("setIgnoresMouseEvents:"), passthrough); + } + #endif + void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { + if (a.w == 0 && a.h == 0) + return; + ((void (*)(id, SEL, NSSize))objc_msgSend) - (win->src.window, sel_registerName("setMinSize:"), NSMakeSize(a.w, a.h)); + (win->src.window, sel_registerName("setMinSize:"), (NSSize){a.w, a.h}); } void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { + if (a.w == 0 && a.h == 0) + return; + ((void (*)(id, SEL, NSSize))objc_msgSend) - (win->src.window, sel_registerName("setMaxSize:"), NSMakeSize(a.w, a.h)); + (win->src.window, sel_registerName("setMaxSize:"), (NSSize){a.w, a.h}); } void RGFW_window_setIcon(RGFW_window* win, u8* data, RGFW_area area, i32 channels) { @@ -5802,7 +7861,7 @@ static HMODULE wglinstance = NULL; memcpy(NSBitmapImageRep_bitmapData(representation), data, area.w * area.h * channels); // Add ze representation. - void* dock_image = NSImage_initWithSize(NSMakeSize(area.w, area.h)); + void* dock_image = NSImage_initWithSize((NSSize){area.w, area.h}); NSImage_addRepresentation(dock_image, (void*) representation); // Finally, set the dock image to it. @@ -5832,11 +7891,11 @@ static HMODULE wglinstance = NULL; memcpy(NSBitmapImageRep_bitmapData(representation), image, a.w * a.h * channels); // Add ze representation. - void* cursor_image = NSImage_initWithSize(NSMakeSize(a.w, a.h)); + void* cursor_image = NSImage_initWithSize((NSSize){a.w, a.h}); NSImage_addRepresentation(cursor_image, representation); // Finally, set the cursor image. - void* cursor = NSCursor_initWithImage(cursor_image, NSMakePoint(0, 0)); + void* cursor = NSCursor_initWithImage(cursor_image, (NSPoint){0.0, 0.0}); objc_msgSend_void(cursor, sel_registerName("set")); @@ -5846,7 +7905,7 @@ static HMODULE wglinstance = NULL; } void RGFW_window_setMouseDefault(RGFW_window* win) { - RGFW_window_setMouseStandard(win, NSCursor_arrowStr("arrowCursor")); + RGFW_window_setMouseStandard(win, RGFW_MOUSE_ARROW); } void RGFW_window_showMouse(RGFW_window* win, i8 show) { @@ -5860,17 +7919,36 @@ static HMODULE wglinstance = NULL; } } - void RGFW_window_setMouseStandard(RGFW_window* win, void* mouse) { + void RGFW_window_setMouseStandard(RGFW_window* win, u8 stdMouses) { + if (stdMouses > ((sizeof(RGFW_mouseIconSrc)) / (sizeof(char*)))) + return; + + char* mouseStr = RGFW_mouseIconSrc[stdMouses]; + void* mouse = NSCursor_arrowStr(mouseStr); + + if (mouse == NULL) + return; + RGFW_UNUSED(win); CGDisplayShowCursor(kCGDirectMainDisplay); objc_msgSend_void(mouse, sel_registerName("set")); } + + void RGFW_releaseCursor(RGFW_window* win) { + CGAssociateMouseAndMouseCursorPosition(1); + } - void RGFW_window_moveMouse(RGFW_window* win, RGFW_vector v) { + void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { + RGFW_UNUSED(win) + + CGWarpMouseCursorPosition(CGPointMake(r.x + (r.w / 2), r.y + (r.h / 2))); + CGAssociateMouseAndMouseCursorPosition(0); + } + + void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); - assert(win != NULL); - - CGWarpMouseCursorPosition(CGPointMake(v.x, v.y)); + + CGWarpMouseCursorPosition(CGPointMake(v.x, v.y)); } @@ -5952,40 +8030,25 @@ static HMODULE wglinstance = NULL; return RGFW_NSCreateMonitor(win->src.display); } - u8 RGFW_isPressedI(RGFW_window* win, u32 key) { - RGFW_UNUSED(win); - if (key >= 128) { -#ifdef RGFW_PRINT_ERRORS - fprintf(stderr, "RGFW_isPressedI : invalid keycode\n"); -#endif - RGFW_error = 1; - } - - return RGFW_keyBoard[key]; - } - - u8 RGFW_wasPressedI(RGFW_window* win, u32 key) { - RGFW_UNUSED(win); - if (key >= 128) { -#ifdef RGFW_PRINT_ERRORS - fprintf(stderr, "RGFW_wasPressedI : invalid keycode\n"); -#endif - RGFW_error = 1; - } - - return RGFW_keyBoard_prev[key]; - } - -#ifdef __cplusplus -#define APPKIT_EXTERN extern "C" -#else -#define APPKIT_EXTERN extern -#endif - char* RGFW_readClipboard(size_t* size) { - char* str = strdup((char*) NSPasteboard_stringForType(NSPasteboard_generalPasteboard(), NSPasteboardTypeString)); + char* clip = (char*)NSPasteboard_stringForType(NSPasteboard_generalPasteboard(), NSPasteboardTypeString); + + size_t clip_len = 1; + + if (clip != NULL) { + clip_len = strlen(clip) + 1; + } + + char* str = (char*)RGFW_MALLOC(sizeof(char) * clip_len); + + if (clip != NULL) { + strncpy(str, clip, clip_len); + } + + str[clip_len] = '\0'; + if (size != NULL) - *size = strlen(str); + *size = clip_len; return str; } @@ -6011,27 +8074,94 @@ static HMODULE wglinstance = NULL; assert(win != NULL); - return win->src.joystickCount - 1; + return RGFW_joystickCount - 1; + } + + #ifdef RGFW_OPENGL + void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { + assert(win != NULL); + objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext")); + } + #endif + + #if !defined(RGFW_EGL) + void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { + assert(win != NULL); + #if defined(RGFW_OPENGL) + + NSOpenGLContext_setValues(win->src.ctx, &swapInterval, 222); + #endif + } + #endif + + // Function to create a CGImageRef from an array of bytes + CGImageRef createImageFromBytes(unsigned char *buffer, int width, int height) + { + // Define color space + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + // Create bitmap context + CGContextRef context = CGBitmapContextCreate( + buffer, + width, height, + 8, + RGFW_bufferSize.w * 4, + colorSpace, + kCGImageAlphaPremultipliedLast); + // Create image from bitmap context + CGImageRef image = CGBitmapContextCreateImage(context); + // Release the color space and context + CGColorSpaceRelease(colorSpace); + CGContextRelease(context); + + return image; + } + + void RGFW_window_swapBuffers(RGFW_window* win) { + assert(win != NULL); + /* clear the window*/ + + if (!(win->_winArgs & RGFW_NO_CPU_RENDER)) { +#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + #ifdef RGFW_OSMESA + RGFW_OSMesa_reorganize(); + #endif + + void* view = NSWindow_contentView(win->src.window); + void* layer = objc_msgSend_id(view, sel_registerName("layer")); + + ((void(*)(id, SEL, NSRect))objc_msgSend)(layer, + sel_registerName("setFrame:"), + (NSRect){{0, 0}, {win->r.w, win->r.h}}); + + CGImageRef image = createImageFromBytes(win->buffer, win->r.w, win->r.h); + // Get the current graphics context + id graphicsContext = objc_msgSend_class(objc_getClass("NSGraphicsContext"), sel_registerName("currentContext")); + // Get the CGContext from the current NSGraphicsContext + id cgContext = objc_msgSend_id(graphicsContext, sel_registerName("graphicsPort")); + // Draw the image in the context + NSRect bounds = (NSRect){{0,0}, {win->r.w, win->r.h}}; + CGContextDrawImage((void*)cgContext, *(CGRect*)&bounds, image); + // Flush the graphics context to ensure the drawing is displayed + objc_msgSend_id(graphicsContext, sel_registerName("flushGraphics")); + + objc_msgSend_void_id(layer, sel_registerName("setContents:"), (id)image); + objc_msgSend_id(layer, sel_registerName("setNeedsDisplay")); + + CGImageRelease(image); +#endif + } + + if (!(win->_winArgs & RGFW_NO_GPU_RENDER)) { + #ifdef RGFW_EGL + eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); + #elif defined(RGFW_OPENGL) + objc_msgSend_void(win->src.ctx, sel_registerName("flushBuffer")); + #endif + } } void RGFW_window_close(RGFW_window* win) { assert(win != NULL); - -#ifdef RGFW_VULKAN - for (int i = 0; i < win->src.image_count; i++) { - vkDestroyFramebuffer(RGFW_vulkan_info.device, RGFW_vulkan_info.framebuffers[i], NULL); - } - - for (int i = 0; i < win->src.image_count; i++) { - vkDestroyImageView(RGFW_vulkan_info.device, win->src.swapchain_image_views[i], NULL); - } - - vkDestroySwapchainKHR(RGFW_vulkan_info.device, win->src.swapchain, NULL); - vkDestroySurfaceKHR(RGFW_vulkan_info.instance, win->src.rSurf, NULL); - free(win->src.swapchain_image_views); - free(win->src.swapchain_images); -#endif - release(win->src.view); #ifdef RGFW_ALLOC_DROPFILES @@ -6044,21 +8174,7 @@ static HMODULE wglinstance = NULL; RGFW_FREE(win->event.droppedFiles); } #endif - - u32 i; - for (i = 0; i < RGFW_windows_size; i++) - if (RGFW_windows[i]->src.window == win->src.window) { - RGFW_windows[i] = NULL; - break; - } - - if (!i) { - RGFW_windows_size = 0; - - objc_msgSend_void_id(NSApp, sel_registerName("terminate:"), (id) win->src.window); - NSApp = NULL; - } - + #ifdef RGFW_BUFFER release(win->src.bitmap); release(win->src.image); @@ -6067,12 +8183,737 @@ static HMODULE wglinstance = NULL; CVDisplayLinkStop(win->src.displayLink); CVDisplayLinkRelease(win->src.displayLink); - free(win); + RGFW_FREE(win); } + + u64 RGFW_getTimeNS(void) { + static mach_timebase_info_data_t timebase_info; + if (timebase_info.denom == 0) { + mach_timebase_info(&timebase_info); + } + return mach_absolute_time() * timebase_info.numer / timebase_info.denom; + } + + u64 RGFW_getTime(void) { + static mach_timebase_info_data_t timebase_info; + if (timebase_info.denom == 0) { + mach_timebase_info(&timebase_info); + } + return (double) mach_absolute_time() * (double) timebase_info.numer / ((double) timebase_info.denom * 1e9); + } +#endif /* RGFW_MACOS */ + +/* + End of MaOS defines +*/ + +/* + WEBASM defines +*/ + +#ifdef RGFW_WEBASM +RGFW_Event RGFW_events[20]; +size_t RGFW_eventLen = 0; + +EM_BOOL Emscripten_on_keydown(int eventType, const EmscriptenKeyboardEvent* e, void* userData) { + RGFW_UNUSED(eventType); RGFW_UNUSED(userData); + + RGFW_events[RGFW_eventLen].type = RGFW_keyPressed; + memcpy(RGFW_events[RGFW_eventLen].keyName, e->key, 16); + RGFW_events[RGFW_eventLen].keyCode = RGFW_apiKeyCodeToRGFW(e->keyCode); + RGFW_events[RGFW_eventLen].lockState = 0; + RGFW_eventLen++; + + RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].prev = RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current; + RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current = 1; + RGFW_keyCallback(RGFW_root, RGFW_apiKeyCodeToRGFW(e->keyCode), RGFW_events[RGFW_eventLen].keyName, 0, 1); + + return EM_TRUE; +} + +EM_BOOL Emscripten_on_keyup(int eventType, const EmscriptenKeyboardEvent* e, void* userData) { + RGFW_UNUSED(eventType); RGFW_UNUSED(userData); + + RGFW_events[RGFW_eventLen].type = RGFW_keyReleased; + memcpy(RGFW_events[RGFW_eventLen].keyName, e->key, 16); + RGFW_events[RGFW_eventLen].keyCode = RGFW_apiKeyCodeToRGFW(e->keyCode); + RGFW_events[RGFW_eventLen].lockState = 0; + RGFW_eventLen++; + + RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].prev = RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current; + RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current = 0; + + RGFW_keyCallback(RGFW_root, RGFW_apiKeyCodeToRGFW(e->keyCode), RGFW_events[RGFW_eventLen].keyName, 0, 0); + + return EM_TRUE; +} + +EM_BOOL Emscripten_on_resize(int eventType, const EmscriptenUiEvent* e, void* userData) { + RGFW_UNUSED(eventType); RGFW_UNUSED(userData); + + RGFW_events[RGFW_eventLen].type = RGFW_windowResized; + RGFW_eventLen++; + + RGFW_windowResizeCallback(RGFW_root, RGFW_RECT(0, 0, e->windowInnerWidth, e->windowInnerHeight)); + return EM_TRUE; +} + +EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreenChangeEvent* e, void* userData) { + RGFW_UNUSED(eventType); RGFW_UNUSED(userData); + + RGFW_events[RGFW_eventLen].type = RGFW_windowResized; + RGFW_eventLen++; + + RGFW_root->r = RGFW_RECT(0, 0, e->elementWidth, e->elementHeight); + RGFW_windowResizeCallback(RGFW_root, RGFW_root->r); + return EM_TRUE; +} + +EM_BOOL Emscripten_on_focusin(int eventType, const EmscriptenFocusEvent* e, void* userData) { + RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(e); + + RGFW_events[RGFW_eventLen].type = RGFW_focusIn; + RGFW_eventLen++; + + RGFW_root->event.inFocus = 1; + RGFW_focusCallback(RGFW_root, 1); + return EM_TRUE; +} + +EM_BOOL Emscripten_on_focusout(int eventType, const EmscriptenFocusEvent* e, void* userData) { + RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(e); + + RGFW_events[RGFW_eventLen].type = RGFW_focusOut; + RGFW_eventLen++; + + RGFW_root->event.inFocus = 0; + RGFW_focusCallback(RGFW_root, 0); + return EM_TRUE; +} + +EM_BOOL Emscripten_on_mousemove(int eventType, const EmscriptenMouseEvent* e, void* userData) { + RGFW_UNUSED(eventType); RGFW_UNUSED(userData); + + RGFW_events[RGFW_eventLen].type = RGFW_mousePosChanged; + + if ((RGFW_root->_winArgs & RGFW_HOLD_MOUSE)) { + RGFW_point p = RGFW_POINT(e->movementX, e->movementY); + RGFW_events[RGFW_eventLen].point = p; + } + else + RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->targetX, e->targetY); + RGFW_eventLen++; + + RGFW_mousePosCallback(RGFW_root, RGFW_events[RGFW_eventLen].point); + return EM_TRUE; +} + +EM_BOOL Emscripten_on_mousedown(int eventType, const EmscriptenMouseEvent* e, void* userData) { + RGFW_UNUSED(eventType); RGFW_UNUSED(userData); + + RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonPressed; + RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->targetX, e->targetY); + RGFW_events[RGFW_eventLen].button = e->button + 1; + RGFW_events[RGFW_eventLen].scroll = 0; + + RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current; + RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 1; + + RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 1); + RGFW_eventLen++; + + return EM_TRUE; +} + +EM_BOOL Emscripten_on_mouseup(int eventType, const EmscriptenMouseEvent* e, void* userData) { + RGFW_UNUSED(eventType); RGFW_UNUSED(userData); + + RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonReleased; + RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->targetX, e->targetY); + RGFW_events[RGFW_eventLen].button = e->button + 1; + RGFW_events[RGFW_eventLen].scroll = 0; + + RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current; + RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 0; + + RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 0); + RGFW_eventLen++; + return EM_TRUE; +} + +EM_BOOL Emscripten_on_wheel(int eventType, const EmscriptenWheelEvent* e, void* userData) { + RGFW_UNUSED(eventType); RGFW_UNUSED(userData); + + RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonPressed; + RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->mouse.targetX, e->mouse.targetY); + RGFW_events[RGFW_eventLen].button = RGFW_mouseScrollUp + (e->deltaY < 0); + RGFW_events[RGFW_eventLen].scroll = e->deltaY; + + RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current; + RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 1; + + RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 1); + RGFW_eventLen++; + + return EM_TRUE; +} + +EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent* e, void* userData) { + RGFW_UNUSED(eventType); RGFW_UNUSED(userData); + + size_t i; + for (i = 0; i < (size_t)e->numTouches; i++) { + RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonPressed; + RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY); + RGFW_events[RGFW_eventLen].button = 1; + RGFW_events[RGFW_eventLen].scroll = 0; + + + RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current; + RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 1; + + RGFW_mousePosCallback(RGFW_root, RGFW_events[RGFW_eventLen].point); + + RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 1); + RGFW_eventLen++; + } + + return EM_TRUE; +} +EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent* e, void* userData) { + RGFW_UNUSED(eventType); RGFW_UNUSED(userData); + + size_t i; + for (i = 0; i < (size_t)e->numTouches; i++) { + RGFW_events[RGFW_eventLen].type = RGFW_mousePosChanged; + RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY); + + RGFW_mousePosCallback(RGFW_root, RGFW_events[RGFW_eventLen].point); + RGFW_eventLen++; + } + return EM_TRUE; +} + +EM_BOOL Emscripten_on_touchend(int eventType, const EmscriptenTouchEvent* e, void* userData) { + RGFW_UNUSED(eventType); RGFW_UNUSED(userData); + + size_t i; + for (i = 0; i < (size_t)e->numTouches; i++) { + RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonReleased; + RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY); + RGFW_events[RGFW_eventLen].button = 1; + RGFW_events[RGFW_eventLen].scroll = 0; + + RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current; + RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 0; + + RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 0); + RGFW_eventLen++; + } + return EM_TRUE; +} + +EM_BOOL Emscripten_on_touchcancel(int eventType, const EmscriptenTouchEvent* e, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(e); return EM_TRUE; } + +EM_BOOL Emscripten_on_gamepad(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) { + RGFW_UNUSED(eventType); RGFW_UNUSED(userData); + + if (gamepadEvent->index >= 4) + return 0; + + RGFW_joysticks[gamepadEvent->index] = gamepadEvent->connected; + + return 1; // The event was consumed by the callback handler +} + +void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) { + if (!(RGFW_root->_winArgs & RGFW_ALLOW_DND)) + return; + + RGFW_events[RGFW_eventLen].droppedFilesCount = count; + RGFW_dndCallback(RGFW_root, RGFW_events[RGFW_eventLen].droppedFiles, count); + RGFW_eventLen++; +} + +b8 RGFW_stopCheckEvents_bool = RGFW_FALSE; +void RGFW_stopCheckEvents(void) { + RGFW_stopCheckEvents_bool = RGFW_TRUE; +} + +void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { + RGFW_UNUSED(win); + + if (waitMS == 0) + return; + + u32 start = (u32)(((u64)RGFW_getTimeNS()) / 1e+6); + + while ((RGFW_eventLen == 0) && RGFW_stopCheckEvents_bool == RGFW_FALSE && + (waitMS < 0 || (RGFW_getTimeNS() / 1e+6) - start < waitMS) + ) { + emscripten_sleep(0); + } + + RGFW_stopCheckEvents_bool = RGFW_FALSE; +} + +RGFWDEF void RGFW_init_buffer(RGFW_window* win); +void RGFW_init_buffer(RGFW_window* win) { + #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0) + RGFW_bufferSize = RGFW_getScreenSize(); + + win->buffer = RGFW_MALLOC(RGFW_bufferSize.w * RGFW_bufferSize.h * 4); + #ifdef RGFW_OSMESA + win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); + OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h); + #endif + #else + RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ + #endif +} + +void EMSCRIPTEN_KEEPALIVE RGFW_makeSetValue(size_t index, char* file) { + /* This seems like a terrible idea, don't replicate this unless you hate yourself or the OS */ + /* TODO: find a better way to do this, + strcpy doesn't seem to work, maybe because of asyncio + */ + + RGFW_events[RGFW_eventLen].type = RGFW_dnd; + char** arr = (char**)&RGFW_events[RGFW_eventLen].droppedFiles[index]; + *arr = file; +} + +#include +#include +#include + +void EMSCRIPTEN_KEEPALIVE RGFW_mkdir(char* name) { mkdir(name, 0755); } + +void EMSCRIPTEN_KEEPALIVE RGFW_writeFile(const char *path, const char *data, size_t len) { + FILE* file = fopen(path, "w+"); + if (file == NULL) + return; + + fwrite(data, sizeof(char), len, file); + fclose(file); +} + +RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) { + RGFW_UNUSED(name) + + RGFW_UNUSED(RGFW_initFormatAttribs); + + RGFW_window* win = RGFW_window_basic_init(rect, args); + + EmscriptenWebGLContextAttributes attrs; + attrs.alpha = EM_TRUE; + attrs.depth = EM_TRUE; + attrs.alpha = EM_TRUE; + attrs.stencil = RGFW_STENCIL; + attrs.antialias = RGFW_SAMPLES; + attrs.premultipliedAlpha = EM_TRUE; + attrs.preserveDrawingBuffer = EM_FALSE; + + if (RGFW_DOUBLE_BUFFER == 0) + attrs.renderViaOffscreenBackBuffer = 0; + else + attrs.renderViaOffscreenBackBuffer = RGFW_AUX_BUFFERS; + + attrs.failIfMajorPerformanceCaveat = EM_FALSE; + attrs.majorVersion = (RGFW_majorVersion == 0) ? 1 : RGFW_majorVersion; + attrs.minorVersion = RGFW_minorVersion; + + attrs.enableExtensionsByDefault = EM_TRUE; + attrs.explicitSwapControl = EM_TRUE; + + emscripten_webgl_init_context_attributes(&attrs); + win->src.ctx = emscripten_webgl_create_context("#canvas", &attrs); + emscripten_webgl_make_context_current(win->src.ctx); + + #ifdef LEGACY_GL_EMULATION + EM_ASM("Module.useWebGL = true; GLImmediate.init();"); + #endif + + emscripten_set_canvas_element_size("#canvas", rect.w, rect.h); + emscripten_set_window_title(name); + + /* load callbacks */ + emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_keydown); + emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_keyup); + emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_resize); + emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, EM_FALSE, Emscripten_on_fullscreenchange); + emscripten_set_mousemove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousemove); + emscripten_set_touchstart_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchstart); + emscripten_set_touchend_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchend); + emscripten_set_touchmove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchmove); + emscripten_set_touchcancel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchcancel); + emscripten_set_mousedown_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousedown); + emscripten_set_mouseup_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mouseup); + emscripten_set_wheel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_wheel); + emscripten_set_focusin_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusin); + emscripten_set_focusout_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusout); + emscripten_set_gamepadconnected_callback(NULL, 1, Emscripten_on_gamepad); + emscripten_set_gamepaddisconnected_callback(NULL, 1, Emscripten_on_gamepad); + + if (args & RGFW_ALLOW_DND) { + win->_winArgs |= RGFW_ALLOW_DND; + } + + EM_ASM({ + var canvas = document.getElementById('canvas'); + canvas.addEventListener('drop', function(e) { + e.preventDefault(); + if (e.dataTransfer.file < 0) + return; + + var filenamesArray = []; + var count = e.dataTransfer.files.length; + + /* Read and save the files to emscripten's files */ + var drop_dir = '.rgfw_dropped_files'; + Module._RGFW_mkdir(drop_dir); + + for (var i = 0; i < count; i++) { + var file = e.dataTransfer.files[i]; + + var path = '/' + drop_dir + '/' + file.name.replace("//", '_'); + var reader = new FileReader(); + + reader.onloadend = (e) => { + if (reader.readyState != 2) { + out('failed to read dropped file: '+file.name+': '+reader.error); + } + else { + var data = e.target.result; + + _RGFW_writeFile(path, new Uint8Array(data), file.size); + } + }; + + reader.readAsArrayBuffer(file); + // This works weird on modern opengl + var filename = stringToNewUTF8(path); + + filenamesArray.push(filename); + + Module._RGFW_makeSetValue(i, filename); + } + + Module._Emscripten_onDrop(count); + + for (var i = 0; i < count; ++i) { + _free(filenamesArray[i]); + } + }, true); + + canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; }, true); + }); + + RGFW_init_buffer(win); + glViewport(0, 0, rect.w, rect.h); + + RGFW_root = win; + + if (args & RGFW_HIDE_MOUSE) { + RGFW_window_showMouse(win, 0); + } + + if (args & RGFW_FULLSCREEN) { + RGFW_window_resize(win, RGFW_getScreenSize()); + } + + return win; +} + +RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) { + static u8 index = 0; + + if (index == 0) + RGFW_resetKey(); + + /* check gamepads */ + for (int i = 0; (i < emscripten_get_num_gamepads()) && (i < 4); i++) { + if (RGFW_joysticks[i] == 0) + continue;; + + EmscriptenGamepadEvent gamepadState; + + if (emscripten_get_gamepad_status(i, &gamepadState) != EMSCRIPTEN_RESULT_SUCCESS) + break; + + // Register buttons data for every connected gamepad + for (int j = 0; (j < gamepadState.numButtons) && (j < 16); j++) { + u32 map[] = { + RGFW_JS_A, RGFW_JS_X, RGFW_JS_B, RGFW_JS_Y, + RGFW_JS_L1, RGFW_JS_R1, RGFW_JS_L2, RGFW_JS_R2, + RGFW_JS_SELECT, RGFW_JS_START, + 0, 0, + RGFW_JS_UP, RGFW_JS_DOWN, RGFW_JS_LEFT, RGFW_JS_RIGHT + }; + + u32 button = map[j]; + if (RGFW_jsPressed[i][button] != gamepadState.digitalButton[j]) { + win->event.type = RGFW_jsButtonPressed; + win->event.joystick = i; + win->event.button = map[j]; + return &win->event; + } + + RGFW_jsPressed[i][button] = gamepadState.digitalButton[j]; + } + + for (int j = 0; (j < gamepadState.numAxes) && (j < 4); j += 2) { + win->event.axisesCount = gamepadState.numAxes; + if (win->event.axis[j].x != gamepadState.axis[j] || + win->event.axis[j].y != gamepadState.axis[j + 1] + ) { + win->event.axis[j].x = gamepadState.axis[j]; + win->event.axis[j].y = gamepadState.axis[j + 1]; + win->event.type = RGFW_jsAxisMove; + win->event.joystick = i; + return &win->event; + } + } + } + + /* check queued events */ + if (RGFW_eventLen == 0) + return NULL; + + RGFW_events[index].frameTime = win->event.frameTime; + RGFW_events[index].frameTime2 = win->event.frameTime2; + RGFW_events[index].inFocus = win->event.inFocus; + + win->event = RGFW_events[index]; + + RGFW_eventLen--; + + if (RGFW_eventLen) + index++; + else + index = 0; + + return &win->event; +} + +void RGFW_window_resize(RGFW_window* win, RGFW_area a) { + RGFW_UNUSED(win) + emscripten_set_canvas_element_size("#canvas", a.w, a.h); +} + +/* NOTE: I don't know if this is possible */ +void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); } +/* this one might be possible but it looks iffy */ +void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) { RGFW_UNUSED(win); RGFW_UNUSED(channels) RGFW_UNUSED(a) RGFW_UNUSED(image) } + +const char RGFW_CURSORS[11][12] = { + "default", + "default", + "text", + "crosshair", + "pointer", + "ew-resize", + "ns-resize", + "nwse-resize", + "nesw-resize", + "move", + "not-allowed" +}; + +void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { + RGFW_UNUSED(win) + EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, RGFW_CURSORS[mouse]); +} + +void RGFW_window_setMouseDefault(RGFW_window* win) { + RGFW_window_setMouseStandard(win, RGFW_MOUSE_NORMAL); +} + +void RGFW_window_showMouse(RGFW_window* win, i8 show) { + if (show) + RGFW_window_setMouseDefault(win); + else + EM_ASM(document.getElementById('canvas').style.cursor = 'none';); +} + +RGFW_point RGFW_getGlobalMousePoint(void) { + RGFW_point point; + point.x = EM_ASM_INT({ + return window.mouseX || 0; + }); + point.y = EM_ASM_INT({ + return window.mouseY || 0; + }); + return point; +} + +RGFW_point RGFW_window_getMousePoint(RGFW_window* win) { + RGFW_UNUSED(win); + + EmscriptenMouseEvent mouseEvent; + emscripten_get_mouse_status(&mouseEvent); + return RGFW_POINT( mouseEvent.targetX, mouseEvent.targetY); +} + +void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) { + RGFW_UNUSED(win); + + EM_ASM_({ + var canvas = document.getElementById('canvas'); + if ($0) { + canvas.style.pointerEvents = 'none'; + } else { + canvas.style.pointerEvents = 'auto'; + } + }, passthrough); +} + +void RGFW_writeClipboard(const char* text, u32 textLen) { + RGFW_UNUSED(textLen) + EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text); +} + + +char* RGFW_readClipboard(size_t* size) { + /* + placeholder code for later + I'm not sure if this is possible do the the async stuff + */ + + if (size != NULL) + *size = 0; + + char* str = (char*)malloc(1); + str[0] = '\0'; + + return str; +} + +void RGFW_window_swapBuffers(RGFW_window* win) { + RGFW_UNUSED(win); + + #ifdef RGFW_BUFFER + if (!(win->_winArgs & RGFW_NO_CPU_RENDER)) { + glEnable(GL_TEXTURE_2D); + + GLuint texture; + glGenTextures(1,&texture); + + glBindTexture(GL_TEXTURE_2D,texture); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, RGFW_bufferSize.w, RGFW_bufferSize.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, win->buffer); + + float ratioX = ((float)win->r.w / (float)RGFW_bufferSize.w); + float ratioY = ((float)win->r.h / (float)RGFW_bufferSize.h); + + // Set up the viewport + glClear(GL_COLOR_BUFFER_BIT); + + glBegin(GL_TRIANGLES); + glTexCoord2f(0, ratioY); glColor3f(1, 1, 1); glVertex2f(-1, -1); + glTexCoord2f(0, 0); glColor3f(1, 1, 1); glVertex2f(-1, 1); + glTexCoord2f(ratioX, ratioY); glColor3f(1, 1, 1); glVertex2f(1, -1); + + glTexCoord2f(ratioX, 0); glColor3f(1, 1, 1); glVertex2f(1, 1); + glTexCoord2f(ratioX, ratioY); glColor3f(1, 1, 1); glVertex2f(1, -1); + glTexCoord2f(0, 0); glColor3f(1, 1, 1); glVertex2f(-1, 1); + glEnd(); + + glDeleteTextures(1, &texture); + } + #endif + + emscripten_webgl_commit_frame(); + emscripten_sleep(0); +} + + +void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { + if (win == NULL) + emscripten_webgl_make_context_current(0); + else + emscripten_webgl_make_context_current(win->src.ctx); +} + +#ifndef RGFW_EGL +void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); } #endif -#if defined(RGFW_X11) || defined(RGFW_MACOS) +void RGFW_window_close(RGFW_window* win) { + emscripten_webgl_destroy_context(win->src.ctx); + free(win); +} + +int RGFW_innerWidth(void) { return EM_ASM_INT({ return window.innerWidth; }); } +int RGFW_innerHeight(void) { return EM_ASM_INT({ return window.innerHeight; }); } + +RGFW_area RGFW_getScreenSize(void) { + return RGFW_AREA(RGFW_innerWidth(), RGFW_innerHeight()); +} + +void* RGFW_getProcAddress(const char* procname) { + return emscripten_webgl_get_proc_address(procname); +} + +void RGFW_sleep(u64 milisecond) { + emscripten_sleep(milisecond); +} + +u64 RGFW_getTimeNS(void) { + return emscripten_get_now() * 1e+6; +} + +u64 RGFW_getTime(void) { + return emscripten_get_now() * 1000; +} + +void RGFW_releaseCursor(RGFW_window* win) { + emscripten_exit_pointerlock(); +} + +void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { + RGFW_UNUSED(win) + + emscripten_request_pointerlock("#canvas", 1); +} + + +void RGFW_window_setName(RGFW_window* win, char* name) { + RGFW_UNUSED(win); + emscripten_set_window_title(name); +} + +/* unsupported functions */ +RGFW_monitor* RGFW_getMonitors(void) { return NULL; } +RGFW_monitor RGFW_getPrimaryMonitor(void) { return (RGFW_monitor){}; } +void RGFW_window_move(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win) RGFW_UNUSED(v) } +void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win) RGFW_UNUSED(a) } +void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win) RGFW_UNUSED(a) } +void RGFW_window_minimize(RGFW_window* win) { RGFW_UNUSED(win)} +void RGFW_window_restore(RGFW_window* win) { RGFW_UNUSED(win) } +void RGFW_window_setBorder(RGFW_window* win, b8 border) { RGFW_UNUSED(win) RGFW_UNUSED(border) } +void RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) { RGFW_UNUSED(win) RGFW_UNUSED(icon) RGFW_UNUSED(a) RGFW_UNUSED(channels) } +void RGFW_window_hide(RGFW_window* win) { RGFW_UNUSED(win) } +void RGFW_window_show(RGFW_window* win) {RGFW_UNUSED(win) } +b8 RGFW_window_isHidden(RGFW_window* win) { RGFW_UNUSED(win) return 0; } +b8 RGFW_window_isMinimized(RGFW_window* win) { RGFW_UNUSED(win) return 0; } +b8 RGFW_window_isMaximized(RGFW_window* win) { RGFW_UNUSED(win) return 0; } +RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { RGFW_UNUSED(win) return (RGFW_monitor){}; } + +#endif + +/* end of web asm defines */ + +/* unix (macOS, linux, web asm) only stuff */ +#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WEBASM) || defined(RGFW_WAYLAND) +/* unix threading */ #ifndef RGFW_NO_THREADS #include @@ -6086,493 +8927,24 @@ static HMODULE wglinstance = NULL; void RGFW_cancelThread(RGFW_thread thread) { pthread_cancel((pthread_t) thread); } void RGFW_joinThread(RGFW_thread thread) { pthread_join((pthread_t) thread, NULL); } #ifdef __linux__ - void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { pthread_setschedprio(thread, priority); } -#endif -#endif -#endif - - void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { - assert(win != NULL); - -#ifdef RGFW_OPENGL -#ifdef RGFW_X11 - glXMakeCurrent((Display*) win->src.display, (Drawable) win->src.window, (GLXContext) win->src.rSurf); -#endif -#ifdef RGFW_WINDOWS - wglMakeCurrent(win->src.hdc, (HGLRC) win->src.rSurf); -#endif -#if defined(RGFW_MACOS) - objc_msgSend_void(win->src.rSurf, sel_registerName("makeCurrentContext")); -#endif -#else -#ifdef RGFW_EGL - eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context); + void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { pthread_setschedprio((pthread_t)thread, priority); } #endif #endif - } - - void RGFW_window_makeCurrent(RGFW_window* win) { - assert(win != NULL); - -#if defined(RGFW_WINDOWS) && defined(RGFW_DIRECTX) - RGFW_dxInfo.pDeviceContext->lpVtbl->OMSetRenderTargets(RGFW_dxInfo.pDeviceContext, 1, &win->src.renderTargetView, NULL); -#endif - -#ifdef RGFW_OPENGL - RGFW_window_makeCurrent_OpenGL(win); -#endif - } - - void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { - assert(win != NULL); - -#ifdef RGFW_OPENGL -#ifdef RGFW_X11 - ((PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddress((GLubyte*) "glXSwapIntervalEXT"))((Display*) win->src.display, (Window) win->src.window, swapInterval); -#endif -#ifdef RGFW_WINDOWS - - typedef BOOL(APIENTRY* PFNWGLSWAPINTERVALEXTPROC)(int interval); - static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; - static void* loadSwapFunc = (void*) 1; - - if (loadSwapFunc == NULL) { - fprintf(stderr, "wglSwapIntervalEXT not supported\n"); - win->fpsCap = (swapInterval == 1) ? 0 : swapInterval; - return; - } - - if (wglSwapIntervalEXT == NULL) { - loadSwapFunc = (void*) wglGetProcAddress("wglSwapIntervalEXT"); - wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) loadSwapFunc; - } - - if (wglSwapIntervalEXT(swapInterval) == FALSE) - fprintf(stderr, "Failed to set swap interval\n"); - -#endif -#if defined(RGFW_MACOS) - NSOpenGLContext_setValues(win->src.rSurf, &swapInterval, 222); -#endif -#endif - -#ifdef RGFW_EGL - eglSwapInterval(win->src.EGL_display, swapInterval); -#endif - - win->fpsCap = (swapInterval == 1) ? 0 : swapInterval; - - } - - void RGFW_window_setGPURender(RGFW_window* win, i8 set) { - if (!set && !(win->src.winArgs & RGFW_NO_GPU_RENDER)) - win->src.winArgs |= RGFW_NO_GPU_RENDER; - - else if (set && win->src.winArgs & RGFW_NO_GPU_RENDER) - win->src.winArgs ^= RGFW_NO_GPU_RENDER; - } - - void RGFW_window_setCPURender(RGFW_window* win, i8 set) { - if (!set && !(win->src.winArgs & RGFW_NO_CPU_RENDER)) - win->src.winArgs |= RGFW_NO_CPU_RENDER; - - else if (set && win->src.winArgs & RGFW_NO_CPU_RENDER) - win->src.winArgs ^= RGFW_NO_CPU_RENDER; - } - - - void RGFW_window_swapBuffers(RGFW_window* win) { - assert(win != NULL); - - RGFW_window_makeCurrent(win); - - /* clear the window*/ - - if (!(win->src.winArgs & RGFW_NO_CPU_RENDER)) { -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) -#ifdef RGFW_OSMESA - u8* row = (u8*) RGFW_MALLOC(win->r.w * 3); - - i32 half_height = win->r.h / 2; - i32 stride = win->r.w * 3; - - i32 y; - for (y = 0; y < half_height; ++y) { - i32 top_offset = y * stride; - i32 bottom_offset = (win->r.h - y - 1) * stride; - memcpy(row, win->buffer + top_offset, stride); - memcpy(win->buffer + top_offset, win->buffer + bottom_offset, stride); - memcpy(win->buffer + bottom_offset, row, stride); - } - - RGFW_FREE(row); -#endif - -#ifdef RGFW_X11 - RGFW_area area = RGFW_getScreenSize(); - -#ifndef RGFW_X11_DONT_CONVERT_BGR - win->src.bitmap->data = (char*) win->buffer; - u32 x, y; - for (y = 0; y < (u32)win->r.h; y++) { - for (x = 0; x < (u32)win->r.w; x++) { - u32 index = (y * 4 * area.w) + x * 4; - - u8 red = win->src.bitmap->data[index]; - win->src.bitmap->data[index] = win->buffer[index + 2]; - win->src.bitmap->data[index + 2] = red; - } - } -#endif - - XPutImage(win->src.display, (Window) win->src.window, XDefaultGC(win->src.display, XDefaultScreen(win->src.display)), win->src.bitmap, 0, 0, 0, 0, win->r.w, win->r.h); -#endif -#ifdef RGFW_WINDOWS - HGDIOBJ oldbmp = SelectObject(win->src.hdcMem, win->src.bitmap); - BitBlt(win->src.hdc, 0, 0, win->r.w, win->r.h, win->src.hdcMem, 0, 0, SRCCOPY); - SelectObject(win->src.hdcMem, oldbmp); -#endif -#if defined(RGFW_MACOS) - RGFW_area area = RGFW_getScreenSize(); - void* view = NSWindow_contentView(win->src.window); - void* layer = objc_msgSend_id(view, sel_registerName("layer")); - - ((void(*)(id, SEL, NSRect))objc_msgSend)(layer, - sel_registerName("setFrame:"), - NSMakeRect(0, 0, win->r.w, win->r.h)); - - NSBitmapImageRep* rep = NSBitmapImageRep_initWithBitmapData( - &win->buffer, win->r.w, win->r.h, 8, 4, true, false, - "NSDeviceRGBColorSpace", 0, - area.w * 4, 32 - ); - id image = NSAlloc((id)objc_getClass("NSImage")); - NSImage_addRepresentation(image, rep); - objc_msgSend_void_id(layer, sel_registerName("setContents:"), (id) image); - - release(image); - release(rep); -#endif -#endif - -#ifdef RGFW_VULKAN -#ifdef RGFW_PRINT_ERRORS - fprintf(stderr, "RGFW_window_swapBuffers %s\n", "RGFW_window_swapBuffers is not yet supported for Vulkan"); - RGFW_error = 1; -#endif -#endif - } - - if (!(win->src.winArgs & RGFW_NO_GPU_RENDER)) { - #ifdef RGFW_EGL - eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); - #elif defined(RGFW_OPENGL) - #if defined(RGFW_X11) && defined(RGFW_OPENGL) - glXSwapBuffers((Display*) win->src.display, (Window) win->src.window); - #elif defined(RGFW_WINDOWS) - SwapBuffers(win->src.hdc); - #elif defined(RGFW_MACOS) - NSOpenGLContext_flushBuffer(win->src.rSurf); - #endif - #endif - - #if defined(RGFW_WINDOWS) && defined(RGFW_DIRECTX) - win->src.swapchain->lpVtbl->Present(win->src.swapchain, 0, 0); - #endif - } - - RGFW_window_checkFPS(win); - } - - void RGFW_window_maximize(RGFW_window* win) { - assert(win != NULL); - - RGFW_area screen = RGFW_getScreenSize(); - - RGFW_window_move(win, RGFW_VECTOR(0, 0)); - RGFW_window_resize(win, screen); - } - - u8 RGFW_window_shouldClose(RGFW_window* win) { - assert(win != NULL); - - /* || RGFW_isPressedI(win, RGFW_Escape) */ - return (win->event.type == RGFW_quit || RGFW_isPressedI(win, RGFW_OS_BASED_VALUE(0xff1b, 0x1B, 53))); - } - - void RGFW_window_setShouldClose(RGFW_window* win) { win->event.type = RGFW_quit; } - - void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m) { - RGFW_window_move(win, RGFW_VECTOR(m.rect.x + win->r.x, m.rect.y + win->r.y)); - } - - void RGFW_window_mouseHold(RGFW_window* win) { - win->src.winArgs |= RGFW_HOLD_MOUSE; - - #ifdef RGFW_WINDOWS - RECT rect = {win->r.x, win->r.y, win->r.x + win->r.w, win->r.y + win->r.h}; - ClipCursor(&rect); - #endif - } - - void RGFW_window_mouseUnhold(RGFW_window* win) { - win->src.winArgs ^= RGFW_HOLD_MOUSE; - - #ifdef RGFW_WINDOWS - ClipCursor(NULL); - #endif - } - +#ifndef RGFW_WEBASM +/* unix sleep */ void RGFW_sleep(u64 ms) { -#ifndef RGFW_WINDOWS struct timespec time; time.tv_sec = 0; time.tv_nsec = ms * 1e+6; nanosleep(&time, NULL); -#else - Sleep(ms); -#endif } - - void RGFW_window_checkFPS(RGFW_window* win) { - u64 deltaTime = RGFW_getTimeNS() - win->event.frameTime; - - u64 fps = round(1e+9 / deltaTime); - win->event.fps = fps; - - if (win->fpsCap && fps > win->fpsCap) { - u64 frameTimeNS = 1e+9 / win->fpsCap; - u64 sleepTimeMS = (frameTimeNS - deltaTime) / 1e6; - - if (sleepTimeMS > 0) { - RGFW_sleep(sleepTimeMS); - win->event.frameTime = 0; - } - } - - win->event.frameTime = RGFW_getTimeNS(); - - if (win->fpsCap) { - u64 deltaTime = RGFW_getTimeNS() - win->event.frameTime2; - - win->event.fps = round(1e+9 / deltaTime); - - win->event.frameTime2 = RGFW_getTimeNS(); - } - } - -#ifdef __APPLE__ -#include #endif - u64 RGFW_getTimeNS(void) { -#ifdef RGFW_WINDOWS - LARGE_INTEGER frequency; - QueryPerformanceFrequency(&frequency); - - LARGE_INTEGER counter; - QueryPerformanceCounter(&counter); - - return (u64) (counter.QuadPart * 1e9 / frequency.QuadPart); -#elif defined(__unix__) - struct timespec ts = { 0 }; - clock_gettime(1, &ts); - unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; - - return nanoSeconds; -#elif defined(__APPLE__) - static mach_timebase_info_data_t timebase_info; - if (timebase_info.denom == 0) { - mach_timebase_info(&timebase_info); - } - return mach_absolute_time() * timebase_info.numer / timebase_info.denom; -#endif - return 0; - } - - u64 RGFW_getTime(void) { -#ifdef RGFW_WINDOWS - LARGE_INTEGER frequency; - QueryPerformanceFrequency(&frequency); - - LARGE_INTEGER counter; - QueryPerformanceCounter(&counter); - return (u64) (counter.QuadPart / (double) frequency.QuadPart); -#elif defined(__unix__) - struct timespec ts = { 0 }; - clock_gettime(1, &ts); - unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; - - return (double)(nanoSeconds) * 1e-9; -#elif defined(__APPLE__) - static mach_timebase_info_data_t timebase_info; - if (timebase_info.denom == 0) { - mach_timebase_info(&timebase_info); - } - return (double) mach_absolute_time() * (double) timebase_info.numer / ((double) timebase_info.denom * 1e9); -#endif - return 0; - } - +#endif /* end of unix / mac stuff*/ #endif /*RGFW_IMPLEMENTATION*/ -#define RGFW_Escape RGFW_OS_BASED_VALUE(0xff1b, 0x1B, 53) -#define RGFW_F1 RGFW_OS_BASED_VALUE(0xffbe, 0x70, 127) -#define RGFW_F2 RGFW_OS_BASED_VALUE(0xffbf, 0x71, 121) -#define RGFW_F3 RGFW_OS_BASED_VALUE(0xffc0, 0x72, 100) -#define RGFW_F4 RGFW_OS_BASED_VALUE(0xffc1, 0x73, 119) -#define RGFW_F5 RGFW_OS_BASED_VALUE(0xffc2, 0x74, 97) -#define RGFW_F6 RGFW_OS_BASED_VALUE(0xffc3, 0x75, 98) -#define RGFW_F7 RGFW_OS_BASED_VALUE(0xffc4, 0x76, 99) -#define RGFW_F8 RGFW_OS_BASED_VALUE(0xffc5, 0x77, 101) -#define RGFW_F9 RGFW_OS_BASED_VALUE(0xffc6, 0x78, 102) -#define RGFW_F10 RGFW_OS_BASED_VALUE(0xffc7, 0x79, 110) -#define RGFW_F11 RGFW_OS_BASED_VALUE(0xffc8, 0x7A, 104) -#define RGFW_F12 RGFW_OS_BASED_VALUE(0xffc9, 0x7B, 112) -#define RGFW_F13 RGFW_OS_BASED_VALUE(0xffca, 0x7C, 106) -#define RGFW_F14 RGFW_OS_BASED_VALUE(0xffcb, 0x7D, 108) -#define RGFW_F15 RGFW_OS_BASED_VALUE(0xffcc, 0x7E, 114) - -#define RGFW_Backtick RGFW_OS_BASED_VALUE(96 , 192, 50) - -#define RGFW_0 RGFW_OS_BASED_VALUE(0x0030, 0x30, 29) -#define RGFW_1 RGFW_OS_BASED_VALUE(0x0031, 0x31, 18) -#define RGFW_2 RGFW_OS_BASED_VALUE(0x0032, 0x32, 19) -#define RGFW_3 RGFW_OS_BASED_VALUE(0x0033, 0x33, 20) -#define RGFW_4 RGFW_OS_BASED_VALUE(0x0034, 0x34, 21) -#define RGFW_5 RGFW_OS_BASED_VALUE(0x0035, 0x35, 23) -#define RGFW_6 RGFW_OS_BASED_VALUE(0x0036, 0x36, 22) -#define RGFW_7 RGFW_OS_BASED_VALUE(0x0037, 0x37, 26) -#define RGFW_8 RGFW_OS_BASED_VALUE(0x0038, 0x38, 28) -#define RGFW_9 RGFW_OS_BASED_VALUE(0x0039, 0x39, 25) - -#define RGFW_Minus RGFW_OS_BASED_VALUE(0x002d, 189, 27) -#define RGFW_Equals RGFW_OS_BASED_VALUE(0x003d, 187, 24) -#define RGFW_BackSpace RGFW_OS_BASED_VALUE(0xff08, 8, 51) -#define RGFW_Tab RGFW_OS_BASED_VALUE(0xff89, 0x09, 48) -#define RGFW_CapsLock RGFW_OS_BASED_VALUE(0xffe5, 20, 57) -#define RGFW_ShiftL RGFW_OS_BASED_VALUE(0xffe1, 0xA0, 56) -#define RGFW_ControlL RGFW_OS_BASED_VALUE(0xffe3, 0x11, 59) -#define RGFW_AltL RGFW_OS_BASED_VALUE(0xffe9, 164, 58) -#define RGFW_SuperL RGFW_OS_BASED_VALUE(0xffeb, 0x5B, 55) -#define RGFW_ShiftR RGFW_OS_BASED_VALUE(0xffe2, 0x5C, 56) -#define RGFW_ControlR RGFW_OS_BASED_VALUE(0xffe4, 0x11, 59) -#define RGFW_AltR RGFW_OS_BASED_VALUE(0xffea, 165, 58) -#define RGFW_SuperR RGFW_OS_BASED_VALUE(0xffec, 0xA4, 55) -#define RGFW_Space RGFW_OS_BASED_VALUE(0x0020, 0x20, 49) - -#define RGFW_A RGFW_OS_BASED_VALUE(0x0041, 0x41, 0) -#define RGFW_B RGFW_OS_BASED_VALUE(0x0042, 0x42, 11) -#define RGFW_C RGFW_OS_BASED_VALUE(0x0043, 0x43, 8) -#define RGFW_D RGFW_OS_BASED_VALUE(0x0044, 0x44, 2) -#define RGFW_E RGFW_OS_BASED_VALUE(0x0045, 0x45, 14) -#define RGFW_F RGFW_OS_BASED_VALUE(0x0046, 0x46, 3) -#define RGFW_G RGFW_OS_BASED_VALUE(0x0047, 0x47, 5) -#define RGFW_H RGFW_OS_BASED_VALUE(0x0048, 0x48, 4) -#define RGFW_I RGFW_OS_BASED_VALUE(0x0049, 0x49, 34) -#define RGFW_J RGFW_OS_BASED_VALUE(0x004a, 0x4A, 38) -#define RGFW_K RGFW_OS_BASED_VALUE(0x004b, 0x4B, 40) -#define RGFW_L RGFW_OS_BASED_VALUE(0x004c, 0x4C, 37) -#define RGFW_M RGFW_OS_BASED_VALUE(0x004d, 0x4D, 46) -#define RGFW_N RGFW_OS_BASED_VALUE(0x004e, 0x4E, 45) -#define RGFW_O RGFW_OS_BASED_VALUE(0x004f, 0x4F, 31) -#define RGFW_P RGFW_OS_BASED_VALUE(0x0050, 0x50, 35) -#define RGFW_Q RGFW_OS_BASED_VALUE(0x0051, 0x51, 12) -#define RGFW_R RGFW_OS_BASED_VALUE(0x0052, 0x52, 15) -#define RGFW_S RGFW_OS_BASED_VALUE(0x0053, 0x53, 1) -#define RGFW_T RGFW_OS_BASED_VALUE(0x0054, 0x54, 17) -#define RGFW_U RGFW_OS_BASED_VALUE(0x0055, 0x55, 32) -#define RGFW_V RGFW_OS_BASED_VALUE(0x0056, 0x56, 9) -#define RGFW_W RGFW_OS_BASED_VALUE(0x0057, 0x57, 13) -#define RGFW_X RGFW_OS_BASED_VALUE(0x0058, 0x58, 7) -#define RGFW_Y RGFW_OS_BASED_VALUE(0x0059, 0x59, 16) -#define RGFW_Z RGFW_OS_BASED_VALUE(0x005a, 0x5A, 6) - -#define RGFW_a RGFW_OS_BASED_VALUE(0x0061, 0x41, 0) -#define RGFW_b RGFW_OS_BASED_VALUE(0x0062, 0x42, 11) -#define RGFW_c RGFW_OS_BASED_VALUE(0x0063, 0x43, 8) -#define RGFW_d RGFW_OS_BASED_VALUE(0x0064, 0x44, 2) -#define RGFW_e RGFW_OS_BASED_VALUE(0x0065, 0x45, 14) -#define RGFW_f RGFW_OS_BASED_VALUE(0x0066, 0x46, 3) -#define RGFW_g RGFW_OS_BASED_VALUE(0x0067, 0x47, 5) -#define RGFW_h RGFW_OS_BASED_VALUE(0x0068, 0x48, 4) -#define RGFW_i RGFW_OS_BASED_VALUE(0x0069, 0x49, 34) -#define RGFW_j RGFW_OS_BASED_VALUE(0x006a, 0x4a, 38) -#define RGFW_k RGFW_OS_BASED_VALUE(0x006b, 0x4b, 40) -#define RGFW_l RGFW_OS_BASED_VALUE(0x006c, 0x4c, 37) -#define RGFW_m RGFW_OS_BASED_VALUE(0x006d, 0x4d, 46) -#define RGFW_n RGFW_OS_BASED_VALUE(0x006e, 0x4e, 45) -#define RGFW_o RGFW_OS_BASED_VALUE(0x006f, 0x4f, 31) -#define RGFW_p RGFW_OS_BASED_VALUE(0x0070, 0x50, 35) -#define RGFW_q RGFW_OS_BASED_VALUE(0x0071, 0x51, 12) -#define RGFW_r RGFW_OS_BASED_VALUE(0x0072, 0x52, 15) -#define RGFW_s RGFW_OS_BASED_VALUE(0x0073, 0x53, 1) -#define RGFW_t RGFW_OS_BASED_VALUE(0x0074, 0x54, 17) -#define RGFW_u RGFW_OS_BASED_VALUE(0x0075, 0x55, 32) -#define RGFW_v RGFW_OS_BASED_VALUE(0x0076, 0x56, 9) -#define RGFW_w RGFW_OS_BASED_VALUE(0x0077, 0x57, 13) -#define RGFW_x RGFW_OS_BASED_VALUE(0x0078, 0x58, 7) -#define RGFW_y RGFW_OS_BASED_VALUE(0x0079, 0x59, 16) -#define RGFW_z RGFW_OS_BASED_VALUE(0x007a, 0x5A, 6) - -#define RGFW_Period RGFW_OS_BASED_VALUE(0x002e, 190, 47) -#define RGFW_Comma RGFW_OS_BASED_VALUE(0x002c, 188, 43) -#define RGFW_Slash RGFW_OS_BASED_VALUE(0x002f, 191, 44) -#define RGFW_Bracket RGFW_OS_BASED_VALUE(0x005b, 219, 33) -#define RGFW_CloseBracket RGFW_OS_BASED_VALUE(0x005d, 221, 30) -#define RGFW_Semicolon RGFW_OS_BASED_VALUE(0x003b, 186, 41) -#define RGFW_Return RGFW_OS_BASED_VALUE(0xff0d, 0x0D, 36) -#define RGFW_Quote RGFW_OS_BASED_VALUE(0x0022, 222, 39) -#define RGFW_BackSlash RGFW_OS_BASED_VALUE(0x005c, 322, 42) - -#define RGFW_Up RGFW_OS_BASED_VALUE(0xff52, 0x26, 126) -#define RGFW_Down RGFW_OS_BASED_VALUE(0xff54, 0x28, 125) -#define RGFW_Left RGFW_OS_BASED_VALUE(0xff51, 0x25, 123) -#define RGFW_Right RGFW_OS_BASED_VALUE(0xff53, 0x27, 124) - -#define RGFW_Delete RGFW_OS_BASED_VALUE(0xffff, 0x2E, 118) -#define RGFW_Insert RGFW_OS_BASED_VALUE(0xff63, 0x2D, 115) -#define RGFW_End RGFW_OS_BASED_VALUE(0xff57, 0x23, 120) -#define RGFW_Home RGFW_OS_BASED_VALUE(0xff50, 0x24, 116) -#define RGFW_PageUp RGFW_OS_BASED_VALUE(0xff55, 336, 117) -#define RGFW_PageDown RGFW_OS_BASED_VALUE(0xff56, 325, 122) - -#define RGFW_Numlock RGFW_OS_BASED_VALUE(0xff7f, 0x90, 72) -#define RGFW_KP_Slash RGFW_OS_BASED_VALUE(0xffaf, 0x6F, 82) -#define RGFW_Multiply RGFW_OS_BASED_VALUE(0xffaa, 0x6A, 76) -#define RGFW_KP_Minus RGFW_OS_BASED_VALUE(0xffad, 0x6D, 67) -#define RGFW_KP_1 RGFW_OS_BASED_VALUE(0xffb1, 0x61, 84) -#define RGFW_KP_2 RGFW_OS_BASED_VALUE(0xffb2, 0x62, 85) -#define RGFW_KP_3 RGFW_OS_BASED_VALUE(0xffb3, 0x63, 86) -#define RGFW_KP_4 RGFW_OS_BASED_VALUE(0xffb4, 0x64, 87) -#define RGFW_KP_5 RGFW_OS_BASED_VALUE(0xffb5, 0x65, 88) -#define RGFW_KP_6 RGFW_OS_BASED_VALUE(0xffb6, 0x66, 89) -#define RGFW_KP_7 RGFW_OS_BASED_VALUE(0xffb7, 0x67, 90) -#define RGFW_KP_8 RGFW_OS_BASED_VALUE(0xffb8, 0x68, 92) -#define RGFW_KP_9 RGFW_OS_BASED_VALUE(0xffb9, 0x619, 93) -#define RGFW_KP_0 RGFW_OS_BASED_VALUE(0xffb0, 0x60, 83) -#define RGFW_KP_Period RGFW_OS_BASED_VALUE(0xffae, 0x6E, 65) -#define RGFW_KP_Return RGFW_OS_BASED_VALUE(0xff8d, 0x92, 77) - -#ifdef __APPLE__ - void* NSCursor_arrowStr(char* str); - void NSCursor_performSelector(void* cursor, void* selector); -#endif - - /* mouse icons */ -#define RGFW_MOUSE_ARROW RGFW_OS_BASED_VALUE(68, 32512, NSCursor_arrowStr("arrowCursor")) -#define RGFW_MOUSE_IBEAM RGFW_OS_BASED_VALUE(152, 32513, NSCursor_arrowStr("IBeamCursor")) -#define RGFW_MOUSE_CROSSHAIR RGFW_OS_BASED_VALUE(34, 32515, NSCursor_arrowStr("crosshairCursor")) -#define RGFW_MOUSE_POINTING_HAND RGFW_OS_BASED_VALUE(60, 32649, NSCursor_arrowStr("pointingHandCursor")) -#define RGFW_MOUSE_RESIZE_EW RGFW_OS_BASED_VALUE(108, 32644, NSCursor_arrowStr("resizeLeftRightCursor")) -#define RGFW_MOUSE_RESIZE_NS RGFW_OS_BASED_VALUE(116, 32645, NSCursor_arrowStr("resizeUpDownCursor")) -#define RGFW_MOUSE_RESIZE_ALL RGFW_OS_BASED_VALUE(52, 32646, NSCursor_arrowStr("closedHandCursor")) -#define RGFW_MOUSE_RESIZE_NWSE RGFW_OS_BASED_VALUE(12, 32642, NSCursor_performSelector(selector("_windowResizeNorthWestSouthEastCursor"))) -#define RGFW_MOUSE_RESIZE_NESW RGFW_OS_BASED_VALUE(14, 32643, NSCursor_performSelector(selector("_windowResizeNorthEastSouthWestCursor"))) -#define RGFW_MOUSE_NOT_ALLOWED RGFW_OS_BASED_VALUE(0, 32648, NSCursor_arrowStr("operationNotAllowedCursor")) - -#ifdef __cplusplus +#if defined(__cplusplus) && !defined(__EMSCRIPTEN__) } #endif diff --git a/src/external/glfw/src/mappings.h b/src/external/glfw/src/mappings.h index 270fa4cd8..7b0f35a26 100644 --- a/src/external/glfw/src/mappings.h +++ b/src/external/glfw/src/mappings.h @@ -996,6 +996,7 @@ const char* _glfwDefaultMappings[] = "03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,", "03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", "03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"03000000af1e00002400000010010000,Clockwork Pi DevTerm,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b9,x:b3,y:b0,platform:Linux,", #endif // GLFW_BUILD_LINUX_JOYSTICK }; diff --git a/src/external/jar_xm.h b/src/external/jar_xm.h index 4a1bfbf67..b5e80e48a 100644 --- a/src/external/jar_xm.h +++ b/src/external/jar_xm.h @@ -1204,7 +1204,7 @@ static void jar_xm_tone_portamento(jar_xm_context_t* ctx, jar_xm_channel_context } static void jar_xm_pitch_slide(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch, float period_offset) { - /* Don't ask about the 4.f coefficient. I found mention of it nowhere. Found by ear™. */ + /* Don't ask about the 4.f coefficient. I found mention of it nowhere. Found by ear. */ if(ctx->module.frequency_type == jar_xm_LINEAR_FREQUENCIES) {period_offset *= 4.f; } ch->period += period_offset; jar_xm_CLAMP_DOWN(ch->period); @@ -1507,7 +1507,7 @@ static void jar_xm_handle_note_and_instrument(jar_xm_context_t* ctx, jar_xm_chan jar_xm_volume_slide(ch, ch->fine_volume_slide_param); break; case 0xD: /* EDy: Note delay */ - /* XXX: figure this out better. EDx triggers the note even when there no note and no instrument. But ED0 acts like like a ghost note, EDx (x ≠ 0) does not. */ + /* XXX: figure this out better. EDx triggers the note even when there no note and no instrument. But ED0 acts like like a ghost note, EDx (x != 0) does not. */ if(s->note == 0 && s->instrument == 0) { unsigned int flags = jar_xm_TRIGGER_KEEP_VOLUME; if(ch->current->effect_param & 0x0F) { @@ -1795,7 +1795,7 @@ static void jar_xm_tick(jar_xm_context_t* ctx) { if(ch->current->effect_param > 0) { char arp_offset = ctx->tempo % 3; switch(arp_offset) { - case 2: /* 0 -> x -> 0 -> y -> x -> … */ + case 2: /* 0 -> x -> 0 -> y -> x -> ... */ if(ctx->current_tick == 1) { ch->arp_in_progress = true; ch->arp_note_offset = ch->current->effect_param >> 4; @@ -1803,7 +1803,7 @@ static void jar_xm_tick(jar_xm_context_t* ctx) { break; } /* No break here, this is intended */ - case 1: /* 0 -> 0 -> y -> x -> … */ + case 1: /* 0 -> 0 -> y -> x -> ... */ if(ctx->current_tick == 0) { ch->arp_in_progress = false; ch->arp_note_offset = 0; @@ -1811,7 +1811,7 @@ static void jar_xm_tick(jar_xm_context_t* ctx) { break; } /* No break here, this is intended */ - case 0: /* 0 -> y -> x -> … */ + case 0: /* 0 -> y -> x -> ... */ jar_xm_arpeggio(ctx, ch, ch->current->effect_param, ctx->current_tick - arp_offset); default: break; diff --git a/src/external/miniaudio.h b/src/external/miniaudio.h index 47332e11a..ad113337e 100644 --- a/src/external/miniaudio.h +++ b/src/external/miniaudio.h @@ -21473,7 +21473,9 @@ static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device MA_ASSERT(pContext != NULL); MA_ASSERT(ppMMDevice != NULL); + ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); hr = ma_CoCreateInstance(pContext, &MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); + ma_CoUninitialize(pContext); if (FAILED(hr)) { ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create IMMDeviceEnumerator.\n"); return ma_result_from_HRESULT(hr); @@ -36076,9 +36078,15 @@ static ma_result ma_context_get_device_info_from_fd__audio4(ma_context* pContext ma_uint32 channels; ma_uint32 sampleRate; +#ifdef __NetBSD__ + if (ioctl(fd, AUDIO_GETFORMAT, &fdInfo) < 0) { + return MA_ERROR; + } +#else if (ioctl(fd, AUDIO_GETINFO, &fdInfo) < 0) { return MA_ERROR; } +#endif if (deviceType == ma_device_type_playback) { channels = fdInfo.play.channels; @@ -36356,7 +36364,11 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c /* We're using a default device. Get the info from the /dev/audioctl file instead of /dev/audio. */ int fdctl = open(pDefaultDeviceCtlNames[iDefaultDevice], fdFlags, 0); if (fdctl != -1) { +#ifdef __NetBSD__ + fdInfoResult = ioctl(fdctl, AUDIO_GETFORMAT, &fdInfo); +#else fdInfoResult = ioctl(fdctl, AUDIO_GETINFO, &fdInfo); +#endif close(fdctl); } } diff --git a/src/external/par_shapes.h b/src/external/par_shapes.h index 994a605a9..d5309137b 100644 --- a/src/external/par_shapes.h +++ b/src/external/par_shapes.h @@ -1130,7 +1130,7 @@ static par_shapes__rule* par_shapes__pick_rule(const char* name, total += rule->weight; } } - float r = (float) rand() / RAND_MAX; + float r = (float) rand() / (float) RAND_MAX; float t = 0; for (int i = 0; i < nrules; i++) { rule = rules + i; diff --git a/src/external/rl_gputex.h b/src/external/rl_gputex.h index c57730552..6b26d1c8d 100644 --- a/src/external/rl_gputex.h +++ b/src/external/rl_gputex.h @@ -171,6 +171,10 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ *width = header->width; *height = header->height; + + if (*width % 4 != 0) LOG("WARNING: IMAGE: DDS file width must be multiple of 4. Image will not display correctly"); + if (*height % 4 != 0) LOG("WARNING: IMAGE: DDS file height must be multiple of 4. Image will not display correctly"); + image_pixel_size = header->width*header->height; if (header->mipmap_count == 0) *mips = 1; // Parameter not used diff --git a/src/external/stb_image_resize2.h b/src/external/stb_image_resize2.h index e0c428246..ae8d730bf 100644 --- a/src/external/stb_image_resize2.h +++ b/src/external/stb_image_resize2.h @@ -1,9 +1,9 @@ -/* stb_image_resize2 - v2.01 - public domain image resizing - - by Jeff Roberts (v2) and Jorge L Rodriguez +/* stb_image_resize2 - v2.10 - public domain image resizing + + by Jeff Roberts (v2) and Jorge L Rodriguez http://github.com/nothings/stb - Can be threaded with the extended API. SSE2, AVX, Neon and WASM SIMD support. Only + Can be threaded with the extended API. SSE2, AVX, Neon and WASM SIMD support. Only scaling and translation is supported, no rotations or shears. COMPILING & LINKING @@ -67,60 +67,60 @@ ADDITIONAL DOCUMENTATION MEMORY ALLOCATION - By default, we use malloc and free for memory allocation. To override the + By default, we use malloc and free for memory allocation. To override the memory allocation, before the implementation #include, add a: #define STBIR_MALLOC(size,user_data) ... #define STBIR_FREE(ptr,user_data) ... - Each resize makes exactly one call to malloc/free (unless you use the + Each resize makes exactly one call to malloc/free (unless you use the extended API where you can do one allocation for many resizes). Under address sanitizer, we do separate allocations to find overread/writes. PERFORMANCE This library was written with an emphasis on performance. When testing - stb_image_resize with RGBA, the fastest mode is STBIR_4CHANNEL with + stb_image_resize with RGBA, the fastest mode is STBIR_4CHANNEL with STBIR_TYPE_UINT8 pixels and CLAMPed edges (which is what many other resize - libs do by default). Also, make sure SIMD is turned on of course (default + libs do by default). Also, make sure SIMD is turned on of course (default for 64-bit targets). Avoid WRAP edge mode if you want the fastest speed. This library also comes with profiling built-in. If you define STBIR_PROFILE, - you can use the advanced API and get low-level profiling information by + you can use the advanced API and get low-level profiling information by calling stbir_resize_extended_profile_info() or stbir_resize_split_profile_info() after a resize. SIMD - Most of the routines have optimized SSE2, AVX, NEON and WASM versions. + Most of the routines have optimized SSE2, AVX, NEON and WASM versions. - On Microsoft compilers, we automatically turn on SIMD for 64-bit x64 and - ARM; for 32-bit x86 and ARM, you select SIMD mode by defining STBIR_SSE2 or + On Microsoft compilers, we automatically turn on SIMD for 64-bit x64 and + ARM; for 32-bit x86 and ARM, you select SIMD mode by defining STBIR_SSE2 or STBIR_NEON. For AVX and AVX2, we auto-select it by detecting the /arch:AVX - or /arch:AVX2 switches. You can also always manually turn SSE2, AVX or AVX2 + or /arch:AVX2 switches. You can also always manually turn SSE2, AVX or AVX2 support on by defining STBIR_SSE2, STBIR_AVX or STBIR_AVX2. On Linux, SSE2 and Neon is on by default for 64-bit x64 or ARM64. For 32-bit, we select x86 SIMD mode by whether you have -msse2, -mavx or -mavx2 enabled on the command line. For 32-bit ARM, you must pass -mfpu=neon-vfpv4 for both - clang and GCC, but GCC also requires an additional -mfp16-format=ieee to + clang and GCC, but GCC also requires an additional -mfp16-format=ieee to automatically enable NEON. On x86 platforms, you can also define STBIR_FP16C to turn on FP16C instructions for converting back and forth to half-floats. This is autoselected when we - are using AVX2. Clang and GCC also require the -mf16c switch. ARM always uses - the built-in half float hardware NEON instructions. + are using AVX2. Clang and GCC also require the -mf16c switch. ARM always uses + the built-in half float hardware NEON instructions. - You can also tell us to use multiply-add instructions with STBIR_USE_FMA. + You can also tell us to use multiply-add instructions with STBIR_USE_FMA. Because x86 doesn't always have fma, we turn it off by default to maintain determinism across all platforms. If you don't care about non-FMA determinism - and are willing to restrict yourself to more recent x86 CPUs (around the AVX + and are willing to restrict yourself to more recent x86 CPUs (around the AVX timeframe), then fma will give you around a 15% speedup. You can force off SIMD in all cases by defining STBIR_NO_SIMD. You can turn off AVX or AVX2 specifically with STBIR_NO_AVX or STBIR_NO_AVX2. AVX is 10% to 40% faster, and AVX2 is generally another 12%. - + ALPHA CHANNEL - Most of the resizing functions provide the ability to control how the alpha + Most of the resizing functions provide the ability to control how the alpha channel of an image is processed. When alpha represents transparency, it is important that when combining @@ -167,33 +167,33 @@ stb_image_resize expects case #1 by default, applying alpha weighting to images, expecting the input images to be unpremultiplied. This is what the - COLOR+ALPHA buffer types tell the resizer to do. + COLOR+ALPHA buffer types tell the resizer to do. - When you use the pixel layouts STBIR_RGBA, STBIR_BGRA, STBIR_ARGB, - STBIR_ABGR, STBIR_RX, or STBIR_XR you are telling us that the pixels are - non-premultiplied. In these cases, the resizer will alpha weight the colors - (effectively creating the premultiplied image), do the filtering, and then + When you use the pixel layouts STBIR_RGBA, STBIR_BGRA, STBIR_ARGB, + STBIR_ABGR, STBIR_RX, or STBIR_XR you are telling us that the pixels are + non-premultiplied. In these cases, the resizer will alpha weight the colors + (effectively creating the premultiplied image), do the filtering, and then convert back to non-premult on exit. When you use the pixel layouts STBIR_RGBA_PM, STBIR_RGBA_PM, STBIR_RGBA_PM, - STBIR_RGBA_PM, STBIR_RX_PM or STBIR_XR_PM, you are telling that the pixels - ARE premultiplied. In this case, the resizer doesn't have to do the - premultipling - it can filter directly on the input. This about twice as - fast as the non-premultiplied case, so it's the right option if your data is + STBIR_RGBA_PM, STBIR_RX_PM or STBIR_XR_PM, you are telling that the pixels + ARE premultiplied. In this case, the resizer doesn't have to do the + premultipling - it can filter directly on the input. This about twice as + fast as the non-premultiplied case, so it's the right option if your data is already setup correctly. - When you use the pixel layout STBIR_4CHANNEL or STBIR_2CHANNEL, you are - telling us that there is no channel that represents transparency; it may be - RGB and some unrelated fourth channel that has been stored in the alpha - channel, but it is actually not alpha. No special processing will be - performed. + When you use the pixel layout STBIR_4CHANNEL or STBIR_2CHANNEL, you are + telling us that there is no channel that represents transparency; it may be + RGB and some unrelated fourth channel that has been stored in the alpha + channel, but it is actually not alpha. No special processing will be + performed. - The difference between the generic 4 or 2 channel layouts, and the + The difference between the generic 4 or 2 channel layouts, and the specialized _PM versions is with the _PM versions you are telling us that the data *is* alpha, just don't premultiply it. That's important when using SRGB pixel formats, we need to know where the alpha is, because it is converted linearly (rather than with the SRGB converters). - + Because alpha weighting produces the same effect as premultiplying, you even have the option with non-premultiplied inputs to let the resizer produce a premultiplied output. Because the intially computed alpha-weighted @@ -201,10 +201,10 @@ than the normal path which un-premultiplies the output image as a final step. Finally, when converting both in and out of non-premulitplied space (for - example, when using STBIR_RGBA), we go to somewhat heroic measures to - ensure that areas with zero alpha value pixels get something reasonable - in the RGB values. If you don't care about the RGB values of zero alpha - pixels, you can call the stbir_set_non_pm_alpha_speed_over_quality() + example, when using STBIR_RGBA), we go to somewhat heroic measures to + ensure that areas with zero alpha value pixels get something reasonable + in the RGB values. If you don't care about the RGB values of zero alpha + pixels, you can call the stbir_set_non_pm_alpha_speed_over_quality() function - this runs a premultiplied resize about 25% faster. That said, when you really care about speed, using premultiplied pixels for both in and out (STBIR_RGBA_PM, etc) much faster than both of these premultiplied @@ -218,38 +218,38 @@ layouts with the same number of channels. DETERMINISM - We commit to being deterministic (from x64 to ARM to scalar to SIMD, etc). - This requires compiling with fast-math off (using at least /fp:precise). + We commit to being deterministic (from x64 to ARM to scalar to SIMD, etc). + This requires compiling with fast-math off (using at least /fp:precise). Also, you must turn off fp-contracting (which turns mult+adds into fmas)! - We attempt to do this with pragmas, but with Clang, you usually want to add + We attempt to do this with pragmas, but with Clang, you usually want to add -ffp-contract=off to the command line as well. - For 32-bit x86, you must use SSE and SSE2 codegen for determinism. That is, - if the scalar x87 unit gets used at all, we immediately lose determinism. + For 32-bit x86, you must use SSE and SSE2 codegen for determinism. That is, + if the scalar x87 unit gets used at all, we immediately lose determinism. On Microsoft Visual Studio 2008 and earlier, from what we can tell there is - no way to be deterministic in 32-bit x86 (some x87 always leaks in, even - with fp:strict). On 32-bit x86 GCC, determinism requires both -msse2 and + no way to be deterministic in 32-bit x86 (some x87 always leaks in, even + with fp:strict). On 32-bit x86 GCC, determinism requires both -msse2 and -fpmath=sse. Note that we will not be deterministic with float data containing NaNs - - the NaNs will propagate differently on different SIMD and platforms. + the NaNs will propagate differently on different SIMD and platforms. - If you turn on STBIR_USE_FMA, then we will be deterministic with other - fma targets, but we will differ from non-fma targets (this is unavoidable, - because a fma isn't simply an add with a mult - it also introduces a - rounding difference compared to non-fma instruction sequences. + If you turn on STBIR_USE_FMA, then we will be deterministic with other + fma targets, but we will differ from non-fma targets (this is unavoidable, + because a fma isn't simply an add with a mult - it also introduces a + rounding difference compared to non-fma instruction sequences. FLOAT PIXEL FORMAT RANGE - Any range of values can be used for the non-alpha float data that you pass - in (0 to 1, -1 to 1, whatever). However, if you are inputting float values - but *outputting* bytes or shorts, you must use a range of 0 to 1 so that we - scale back properly. The alpha channel must also be 0 to 1 for any format - that does premultiplication prior to resizing. + Any range of values can be used for the non-alpha float data that you pass + in (0 to 1, -1 to 1, whatever). However, if you are inputting float values + but *outputting* bytes or shorts, you must use a range of 0 to 1 so that we + scale back properly. The alpha channel must also be 0 to 1 for any format + that does premultiplication prior to resizing. - Note also that with float output, using filters with negative lobes, the - output filtered values might go slightly out of range. You can define - STBIR_FLOAT_LOW_CLAMP and/or STBIR_FLOAT_HIGH_CLAMP to specify the range - to clamp to on output, if that's important. + Note also that with float output, using filters with negative lobes, the + output filtered values might go slightly out of range. You can define + STBIR_FLOAT_LOW_CLAMP and/or STBIR_FLOAT_HIGH_CLAMP to specify the range + to clamp to on output, if that's important. MAX/MIN SCALE FACTORS The input pixel resolutions are in integers, and we do the internal pointer @@ -263,13 +263,13 @@ buffers). FLIPPED IMAGES - Stride is just the delta from one scanline to the next. This means you can - use a negative stride to handle inverted images (point to the final + Stride is just the delta from one scanline to the next. This means you can + use a negative stride to handle inverted images (point to the final scanline and use a negative stride). You can invert the input or output, using negative strides. DEFAULT FILTERS - For functions which don't provide explicit control over what filters to + For functions which don't provide explicit control over what filters to use, you can change the compile-time defaults with: #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something @@ -278,18 +278,18 @@ See stbir_filter in the header-file section for the list of filters. NEW FILTERS - A number of 1D filter kernels are supplied. For a list of supported - filters, see the stbir_filter enum. You can install your own filters by + A number of 1D filter kernels are supplied. For a list of supported + filters, see the stbir_filter enum. You can install your own filters by using the stbir_set_filter_callbacks function. PROGRESS - For interactive use with slow resize operations, you can use the the - scanline callbacks in the extended API. It would have to be a *very* large + For interactive use with slow resize operations, you can use the the + scanline callbacks in the extended API. It would have to be a *very* large image resample to need progress though - we're very fast. CEIL and FLOOR - In scalar mode, the only functions we use from math.h are ceilf and floorf, - but if you have your own versions, you can define the STBIR_CEILF(v) and + In scalar mode, the only functions we use from math.h are ceilf and floorf, + but if you have your own versions, you can define the STBIR_CEILF(v) and STBIR_FLOORF(v) macros and we'll use them instead. In SIMD, we just use our own versions. @@ -304,7 +304,7 @@ * For SIMD encode and decode scanline routines, do any pre-aligning for bad input/output buffer alignments and pitch? * For very wide scanlines, we should we do vertical strips to stay within - L2 cache. Maybe do chunks of 1K pixels at a time. There would be + L2 cache. Maybe do chunks of 1K pixels at a time. There would be some pixel reconversion, but probably dwarfed by things falling out of cache. Probably also something possible with alternating between scattering and gathering at high resize scales? @@ -316,21 +316,38 @@ the pivot cost and the extra memory touches). Need to buffer the whole image so have to balance memory use. * Most of our code is internally function pointers, should we compile - all the SIMD stuff always and dynamically dispatch? + all the SIMD stuff always and dynamically dispatch? CONTRIBUTORS Jeff Roberts: 2.0 implementation, optimizations, SIMD - Martins Mozeiko: NEON simd, WASM simd, clang and GCC whisperer. + Martins Mozeiko: NEON simd, WASM simd, clang and GCC whisperer Fabian Giesen: half float and srgb converters Sean Barrett: API design, optimizations Jorge L Rodriguez: Original 1.0 implementation - Aras Pranckevicius: bugfixes for 1.0 + Aras Pranckevicius: bugfixes Nathan Reed: warning fixes for 1.0 REVISIONS - 2.00 (2022-02-20) mostly new source: new api, optimizations, simd, vertical-first, etc - (2x-5x faster without simd, 4x-12x faster with simd) - (in some cases, 20x to 40x faster - resizing to very small for example) + 2.10 (2024-07-27) fix the defines GCC and mingw for loop unroll control, + fix MSVC 32-bit arm half float routines. + 2.09 (2024-06-19) fix the defines for 32-bit ARM GCC builds (was selecting + hardware half floats). + 2.08 (2024-06-10) fix for RGB->BGR three channel flips and add SIMD (thanks + to Ryan Salsbury), fix for sub-rect resizes, use the + pragmas to control unrolling when they are available. + 2.07 (2024-05-24) fix for slow final split during threaded conversions of very + wide scanlines when downsampling (caused by extra input + converting), fix for wide scanline resamples with many + splits (int overflow), fix GCC warning. + 2.06 (2024-02-10) fix for identical width/height 3x or more down-scaling + undersampling a single row on rare resize ratios (about 1%). + 2.05 (2024-02-07) fix for 2 pixel to 1 pixel resizes with wrap (thanks Aras), + fix for output callback (thanks Julien Koenen). + 2.04 (2023-11-17) fix for rare AVX bug, shadowed symbol (thanks Nikola Smiljanic). + 2.03 (2023-11-01) ASAN and TSAN warnings fixed, minor tweaks. + 2.00 (2023-10-10) mostly new source: new api, optimizations, simd, vertical-first, etc + 2x-5x faster without simd, 4x-12x faster with simd, + in some cases, 20x to 40x faster esp resizing large to very small. 0.96 (2019-03-04) fixed warnings 0.95 (2017-07-23) fixed warnings 0.94 (2017-03-18) fixed warnings @@ -368,7 +385,7 @@ typedef uint64_t stbir_uint64; #define STBIR_SSE #endif #endif -#endif +#endif #if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(_M_AMD64) || defined(__SSE2__) || defined(STBIR_SSE) || defined(STBIR_SSE2) #ifndef STBIR_SSE2 @@ -383,7 +400,7 @@ typedef uint64_t stbir_uint64; #endif #if defined(__AVX2__) || defined(STBIR_AVX2) #ifndef STBIR_NO_AVX2 - #ifndef STBIR_AVX2 + #ifndef STBIR_AVX2 #define STBIR_AVX2 #endif #if defined( _MSC_VER ) && !defined(__clang__) @@ -400,15 +417,15 @@ typedef uint64_t stbir_uint64; #endif #endif -#if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(_M_ARM) || (__ARM_NEON_FP & 4) != 0 && __ARM_FP16_FORMAT_IEEE != 0 +#if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || ((__ARM_NEON_FP & 4) != 0) || defined(__ARM_NEON__) #ifndef STBIR_NEON #define STBIR_NEON #endif #endif -#if defined(_M_ARM) +#if defined(_M_ARM) || defined(__arm__) #ifdef STBIR_USE_FMA -#undef STBIR_USE_FMA // no FMA for 32-bit arm on MSVC +#undef STBIR_USE_FMA // no FMA for 32-bit arm on MSVC #endif #endif @@ -435,7 +452,7 @@ typedef uint64_t stbir_uint64; // // Easy-to-use API: // -// * stride is the offset between successive rows of image data +// * stride is the offset between successive rows of image data // in memory, in bytes. specify 0 for packed continuously in memory // * colorspace is linear or sRGB as specified by function name // * Uses the default filters @@ -448,27 +465,35 @@ typedef uint64_t stbir_uint64; // order of channels // whether color is premultiplied by alpha // for back compatibility, you can cast the old channel count to an stbir_pixel_layout -typedef enum +typedef enum { - STBIR_BGR = 0, // 3-chan, with order specified (for channel flipping) - STBIR_1CHANNEL = 1, + STBIR_1CHANNEL = 1, STBIR_2CHANNEL = 2, - STBIR_RGB = 3, // 3-chan, with order specified (for channel flipping) - STBIR_RGBA = 4, // alpha formats, alpha is NOT premultiplied into color channels - + STBIR_RGB = 3, // 3-chan, with order specified (for channel flipping) + STBIR_BGR = 0, // 3-chan, with order specified (for channel flipping) STBIR_4CHANNEL = 5, + + STBIR_RGBA = 4, // alpha formats, where alpha is NOT premultiplied into color channels STBIR_BGRA = 6, STBIR_ARGB = 7, STBIR_ABGR = 8, STBIR_RA = 9, STBIR_AR = 10, - STBIR_RGBA_PM = 11, // alpha formats, alpha is premultiplied into color channels + STBIR_RGBA_PM = 11, // alpha formats, where alpha is premultiplied into color channels STBIR_BGRA_PM = 12, STBIR_ARGB_PM = 13, STBIR_ABGR_PM = 14, STBIR_RA_PM = 15, STBIR_AR_PM = 16, + + STBIR_RGBA_NO_AW = 11, // alpha formats, where NO alpha weighting is applied at all! + STBIR_BGRA_NO_AW = 12, // these are just synonyms for the _PM flags (which also do + STBIR_ARGB_NO_AW = 13, // no alpha weighting). These names just make it more clear + STBIR_ABGR_NO_AW = 14, // for some folks). + STBIR_RA_NO_AW = 15, + STBIR_AR_NO_AW = 16, + } stbir_pixel_layout; //=============================================================== @@ -549,8 +574,8 @@ STBIRDEF void * stbir_resize( const void *input_pixels , int input_w , int inpu // * Separate input and output data types // * Can specify regions with subpixel correctness // * Can specify alpha flags -// * Can specify a memory callback -// * Can specify a callback data type for pixel input and output +// * Can specify a memory callback +// * Can specify a callback data type for pixel input and output // * Can be threaded for a single resize // * Can be used to resize many frames without recalculating the sampler info // @@ -577,7 +602,7 @@ typedef float stbir__kernel_callback( float x, float scale, void * user_data ); typedef float stbir__support_callback( float scale, void * user_data ); // internal structure with precomputed scaling -typedef struct stbir__info stbir__info; +typedef struct stbir__info stbir__info; typedef struct STBIR_RESIZE // use the stbir_resize_init and stbir_override functions to set these values for future compatibility { @@ -604,7 +629,7 @@ typedef struct STBIR_RESIZE // use the stbir_resize_init and stbir_override fun stbir_edge horizontal_edge, vertical_edge; stbir__kernel_callback * horizontal_filter_kernel; stbir__support_callback * horizontal_filter_support; stbir__kernel_callback * vertical_filter_kernel; stbir__support_callback * vertical_filter_support; - stbir__info * samplers; + stbir__info * samplers; } STBIR_RESIZE; // extended complexity api @@ -620,7 +645,7 @@ STBIRDEF void stbir_resize_init( STBIR_RESIZE * resize, // You can update these parameters any time after resize_init and there is no cost //-------------------------------- -STBIRDEF void stbir_set_datatypes( STBIR_RESIZE * resize, stbir_datatype input_type, stbir_datatype output_type ); +STBIRDEF void stbir_set_datatypes( STBIR_RESIZE * resize, stbir_datatype input_type, stbir_datatype output_type ); STBIRDEF void stbir_set_pixel_callbacks( STBIR_RESIZE * resize, stbir_input_callback * input_cb, stbir_output_callback * output_cb ); // no callbacks by default STBIRDEF void stbir_set_user_data( STBIR_RESIZE * resize, void * user_data ); // pass back STBIR_RESIZE* by default STBIRDEF void stbir_set_buffer_ptrs( STBIR_RESIZE * resize, const void * input_pixels, int input_stride_in_bytes, void * output_pixels, int output_stride_in_bytes ); @@ -636,7 +661,7 @@ STBIRDEF int stbir_set_pixel_layouts( STBIR_RESIZE * resize, stbir_pixel_layout STBIRDEF int stbir_set_edgemodes( STBIR_RESIZE * resize, stbir_edge horizontal_edge, stbir_edge vertical_edge ); // CLAMP by default STBIRDEF int stbir_set_filters( STBIR_RESIZE * resize, stbir_filter horizontal_filter, stbir_filter vertical_filter ); // STBIR_DEFAULT_FILTER_UPSAMPLE/DOWNSAMPLE by default -STBIRDEF int stbir_set_filter_callbacks( STBIR_RESIZE * resize, stbir__kernel_callback * horizontal_filter, stbir__support_callback * horizontal_support, stbir__kernel_callback * vertical_filter, stbir__support_callback * vertical_support ); +STBIRDEF int stbir_set_filter_callbacks( STBIR_RESIZE * resize, stbir__kernel_callback * horizontal_filter, stbir__support_callback * horizontal_support, stbir__kernel_callback * vertical_filter, stbir__support_callback * vertical_support ); STBIRDEF int stbir_set_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, int subw, int subh ); // sets both sub-regions (full regions by default) STBIRDEF int stbir_set_input_subrect( STBIR_RESIZE * resize, double s0, double t0, double s1, double t1 ); // sets input sub-region (full region by default) @@ -658,7 +683,7 @@ STBIRDEF int stbir_set_non_pm_alpha_speed_over_quality( STBIR_RESIZE * resize, i //-------------------------------- // This builds the samplers and does one allocation -STBIRDEF int stbir_build_samplers( STBIR_RESIZE * resize ); +STBIRDEF int stbir_build_samplers( STBIR_RESIZE * resize ); // You MUST call this, if you call stbir_build_samplers or stbir_build_samplers_with_splits STBIRDEF void stbir_free_samplers( STBIR_RESIZE * resize ); @@ -681,7 +706,7 @@ STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize ); // It returns the number of splits (threads) that you can call it with. /// It might be less if the image resize can't be split up that many ways. -STBIRDEF int stbir_build_samplers_with_splits( STBIR_RESIZE * resize, int try_splits ); +STBIRDEF int stbir_build_samplers_with_splits( STBIR_RESIZE * resize, int try_splits ); // This function does a split of the resizing (you call this fuction for each // split, on multiple threads). A split is a piece of the output resize pixel space. @@ -691,10 +716,10 @@ STBIRDEF int stbir_build_samplers_with_splits( STBIR_RESIZE * resize, int try_sp // Usually, you will always call stbir_resize_split with split_start as the thread_index // and "1" for the split_count. // But, if you have a weird situation where you MIGHT want 8 threads, but sometimes -// only 4 threads, you can use 0,2,4,6 for the split_start's and use "2" for the +// only 4 threads, you can use 0,2,4,6 for the split_start's and use "2" for the // split_count each time to turn in into a 4 thread resize. (This is unusual). -STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start, int split_count ); +STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start, int split_count ); //=============================================================== @@ -705,10 +730,10 @@ STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start // The input callback is super flexible - it calls you with the input address // (based on the stride and base pointer), it gives you an optional_output // pointer that you can fill, or you can just return your own pointer into -// your own data. +// your own data. // -// You can also do conversion from non-supported data types if necessary - in -// this case, you ignore the input_ptr and just use the x and y parameters to +// You can also do conversion from non-supported data types if necessary - in +// this case, you ignore the input_ptr and just use the x and y parameters to // calculate your own input_ptr based on the size of each non-supported pixel. // (Something like the third example below.) // @@ -722,14 +747,14 @@ STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start // return input_ptr; // use buffer from call // } // -// Next example, copying: (copy from some other buffer or stream): +// Next example, copying: (copy from some other buffer or stream): // void const * my_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context ) // { // CopyOrStreamData( optional_output, other_data_src, num_pixels * pixel_width_in_bytes ); // return optional_output; // return the optional buffer that we filled // } // -// Third example, input another buffer without copying: (zero-copy from other buffer): +// Third example, input another buffer without copying: (zero-copy from other buffer): // void const * my_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context ) // { // void * pixels = ( (char*) other_image_base ) + ( y * other_image_stride ) + ( x * other_pixel_width_in_bytes ); @@ -758,7 +783,7 @@ STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start #ifdef STBIR_PROFILE -typedef struct STBIR_PROFILE_INFO +typedef struct STBIR_PROFILE_INFO { stbir_uint64 total_clocks; @@ -766,7 +791,7 @@ typedef struct STBIR_PROFILE_INFO // there are "resize_count" number of zones stbir_uint64 clocks[ 8 ]; char const ** descriptions; - + // count of clocks and descriptions stbir_uint32 count; } STBIR_PROFILE_INFO; @@ -865,15 +890,15 @@ STBIRDEF void stbir_resize_split_profile_info( STBIR_PROFILE_INFO * out_info, ST #endif // the internal pixel layout enums are in a different order, so we can easily do range comparisons of types -// the public pixel layout is ordered in a way that if you cast num_channels (1-4) to the enum, you get something sensible -typedef enum +// the public pixel layout is ordered in a way that if you cast num_channels (1-4) to the enum, you get something sensible +typedef enum { STBIRI_1CHANNEL = 0, STBIRI_2CHANNEL = 1, STBIRI_RGB = 2, STBIRI_BGR = 3, STBIRI_4CHANNEL = 4, - + STBIRI_RGBA = 5, STBIRI_BGRA = 6, STBIRI_ARGB = 7, @@ -979,7 +1004,7 @@ typedef struct stbir__span spans[2]; // can be two spans, if doing input subrect with clamp mode WRAP } stbir__extents; -typedef struct +typedef struct { #ifdef STBIR_PROFILE union @@ -1010,7 +1035,7 @@ typedef struct typedef void stbir__decode_pixels_func( float * decode, int width_times_channels, void const * input ); typedef void stbir__alpha_weight_func( float * decode_buffer, int width_times_channels ); -typedef void stbir__horizontal_gather_channels_func( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, +typedef void stbir__horizontal_gather_channels_func( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ); typedef void stbir__alpha_unweight_func(float * encode_buffer, int width_times_channels ); typedef void stbir__encode_pixels_func( void * output, int width_times_channels, float const * encode ); @@ -1053,10 +1078,10 @@ struct stbir__info stbir__horizontal_gather_channels_func * horizontal_gather_channels; stbir__alpha_unweight_func * alpha_unweight; stbir__encode_pixels_func * encode_pixels; - - int alloced_total; + + int alloc_ring_buffer_num_entries; // Number of entries in the ring buffer that will be allocated int splits; // count of splits - + stbir_internal_pixel_layout input_pixel_layout_internal; stbir_internal_pixel_layout output_pixel_layout_internal; @@ -1065,7 +1090,7 @@ struct stbir__info int vertical_first; int channels; int effective_channels; // same as channels, except on RGBA/ARGB (7), or XA/AX (3) - int alloc_ring_buffer_num_entries; // Number of entries in the ring buffer that will be allocated + size_t alloced_total; }; @@ -1076,10 +1101,11 @@ struct stbir__info #define stbir__small_float ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20)) // min/max friendly -#define STBIR_CLAMP(x, xmin, xmax) do { \ +#define STBIR_CLAMP(x, xmin, xmax) for(;;) { \ if ( (x) < (xmin) ) (x) = (xmin); \ if ( (x) > (xmax) ) (x) = (xmax); \ -} while (0) + break; \ +} static stbir__inline int stbir__min(int a, int b) { @@ -1141,7 +1167,7 @@ static const stbir_uint32 fp32_to_srgb8_tab4[104] = { 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559, 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723, }; - + static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) { static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps @@ -1172,19 +1198,44 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #define STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT 32 // when downsampling and <= 32 scanlines of buffering, use gather. gather used down to 1/8th scaling for 25% win. #endif -// restrict pointers for the output pointers +#ifndef STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS +#define STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS 4 // when threading, what is the minimum number of scanlines for a split? +#endif + +// restrict pointers for the output pointers, other loop and unroll control #if defined( _MSC_VER ) && !defined(__clang__) #define STBIR_STREAMOUT_PTR( star ) star __restrict #define STBIR_NO_UNROLL( ptr ) __assume(ptr) // this oddly keeps msvc from unrolling a loop -#elif defined( __clang__ ) - #define STBIR_STREAMOUT_PTR( star ) star __restrict__ - #define STBIR_NO_UNROLL( ptr ) __asm__ (""::"r"(ptr)) -#elif defined( __GNUC__ ) + #if _MSC_VER >= 1900 + #define STBIR_NO_UNROLL_LOOP_START __pragma(loop( no_vector )) + #else + #define STBIR_NO_UNROLL_LOOP_START + #endif +#elif defined( __clang__ ) + #define STBIR_STREAMOUT_PTR( star ) star __restrict__ + #define STBIR_NO_UNROLL( ptr ) __asm__ (""::"r"(ptr)) + #if ( __clang_major__ >= 4 ) || ( ( __clang_major__ >= 3 ) && ( __clang_minor__ >= 5 ) ) + #define STBIR_NO_UNROLL_LOOP_START _Pragma("clang loop unroll(disable)") _Pragma("clang loop vectorize(disable)") + #else + #define STBIR_NO_UNROLL_LOOP_START + #endif +#elif defined( __GNUC__ ) #define STBIR_STREAMOUT_PTR( star ) star __restrict__ #define STBIR_NO_UNROLL( ptr ) __asm__ (""::"r"(ptr)) + #if __GNUC__ >= 14 + #define STBIR_NO_UNROLL_LOOP_START _Pragma("GCC unroll 0") _Pragma("GCC novector") + #else + #define STBIR_NO_UNROLL_LOOP_START + #endif + #define STBIR_NO_UNROLL_LOOP_START_INF_FOR #else #define STBIR_STREAMOUT_PTR( star ) star #define STBIR_NO_UNROLL( ptr ) + #define STBIR_NO_UNROLL_LOOP_START +#endif + +#ifndef STBIR_NO_UNROLL_LOOP_START_INF_FOR +#define STBIR_NO_UNROLL_LOOP_START_INF_FOR STBIR_NO_UNROLL_LOOP_START #endif #ifdef STBIR_NO_SIMD // force simd off for whatever reason @@ -1223,7 +1274,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #ifdef STBIR_SSE2 #include - + #define stbir__simdf __m128 #define stbir__simdi __m128i @@ -1254,7 +1305,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #define stbir__simdi_store2( ptr, reg ) _mm_storel_epi64( (__m128i*)(ptr), (reg) ) #define stbir__prefetch( ptr ) _mm_prefetch((char*)(ptr), _MM_HINT_T0 ) - + #define stbir__simdi_expand_u8_to_u32(out0,out1,out2,out3,ireg) \ { \ stbir__simdi zero = _mm_setzero_si128(); \ @@ -1285,7 +1336,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #define stbir__simdf_convert_float_to_uint8( f ) ((unsigned char)_mm_cvtsi128_si32(_mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(f,STBIR__CONSTF(STBIR_max_uint8_as_float)),_mm_setzero_ps())))) #define stbir__simdf_convert_float_to_short( f ) ((unsigned short)_mm_cvtsi128_si32(_mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(f,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())))) - #define stbir__simdi_to_int( i ) _mm_cvtsi128_si32(i) + #define stbir__simdi_to_int( i ) _mm_cvtsi128_si32(i) #define stbir__simdi_convert_i32_to_float(out, ireg) (out) = _mm_cvtepi32_ps( ireg ) #define stbir__simdf_add( out, reg0, reg1 ) (out) = _mm_add_ps( reg0, reg1 ) #define stbir__simdf_mult( out, reg0, reg1 ) (out) = _mm_mul_ps( reg0, reg1 ) @@ -1440,10 +1491,10 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #define stbir__simdi8_convert_i32_to_float(out, ireg) (out) = _mm256_cvtepi32_ps( ireg ) #define stbir__simdf8_convert_float_to_i32( i, f ) (i) = _mm256_cvttps_epi32(f) - + #define stbir__simdf8_bot4s( out, a, b ) (out) = _mm256_permute2f128_ps(a,b, (0<<0)+(2<<4) ) #define stbir__simdf8_top4s( out, a, b ) (out) = _mm256_permute2f128_ps(a,b, (1<<0)+(3<<4) ) - + #define stbir__simdf8_gettop4( reg ) _mm256_extractf128_ps(reg,1) #ifdef STBIR_AVX2 @@ -1471,8 +1522,8 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) out = _mm256_castsi256_si128( _mm256_permute4x64_epi64( _mm256_packus_epi16( t, t ), (0<<0)+(2<<2)+(1<<4)+(3<<6) ) ); \ } - #define stbir__simdi8_expand_u16_to_u32(out,ireg) out = _mm256_unpacklo_epi16( _mm256_permute4x64_epi64(_mm256_castsi128_si256(ireg),(0<<0)+(2<<2)+(1<<4)+(3<<6)), _mm256_setzero_si256() ); - + #define stbir__simdi8_expand_u16_to_u32(out,ireg) out = _mm256_unpacklo_epi16( _mm256_permute4x64_epi64(_mm256_castsi128_si256(ireg),(0<<0)+(2<<2)+(1<<4)+(3<<6)), _mm256_setzero_si256() ); + #define stbir__simdf8_pack_to_16words(out,aa,bb) \ { \ stbir__simdf8 af,bf; \ @@ -1496,7 +1547,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) a = _mm_unpackhi_epi8( ireg, zero ); \ out1 = _mm256_setr_m128i( _mm_unpacklo_epi16( a, zero ), _mm_unpackhi_epi16( a, zero ) ); \ } - + #define stbir__simdf8_pack_to_16bytes(out,aa,bb) \ { \ stbir__simdi t; \ @@ -1514,7 +1565,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) t = _mm_packus_epi16( t, t ); \ out = _mm_castps_si128( _mm_shuffle_ps( _mm_castsi128_ps(out), _mm_castsi128_ps(t), (0<<0)+(1<<2)+(0<<4)+(1<<6) ) ); \ } - + #define stbir__simdi8_expand_u16_to_u32(out,ireg) \ { \ stbir__simdi a,b,zero = _mm_setzero_si128(); \ @@ -1549,7 +1600,6 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #define stbir__simdf8_0123to2222( out, in ) (out) = stbir__simdf_swiz(_mm256_castps256_ps128(in), 2,2,2,2 ) - #define stbir__simdf8_load2( out, ptr ) (out) = _mm256_castsi256_ps(_mm256_castsi128_si256( _mm_loadl_epi64( (__m128i*)(ptr)) )) // top values can be random (not denormal or nan for perf) #define stbir__simdf8_load4b( out, ptr ) (out) = _mm256_broadcast_ps( (__m128 const *)(ptr) ) static __m256i stbir_00112233 = { STBIR__CONST_4d_32i( 0, 0, 1, 1 ), STBIR__CONST_4d_32i( 2, 2, 3, 3 ) }; @@ -1582,11 +1632,11 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #ifdef STBIR_USE_FMA // not on by default to maintain bit identical simd to non-simd #define stbir__simdf8_madd( out, add, mul1, mul2 ) (out) = _mm256_fmadd_ps( mul1, mul2, add ) #define stbir__simdf8_madd_mem( out, add, mul, ptr ) (out) = _mm256_fmadd_ps( mul, _mm256_loadu_ps( (float const*)(ptr) ), add ) - #define stbir__simdf8_madd_mem4( out, add, mul, ptr ) (out) = _mm256_fmadd_ps( _mm256_castps128_ps256( mul ), _mm256_castps128_ps256( _mm_loadu_ps( (float const*)(ptr) ) ), add ) + #define stbir__simdf8_madd_mem4( out, add, mul, ptr )(out) = _mm256_fmadd_ps( _mm256_setr_m128( mul, _mm_setzero_ps() ), _mm256_setr_m128( _mm_loadu_ps( (float const*)(ptr) ), _mm_setzero_ps() ), add ) #else #define stbir__simdf8_madd( out, add, mul1, mul2 ) (out) = _mm256_add_ps( add, _mm256_mul_ps( mul1, mul2 ) ) #define stbir__simdf8_madd_mem( out, add, mul, ptr ) (out) = _mm256_add_ps( add, _mm256_mul_ps( mul, _mm256_loadu_ps( (float const*)(ptr) ) ) ) - #define stbir__simdf8_madd_mem4( out, add, mul, ptr ) (out) = _mm256_add_ps( add, _mm256_castps128_ps256( _mm_mul_ps( mul, _mm_loadu_ps( (float const*)(ptr) ) ) ) ) + #define stbir__simdf8_madd_mem4( out, add, mul, ptr ) (out) = _mm256_add_ps( add, _mm256_setr_m128( _mm_mul_ps( mul, _mm_loadu_ps( (float const*)(ptr) ) ), _mm_setzero_ps() ) ) #endif #define stbir__if_simdf8_cast_to_simdf4( val ) _mm256_castps256_ps128( val ) @@ -1627,7 +1677,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) } #elif defined(STBIR_NEON) - + #include #define stbir__simdf float32x4_t @@ -1686,7 +1736,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #define stbir__simdf_convert_float_to_i32( i, f ) (i) = vreinterpretq_u32_s32( vcvtq_s32_f32(f) ) #define stbir__simdf_convert_float_to_int( f ) vgetq_lane_s32(vcvtq_s32_f32(f), 0) - #define stbir__simdi_to_int( i ) (int)vgetq_lane_u32(i, 0) + #define stbir__simdi_to_int( i ) (int)vgetq_lane_u32(i, 0) #define stbir__simdf_convert_float_to_uint8( f ) ((unsigned char)vgetq_lane_s32(vcvtq_s32_f32(vmaxq_f32(vminq_f32(f,STBIR__CONSTF(STBIR_max_uint8_as_float)),vdupq_n_f32(0))), 0)) #define stbir__simdf_convert_float_to_short( f ) ((unsigned short)vgetq_lane_s32(vcvtq_s32_f32(vmaxq_f32(vminq_f32(f,STBIR__CONSTF(STBIR_max_uint16_as_float)),vdupq_n_f32(0))), 0)) #define stbir__simdi_convert_i32_to_float(out, ireg) (out) = vcvtq_f32_s32( vreinterpretq_s32_u32(ireg) ) @@ -1737,12 +1787,20 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) ((stbir_uint64)(4*b+0)<<32) | ((stbir_uint64)(4*b+1)<<40) | ((stbir_uint64)(4*b+2)<<48) | ((stbir_uint64)(4*b+3)<<56)), \ vcreate_u8( (4*c+0) | ((4*c+1)<<8) | ((4*c+2)<<16) | ((4*c+3)<<24) | \ ((stbir_uint64)(4*d+0)<<32) | ((stbir_uint64)(4*d+1)<<40) | ((stbir_uint64)(4*d+2)<<48) | ((stbir_uint64)(4*d+3)<<56) ) ) + + static stbir__inline uint8x16x2_t stbir_make16x2(float32x4_t rega,float32x4_t regb) + { + uint8x16x2_t r = { vreinterpretq_u8_f32(rega), vreinterpretq_u8_f32(regb) }; + return r; + } #else #define stbir_make16(a,b,c,d) (uint8x16_t){4*a+0,4*a+1,4*a+2,4*a+3,4*b+0,4*b+1,4*b+2,4*b+3,4*c+0,4*c+1,4*c+2,4*c+3,4*d+0,4*d+1,4*d+2,4*d+3} + #define stbir_make16x2(a,b) (uint8x16x2_t){{vreinterpretq_u8_f32(a),vreinterpretq_u8_f32(b)}} #endif #define stbir__simdf_swiz( reg, one, two, three, four ) vreinterpretq_f32_u8( vqtbl1q_u8( vreinterpretq_u8_f32(reg), stbir_make16(one, two, three, four) ) ) - + #define stbir__simdf_swiz2( rega, regb, one, two, three, four ) vreinterpretq_f32_u8( vqtbl2q_u8( stbir_make16x2(rega,regb), stbir_make16(one, two, three, four) ) ) + #define stbir__simdi_16madd( out, reg0, reg1 ) \ { \ int16x8_t r0 = vreinterpretq_s16_u32(reg0); \ @@ -1942,7 +2000,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #define stbir__simdf_convert_float_to_i32( i, f ) (i) = wasm_i32x4_trunc_sat_f32x4(f) #define stbir__simdf_convert_float_to_int( f ) wasm_i32x4_extract_lane(wasm_i32x4_trunc_sat_f32x4(f), 0) - #define stbir__simdi_to_int( i ) wasm_i32x4_extract_lane(i, 0) + #define stbir__simdi_to_int( i ) wasm_i32x4_extract_lane(i, 0) #define stbir__simdf_convert_float_to_uint8( f ) ((unsigned char)wasm_i32x4_extract_lane(wasm_i32x4_trunc_sat_f32x4(wasm_f32x4_max(wasm_f32x4_min(f,STBIR_max_uint8_as_float),wasm_f32x4_const_splat(0))), 0)) #define stbir__simdf_convert_float_to_short( f ) ((unsigned short)wasm_i32x4_extract_lane(wasm_i32x4_trunc_sat_f32x4(wasm_f32x4_max(wasm_f32x4_min(f,STBIR_max_uint16_as_float),wasm_f32x4_const_splat(0))), 0)) #define stbir__simdi_convert_i32_to_float(out, ireg) (out) = wasm_f32x4_convert_i32x4(ireg) @@ -2125,7 +2183,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #endif -#if defined(STBIR_NEON) && !defined(_M_ARM) +#if defined(STBIR_NEON) && !defined(_M_ARM) && !defined(__arm__) #if defined( _MSC_VER ) && !defined(__clang__) typedef __int16 stbir__FP16; @@ -2142,7 +2200,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #endif -#if !defined(STBIR_NEON) && !defined(STBIR_FP16C) || defined(STBIR_NEON) && defined(_M_ARM) +#if (!defined(STBIR_NEON) && !defined(STBIR_FP16C)) || (defined(STBIR_NEON) && defined(_M_ARM)) || (defined(STBIR_NEON) && defined(__arm__)) // Fabian's half float routines, see: https://gist.github.com/rygorous/2156668 @@ -2168,7 +2226,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) unsigned int sign_mask = 0x80000000u; stbir__FP16 o = { 0 }; stbir__FP32 f; - unsigned int sign; + unsigned int sign; f.f = val; sign = f.u & sign_mask; @@ -2369,24 +2427,6 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) stbir__simdi_store( output,final ); } -#elif defined(STBIR_WASM) || (defined(STBIR_NEON) && defined(_MSC_VER) && defined(_M_ARM)) // WASM or 32-bit ARM on MSVC/clang - - static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input) - { - for (int i=0; i<8; i++) - { - output[i] = stbir__half_to_float(input[i]); - } - } - - static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input) - { - for (int i=0; i<8; i++) - { - output[i] = stbir__float_to_half(input[i]); - } - } - #elif defined(STBIR_NEON) && defined(_MSC_VER) && defined(_M_ARM64) && !defined(__clang__) // 64-bit ARM on MSVC (not clang) static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input) @@ -2415,7 +2455,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) return vget_lane_f16(vcvt_f16_f32(vdupq_n_f32(f)), 0).n16_u16[0]; } -#elif defined(STBIR_NEON) // 64-bit ARM +#elif defined(STBIR_NEON) && ( defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) ) // 64-bit ARM static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input) { @@ -2441,6 +2481,23 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) return vget_lane_f16(vcvt_f16_f32(vdupq_n_f32(f)), 0); } +#elif defined(STBIR_WASM) || (defined(STBIR_NEON) && (defined(_MSC_VER) || defined(_M_ARM) || defined(__arm__))) // WASM or 32-bit ARM on MSVC/clang + + static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input) + { + for (int i=0; i<8; i++) + { + output[i] = stbir__half_to_float(input[i]); + } + } + static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input) + { + for (int i=0; i<8; i++) + { + output[i] = stbir__float_to_half(input[i]); + } + } + #endif @@ -2462,10 +2519,10 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #define stbir__simdf_0123to3012( out, reg ) (out) = stbir__simdf_swiz( reg, 3,0,1,2 ) #define stbir__simdf_0123to0011( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,1,1 ) #define stbir__simdf_0123to1100( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,0,0 ) -#define stbir__simdf_0123to2233( out, reg ) (out) = stbir__simdf_swiz( reg, 2,2,3,3 ) -#define stbir__simdf_0123to1133( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,3,3 ) -#define stbir__simdf_0123to0022( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,2,2 ) -#define stbir__simdf_0123to1032( out, reg ) (out) = stbir__simdf_swiz( reg, 1,0,3,2 ) +#define stbir__simdf_0123to2233( out, reg ) (out) = stbir__simdf_swiz( reg, 2,2,3,3 ) +#define stbir__simdf_0123to1133( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,3,3 ) +#define stbir__simdf_0123to0022( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,2,2 ) +#define stbir__simdf_0123to1032( out, reg ) (out) = stbir__simdf_swiz( reg, 1,0,3,2 ) typedef union stbir__simdi_u32 { @@ -2493,14 +2550,16 @@ static const STBIR__SIMDI_CONST(STBIR_topscale, 0x02000000); // Adding this switch saves about 5K on clang which is Captain Unroll the 3rd. #define STBIR_SIMD_STREAMOUT_PTR( star ) STBIR_STREAMOUT_PTR( star ) #define STBIR_SIMD_NO_UNROLL(ptr) STBIR_NO_UNROLL(ptr) +#define STBIR_SIMD_NO_UNROLL_LOOP_START STBIR_NO_UNROLL_LOOP_START +#define STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR STBIR_NO_UNROLL_LOOP_START_INF_FOR #ifdef STBIR_MEMCPY #undef STBIR_MEMCPY -#define STBIR_MEMCPY stbir_simd_memcpy #endif +#define STBIR_MEMCPY stbir_simd_memcpy // override normal use of memcpy with much simpler copy (faster and smaller with our sized copies) -static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes ) +static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes ) { char STBIR_SIMD_STREAMOUT_PTR (*) d = (char*) dest; char STBIR_SIMD_STREAMOUT_PTR( * ) d_end = ((char*) dest) + bytes; @@ -2513,8 +2572,9 @@ static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes ) { if ( bytes < 16 ) { - if ( bytes ) + if ( bytes ) { + STBIR_SIMD_NO_UNROLL_LOOP_START do { STBIR_SIMD_NO_UNROLL(d); @@ -2529,8 +2589,9 @@ static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes ) // do one unaligned to get us aligned for the stream out below stbir__simdf_load( x, ( d + ofs_to_src ) ); stbir__simdf_store( d, x ); - d = (char*)( ( ( (ptrdiff_t)d ) + 16 ) & ~15 ); + d = (char*)( ( ( (size_t)d ) + 16 ) & ~15 ); + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { STBIR_SIMD_NO_UNROLL(d); @@ -2561,12 +2622,13 @@ static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes ) stbir__simdfX_store( d + 4*stbir__simdfX_float_count, x1 ); stbir__simdfX_store( d + 8*stbir__simdfX_float_count, x2 ); stbir__simdfX_store( d + 12*stbir__simdfX_float_count, x3 ); - d = (char*)( ( ( (ptrdiff_t)d ) + (16*stbir__simdfX_float_count) ) & ~((16*stbir__simdfX_float_count)-1) ); + d = (char*)( ( ( (size_t)d ) + (16*stbir__simdfX_float_count) ) & ~((16*stbir__simdfX_float_count)-1) ); + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { STBIR_SIMD_NO_UNROLL(d); - + if ( d > ( d_end - (16*stbir__simdfX_float_count) ) ) { if ( d == d_end ) @@ -2590,7 +2652,7 @@ static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes ) // memcpy that is specically intentionally overlapping (src is smaller then dest, so can be // a normal forward copy, bytes is divisible by 4 and bytes is greater than or equal to // the diff between dest and src) -static void stbir_overlapping_memcpy( void * dest, void const * src, size_t bytes ) +static void stbir_overlapping_memcpy( void * dest, void const * src, size_t bytes ) { char STBIR_SIMD_STREAMOUT_PTR (*) sd = (char*) src; char STBIR_SIMD_STREAMOUT_PTR( * ) s_end = ((char*) src) + bytes; @@ -2599,6 +2661,7 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte if ( ofs_to_dest >= 16 ) // is the overlap more than 16 away? { char STBIR_SIMD_STREAMOUT_PTR( * ) s_end16 = ((char*) src) + (bytes&~15); + STBIR_SIMD_NO_UNROLL_LOOP_START do { stbir__simdf x; @@ -2615,7 +2678,7 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte do { STBIR_SIMD_NO_UNROLL(sd); - *(int*)( sd + ofs_to_dest ) = *(int*) sd; + *(int*)( sd + ofs_to_dest ) = *(int*) sd; sd += 4; } while ( sd < s_end ); } @@ -2624,13 +2687,17 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte // when in scalar mode, we let unrolling happen, so this macro just does the __restrict #define STBIR_SIMD_STREAMOUT_PTR( star ) STBIR_STREAMOUT_PTR( star ) -#define STBIR_SIMD_NO_UNROLL(ptr) +#define STBIR_SIMD_NO_UNROLL(ptr) +#define STBIR_SIMD_NO_UNROLL_LOOP_START +#define STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR #endif // SSE2 #ifdef STBIR_PROFILE +#ifndef STBIR_PROFILE_FUNC + #if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(__SSE2__) || defined(STBIR_SSE) || defined( _M_IX86_FP ) || defined(__i386) || defined( __i386__ ) || defined( _M_IX86 ) || defined( _X86_ ) #ifdef _MSC_VER @@ -2640,7 +2707,7 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte #else // non msvc - static stbir__inline stbir_uint64 STBIR_PROFILE_FUNC() + static stbir__inline stbir_uint64 STBIR_PROFILE_FUNC() { stbir_uint32 lo, hi; asm volatile ("rdtsc" : "=a" (lo), "=d" (hi) ); @@ -2649,7 +2716,7 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte #endif // msvc -#elif defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(__ARM_NEON__) +#elif defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(__ARM_NEON__) #if defined( _MSC_VER ) && !defined(__clang__) @@ -2670,8 +2737,9 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte #error Unknown platform for profiling. -#endif //x64 and +#endif // x64, arm +#endif // STBIR_PROFILE_FUNC #define STBIR_ONLY_PROFILE_GET_SPLIT_INFO ,stbir__per_split_info * split_info #define STBIR_ONLY_PROFILE_SET_SPLIT_INFO ,split_info @@ -2680,7 +2748,7 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte #define STBIR_ONLY_PROFILE_BUILD_SET_INFO ,profile_info // super light-weight micro profiler -#define STBIR_PROFILE_START_ll( info, wh ) { stbir_uint64 wh##thiszonetime = STBIR_PROFILE_FUNC(); stbir_uint64 * wh##save_parent_excluded_ptr = info->current_zone_excluded_ptr; stbir_uint64 wh##current_zone_excluded = 0; info->current_zone_excluded_ptr = &wh##current_zone_excluded; +#define STBIR_PROFILE_START_ll( info, wh ) { stbir_uint64 wh##thiszonetime = STBIR_PROFILE_FUNC(); stbir_uint64 * wh##save_parent_excluded_ptr = info->current_zone_excluded_ptr; stbir_uint64 wh##current_zone_excluded = 0; info->current_zone_excluded_ptr = &wh##current_zone_excluded; #define STBIR_PROFILE_END_ll( info, wh ) wh##thiszonetime = STBIR_PROFILE_FUNC() - wh##thiszonetime; info->profile.named.wh += wh##thiszonetime - wh##current_zone_excluded; *wh##save_parent_excluded_ptr += wh##thiszonetime; info->current_zone_excluded_ptr = wh##save_parent_excluded_ptr; } #define STBIR_PROFILE_FIRST_START_ll( info, wh ) { int i; info->current_zone_excluded_ptr = &info->profile.named.total; for(i=0;iprofile.array);i++) info->profile.array[i]=0; } STBIR_PROFILE_START_ll( info, wh ); #define STBIR_PROFILE_CLEAR_EXTRAS_ll( info, num ) { int extra; for(extra=1;extra<(num);extra++) { int i; for(i=0;iprofile.array);i++) (info)[extra].profile.array[i]=0; } } @@ -2710,8 +2778,8 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte #define STBIR_PROFILE_FIRST_START( wh ) #define STBIR_PROFILE_CLEAR_EXTRAS( ) -#define STBIR_PROFILE_BUILD_START( wh ) -#define STBIR_PROFILE_BUILD_END( wh ) +#define STBIR_PROFILE_BUILD_START( wh ) +#define STBIR_PROFILE_BUILD_END( wh ) #define STBIR_PROFILE_BUILD_FIRST_START( wh ) #define STBIR_PROFILE_BUILD_CLEAR( info ) @@ -2736,10 +2804,10 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte #ifndef STBIR_SIMD -// memcpy that is specically intentionally overlapping (src is smaller then dest, so can be +// memcpy that is specifically intentionally overlapping (src is smaller then dest, so can be // a normal forward copy, bytes is divisible by 4 and bytes is greater than or equal to // the diff between dest and src) -static void stbir_overlapping_memcpy( void * dest, void const * src, size_t bytes ) +static void stbir_overlapping_memcpy( void * dest, void const * src, size_t bytes ) { char STBIR_SIMD_STREAMOUT_PTR (*) sd = (char*) src; char STBIR_SIMD_STREAMOUT_PTR( * ) s_end = ((char*) src) + bytes; @@ -2748,10 +2816,11 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte if ( ofs_to_dest >= 8 ) // is the overlap more than 8 away? { char STBIR_SIMD_STREAMOUT_PTR( * ) s_end8 = ((char*) src) + (bytes&~7); + STBIR_NO_UNROLL_LOOP_START do { STBIR_NO_UNROLL(sd); - *(stbir_uint64*)( sd + ofs_to_dest ) = *(stbir_uint64*) sd; + *(stbir_uint64*)( sd + ofs_to_dest ) = *(stbir_uint64*) sd; sd += 8; } while ( sd < s_end8 ); @@ -2759,10 +2828,11 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte return; } + STBIR_NO_UNROLL_LOOP_START do { STBIR_NO_UNROLL(sd); - *(int*)( sd + ofs_to_dest ) = *(int*) sd; + *(int*)( sd + ofs_to_dest ) = *(int*) sd; sd += 4; } while ( sd < s_end ); } @@ -2863,13 +2933,6 @@ static float stbir__filter_mitchell(float x, float s, void * user_data) return (0.0f); } -static float stbir__support_zero(float s, void * user_data) -{ - STBIR__UNUSED(s); - STBIR__UNUSED(user_data); - return 0; -} - static float stbir__support_zeropoint5(float s, void * user_data) { STBIR__UNUSED(s); @@ -2884,7 +2947,7 @@ static float stbir__support_one(float s, void * user_data) return 1; } -static float stbir__support_two(float s, void * user_data) +static float stbir__support_two(float s, void * user_data) { STBIR__UNUSED(s); STBIR__UNUSED(user_data); @@ -2903,7 +2966,7 @@ static int stbir__get_filter_pixel_width(stbir__support_callback * support, floa return (int)STBIR_CEILF(support(scale,user_data) * 2.0f / scale); } -// this is how many coefficents per run of the filter (which is different +// this is how many coefficents per run of the filter (which is different // from the filter_pixel_width depending on if we are scattering or gathering) static int stbir__get_coefficient_width(stbir__sampler * samp, int is_gather, void * user_data) { @@ -2924,7 +2987,7 @@ static int stbir__get_coefficient_width(stbir__sampler * samp, int is_gather, vo } } -static int stbir__get_contributors(stbir__sampler * samp, int is_gather) +static int stbir__get_contributors(stbir__sampler * samp, int is_gather) { if (is_gather) return samp->scale_info.output_sub_size; @@ -2954,7 +3017,7 @@ static int stbir__edge_reflect_full( int n, int max ) { if (n < 0) { - if (n > -max) + if (n > -max) return -n; else return max - 1; @@ -3056,7 +3119,7 @@ static void stbir__get_extents( stbir__sampler * samp, stbir__extents * scanline left_margin = -min_n; min_n = 0; } - + right_margin = 0; if ( max_n >= input_full_size ) { @@ -3081,7 +3144,7 @@ static void stbir__get_extents( stbir__sampler * samp, stbir__extents * scanline // don't have to do edge calc for zero clamp if ( edge == STBIR_EDGE_ZERO ) return; - + // convert margin pixels to the pixels within the input (min and max) for( j = -left_margin ; j < 0 ; j++ ) { @@ -3179,20 +3242,20 @@ static void stbir__calculate_in_pixel_range( int * first_pixel, int * last_pixel float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius; float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius; - float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) * inv_scale; - float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) * inv_scale; + float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) * inv_scale; + float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) * inv_scale; first = (int)(STBIR_FLOORF(in_pixel_influence_lowerbound + 0.5f)); last = (int)(STBIR_FLOORF(in_pixel_influence_upperbound - 0.5f)); if ( edge == STBIR_EDGE_WRAP ) { - if ( first <= -input_size ) - first = -(input_size-1); + if ( first < -input_size ) + first = -input_size; if ( last >= (input_size*2)) last = (input_size*2) - 1; } - + *first_pixel = first; *last_pixel = last; } @@ -3213,10 +3276,10 @@ static void stbir__calculate_coefficients_for_gather_upsample( float out_filter_ int i; int last_non_zero; float out_pixel_center = (float)n + 0.5f; - float in_center_of_out = (out_pixel_center + out_shift) * inv_scale; + float in_center_of_out = (out_pixel_center + out_shift) * inv_scale; int in_first_pixel, in_last_pixel; - + stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, out_pixel_center, out_filter_radius, inv_scale, out_shift, input_size, edge ); last_non_zero = -1; @@ -3229,7 +3292,7 @@ static void stbir__calculate_coefficients_for_gather_upsample( float out_filter_ if ( ( ( coeff < stbir__small_float ) && ( coeff > -stbir__small_float ) ) ) { if ( i == 0 ) // if we're at the front, just eat zero contributors - { + { STBIR_ASSERT ( ( in_last_pixel - in_first_pixel ) != 0 ); // there should be at least one contrib ++in_first_pixel; i--; @@ -3239,10 +3302,10 @@ static void stbir__calculate_coefficients_for_gather_upsample( float out_filter_ } else last_non_zero = i; - + coefficient_group[i] = coeff; } - + in_last_pixel = last_non_zero+in_first_pixel; // kills trailing zeros contributors->n0 = in_first_pixel; contributors->n1 = in_last_pixel; @@ -3354,7 +3417,7 @@ static void stbir__calculate_coefficients_for_gather_downsample( int start, int stbir__contributors * contribs = contributors + out; // is this the first time this output pixel has been seen? Init it. - if ( out > first_out_inited ) + if ( out > first_out_inited ) { STBIR_ASSERT( out == ( first_out_inited + 1 ) ); // ensure we have only advanced one at time first_out_inited = out; @@ -3362,7 +3425,7 @@ static void stbir__calculate_coefficients_for_gather_downsample( int start, int contribs->n1 = in_pixel; coeffs[0] = coeff; } - else + else { // insert on end (always in order) if ( coeffs[0] == 0.0f ) // if the first coefficent is zero, then zap it for this coeffs @@ -3379,10 +3442,16 @@ static void stbir__calculate_coefficients_for_gather_downsample( int start, int } } +#ifdef STBIR_RENORMALIZE_IN_FLOAT +#define STBIR_RENORM_TYPE float +#else +#define STBIR_RENORM_TYPE double +#endif + static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter_extent_info* filter_info, stbir__scale_info * scale_info, int num_contributors, stbir__contributors* contributors, float * coefficient_group, int coefficient_width ) { int input_size = scale_info->input_full_size; - int input_last_n1 = input_size - 1; + int input_last_n1 = input_size - 1; int n, end; int lowest = 0x7fffffff; int highest = -0x7fffffff; @@ -3400,14 +3469,14 @@ static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter for (n = 0; n < end; n++) { int i; - float filter_scale, total_filter = 0; + STBIR_RENORM_TYPE filter_scale, total_filter = 0; int e; // add all contribs e = contribs->n1 - contribs->n0; for( i = 0 ; i <= e ; i++ ) { - total_filter += coeffs[i]; + total_filter += (STBIR_RENORM_TYPE) coeffs[i]; STBIR_ASSERT( ( coeffs[i] >= -2.0f ) && ( coeffs[i] <= 2.0f ) ); // check for wonky weights } @@ -3423,10 +3492,11 @@ static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter // if the total isn't 1.0, rescale everything if ( ( total_filter < (1.0f-stbir__small_float) ) || ( total_filter > (1.0f+stbir__small_float) ) ) { - filter_scale = 1.0f / total_filter; + filter_scale = ((STBIR_RENORM_TYPE)1.0) / total_filter; + // scale them all for (i = 0; i <= e; i++) - coeffs[i] *= filter_scale; + coeffs[i] = (float) ( coeffs[i] * filter_scale ); } } ++contribs; @@ -3483,13 +3553,13 @@ static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter else if ( ( edge == STBIR_EDGE_CLAMP ) || ( edge == STBIR_EDGE_REFLECT ) ) { // for clamp and reflect, calculate the true inbounds position (based on edge type) and just add that to the existing weight - + // right hand side first if ( contribs->n1 > input_last_n1 ) { int start = contribs->n0; int endi = contribs->n1; - contribs->n1 = input_last_n1; + contribs->n1 = input_last_n1; for( i = input_size; i <= endi; i++ ) stbir__insert_coeff( contribs, coeffs, stbir__edge_wrap_slow[edge]( i, input_size ), coeffs[i-start] ); } @@ -3500,18 +3570,18 @@ static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter int save_n0; float save_n0_coeff; float * c = coeffs - ( contribs->n0 + 1 ); - + // reinsert the coeffs with it reflected or clamped (insert accumulates, if the coeffs exist) - for( i = -1 ; i > contribs->n0 ; i-- ) + for( i = -1 ; i > contribs->n0 ; i-- ) stbir__insert_coeff( contribs, coeffs, stbir__edge_wrap_slow[edge]( i, input_size ), *c-- ); save_n0 = contribs->n0; save_n0_coeff = c[0]; // save it, since we didn't do the final one (i==n0), because there might be too many coeffs to hold (before we resize)! // now slide all the coeffs down (since we have accumulated them in the positive contribs) and reset the first contrib - contribs->n0 = 0; + contribs->n0 = 0; for(i = 0 ; i <= contribs->n1 ; i++ ) coeffs[i] = coeffs[i-save_n0]; - + // now that we have shrunk down the contribs, we insert the first one safely stbir__insert_coeff( contribs, coeffs, stbir__edge_wrap_slow[edge]( save_n0, input_size ), save_n0_coeff ); } @@ -3547,7 +3617,9 @@ static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter filter_info->widest = widest; } -static int stbir__pack_coefficients( int num_contributors, stbir__contributors* contributors, float * coefficents, int coefficient_width, int widest, int row_width ) +#undef STBIR_RENORM_TYPE + +static int stbir__pack_coefficients( int num_contributors, stbir__contributors* contributors, float * coefficents, int coefficient_width, int widest, int row0, int row1 ) { #define STBIR_MOVE_1( dest, src ) { STBIR_NO_UNROLL(dest); ((stbir_uint32*)(dest))[0] = ((stbir_uint32*)(src))[0]; } #define STBIR_MOVE_2( dest, src ) { STBIR_NO_UNROLL(dest); ((stbir_uint64*)(dest))[0] = ((stbir_uint64*)(src))[0]; } @@ -3556,6 +3628,10 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* #else #define STBIR_MOVE_4( dest, src ) { STBIR_NO_UNROLL(dest); ((stbir_uint64*)(dest))[0] = ((stbir_uint64*)(src))[0]; ((stbir_uint64*)(dest))[1] = ((stbir_uint64*)(src))[1]; } #endif + + int row_end = row1 + 1; + STBIR__UNUSED( row0 ); // only used in an assert + if ( coefficient_width != widest ) { float * pc = coefficents; @@ -3564,6 +3640,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* switch( widest ) { case 1: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_1( pc, coeffs ); ++pc; @@ -3571,6 +3648,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 2: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_2( pc, coeffs ); pc += 2; @@ -3578,6 +3656,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 3: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_2( pc, coeffs ); STBIR_MOVE_1( pc+2, coeffs+2 ); @@ -3586,6 +3665,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 4: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_4( pc, coeffs ); pc += 4; @@ -3593,6 +3673,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 5: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_4( pc, coeffs ); STBIR_MOVE_1( pc+4, coeffs+4 ); @@ -3601,6 +3682,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 6: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_4( pc, coeffs ); STBIR_MOVE_2( pc+4, coeffs+4 ); @@ -3609,6 +3691,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 7: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_4( pc, coeffs ); STBIR_MOVE_2( pc+4, coeffs+4 ); @@ -3618,6 +3701,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 8: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_4( pc, coeffs ); STBIR_MOVE_4( pc+4, coeffs+4 ); @@ -3626,6 +3710,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 9: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_4( pc, coeffs ); STBIR_MOVE_4( pc+4, coeffs+4 ); @@ -3635,6 +3720,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 10: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_4( pc, coeffs ); STBIR_MOVE_4( pc+4, coeffs+4 ); @@ -3644,6 +3730,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 11: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_4( pc, coeffs ); STBIR_MOVE_4( pc+4, coeffs+4 ); @@ -3654,6 +3741,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 12: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_4( pc, coeffs ); STBIR_MOVE_4( pc+4, coeffs+4 ); @@ -3663,6 +3751,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; default: + STBIR_NO_UNROLL_LOOP_START do { float * copy_end = pc + widest - 4; float * c = coeffs; @@ -3673,6 +3762,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* c += 4; } while ( pc <= copy_end ); copy_end += 4; + STBIR_NO_UNROLL_LOOP_START while ( pc < copy_end ) { STBIR_MOVE_1( pc, c ); @@ -3688,7 +3778,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* coefficents[ widest * num_contributors ] = 8888.0f; // the minimum we might read for unrolled filters widths is 12. So, we need to - // make sure we never read outside the decode buffer, by possibly moving + // make sure we never read outside the decode buffer, by possibly moving // the sample area back into the scanline, and putting zeros weights first. // we start on the right edge and check until we're well past the possible // clip area (2*widest). @@ -3697,13 +3787,13 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* float * coeffs = coefficents + widest * ( num_contributors - 1 ); // go until no chance of clipping (this is usually less than 8 lops) - while ( ( ( contribs->n0 + widest*2 ) >= row_width ) && ( contribs >= contributors ) ) + while ( ( contribs >= contributors ) && ( ( contribs->n0 + widest*2 ) >= row_end ) ) { // might we clip?? - if ( ( contribs->n0 + widest ) > row_width ) + if ( ( contribs->n0 + widest ) > row_end ) { int stop_range = widest; - + // if range is larger than 12, it will be handled by generic loops that can terminate on the exact length // of this contrib n1, instead of a fixed widest amount - so calculate this if ( widest > 12 ) @@ -3712,22 +3802,22 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* // how far will be read in the n_coeff loop (which depends on the widest count mod4); mod = widest & 3; - stop_range = ( ( ( contribs->n1 - contribs->n0 + 1 ) - mod + 3 ) & ~3 ) + mod; + stop_range = ( ( ( contribs->n1 - contribs->n0 + 1 ) - mod + 3 ) & ~3 ) + mod; // the n_coeff loops do a minimum amount of coeffs, so factor that in! if ( stop_range < ( 8 + mod ) ) stop_range = 8 + mod; } // now see if we still clip with the refined range - if ( ( contribs->n0 + stop_range ) > row_width ) + if ( ( contribs->n0 + stop_range ) > row_end ) { - int new_n0 = row_width - stop_range; + int new_n0 = row_end - stop_range; int num = contribs->n1 - contribs->n0 + 1; int backup = contribs->n0 - new_n0; float * from_co = coeffs + num - 1; float * to_co = from_co + backup; - STBIR_ASSERT( ( new_n0 >= 0 ) && ( new_n0 < contribs->n0 ) ); + STBIR_ASSERT( ( new_n0 >= row0 ) && ( new_n0 < contribs->n0 ) ); // move the coeffs over while( num ) @@ -3746,7 +3836,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* // how far will be read in the n_coeff loop (which depends on the widest count mod4); mod = widest & 3; - stop_range = ( ( ( contribs->n1 - contribs->n0 + 1 ) - mod + 3 ) & ~3 ) + mod; + stop_range = ( ( ( contribs->n1 - contribs->n0 + 1 ) - mod + 3 ) & ~3 ) + mod; // the n_coeff loops do a minimum amount of coeffs, so factor that in! if ( stop_range < ( 8 + mod ) ) stop_range = 8 + mod; @@ -3774,7 +3864,7 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot int input_full_size = samp->scale_info.input_full_size; int gather_num_contributors = samp->num_contributors; stbir__contributors* gather_contributors = samp->contributors; - float * gather_coeffs = samp->coefficients; + float * gather_coeffs = samp->coefficients; int gather_coefficient_width = samp->coefficient_width; switch ( samp->is_gather ) @@ -3792,16 +3882,16 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot break; case 0: // scatter downsample (only on vertical) - case 2: // gather downsample + case 2: // gather downsample { float in_pixels_radius = support(scale,user_data) * inv_scale; int filter_pixel_margin = samp->filter_pixel_margin; int input_end = input_full_size + filter_pixel_margin; - + // if this is a scatter, we do a downsample gather to get the coeffs, and then pivot after if ( !samp->is_gather ) { - // check if we are using the same gather downsample on the horizontal as this vertical, + // check if we are using the same gather downsample on the horizontal as this vertical, // if so, then we don't have to generate them, we can just pivot from the horizontal. if ( other_axis_for_pivot ) { @@ -3846,30 +3936,37 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot float * scatter_coeffs = samp->coefficients + ( gn0 + filter_pixel_margin ) * scatter_coefficient_width; float * g_coeffs = gather_coeffs; scatter_contributors = samp->contributors + ( gn0 + filter_pixel_margin ); - + for (k = gn0 ; k <= gn1 ; k++ ) { float gc = *g_coeffs++; - if ( ( k > highest_set ) || ( scatter_contributors->n0 > scatter_contributors->n1 ) ) + + // skip zero and denormals - must skip zeros to avoid adding coeffs beyond scatter_coefficient_width + // (which happens when pivoting from horizontal, which might have dummy zeros) + if ( ( ( gc >= stbir__small_float ) || ( gc <= -stbir__small_float ) ) ) { + if ( ( k > highest_set ) || ( scatter_contributors->n0 > scatter_contributors->n1 ) ) { - // if we are skipping over several contributors, we need to clear the skipped ones - stbir__contributors * clear_contributors = samp->contributors + ( highest_set + filter_pixel_margin + 1); - while ( clear_contributors < scatter_contributors ) { - clear_contributors->n0 = 0; - clear_contributors->n1 = -1; - ++clear_contributors; + // if we are skipping over several contributors, we need to clear the skipped ones + stbir__contributors * clear_contributors = samp->contributors + ( highest_set + filter_pixel_margin + 1); + while ( clear_contributors < scatter_contributors ) + { + clear_contributors->n0 = 0; + clear_contributors->n1 = -1; + ++clear_contributors; + } } + scatter_contributors->n0 = n; + scatter_contributors->n1 = n; + scatter_coeffs[0] = gc; + highest_set = k; } - scatter_contributors->n0 = n; - scatter_contributors->n1 = n; - scatter_coeffs[0] = gc; - highest_set = k; - } - else - { - stbir__insert_coeff( scatter_contributors, scatter_coeffs, n, gc ); + else + { + stbir__insert_coeff( scatter_contributors, scatter_coeffs, n, gc ); + } + STBIR_ASSERT( ( scatter_contributors->n1 - scatter_contributors->n0 + 1 ) <= scatter_coefficient_width ); } ++scatter_contributors; scatter_coeffs += scatter_coefficient_width; @@ -3908,11 +4005,11 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot #define stbir__decode_suffix BGRA #define stbir__decode_swizzle -#define stbir__decode_order0 2 +#define stbir__decode_order0 2 #define stbir__decode_order1 1 #define stbir__decode_order2 0 #define stbir__decode_order3 3 -#define stbir__encode_order0 2 +#define stbir__encode_order0 2 #define stbir__encode_order1 1 #define stbir__encode_order2 0 #define stbir__encode_order3 3 @@ -3922,11 +4019,11 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot #define stbir__decode_suffix ARGB #define stbir__decode_swizzle -#define stbir__decode_order0 1 +#define stbir__decode_order0 1 #define stbir__decode_order1 2 #define stbir__decode_order2 3 #define stbir__decode_order3 0 -#define stbir__encode_order0 3 +#define stbir__encode_order0 3 #define stbir__encode_order1 0 #define stbir__encode_order2 1 #define stbir__encode_order3 2 @@ -3936,11 +4033,11 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot #define stbir__decode_suffix ABGR #define stbir__decode_swizzle -#define stbir__decode_order0 3 +#define stbir__decode_order0 3 #define stbir__decode_order1 2 #define stbir__decode_order2 1 #define stbir__decode_order3 0 -#define stbir__encode_order0 3 +#define stbir__encode_order0 3 #define stbir__encode_order1 2 #define stbir__encode_order2 1 #define stbir__encode_order3 0 @@ -3950,12 +4047,12 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot #define stbir__decode_suffix AR #define stbir__decode_swizzle -#define stbir__decode_order0 1 -#define stbir__decode_order1 0 +#define stbir__decode_order0 1 +#define stbir__decode_order1 0 #define stbir__decode_order2 3 #define stbir__decode_order3 2 -#define stbir__encode_order0 1 -#define stbir__encode_order1 0 +#define stbir__encode_order0 1 +#define stbir__encode_order1 0 #define stbir__encode_order2 3 #define stbir__encode_order3 2 #define stbir__coder_min_num 2 @@ -3973,9 +4070,10 @@ static void stbir__fancy_alpha_weight_4ch( float * out_buffer, int width_times_c // fancy alpha is stored internally as R G B A Rpm Gpm Bpm #ifdef STBIR_SIMD - + #ifdef STBIR_SIMD8 decode += 16; + STBIR_NO_UNROLL_LOOP_START while ( decode <= end_decode ) { stbir__simdf8 d0,d1,a0,a1,p0,p1; @@ -3998,8 +4096,9 @@ static void stbir__fancy_alpha_weight_4ch( float * out_buffer, int width_times_c out += 28; } decode -= 16; - #else + #else decode += 8; + STBIR_NO_UNROLL_LOOP_START while ( decode <= end_decode ) { stbir__simdf d0,a0,d1,a1,p0,p1; @@ -4022,12 +4121,14 @@ static void stbir__fancy_alpha_weight_4ch( float * out_buffer, int width_times_c // might be one last odd pixel #ifdef STBIR_SIMD8 + STBIR_NO_UNROLL_LOOP_START while ( decode < end_decode ) #else if ( decode < end_decode ) #endif { stbir__simdf d,a,p; + STBIR_NO_UNROLL(decode); stbir__simdf_load( d, decode ); stbir__simdf_0123to3333( a, d ); stbir__simdf_mult( p, a, d ); @@ -4069,6 +4170,7 @@ static void stbir__fancy_alpha_weight_2ch( float * out_buffer, int width_times_c decode += 8; if ( decode <= end_decode ) { + STBIR_NO_UNROLL_LOOP_START do { #ifdef STBIR_SIMD8 stbir__simdf8 d0,a0,p0; @@ -4077,11 +4179,11 @@ static void stbir__fancy_alpha_weight_2ch( float * out_buffer, int width_times_c stbir__simdf8_0123to11331133( p0, d0 ); stbir__simdf8_0123to00220022( a0, d0 ); stbir__simdf8_mult( p0, p0, a0 ); - + stbir__simdf_store2( out, stbir__if_simdf8_cast_to_simdf4( d0 ) ); stbir__simdf_store( out+2, stbir__if_simdf8_cast_to_simdf4( p0 ) ); stbir__simdf_store2h( out+3, stbir__if_simdf8_cast_to_simdf4( d0 ) ); - + stbir__simdf_store2( out+6, stbir__simdf8_gettop4( d0 ) ); stbir__simdf_store( out+8, stbir__simdf8_gettop4( p0 ) ); stbir__simdf_store2h( out+9, stbir__simdf8_gettop4( d0 ) ); @@ -4112,6 +4214,7 @@ static void stbir__fancy_alpha_weight_2ch( float * out_buffer, int width_times_c decode -= 8; #endif + STBIR_SIMD_NO_UNROLL_LOOP_START while( decode < end_decode ) { float x = decode[0], y = decode[1]; @@ -4132,6 +4235,7 @@ static void stbir__fancy_alpha_unweight_4ch( float * encode_buffer, int width_ti // fancy RGBA is stored internally as R G B A Rpm Gpm Bpm + STBIR_SIMD_NO_UNROLL_LOOP_START do { float alpha = input[3]; #ifdef STBIR_SIMD @@ -4199,6 +4303,7 @@ static void stbir__simple_alpha_weight_4ch( float * decode_buffer, int width_tim #ifdef STBIR_SIMD { decode += 2 * stbir__simdfX_float_count; + STBIR_NO_UNROLL_LOOP_START while ( decode <= end_decode ) { stbir__simdfX d0,a0,d1,a1; @@ -4217,6 +4322,7 @@ static void stbir__simple_alpha_weight_4ch( float * decode_buffer, int width_tim // few last pixels remnants #ifdef STBIR_SIMD8 + STBIR_NO_UNROLL_LOOP_START while ( decode < end_decode ) #else if ( decode < end_decode ) @@ -4252,6 +4358,7 @@ static void stbir__simple_alpha_weight_2ch( float * decode_buffer, int width_tim #ifdef STBIR_SIMD decode += 2 * stbir__simdfX_float_count; + STBIR_NO_UNROLL_LOOP_START while ( decode <= end_decode ) { stbir__simdfX d0,a0,d1,a1; @@ -4269,6 +4376,7 @@ static void stbir__simple_alpha_weight_2ch( float * decode_buffer, int width_tim decode -= 2 * stbir__simdfX_float_count; #endif + STBIR_SIMD_NO_UNROLL_LOOP_START while( decode < end_decode ) { float alpha = decode[1]; @@ -4283,6 +4391,7 @@ static void stbir__simple_alpha_unweight_4ch( float * encode_buffer, int width_t float STBIR_SIMD_STREAMOUT_PTR(*) encode = encode_buffer; float const * end_output = encode_buffer + width_times_channels; + STBIR_SIMD_NO_UNROLL_LOOP_START do { float alpha = encode[3]; @@ -4330,9 +4439,77 @@ static void stbir__simple_flip_3ch( float * decode_buffer, int width_times_chann float STBIR_STREAMOUT_PTR(*) decode = decode_buffer; float const * end_decode = decode_buffer + width_times_channels; - decode += 12; +#ifdef STBIR_SIMD + #ifdef stbir__simdf_swiz2 // do we have two argument swizzles? + end_decode -= 12; + STBIR_NO_UNROLL_LOOP_START + while( decode <= end_decode ) + { + // on arm64 8 instructions, no overlapping stores + stbir__simdf a,b,c,na,nb; + STBIR_SIMD_NO_UNROLL(decode); + stbir__simdf_load( a, decode ); + stbir__simdf_load( b, decode+4 ); + stbir__simdf_load( c, decode+8 ); + + na = stbir__simdf_swiz2( a, b, 2, 1, 0, 5 ); + b = stbir__simdf_swiz2( a, b, 4, 3, 6, 7 ); + nb = stbir__simdf_swiz2( b, c, 0, 1, 4, 3 ); + c = stbir__simdf_swiz2( b, c, 2, 7, 6, 5 ); + + stbir__simdf_store( decode, na ); + stbir__simdf_store( decode+4, nb ); + stbir__simdf_store( decode+8, c ); + decode += 12; + } + end_decode += 12; + #else + end_decode -= 24; + STBIR_NO_UNROLL_LOOP_START + while( decode <= end_decode ) + { + // 26 instructions on x64 + stbir__simdf a,b,c,d,e,f,g; + float i21, i23; + STBIR_SIMD_NO_UNROLL(decode); + stbir__simdf_load( a, decode ); + stbir__simdf_load( b, decode+3 ); + stbir__simdf_load( c, decode+6 ); + stbir__simdf_load( d, decode+9 ); + stbir__simdf_load( e, decode+12 ); + stbir__simdf_load( f, decode+15 ); + stbir__simdf_load( g, decode+18 ); + + a = stbir__simdf_swiz( a, 2, 1, 0, 3 ); + b = stbir__simdf_swiz( b, 2, 1, 0, 3 ); + c = stbir__simdf_swiz( c, 2, 1, 0, 3 ); + d = stbir__simdf_swiz( d, 2, 1, 0, 3 ); + e = stbir__simdf_swiz( e, 2, 1, 0, 3 ); + f = stbir__simdf_swiz( f, 2, 1, 0, 3 ); + g = stbir__simdf_swiz( g, 2, 1, 0, 3 ); + + // stores overlap, need to be in order, + stbir__simdf_store( decode, a ); + i21 = decode[21]; + stbir__simdf_store( decode+3, b ); + i23 = decode[23]; + stbir__simdf_store( decode+6, c ); + stbir__simdf_store( decode+9, d ); + stbir__simdf_store( decode+12, e ); + stbir__simdf_store( decode+15, f ); + stbir__simdf_store( decode+18, g ); + decode[21] = i23; + decode[23] = i21; + decode += 24; + } + end_decode += 24; + #endif +#else + end_decode -= 12; + STBIR_NO_UNROLL_LOOP_START while( decode <= end_decode ) { + // 16 instructions float t0,t1,t2,t3; STBIR_NO_UNROLL(decode); t0 = decode[0]; t1 = decode[3]; t2 = decode[6]; t3 = decode[9]; @@ -4340,8 +4517,10 @@ static void stbir__simple_flip_3ch( float * decode_buffer, int width_times_chann decode[2] = t0; decode[5] = t1; decode[8] = t2; decode[11] = t3; decode += 12; } - decode -= 12; + end_decode += 12; +#endif + STBIR_NO_UNROLL_LOOP_START while( decode < end_decode ) { float t = decode[0]; @@ -4362,14 +4541,14 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir_edge edge_horizontal = stbir_info->horizontal.edge; stbir_edge edge_vertical = stbir_info->vertical.edge; int row = stbir__edge_wrap(edge_vertical, n, stbir_info->vertical.scale_info.input_full_size); - const void* input_plane_data = ( (char *) stbir_info->input_data ) + (ptrdiff_t)row * (ptrdiff_t) stbir_info->input_stride_bytes; + const void* input_plane_data = ( (char *) stbir_info->input_data ) + (size_t)row * (size_t) stbir_info->input_stride_bytes; stbir__span const * spans = stbir_info->scanline_extents.spans; float* full_decode_buffer = output_buffer - stbir_info->scanline_extents.conservative.n0 * effective_channels; // if we are on edge_zero, and we get in here with an out of bounds n, then the calculate filters has failed STBIR_ASSERT( !(edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->vertical.scale_info.input_full_size)) ); - do + do { float * decode_buffer; void const * input_data; @@ -4377,7 +4556,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float int width_times_channels; int width; - if ( spans->n1 < spans->n0 ) + if ( spans->n1 < spans->n0 ) break; width = spans->n1 + 1 - spans->n0; @@ -4394,7 +4573,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float // call the callback with a temp buffer (that they can choose to use or not). the temp is just right aligned memory in the decode_buffer itself input_data = stbir_info->in_pixels_cb( ( (char*) end_decode ) - ( width * input_sample_in_bytes ), input_plane_data, width, spans->pixel_offset_for_input, row, stbir_info->user_data ); } - + STBIR_PROFILE_START( decode ); // convert the pixels info the float decode_buffer, (we index from end_decode, so that when channelsdecode_pixels( (float*)end_decode - width_times_channels, width_times_channels, input_data ); @@ -4418,7 +4597,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float // this code only runs if we're in edge_wrap, and we're doing the entire scanline int e, start_x[2]; int input_full_size = stbir_info->horizontal.scale_info.input_full_size; - + start_x[0] = -stbir_info->scanline_extents.edge_sizes[0]; // left edge start x start_x[1] = input_full_size; // right edge @@ -4447,7 +4626,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf tot,c; \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load1( c, hc ); \ - stbir__simdf_mult1_mem( tot, c, decode ); + stbir__simdf_mult1_mem( tot, c, decode ); #define stbir__2_coeff_only() \ stbir__simdf tot,c,d; \ @@ -4456,7 +4635,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_load2( d, decode ); \ stbir__simdf_mult( tot, c, d ); \ stbir__simdf_0123to1230( c, tot ); \ - stbir__simdf_add1( tot, tot, c ); + stbir__simdf_add1( tot, tot, c ); #define stbir__3_coeff_only() \ stbir__simdf tot,c,t; \ @@ -4466,7 +4645,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to1230( c, tot ); \ stbir__simdf_0123to2301( t, tot ); \ stbir__simdf_add1( tot, tot, c ); \ - stbir__simdf_add1( tot, tot, t ); + stbir__simdf_add1( tot, tot, t ); #define stbir__store_output_tiny() \ stbir__simdf_store1( output, tot ); \ @@ -4483,7 +4662,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float #define stbir__4_coeff_continue_from_4( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load( c, hc + (ofs) ); \ - stbir__simdf_madd_mem( tot, tot, c, decode+(ofs) ); + stbir__simdf_madd_mem( tot, tot, c, decode+(ofs) ); #define stbir__1_coeff_remnant( ofs ) \ { stbir__simdf d; \ @@ -4495,7 +4674,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float { stbir__simdf d; \ stbir__simdf_load2z( c, hc+(ofs) ); \ stbir__simdf_load2( d, decode+(ofs) ); \ - stbir__simdf_madd( tot, tot, d, c ); } + stbir__simdf_madd( tot, tot, d, c ); } #define stbir__3_coeff_setup() \ stbir__simdf mask; \ @@ -4520,18 +4699,18 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float #define stbir__1_coeff_only() \ float tot; \ - tot = decode[0]*hc[0]; + tot = decode[0]*hc[0]; #define stbir__2_coeff_only() \ float tot; \ tot = decode[0] * hc[0]; \ - tot += decode[1] * hc[1]; + tot += decode[1] * hc[1]; #define stbir__3_coeff_only() \ float tot; \ tot = decode[0] * hc[0]; \ tot += decode[1] * hc[1]; \ - tot += decode[2] * hc[2]; + tot += decode[2] * hc[2]; #define stbir__store_output_tiny() \ output[0] = tot; \ @@ -4544,16 +4723,16 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float tot0 = decode[0] * hc[0]; \ tot1 = decode[1] * hc[1]; \ tot2 = decode[2] * hc[2]; \ - tot3 = decode[3] * hc[3]; + tot3 = decode[3] * hc[3]; #define stbir__4_coeff_continue_from_4( ofs ) \ tot0 += decode[0+(ofs)] * hc[0+(ofs)]; \ tot1 += decode[1+(ofs)] * hc[1+(ofs)]; \ tot2 += decode[2+(ofs)] * hc[2+(ofs)]; \ - tot3 += decode[3+(ofs)] * hc[3+(ofs)]; + tot3 += decode[3+(ofs)] * hc[3+(ofs)]; #define stbir__1_coeff_remnant( ofs ) \ - tot0 += decode[0+(ofs)] * hc[0+(ofs)]; + tot0 += decode[0+(ofs)] * hc[0+(ofs)]; #define stbir__2_coeff_remnant( ofs ) \ tot0 += decode[0+(ofs)] * hc[0+(ofs)]; \ @@ -4562,7 +4741,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float #define stbir__3_coeff_remnant( ofs ) \ tot0 += decode[0+(ofs)] * hc[0+(ofs)]; \ tot1 += decode[1+(ofs)] * hc[1+(ofs)]; \ - tot2 += decode[2+(ofs)] * hc[2+(ofs)]; + tot2 += decode[2+(ofs)] * hc[2+(ofs)]; #define stbir__store_output() \ output[0] = (tot0+tot2)+(tot1+tot3); \ @@ -4570,7 +4749,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float ++horizontal_contributors; \ output += 1; -#endif +#endif #define STBIR__horizontal_channels 1 #define STB_IMAGE_RESIZE_DO_HORIZONTALS @@ -4588,14 +4767,14 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_load1z( c, hc ); \ stbir__simdf_0123to0011( c, c ); \ stbir__simdf_load2( d, decode ); \ - stbir__simdf_mult( tot, d, c ); + stbir__simdf_mult( tot, d, c ); #define stbir__2_coeff_only() \ stbir__simdf tot,c; \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load2( c, hc ); \ stbir__simdf_0123to0011( c, c ); \ - stbir__simdf_mult_mem( tot, c, decode ); + stbir__simdf_mult_mem( tot, c, decode ); #define stbir__3_coeff_only() \ stbir__simdf tot,c,cs,d; \ @@ -4605,7 +4784,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_mult_mem( tot, c, decode ); \ stbir__simdf_0123to2222( c, cs ); \ stbir__simdf_load2z( d, decode+4 ); \ - stbir__simdf_madd( tot, tot, d, c ); + stbir__simdf_madd( tot, tot, d, c ); #define stbir__store_output_tiny() \ stbir__simdf_0123to2301( c, tot ); \ @@ -4628,7 +4807,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf8_load4b( cs, hc + (ofs) ); \ stbir__simdf8_0123to00112233( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); + stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); #define stbir__1_coeff_remnant( ofs ) \ { stbir__simdf t; \ @@ -4649,13 +4828,13 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf8_load4b( cs, hc + (ofs) ); \ stbir__simdf8_0123to00112233( c, cs ); \ stbir__simdf8_load6z( d, decode+(ofs)*2 ); \ - stbir__simdf8_madd( tot0, tot0, c, d ); } + stbir__simdf8_madd( tot0, tot0, c, d ); } #define stbir__store_output() \ - { stbir__simdf t,c; \ + { stbir__simdf t,d; \ stbir__simdf8_add4halves( t, stbir__if_simdf8_cast_to_simdf4(tot0), tot0 ); \ - stbir__simdf_0123to2301( c, t ); \ - stbir__simdf_add( t, t, c ); \ + stbir__simdf_0123to2301( d, t ); \ + stbir__simdf_add( t, t, d ); \ stbir__simdf_store2( output, t ); \ horizontal_coefficients += coefficient_width; \ ++horizontal_contributors; \ @@ -4670,7 +4849,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to0011( c, cs ); \ stbir__simdf_mult_mem( tot0, c, decode ); \ stbir__simdf_0123to2233( c, cs ); \ - stbir__simdf_mult_mem( tot1, c, decode+4 ); + stbir__simdf_mult_mem( tot1, c, decode+4 ); #define stbir__4_coeff_continue_from_4( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -4678,7 +4857,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to0011( c, cs ); \ stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); \ stbir__simdf_0123to2233( c, cs ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*2+4 ); + stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*2+4 ); #define stbir__1_coeff_remnant( ofs ) \ { stbir__simdf d; \ @@ -4690,7 +4869,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float #define stbir__2_coeff_remnant( ofs ) \ stbir__simdf_load2( cs, hc + (ofs) ); \ stbir__simdf_0123to0011( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); + stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); #define stbir__3_coeff_remnant( ofs ) \ { stbir__simdf d; \ @@ -4699,7 +4878,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); \ stbir__simdf_0123to2222( c, cs ); \ stbir__simdf_load2z( d, decode + (ofs) * 2 + 4 ); \ - stbir__simdf_madd( tot1, tot1, d, c ); } + stbir__simdf_madd( tot1, tot1, d, c ); } #define stbir__store_output() \ stbir__simdf_add( tot0, tot0, tot1 ); \ @@ -4718,7 +4897,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float float tota,totb,c; \ c = hc[0]; \ tota = decode[0]*c; \ - totb = decode[1]*c; + totb = decode[1]*c; #define stbir__2_coeff_only() \ float tota,totb,c; \ @@ -4727,7 +4906,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float totb = decode[1]*c; \ c = hc[1]; \ tota += decode[2]*c; \ - totb += decode[3]*c; + totb += decode[3]*c; // this weird order of add matches the simd #define stbir__3_coeff_only() \ @@ -4740,7 +4919,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float totb += decode[5]*c; \ c = hc[1]; \ tota += decode[2]*c; \ - totb += decode[3]*c; + totb += decode[3]*c; #define stbir__store_output_tiny() \ output[0] = tota; \ @@ -4762,7 +4941,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float totb2 = decode[5]*c; \ c = hc[3]; \ tota3 = decode[6]*c; \ - totb3 = decode[7]*c; + totb3 = decode[7]*c; #define stbir__4_coeff_continue_from_4( ofs ) \ c = hc[0+(ofs)]; \ @@ -4776,12 +4955,12 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float totb2 += decode[5+(ofs)*2]*c; \ c = hc[3+(ofs)]; \ tota3 += decode[6+(ofs)*2]*c; \ - totb3 += decode[7+(ofs)*2]*c; + totb3 += decode[7+(ofs)*2]*c; #define stbir__1_coeff_remnant( ofs ) \ c = hc[0+(ofs)]; \ tota0 += decode[0+(ofs)*2] * c; \ - totb0 += decode[1+(ofs)*2] * c; + totb0 += decode[1+(ofs)*2] * c; #define stbir__2_coeff_remnant( ofs ) \ c = hc[0+(ofs)]; \ @@ -4789,7 +4968,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float totb0 += decode[1+(ofs)*2] * c; \ c = hc[1+(ofs)]; \ tota1 += decode[2+(ofs)*2] * c; \ - totb1 += decode[3+(ofs)*2] * c; + totb1 += decode[3+(ofs)*2] * c; #define stbir__3_coeff_remnant( ofs ) \ c = hc[0+(ofs)]; \ @@ -4800,7 +4979,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float totb1 += decode[3+(ofs)*2] * c; \ c = hc[2+(ofs)]; \ tota2 += decode[4+(ofs)*2] * c; \ - totb2 += decode[5+(ofs)*2] * c; + totb2 += decode[5+(ofs)*2] * c; #define stbir__store_output() \ output[0] = (tota0+tota2)+(tota1+tota3); \ @@ -4809,7 +4988,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float ++horizontal_contributors; \ output += 2; -#endif +#endif #define STBIR__horizontal_channels 2 #define STB_IMAGE_RESIZE_DO_HORIZONTALS @@ -4827,7 +5006,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_load1z( c, hc ); \ stbir__simdf_0123to0001( c, c ); \ stbir__simdf_load( d, decode ); \ - stbir__simdf_mult( tot, d, c ); + stbir__simdf_mult( tot, d, c ); #define stbir__2_coeff_only() \ stbir__simdf tot,c,cs,d; \ @@ -4838,7 +5017,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_mult( tot, d, c ); \ stbir__simdf_0123to1111( c, cs ); \ stbir__simdf_load( d, decode+3 ); \ - stbir__simdf_madd( tot, tot, d, c ); + stbir__simdf_madd( tot, tot, d, c ); #define stbir__3_coeff_only() \ stbir__simdf tot,c,d,cs; \ @@ -4852,7 +5031,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_madd( tot, tot, d, c ); \ stbir__simdf_0123to2222( c, cs ); \ stbir__simdf_load( d, decode+6 ); \ - stbir__simdf_madd( tot, tot, d, c ); + stbir__simdf_madd( tot, tot, d, c ); #define stbir__store_output_tiny() \ stbir__simdf_store2( output, tot ); \ @@ -4872,7 +5051,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf8_0123to00001111( c, cs ); \ stbir__simdf8_mult_mem( tot0, c, decode - 1 ); \ stbir__simdf8_0123to22223333( c, cs ); \ - stbir__simdf8_mult_mem( tot1, c, decode+6 - 1 ); + stbir__simdf8_mult_mem( tot1, c, decode+6 - 1 ); #define stbir__4_coeff_continue_from_4( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -4880,26 +5059,26 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf8_0123to00001111( c, cs ); \ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*3 - 1 ); \ stbir__simdf8_0123to22223333( c, cs ); \ - stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*3 + 6 - 1 ); + stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*3 + 6 - 1 ); #define stbir__1_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load1rep4( t, hc + (ofs) ); \ - stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*3 - 1 ); + stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*3 - 1 ); #define stbir__2_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf8_load4b( cs, hc + (ofs) - 2 ); \ stbir__simdf8_0123to22223333( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*3 - 1 ); - + stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*3 - 1 ); + #define stbir__3_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf8_load4b( cs, hc + (ofs) ); \ stbir__simdf8_0123to00001111( c, cs ); \ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*3 - 1 ); \ stbir__simdf8_0123to2222( t, cs ); \ - stbir__simdf8_madd_mem4( tot1, tot1, t, decode+(ofs)*3 + 6 - 1 ); + stbir__simdf8_madd_mem4( tot1, tot1, t, decode+(ofs)*3 + 6 - 1 ); #define stbir__store_output() \ stbir__simdf8_add( tot0, tot0, tot1 ); \ @@ -4930,7 +5109,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to1122( c, cs ); \ stbir__simdf_mult_mem( tot1, c, decode+4 ); \ stbir__simdf_0123to2333( c, cs ); \ - stbir__simdf_mult_mem( tot2, c, decode+8 ); + stbir__simdf_mult_mem( tot2, c, decode+8 ); #define stbir__4_coeff_continue_from_4( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -4940,13 +5119,13 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to1122( c, cs ); \ stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*3+4 ); \ stbir__simdf_0123to2333( c, cs ); \ - stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*3+8 ); + stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*3+8 ); #define stbir__1_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load1z( c, hc + (ofs) ); \ stbir__simdf_0123to0001( c, c ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 ); + stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 ); #define stbir__2_coeff_remnant( ofs ) \ { stbir__simdf d; \ @@ -4956,7 +5135,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 ); \ stbir__simdf_0123to1122( c, cs ); \ stbir__simdf_load2z( d, decode+(ofs)*3+4 ); \ - stbir__simdf_madd( tot1, tot1, c, d ); } + stbir__simdf_madd( tot1, tot1, c, d ); } #define stbir__3_coeff_remnant( ofs ) \ { stbir__simdf d; \ @@ -4968,7 +5147,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*3+4 ); \ stbir__simdf_0123to2222( c, cs ); \ stbir__simdf_load1z( d, decode+(ofs)*3+8 ); \ - stbir__simdf_madd( tot2, tot2, c, d ); } + stbir__simdf_madd( tot2, tot2, c, d ); } #define stbir__store_output() \ stbir__simdf_0123ABCDto3ABx( c, tot0, tot1 ); \ @@ -4999,7 +5178,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float c = hc[0]; \ tot0 = decode[0]*c; \ tot1 = decode[1]*c; \ - tot2 = decode[2]*c; + tot2 = decode[2]*c; #define stbir__2_coeff_only() \ float tot0, tot1, tot2, c; \ @@ -5010,7 +5189,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float c = hc[1]; \ tot0 += decode[3]*c; \ tot1 += decode[4]*c; \ - tot2 += decode[5]*c; + tot2 += decode[5]*c; #define stbir__3_coeff_only() \ float tot0, tot1, tot2, c; \ @@ -5025,7 +5204,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float c = hc[2]; \ tot0 += decode[6]*c; \ tot1 += decode[7]*c; \ - tot2 += decode[8]*c; + tot2 += decode[8]*c; #define stbir__store_output_tiny() \ output[0] = tot0; \ @@ -5052,7 +5231,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float c = hc[3]; \ totd0 = decode[9]*c; \ totd1 = decode[10]*c; \ - totd2 = decode[11]*c; + totd2 = decode[11]*c; #define stbir__4_coeff_continue_from_4( ofs ) \ c = hc[0+(ofs)]; \ @@ -5070,7 +5249,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float c = hc[3+(ofs)]; \ totd0 += decode[9+(ofs)*3]*c; \ totd1 += decode[10+(ofs)*3]*c; \ - totd2 += decode[11+(ofs)*3]*c; + totd2 += decode[11+(ofs)*3]*c; #define stbir__1_coeff_remnant( ofs ) \ c = hc[0+(ofs)]; \ @@ -5100,7 +5279,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float c = hc[2+(ofs)]; \ totc0 += decode[6+(ofs)*3]*c; \ totc1 += decode[7+(ofs)*3]*c; \ - totc2 += decode[8+(ofs)*3]*c; + totc2 += decode[8+(ofs)*3]*c; #define stbir__store_output() \ output[0] = (tota0+totc0)+(totb0+totd0); \ @@ -5110,7 +5289,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float ++horizontal_contributors; \ output += 3; -#endif +#endif #define STBIR__horizontal_channels 3 #define STB_IMAGE_RESIZE_DO_HORIZONTALS @@ -5126,7 +5305,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load1( c, hc ); \ stbir__simdf_0123to0000( c, c ); \ - stbir__simdf_mult_mem( tot, c, decode ); + stbir__simdf_mult_mem( tot, c, decode ); #define stbir__2_coeff_only() \ stbir__simdf tot,c,cs; \ @@ -5135,7 +5314,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to0000( c, cs ); \ stbir__simdf_mult_mem( tot, c, decode ); \ stbir__simdf_0123to1111( c, cs ); \ - stbir__simdf_madd_mem( tot, tot, c, decode+4 ); + stbir__simdf_madd_mem( tot, tot, c, decode+4 ); #define stbir__3_coeff_only() \ stbir__simdf tot,c,cs; \ @@ -5146,7 +5325,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to1111( c, cs ); \ stbir__simdf_madd_mem( tot, tot, c, decode+4 ); \ stbir__simdf_0123to2222( c, cs ); \ - stbir__simdf_madd_mem( tot, tot, c, decode+8 ); + stbir__simdf_madd_mem( tot, tot, c, decode+8 ); #define stbir__store_output_tiny() \ stbir__simdf_store( output, tot ); \ @@ -5163,7 +5342,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf8_0123to00001111( c, cs ); \ stbir__simdf8_mult_mem( tot0, c, decode ); \ stbir__simdf8_0123to22223333( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+8 ); + stbir__simdf8_madd_mem( tot0, tot0, c, decode+8 ); #define stbir__4_coeff_continue_from_4( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5171,26 +5350,26 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf8_0123to00001111( c, cs ); \ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); \ stbir__simdf8_0123to22223333( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4+8 ); + stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4+8 ); #define stbir__1_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load1rep4( t, hc + (ofs) ); \ - stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*4 ); + stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*4 ); #define stbir__2_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf8_load4b( cs, hc + (ofs) - 2 ); \ stbir__simdf8_0123to22223333( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); - + stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); + #define stbir__3_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf8_load4b( cs, hc + (ofs) ); \ stbir__simdf8_0123to00001111( c, cs ); \ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); \ stbir__simdf8_0123to2222( t, cs ); \ - stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*4+8 ); + stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*4+8 ); #define stbir__store_output() \ stbir__simdf8_add4halves( t, stbir__if_simdf8_cast_to_simdf4(tot0), tot0 ); \ @@ -5199,7 +5378,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float ++horizontal_contributors; \ output += 4; -#else +#else #define stbir__4_coeff_start() \ stbir__simdf tot0,tot1,c,cs; \ @@ -5212,7 +5391,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to2222( c, cs ); \ stbir__simdf_madd_mem( tot0, tot0, c, decode+8 ); \ stbir__simdf_0123to3333( c, cs ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+12 ); + stbir__simdf_madd_mem( tot1, tot1, c, decode+12 ); #define stbir__4_coeff_continue_from_4( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5224,13 +5403,13 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to2222( c, cs ); \ stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4+8 ); \ stbir__simdf_0123to3333( c, cs ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+12 ); + stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+12 ); #define stbir__1_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load1( c, hc + (ofs) ); \ stbir__simdf_0123to0000( c, c ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); + stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); #define stbir__2_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5238,8 +5417,8 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to0000( c, cs ); \ stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); \ stbir__simdf_0123to1111( c, cs ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+4 ); - + stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+4 ); + #define stbir__3_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load( cs, hc + (ofs) ); \ @@ -5365,7 +5544,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float x0 += decode[0+(ofs)*4] * c; \ x1 += decode[1+(ofs)*4] * c; \ x2 += decode[2+(ofs)*4] * c; \ - x3 += decode[3+(ofs)*4] * c; + x3 += decode[3+(ofs)*4] * c; #define stbir__2_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5378,8 +5557,8 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float y0 += decode[4+(ofs)*4] * c; \ y1 += decode[5+(ofs)*4] * c; \ y2 += decode[6+(ofs)*4] * c; \ - y3 += decode[7+(ofs)*4] * c; - + y3 += decode[7+(ofs)*4] * c; + #define stbir__3_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ c = hc[0+(ofs)]; \ @@ -5396,7 +5575,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float x0 += decode[8+(ofs)*4] * c; \ x1 += decode[9+(ofs)*4] * c; \ x2 += decode[10+(ofs)*4] * c; \ - x3 += decode[11+(ofs)*4] * c; + x3 += decode[11+(ofs)*4] * c; #define stbir__store_output() \ output[0] = x0 + y0; \ @@ -5407,7 +5586,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float ++horizontal_contributors; \ output += 4; -#endif +#endif #define STBIR__horizontal_channels 4 #define STB_IMAGE_RESIZE_DO_HORIZONTALS @@ -5426,7 +5605,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_load1( c, hc ); \ stbir__simdf_0123to0000( c, c ); \ stbir__simdf_mult_mem( tot0, c, decode ); \ - stbir__simdf_mult_mem( tot1, c, decode+3 ); + stbir__simdf_mult_mem( tot1, c, decode+3 ); #define stbir__2_coeff_only() \ stbir__simdf tot0,tot1,c,cs; \ @@ -5437,7 +5616,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_mult_mem( tot1, c, decode+3 ); \ stbir__simdf_0123to1111( c, cs ); \ stbir__simdf_madd_mem( tot0, tot0, c, decode+7 ); \ - stbir__simdf_madd_mem( tot1, tot1, c,decode+10 ); + stbir__simdf_madd_mem( tot1, tot1, c,decode+10 ); #define stbir__3_coeff_only() \ stbir__simdf tot0,tot1,c,cs; \ @@ -5451,7 +5630,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_madd_mem( tot1, tot1, c, decode+10 ); \ stbir__simdf_0123to2222( c, cs ); \ stbir__simdf_madd_mem( tot0, tot0, c, decode+14 ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+17 ); + stbir__simdf_madd_mem( tot1, tot1, c, decode+17 ); #define stbir__store_output_tiny() \ stbir__simdf_store( output+3, tot1 ); \ @@ -5473,7 +5652,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf8_0123to22222222( c, cs ); \ stbir__simdf8_madd_mem( tot0, tot0, c, decode+14 ); \ stbir__simdf8_0123to33333333( c, cs ); \ - stbir__simdf8_madd_mem( tot1, tot1, c, decode+21 ); + stbir__simdf8_madd_mem( tot1, tot1, c, decode+21 ); #define stbir__4_coeff_continue_from_4( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5485,19 +5664,19 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf8_0123to22222222( c, cs ); \ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 ); \ stbir__simdf8_0123to33333333( c, cs ); \ - stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+21 ); + stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+21 ); #define stbir__1_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf8_load1b( c, hc + (ofs) ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); + stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); #define stbir__2_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf8_load1b( c, hc + (ofs) ); \ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \ stbir__simdf8_load1b( c, hc + (ofs)+1 ); \ - stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+7 ); + stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+7 ); #define stbir__3_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5507,7 +5686,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf8_0123to11111111( c, cs ); \ stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+7 ); \ stbir__simdf8_0123to22222222( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 ); + stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 ); #define stbir__store_output() \ stbir__simdf8_add( tot0, tot0, tot1 ); \ @@ -5540,7 +5719,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_madd_mem( tot1, tot1, c, decode+17 ); \ stbir__simdf_0123to3333( c, cs ); \ stbir__simdf_madd_mem( tot2, tot2, c, decode+21 ); \ - stbir__simdf_madd_mem( tot3, tot3, c, decode+24 ); + stbir__simdf_madd_mem( tot3, tot3, c, decode+24 ); #define stbir__4_coeff_continue_from_4( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5556,7 +5735,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+17 ); \ stbir__simdf_0123to3333( c, cs ); \ stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*7+21 ); \ - stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+24 ); + stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+24 ); #define stbir__1_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5573,8 +5752,8 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+3 ); \ stbir__simdf_0123to1111( c, cs ); \ stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*7+7 ); \ - stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+10 ); - + stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+10 ); + #define stbir__3_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load( cs, hc + (ofs) ); \ @@ -5586,7 +5765,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+10 ); \ stbir__simdf_0123to2222( c, cs ); \ stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+17 ); + stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+17 ); #define stbir__store_output() \ stbir__simdf_add( tot0, tot0, tot2 ); \ @@ -5610,7 +5789,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float tot3 = decode[3]*c; \ tot4 = decode[4]*c; \ tot5 = decode[5]*c; \ - tot6 = decode[6]*c; + tot6 = decode[6]*c; #define stbir__2_coeff_only() \ float tot0, tot1, tot2, tot3, tot4, tot5, tot6, c; \ @@ -5704,7 +5883,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float y3 += decode[24] * c; \ y4 += decode[25] * c; \ y5 += decode[26] * c; \ - y6 += decode[27] * c; + y6 += decode[27] * c; #define stbir__4_coeff_continue_from_4( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5739,7 +5918,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float y3 += decode[24+(ofs)*7] * c; \ y4 += decode[25+(ofs)*7] * c; \ y5 += decode[26+(ofs)*7] * c; \ - y6 += decode[27+(ofs)*7] * c; + y6 += decode[27+(ofs)*7] * c; #define stbir__1_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5770,7 +5949,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float y4 += decode[11+(ofs)*7] * c; \ y5 += decode[12+(ofs)*7] * c; \ y6 += decode[13+(ofs)*7] * c; \ - + #define stbir__3_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ c = hc[0+(ofs)]; \ @@ -5810,7 +5989,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float ++horizontal_contributors; \ output += 7; -#endif +#endif #define STBIR__horizontal_channels 7 #define STB_IMAGE_RESIZE_DO_HORIZONTALS @@ -5937,7 +6116,7 @@ static void stbir__encode_scanline( stbir__info const * stbir_info, void *output // if we have an output callback, we first convert the decode buffer in place (and then hand that to the callback) if ( stbir_info->out_pixels_cb ) output_buffer = encode_buffer; - + STBIR_PROFILE_START( encode ); // convert into the output buffer stbir_info->encode_pixels( output_buffer, width_times_channels, encode_buffer ); @@ -5945,7 +6124,7 @@ static void stbir__encode_scanline( stbir__info const * stbir_info, void *output // if we have an output callback, call it to send the data if ( stbir_info->out_pixels_cb ) - stbir_info->out_pixels_cb( output_buffer_data, num_pixels, row, stbir_info->user_data ); + stbir_info->out_pixels_cb( output_buffer, num_pixels, row, stbir_info->user_data ); } @@ -6015,7 +6194,7 @@ static void stbir__resample_vertical_gather(stbir__info const * stbir_info, stbi stbir__resample_horizontal_gather(stbir_info, encode_buffer, decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); } - stbir__encode_scanline( stbir_info, ( (char *) stbir_info->output_data ) + ((ptrdiff_t)n * (ptrdiff_t)stbir_info->output_stride_bytes), + stbir__encode_scanline( stbir_info, ( (char *) stbir_info->output_data ) + ((size_t)n * (size_t)stbir_info->output_stride_bytes), encode_buffer, n STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); } @@ -6030,7 +6209,7 @@ static void stbir__decode_and_resample_for_vertical_gather_loop(stbir__info cons // update new end scanline split_info->ring_buffer_last_scanline = n; - // get ring buffer + // get ring buffer ring_buffer_index = (split_info->ring_buffer_begin_index + (split_info->ring_buffer_last_scanline - split_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries; ring_buffer = stbir__get_ring_buffer_entry(stbir_info, split_info, ring_buffer_index); @@ -6056,7 +6235,7 @@ static void stbir__vertical_gather_loop( stbir__info const * stbir_info, stbir__ // initialize the ring buffer for gathering split_info->ring_buffer_begin_index = 0; - split_info->ring_buffer_first_scanline = stbir_info->vertical.extent_info.lowest; + split_info->ring_buffer_first_scanline = vertical_contributors->n0; split_info->ring_buffer_last_scanline = split_info->ring_buffer_first_scanline - 1; // means "empty" for (y = start_output_y; y < end_output_y; y++) @@ -6080,12 +6259,12 @@ static void stbir__vertical_gather_loop( stbir__info const * stbir_info, stbir__ split_info->ring_buffer_first_scanline++; split_info->ring_buffer_begin_index++; } - + if ( stbir_info->vertical_first ) { float * ring_buffer = stbir__get_ring_buffer_scanline( stbir_info, split_info, ++split_info->ring_buffer_last_scanline ); // Decode the nth scanline from the source image into the decode buffer. - stbir__decode_scanline( stbir_info, split_info->ring_buffer_last_scanline, ring_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); + stbir__decode_scanline( stbir_info, split_info->ring_buffer_last_scanline, ring_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); } else { @@ -6108,10 +6287,10 @@ static void stbir__encode_first_scanline_from_scatter(stbir__info const * stbir_ { // evict a scanline out into the output buffer float* ring_buffer_entry = stbir__get_ring_buffer_entry(stbir_info, split_info, split_info->ring_buffer_begin_index ); - + // dump the scanline out - stbir__encode_scanline( stbir_info, ( (char *)stbir_info->output_data ) + ( (ptrdiff_t)split_info->ring_buffer_first_scanline * (ptrdiff_t)stbir_info->output_stride_bytes ), ring_buffer_entry, split_info->ring_buffer_first_scanline STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); - + stbir__encode_scanline( stbir_info, ( (char *)stbir_info->output_data ) + ( (size_t)split_info->ring_buffer_first_scanline * (size_t)stbir_info->output_stride_bytes ), ring_buffer_entry, split_info->ring_buffer_first_scanline STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); + // mark it as empty ring_buffer_entry[ 0 ] = STBIR__FLOAT_EMPTY_MARKER; @@ -6129,10 +6308,10 @@ static void stbir__horizontal_resample_and_encode_first_scanline_from_scatter(st // Now resample it into the buffer. stbir__resample_horizontal_gather( stbir_info, split_info->vertical_buffer, ring_buffer_entry STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); - + // dump the scanline out - stbir__encode_scanline( stbir_info, ( (char *)stbir_info->output_data ) + ( (ptrdiff_t)split_info->ring_buffer_first_scanline * (ptrdiff_t)stbir_info->output_stride_bytes ), split_info->vertical_buffer, split_info->ring_buffer_first_scanline STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); - + stbir__encode_scanline( stbir_info, ( (char *)stbir_info->output_data ) + ( (size_t)split_info->ring_buffer_first_scanline * (size_t)stbir_info->output_stride_bytes ), split_info->vertical_buffer, split_info->ring_buffer_first_scanline STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); + // mark it as empty ring_buffer_entry[ 0 ] = STBIR__FLOAT_EMPTY_MARKER; @@ -6172,7 +6351,7 @@ static void stbir__resample_vertical_scatter(stbir__info const * stbir_info, stb STBIR_PROFILE_END( vertical ); } -typedef void stbir__handle_scanline_for_scatter_func(stbir__info const * stbir_info, stbir__per_split_info* split_info); +typedef void stbir__handle_scanline_for_scatter_func(stbir__info const * stbir_info, stbir__per_split_info* split_info); static void stbir__vertical_scatter_loop( stbir__info const * stbir_info, stbir__per_split_info* split_info, int split_count ) { @@ -6193,7 +6372,7 @@ static void stbir__vertical_scatter_loop( stbir__info const * stbir_info, stbir_ end_input_y = split_info[split_count-1].end_input_y; // adjust for starting offset start_input_y - y = start_input_y + stbir_info->vertical.filter_pixel_margin; + y = start_input_y + stbir_info->vertical.filter_pixel_margin; vertical_contributors += y ; vertical_coefficients += stbir_info->vertical.coefficient_width * y; @@ -6240,7 +6419,7 @@ static void stbir__vertical_scatter_loop( stbir__info const * stbir_info, stbir_ split_info->start_input_y = y; on_first_input_y = 0; - // clip the region + // clip the region if ( out_first_scanline < start_output_y ) { vc += start_output_y - out_first_scanline; @@ -6253,11 +6432,11 @@ static void stbir__vertical_scatter_loop( stbir__info const * stbir_info, stbir_ // if very first scanline, init the index if (split_info->ring_buffer_begin_index < 0) split_info->ring_buffer_begin_index = out_first_scanline - start_output_y; - + STBIR_ASSERT( split_info->ring_buffer_begin_index <= out_first_scanline ); // Decode the nth scanline from the source image into the decode buffer. - stbir__decode_scanline( stbir_info, y, split_info->decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); + stbir__decode_scanline( stbir_info, y, split_info->decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); // When horizontal first, we resample horizontally into the vertical buffer before we scatter it out if ( !stbir_info->vertical_first ) @@ -6269,7 +6448,7 @@ static void stbir__vertical_scatter_loop( stbir__info const * stbir_info, stbir_ if ( ( ( split_info->ring_buffer_last_scanline - split_info->ring_buffer_first_scanline + 1 ) == stbir_info->ring_buffer_num_entries ) && ( out_last_scanline > split_info->ring_buffer_last_scanline ) ) handle_scanline_for_scatter( stbir_info, split_info ); - + // Now the horizontal buffer is ready to write to all ring buffer rows, so do it. stbir__resample_vertical_scatter(stbir_info, split_info, out_first_scanline, out_last_scanline, vc, (float*)scanline_scatter_buffer, (float*)scanline_scatter_buffer_end ); @@ -6305,7 +6484,7 @@ static void stbir__set_sampler(stbir__sampler * samp, stbir_filter filter, stbir if (scale_info->scale >= ( 1.0f - stbir__small_float ) ) { if ( (scale_info->scale <= ( 1.0f + stbir__small_float ) ) && ( STBIR_CEILF(scale_info->pixel_shift) == scale_info->pixel_shift ) ) - filter = STBIR_FILTER_POINT_SAMPLE; + filter = STBIR_FILTER_POINT_SAMPLE; else filter = STBIR_DEFAULT_FILTER_UPSAMPLE; } @@ -6313,7 +6492,7 @@ static void stbir__set_sampler(stbir__sampler * samp, stbir_filter filter, stbir samp->filter_enum = filter; STBIR_ASSERT(samp->filter_enum != 0); - STBIR_ASSERT((unsigned)samp->filter_enum < STBIR_FILTER_OTHER); + STBIR_ASSERT((unsigned)samp->filter_enum < STBIR_FILTER_OTHER); samp->filter_kernel = stbir__builtin_kernels[ filter ]; samp->filter_support = stbir__builtin_supports[ filter ]; @@ -6339,15 +6518,31 @@ static void stbir__set_sampler(stbir__sampler * samp, stbir_filter filter, stbir // pre calculate stuff based on the above samp->coefficient_width = stbir__get_coefficient_width(samp, samp->is_gather, user_data); + // filter_pixel_width is the conservative size in pixels of input that affect an output pixel. + // In rare cases (only with 2 pix to 1 pix with the default filters), it's possible that the + // filter will extend before or after the scanline beyond just one extra entire copy of the + // scanline (we would hit the edge twice). We don't let you do that, so we clamp the total + // width to 3x the total of input pixel (once for the scanline, once for the left side + // overhang, and once for the right side). We only do this for edge mode, since the other + // modes can just re-edge clamp back in again. if ( edge == STBIR_EDGE_WRAP ) - if ( samp->filter_pixel_width > ( scale_info->input_full_size * 2 ) ) // this can only happen when shrinking to a single pixel - samp->filter_pixel_width = scale_info->input_full_size * 2; + if ( samp->filter_pixel_width > ( scale_info->input_full_size * 3 ) ) + samp->filter_pixel_width = scale_info->input_full_size * 3; // This is how much to expand buffers to account for filters seeking outside // the image boundaries. samp->filter_pixel_margin = samp->filter_pixel_width / 2; + + // filter_pixel_margin is the amount that this filter can overhang on just one side of either + // end of the scanline (left or the right). Since we only allow you to overhang 1 scanline's + // worth of pixels, we clamp this one side of overhang to the input scanline size. Again, + // this clamping only happens in rare cases with the default filters (2 pix to 1 pix). + if ( edge == STBIR_EDGE_WRAP ) + if ( samp->filter_pixel_margin > scale_info->input_full_size ) + samp->filter_pixel_margin = scale_info->input_full_size; samp->num_contributors = stbir__get_contributors(samp, samp->is_gather); + samp->contributors_size = samp->num_contributors * sizeof(stbir__contributors); samp->coefficients_size = samp->num_contributors * samp->coefficient_width * sizeof(float) + sizeof(float); // extra sizeof(float) is padding @@ -6397,8 +6592,8 @@ static void stbir__get_conservative_extents( stbir__sampler * samp, stbir__contr range->n0 = in_first_pixel; stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, (float)output_sub_size, 0, inv_scale, out_shift, input_full_size, edge ); range->n1 = in_last_pixel; - - // now go through the margin to the start of area to find bottom + + // now go through the margin to the start of area to find bottom n = range->n0 + 1; input_end = -filter_pixel_margin; while( n >= input_end ) @@ -6413,7 +6608,7 @@ static void stbir__get_conservative_extents( stbir__sampler * samp, stbir__contr --n; } - // now go through the end of the area through the margin to find top + // now go through the end of the area through the margin to find top n = range->n1 - 1; input_end = n + 1 + filter_pixel_margin; while( n <= input_end ) @@ -6462,7 +6657,7 @@ static void stbir__get_split_info( stbir__per_split_info* split_info, int splits cur = 0; for( i = 0 ; i < splits ; i++ ) { - int each; + int each; split_info[i].start_output_y = cur; each = left / ( splits - i ); split_info[i].end_output_y = cur + each; @@ -6478,7 +6673,7 @@ static void stbir__get_split_info( stbir__per_split_info* split_info, int splits static void stbir__free_internal_mem( stbir__info *info ) { #define STBIR__FREE_AND_CLEAR( ptr ) { if ( ptr ) { void * p = (ptr); (ptr) = 0; STBIR_FREE( p, info->user_data); } } - + if ( info ) { #ifndef STBIR__SEPARATE_ALLOCATIONS @@ -6496,16 +6691,16 @@ static void stbir__free_internal_mem( stbir__info *info ) for( j = 0 ; j < info->alloc_ring_buffer_num_entries ; j++ ) { #ifdef STBIR_SIMD8 - if ( info->effective_channels == 3 ) + if ( info->effective_channels == 3 ) --info->split_info[i].ring_buffers[j]; // avx in 3 channel mode needs one float at the start of the buffer - #endif + #endif STBIR__FREE_AND_CLEAR( info->split_info[i].ring_buffers[j] ); } #ifdef STBIR_SIMD8 - if ( info->effective_channels == 3 ) + if ( info->effective_channels == 3 ) --info->split_info[i].decode_buffer; // avx in 3 channel mode needs one float at the start of the buffer - #endif + #endif STBIR__FREE_AND_CLEAR( info->split_info[i].decode_buffer ); STBIR__FREE_AND_CLEAR( info->split_info[i].ring_buffers ); STBIR__FREE_AND_CLEAR( info->split_info[i].vertical_buffer ); @@ -6522,7 +6717,7 @@ static void stbir__free_internal_mem( stbir__info *info ) STBIR__FREE_AND_CLEAR( info ); #endif } - + #undef STBIR__FREE_AND_CLEAR } @@ -6534,20 +6729,20 @@ static int stbir__get_max_split( int splits, int height ) for( i = 0 ; i < splits ; i++ ) { int each = height / ( splits - i ); - if ( each > max ) + if ( each > max ) max = each; height -= each; } return max; } -static stbir__horizontal_gather_channels_func ** stbir__horizontal_gather_n_coeffs_funcs[8] = -{ +static stbir__horizontal_gather_channels_func ** stbir__horizontal_gather_n_coeffs_funcs[8] = +{ 0, stbir__horizontal_gather_1_channels_with_n_coeffs_funcs, stbir__horizontal_gather_2_channels_with_n_coeffs_funcs, stbir__horizontal_gather_3_channels_with_n_coeffs_funcs, stbir__horizontal_gather_4_channels_with_n_coeffs_funcs, 0,0, stbir__horizontal_gather_7_channels_with_n_coeffs_funcs }; -static stbir__horizontal_gather_channels_func ** stbir__horizontal_gather_channels_funcs[8] = -{ +static stbir__horizontal_gather_channels_func ** stbir__horizontal_gather_channels_funcs[8] = +{ 0, stbir__horizontal_gather_1_channels_funcs, stbir__horizontal_gather_2_channels_funcs, stbir__horizontal_gather_3_channels_funcs, stbir__horizontal_gather_4_channels_funcs, 0,0, stbir__horizontal_gather_7_channels_funcs }; @@ -6622,28 +6817,28 @@ static STBIR__V_FIRST_INFO STBIR__V_FIRST_INFO_BUFFER = {0}; #endif // Figure out whether to scale along the horizontal or vertical first. -// This only *super* important when you are scaling by a massively -// different amount in the vertical vs the horizontal (for example, if -// you are scaling by 2x in the width, and 0.5x in the height, then you -// want to do the vertical scale first, because it's around 3x faster +// This only *super* important when you are scaling by a massively +// different amount in the vertical vs the horizontal (for example, if +// you are scaling by 2x in the width, and 0.5x in the height, then you +// want to do the vertical scale first, because it's around 3x faster // in that order. // -// In more normal circumstances, this makes a 20-40% differences, so +// In more normal circumstances, this makes a 20-40% differences, so // it's good to get right, but not critical. The normal way that you -// decide which direction goes first is just figuring out which -// direction does more multiplies. But with modern CPUs with their +// decide which direction goes first is just figuring out which +// direction does more multiplies. But with modern CPUs with their // fancy caches and SIMD and high IPC abilities, so there's just a lot -// more that goes into it. +// more that goes into it. // -// My handwavy sort of solution is to have an app that does a whole +// My handwavy sort of solution is to have an app that does a whole // bunch of timing for both vertical and horizontal first modes, // and then another app that can read lots of these timing files // and try to search for the best weights to use. Dotimings.c // is the app that does a bunch of timings, and vf_train.c is the -// app that solves for the best weights (and shows how well it +// app that solves for the best weights (and shows how well it // does currently). -static int stbir__should_do_vertical_first( float weights_table[STBIR_RESIZE_CLASSIFICATIONS][4], int horizontal_filter_pixel_width, float horizontal_scale, int horizontal_output_size, int vertical_filter_pixel_width, float vertical_scale, int vertical_output_size, int is_gather, STBIR__V_FIRST_INFO * info ) +static int stbir__should_do_vertical_first( float weights_table[STBIR_RESIZE_CLASSIFICATIONS][4], int horizontal_filter_pixel_width, float horizontal_scale, int horizontal_output_size, int vertical_filter_pixel_width, float vertical_scale, int vertical_output_size, int is_gather, STBIR__V_FIRST_INFO * info ) { double v_cost, h_cost; float * weights; @@ -6655,15 +6850,15 @@ static int stbir__should_do_vertical_first( float weights_table[STBIR_RESIZE_CLA v_classification = ( vertical_output_size < horizontal_output_size ) ? 6 : 7; else if ( vertical_scale <= 1.0f ) v_classification = ( is_gather ) ? 1 : 0; - else if ( vertical_scale <= 2.0f) + else if ( vertical_scale <= 2.0f) v_classification = 2; - else if ( vertical_scale <= 3.0f) + else if ( vertical_scale <= 3.0f) v_classification = 3; - else if ( vertical_scale <= 4.0f) + else if ( vertical_scale <= 4.0f) v_classification = 5; - else + else v_classification = 6; - + // use the right weights weights = weights_table[ v_classification ]; @@ -6684,10 +6879,10 @@ static int stbir__should_do_vertical_first( float weights_table[STBIR_RESIZE_CLA info->is_gather = is_gather; } - // and this allows us to override everything for testing (see dotiming.c) - if ( ( info ) && ( info->control_v_first ) ) + // and this allows us to override everything for testing (see dotiming.c) + if ( ( info ) && ( info->control_v_first ) ) vertical_first = ( info->control_v_first == 2 ) ? 1 : 0; - + return vertical_first; } @@ -6699,9 +6894,9 @@ static unsigned char stbir__pixel_channels[] = { }; // the internal pixel layout enums are in a different order, so we can easily do range comparisons of types -// the public pixel layout is ordered in a way that if you cast num_channels (1-4) to the enum, you get something sensible +// the public pixel layout is ordered in a way that if you cast num_channels (1-4) to the enum, you get something sensible static stbir_internal_pixel_layout stbir__pixel_layout_convert_public_to_internal[] = { - STBIRI_BGR, STBIRI_1CHANNEL, STBIRI_2CHANNEL, STBIRI_RGB, STBIRI_RGBA, + STBIRI_BGR, STBIRI_1CHANNEL, STBIRI_2CHANNEL, STBIRI_RGB, STBIRI_RGBA, STBIRI_4CHANNEL, STBIRI_BGRA, STBIRI_ARGB, STBIRI_ABGR, STBIRI_RA, STBIRI_AR, STBIRI_RGBA_PM, STBIRI_BGRA_PM, STBIRI_ARGB_PM, STBIRI_ABGR_PM, STBIRI_RA_PM, STBIRI_AR_PM, }; @@ -6712,17 +6907,17 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample stbir__info * info = 0; void * alloced = 0; - int alloced_total = 0; + size_t alloced_total = 0; int vertical_first; int decode_buffer_size, ring_buffer_length_bytes, ring_buffer_size, vertical_buffer_size, alloc_ring_buffer_num_entries; int alpha_weighting_type = 0; // 0=none, 1=simple, 2=fancy - int conservative_split_output_size = stbir__get_max_split( splits, vertical->scale_info.output_sub_size ); - stbir_internal_pixel_layout input_pixel_layout = stbir__pixel_layout_convert_public_to_internal[ input_pixel_layout_public ]; + int conservative_split_output_size = stbir__get_max_split( splits, vertical->scale_info.output_sub_size ); + stbir_internal_pixel_layout input_pixel_layout = stbir__pixel_layout_convert_public_to_internal[ input_pixel_layout_public ]; stbir_internal_pixel_layout output_pixel_layout = stbir__pixel_layout_convert_public_to_internal[ output_pixel_layout_public ]; - int channels = stbir__pixel_channels[ input_pixel_layout ]; + int channels = stbir__pixel_channels[ input_pixel_layout ]; int effective_channels = channels; - + // first figure out what type of alpha weighting to use (if any) if ( ( horizontal->filter_enum != STBIR_FILTER_POINT_SAMPLE ) || ( vertical->filter_enum != STBIR_FILTER_POINT_SAMPLE ) ) // no alpha weighting on point sampling { @@ -6760,11 +6955,11 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample // sometimes read one float off in some of the unrolled loops (with a weight of zero coeff, so it doesn't have an effect) decode_buffer_size = ( conservative->n1 - conservative->n0 + 1 ) * effective_channels * sizeof(float) + sizeof(float); // extra float for padding - + #if defined( STBIR__SEPARATE_ALLOCATIONS ) && defined(STBIR_SIMD8) if ( effective_channels == 3 ) decode_buffer_size += sizeof(float); // avx in 3 channel mode needs one float at the start of the buffer (only with separate allocations) -#endif +#endif ring_buffer_length_bytes = horizontal->scale_info.output_sub_size * effective_channels * sizeof(float) + sizeof(float); // extra float for padding @@ -6803,9 +6998,9 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample #define STBIR__NEXT_PTR( ptr, size, ntype ) advance_mem = (void*) ( ( ((size_t)advance_mem) + 15 ) & ~15 ); if ( alloced ) ptr = (ntype*)advance_mem; advance_mem = ((char*)advance_mem) + (size); #endif - STBIR__NEXT_PTR( info, sizeof( stbir__info ), stbir__info ); + STBIR__NEXT_PTR( info, sizeof( stbir__info ), stbir__info ); - STBIR__NEXT_PTR( info->split_info, sizeof( stbir__per_split_info ) * splits, stbir__per_split_info ); + STBIR__NEXT_PTR( info->split_info, sizeof( stbir__per_split_info ) * splits, stbir__per_split_info ); if ( info ) { @@ -6820,39 +7015,39 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample info->channels = channels; info->effective_channels = effective_channels; - + info->offset_x = new_x; info->offset_y = new_y; info->alloc_ring_buffer_num_entries = alloc_ring_buffer_num_entries; - info->ring_buffer_num_entries = 0; + info->ring_buffer_num_entries = 0; info->ring_buffer_length_bytes = ring_buffer_length_bytes; info->splits = splits; info->vertical_first = vertical_first; - info->input_pixel_layout_internal = input_pixel_layout; + info->input_pixel_layout_internal = input_pixel_layout; info->output_pixel_layout_internal = output_pixel_layout; // setup alpha weight functions info->alpha_weight = 0; info->alpha_unweight = 0; - + // handle alpha weighting functions and overrides if ( alpha_weighting_type == 2 ) { // high quality alpha multiplying on the way in, dividing on the way out - info->alpha_weight = fancy_alpha_weights[ input_pixel_layout - STBIRI_RGBA ]; + info->alpha_weight = fancy_alpha_weights[ input_pixel_layout - STBIRI_RGBA ]; info->alpha_unweight = fancy_alpha_unweights[ output_pixel_layout - STBIRI_RGBA ]; } else if ( alpha_weighting_type == 4 ) { // fast alpha multiplying on the way in, dividing on the way out - info->alpha_weight = simple_alpha_weights[ input_pixel_layout - STBIRI_RGBA ]; + info->alpha_weight = simple_alpha_weights[ input_pixel_layout - STBIRI_RGBA ]; info->alpha_unweight = simple_alpha_unweights[ output_pixel_layout - STBIRI_RGBA ]; } else if ( alpha_weighting_type == 1 ) { // fast alpha on the way in, leave in premultiplied form on way out - info->alpha_weight = simple_alpha_weights[ input_pixel_layout - STBIRI_RGBA ]; + info->alpha_weight = simple_alpha_weights[ input_pixel_layout - STBIRI_RGBA ]; } else if ( alpha_weighting_type == 3 ) { @@ -6871,7 +7066,7 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample info->alpha_weight = stbir__simple_flip_3ch; } - } + } // get all the per-split buffers for( i = 0 ; i < splits ; i++ ) @@ -6883,7 +7078,7 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample #ifdef STBIR_SIMD8 if ( ( info ) && ( effective_channels == 3 ) ) ++info->split_info[i].decode_buffer; // avx in 3 channel mode needs one float at the start of the buffer - #endif + #endif STBIR__NEXT_PTR( info->split_info[i].ring_buffers, alloc_ring_buffer_num_entries * sizeof(float*), float* ); { @@ -6894,7 +7089,7 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample #ifdef STBIR_SIMD8 if ( ( info ) && ( effective_channels == 3 ) ) ++info->split_info[i].ring_buffers[j]; // avx in 3 channel mode needs one float at the start of the buffer - #endif + #endif } } #else @@ -6922,10 +7117,10 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample #endif if ( temp_mem_amt >= both ) { - if ( info ) - { - vertical->gather_prescatter_contributors = (stbir__contributors*)info->split_info[0].decode_buffer; - vertical->gather_prescatter_coefficients = (float*) ( ( (char*)info->split_info[0].decode_buffer ) + vertical->gather_prescatter_contributors_size ); + if ( info ) + { + vertical->gather_prescatter_contributors = (stbir__contributors*)info->split_info[0].decode_buffer; + vertical->gather_prescatter_coefficients = (float*) ( ( (char*)info->split_info[0].decode_buffer ) + vertical->gather_prescatter_contributors_size ); } } else @@ -6948,7 +7143,7 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample if ( diff_shift < 0.0f ) diff_shift = -diff_shift; if ( ( diff_scale <= stbir__small_float ) && ( diff_shift <= stbir__small_float ) ) { - if ( horizontal->is_gather == vertical->is_gather ) + if ( horizontal->is_gather == vertical->is_gather ) { copy_horizontal = 1; goto no_vert_alloc; @@ -6975,16 +7170,16 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample // but if the number of coeffs <= 12, use another set of special cases. <=12 coeffs is any enlarging resize, or shrinking resize down to about 1/3 size if ( horizontal->extent_info.widest <= 12 ) info->horizontal_gather_channels = stbir__horizontal_gather_channels_funcs[ effective_channels ][ horizontal->extent_info.widest - 1 ]; - + info->scanline_extents.conservative.n0 = conservative->n0; info->scanline_extents.conservative.n1 = conservative->n1; - + // get exact extents stbir__get_extents( horizontal, &info->scanline_extents ); // pack the horizontal coeffs - horizontal->coefficient_width = stbir__pack_coefficients(horizontal->num_contributors, horizontal->contributors, horizontal->coefficients, horizontal->coefficient_width, horizontal->extent_info.widest, info->scanline_extents.conservative.n1 + 1 ); - + horizontal->coefficient_width = stbir__pack_coefficients(horizontal->num_contributors, horizontal->contributors, horizontal->coefficients, horizontal->coefficient_width, horizontal->extent_info.widest, info->scanline_extents.conservative.n0, info->scanline_extents.conservative.n1 ); + STBIR_MEMCPY( &info->horizontal, horizontal, sizeof( stbir__sampler ) ); STBIR_PROFILE_BUILD_END( horizontal ); @@ -7014,36 +7209,27 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample info->ring_buffer_num_entries = conservative_split_output_size; STBIR_ASSERT( info->ring_buffer_num_entries <= info->alloc_ring_buffer_num_entries ); - // a few of the horizontal gather functions read one dword past the end (but mask it out), so put in a normal value so no snans or denormals accidentally sneak in + // a few of the horizontal gather functions read past the end of the decode (but mask it out), + // so put in normal values so no snans or denormals accidentally sneak in (also, in the ring + // buffer for vertical first) for( i = 0 ; i < splits ; i++ ) { - int width, ofs; - - // find the right most span - if ( info->scanline_extents.spans[0].n1 > info->scanline_extents.spans[1].n1 ) - width = info->scanline_extents.spans[0].n1 - info->scanline_extents.spans[0].n0; - else - width = info->scanline_extents.spans[1].n1 - info->scanline_extents.spans[1].n0; - - // this calc finds the exact end of the decoded scanline for all filter modes. - // usually this is just the width * effective channels. But we have to account - // for the area to the left of the scanline for wrap filtering and alignment, this - // is stored as a negative value in info->scanline_extents.conservative.n0. Next, - // we need to skip the exact size of the right hand size filter area (again for - // wrap mode), this is in info->scanline_extents.edge_sizes[1]). - ofs = ( width + 1 - info->scanline_extents.conservative.n0 + info->scanline_extents.edge_sizes[1] ) * effective_channels; - - // place a known, but numerically valid value in the decode buffer - info->split_info[i].decode_buffer[ ofs ] = 9999.0f; + int t, ofs, start; + + ofs = decode_buffer_size / 4; + start = ofs - 4; + if ( start < 0 ) start = 0; + + for( t = start ; t < ofs; t++ ) + info->split_info[i].decode_buffer[ t ] = 9999.0f; - // if vertical filtering first, place a known, but numerically valid value in the all - // of the ring buffer accumulators if ( vertical_first ) { - int j; + int j; for( j = 0; j < info->ring_buffer_num_entries ; j++ ) { - stbir__get_ring_buffer_entry( info, info->split_info + i, j )[ ofs ] = 9999.0f; + for( t = start ; t < ofs; t++ ) + stbir__get_ring_buffer_entry( info, info->split_info + i, j )[ t ] = 9999.0f; } } } @@ -7055,7 +7241,7 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample // is this the first time through loop? if ( info == 0 ) { - alloced_total = (int) ( 15 + (size_t)advance_mem ); + alloced_total = ( 15 + (size_t)advance_mem ); alloced = STBIR_MALLOC( alloced_total, user_data ); if ( alloced == 0 ) return 0; @@ -7065,7 +7251,7 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample } } -static int stbir__perform_resize( stbir__info const * info, int split_start, int split_count ) +static int stbir__perform_resize( stbir__info const * info, int split_start, int split_count ) { stbir__per_split_info * split_info = info->split_info + split_start; @@ -7085,7 +7271,7 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r { static stbir__decode_pixels_func * decode_simple[STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]= { - /* 1ch-4ch */ stbir__decode_uint8_srgb, stbir__decode_uint8_srgb, 0, stbir__decode_float_linear, stbir__decode_half_float_linear, + /* 1ch-4ch */ stbir__decode_uint8_srgb, stbir__decode_uint8_srgb, 0, stbir__decode_float_linear, stbir__decode_half_float_linear, }; static stbir__decode_pixels_func * decode_alphas[STBIRI_AR-STBIRI_RGBA+1][STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]= @@ -7148,7 +7334,7 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r stbir_datatype input_type, output_type; input_type = resize->input_data_type; - output_type = resize->output_data_type; + output_type = resize->output_data_type; info->input_data = resize->input_pixels; info->input_stride_bytes = resize->input_stride_in_bytes; info->output_stride_bytes = resize->output_stride_in_bytes; @@ -7156,7 +7342,7 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r // if we're completely point sampling, then we can turn off SRGB if ( ( info->horizontal.filter_enum == STBIR_FILTER_POINT_SAMPLE ) && ( info->vertical.filter_enum == STBIR_FILTER_POINT_SAMPLE ) ) { - if ( ( ( input_type == STBIR_TYPE_UINT8_SRGB ) || ( input_type == STBIR_TYPE_UINT8_SRGB_ALPHA ) ) && + if ( ( ( input_type == STBIR_TYPE_UINT8_SRGB ) || ( input_type == STBIR_TYPE_UINT8_SRGB_ALPHA ) ) && ( ( output_type == STBIR_TYPE_UINT8_SRGB ) || ( output_type == STBIR_TYPE_UINT8_SRGB_ALPHA ) ) ) { input_type = STBIR_TYPE_UINT8; @@ -7164,7 +7350,7 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r } } - // recalc the output and input strides + // recalc the output and input strides if ( info->input_stride_bytes == 0 ) info->input_stride_bytes = info->channels * info->horizontal.scale_info.input_full_size * stbir__type_size[input_type]; @@ -7172,7 +7358,7 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r info->output_stride_bytes = info->channels * info->horizontal.scale_info.output_sub_size * stbir__type_size[output_type]; // calc offset - info->output_data = ( (char*) resize->output_pixels ) + ( (ptrdiff_t) info->offset_y * (ptrdiff_t) resize->output_stride_in_bytes ) + ( info->offset_x * info->channels * stbir__type_size[output_type] ); + info->output_data = ( (char*) resize->output_pixels ) + ( (size_t) info->offset_y * (size_t) resize->output_stride_in_bytes ) + ( info->offset_x * info->channels * stbir__type_size[output_type] ); info->in_pixels_cb = resize->input_cb; info->user_data = resize->user_data; @@ -7205,7 +7391,7 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r if ( ( output_type == STBIR_TYPE_UINT8 ) || ( output_type == STBIR_TYPE_UINT16 ) ) { int non_scaled = 0; - + // check if we can run unscaled - 0-255.0/0-65535.0 instead of 0-1.0 (which is a tiny bit faster when doing linear 8->8 or 16->16) if ( ( !info->alpha_weight ) && ( !info->alpha_unweight ) ) // don't short circuit when alpha weighting (get everything to 0-1.0 as usual) if ( ( ( input_type == STBIR_TYPE_UINT8 ) && ( output_type == STBIR_TYPE_UINT8 ) ) || ( ( input_type == STBIR_TYPE_UINT16 ) && ( output_type == STBIR_TYPE_UINT16 ) ) ) @@ -7225,16 +7411,16 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r } info->input_type = input_type; - info->output_type = output_type; + info->output_type = output_type; info->decode_pixels = decode_pixels; - info->encode_pixels = encode_pixels; + info->encode_pixels = encode_pixels; } static void stbir__clip( int * outx, int * outsubw, int outw, double * u0, double * u1 ) { double per, adj; int over; - + // do left/top edge if ( *outx < 0 ) { @@ -7253,7 +7439,7 @@ static void stbir__clip( int * outx, int * outsubw, int outw, double * u0, doubl *u1 += adj; // decrease u1 *outsubw = outw - *outx; } -} +} // converts a double to a rational that has less than one float bit of error (returns 0 if unable to do so) static int stbir__double_to_rational(double f, stbir_uint32 limit, stbir_uint32 *numer, stbir_uint32 *denom, int limit_denom ) // limit_denom (1) or limit numer (0) @@ -7270,7 +7456,7 @@ static int stbir__double_to_rational(double f, stbir_uint32 limit, stbir_uint32 bot = 1 << 25; // keep refining, but usually stops in a few loops - usually 5 for bad cases - for(;;) + for(;;) { stbir_uint64 est, temp; @@ -7303,13 +7489,13 @@ static int stbir__double_to_rational(double f, stbir_uint32 limit, stbir_uint32 bot = temp; // move remainders - temp = est * denom_estimate + denom_last; - denom_last = denom_estimate; + temp = est * denom_estimate + denom_last; + denom_last = denom_estimate; denom_estimate = temp; // move remainders - temp = est * numer_estimate + numer_last; - numer_last = numer_estimate; + temp = est * numer_estimate + numer_last; + numer_last = numer_estimate; numer_estimate = temp; } @@ -7353,11 +7539,11 @@ static int stbir__calculate_region_transform( stbir__scale_info * scale_info, in output_s = ( (double)output_sub_range) / output_range; - // figure out the scaling to use - ratio = output_s / input_s; + // figure out the scaling to use + ratio = output_s / input_s; // save scale before clipping - scale = ( output_range / input_range ) * ratio; + scale = ( output_range / input_range ) * ratio; scale_info->scale = (float)scale; scale_info->inv_scale = (float)( 1.0 / scale ); @@ -7368,11 +7554,11 @@ static int stbir__calculate_region_transform( stbir__scale_info * scale_info, in input_s = input_s1 - input_s0; // after clipping do we have zero input area? - if ( input_s <= stbir__small_float ) + if ( input_s <= stbir__small_float ) return 0; - // calculate and store the starting source offsets in output pixel space - scale_info->pixel_shift = (float) ( input_s0 * ratio * output_range ); + // calculate and store the starting source offsets in output pixel space + scale_info->pixel_shift = (float) ( input_s0 * ratio * output_range ); scale_info->scale_is_rational = stbir__double_to_rational( scale, ( scale <= 1.0 ) ? output_full_range : input_full_range, &scale_info->scale_numerator, &scale_info->scale_denominator, ( scale >= 1.0 ) ); @@ -7389,7 +7575,6 @@ static void stbir__init_and_set_layout( STBIR_RESIZE * resize, stbir_pixel_layou resize->output_cb = 0; resize->user_data = resize; resize->samplers = 0; - resize->needs_rebuild = 1; resize->called_alloc = 0; resize->horizontal_filter = STBIR_FILTER_DEFAULT; resize->horizontal_filter_kernel = 0; resize->horizontal_filter_support = 0; @@ -7403,9 +7588,10 @@ static void stbir__init_and_set_layout( STBIR_RESIZE * resize, stbir_pixel_layou resize->output_data_type = data_type; resize->input_pixel_layout_public = pixel_layout; resize->output_pixel_layout_public = pixel_layout; + resize->needs_rebuild = 1; } -STBIRDEF void stbir_resize_init( STBIR_RESIZE * resize, +STBIRDEF void stbir_resize_init( STBIR_RESIZE * resize, const void *input_pixels, int input_w, int input_h, int input_stride_in_bytes, // stride can be zero void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, // stride can be zero stbir_pixel_layout pixel_layout, stbir_datatype data_type ) @@ -7428,17 +7614,27 @@ STBIRDEF void stbir_set_datatypes( STBIR_RESIZE * resize, stbir_datatype input_t { resize->input_data_type = input_type; resize->output_data_type = output_type; + if ( ( resize->samplers ) && ( !resize->needs_rebuild ) ) + stbir__update_info_from_resize( resize->samplers, resize ); } STBIRDEF void stbir_set_pixel_callbacks( STBIR_RESIZE * resize, stbir_input_callback * input_cb, stbir_output_callback * output_cb ) // no callbacks by default { resize->input_cb = input_cb; resize->output_cb = output_cb; + + if ( ( resize->samplers ) && ( !resize->needs_rebuild ) ) + { + resize->samplers->in_pixels_cb = input_cb; + resize->samplers->out_pixels_cb = output_cb; + } } STBIRDEF void stbir_set_user_data( STBIR_RESIZE * resize, void * user_data ) // pass back STBIR_RESIZE* by default { resize->user_data = user_data; + if ( ( resize->samplers ) && ( !resize->needs_rebuild ) ) + resize->samplers->user_data = user_data; } STBIRDEF void stbir_set_buffer_ptrs( STBIR_RESIZE * resize, const void * input_pixels, int input_stride_in_bytes, void * output_pixels, int output_stride_in_bytes ) @@ -7447,6 +7643,8 @@ STBIRDEF void stbir_set_buffer_ptrs( STBIR_RESIZE * resize, const void * input_p resize->input_stride_in_bytes = input_stride_in_bytes; resize->output_pixels = output_pixels; resize->output_stride_in_bytes = output_stride_in_bytes; + if ( ( resize->samplers ) && ( !resize->needs_rebuild ) ) + stbir__update_info_from_resize( resize->samplers, resize ); } @@ -7549,7 +7747,7 @@ STBIRDEF int stbir_set_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, return 1; } -static int stbir__perform_build( STBIR_RESIZE * resize, int splits ) +static int stbir__perform_build( STBIR_RESIZE * resize, int splits ) { stbir__contributors conservative = { 0, 0 }; stbir__sampler horizontal, vertical; @@ -7563,13 +7761,13 @@ static int stbir__perform_build( STBIR_RESIZE * resize, int splits ) // have we already built the samplers? if ( resize->samplers ) return 0; - + #define STBIR_RETURN_ERROR_AND_ASSERT( exp ) STBIR_ASSERT( !(exp) ); if (exp) return 0; STBIR_RETURN_ERROR_AND_ASSERT( (unsigned)resize->horizontal_filter >= STBIR_FILTER_OTHER) STBIR_RETURN_ERROR_AND_ASSERT( (unsigned)resize->vertical_filter >= STBIR_FILTER_OTHER) #undef STBIR_RETURN_ERROR_AND_ASSERT - if ( splits <= 0 ) + if ( splits <= 0 ) return 0; STBIR_PROFILE_BUILD_FIRST_START( build ); @@ -7593,9 +7791,9 @@ static int stbir__perform_build( STBIR_RESIZE * resize, int splits ) stbir__get_conservative_extents( &horizontal, &conservative, resize->user_data ); stbir__set_sampler(&vertical, resize->vertical_filter, resize->horizontal_filter_kernel, resize->vertical_filter_support, resize->vertical_edge, &vertical.scale_info, 0, resize->user_data ); - if ( ( vertical.scale_info.output_sub_size / splits ) < 4 ) // each split should be a minimum of 4 scanlines (handwavey choice) + if ( ( vertical.scale_info.output_sub_size / splits ) < STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS ) // each split should be a minimum of 4 scanlines (handwavey choice) { - splits = vertical.scale_info.output_sub_size / 4; + splits = vertical.scale_info.output_sub_size / STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS; if ( splits == 0 ) splits = 1; } @@ -7603,7 +7801,7 @@ static int stbir__perform_build( STBIR_RESIZE * resize, int splits ) out_info = stbir__alloc_internal_mem_and_build_samplers( &horizontal, &vertical, &conservative, resize->input_pixel_layout_public, resize->output_pixel_layout_public, splits, new_output_subx, new_output_suby, resize->fast_alpha, resize->user_data STBIR_ONLY_PROFILE_BUILD_SET_INFO ); STBIR_PROFILE_BUILD_END( alloc ); STBIR_PROFILE_BUILD_END( build ); - + if ( out_info ) { resize->splits = splits; @@ -7612,6 +7810,10 @@ static int stbir__perform_build( STBIR_RESIZE * resize, int splits ) #ifdef STBIR_PROFILE STBIR_MEMCPY( &out_info->profile, &profile_infod.profile, sizeof( out_info->profile ) ); #endif + + // update anything that can be changed without recalcing samplers + stbir__update_info_from_resize( out_info, resize ); + return splits; } @@ -7640,7 +7842,7 @@ STBIRDEF int stbir_build_samplers_with_splits( STBIR_RESIZE * resize, int splits } STBIR_PROFILE_BUILD_CLEAR( resize->samplers ); - + return 1; } @@ -7652,7 +7854,7 @@ STBIRDEF int stbir_build_samplers( STBIR_RESIZE * resize ) STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize ) { int result; - + if ( ( resize->samplers == 0 ) || ( resize->needs_rebuild ) ) { int alloc_state = resize->called_alloc; // remember allocated state @@ -7665,10 +7867,10 @@ STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize ) if ( !stbir_build_samplers( resize ) ) return 0; - + resize->called_alloc = alloc_state; - // if build_samplers succeeded (above), but there are no samplers set, then + // if build_samplers succeeded (above), but there are no samplers set, then // the area to stretch into was zero pixels, so don't do anything and return // success if ( resize->samplers == 0 ) @@ -7680,10 +7882,6 @@ STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize ) STBIR_PROFILE_BUILD_CLEAR( resize->samplers ); } - - // update anything that can be changed without recalcing samplers - stbir__update_info_from_resize( resize->samplers, resize ); - // do resize result = stbir__perform_resize( resize->samplers, 0, resize->splits ); @@ -7692,7 +7890,7 @@ STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize ) { stbir_free_samplers( resize ); resize->samplers = 0; - } + } return result; } @@ -7707,14 +7905,11 @@ STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start // you **must** build samplers first when using split resize if ( ( resize->samplers == 0 ) || ( resize->needs_rebuild ) ) - return 0; - + return 0; + if ( ( split_start >= resize->splits ) || ( split_start < 0 ) || ( ( split_start + split_count ) > resize->splits ) || ( split_count <= 0 ) ) return 0; - - // update anything that can be changed without recalcing samplers - stbir__update_info_from_resize( resize->samplers, resize ); - + // do resize return stbir__perform_resize( resize->samplers, split_start, split_count ); } @@ -7735,7 +7930,7 @@ static int stbir__check_output_stuff( void ** ret_ptr, int * ret_pitch, void * o if ( output_stride_in_bytes < pitch ) return 0; - size = output_stride_in_bytes * output_h; + size = (size_t)output_stride_in_bytes * (size_t)output_h; if ( size == 0 ) return 0; @@ -7752,7 +7947,7 @@ static int stbir__check_output_stuff( void ** ret_ptr, int * ret_pitch, void * o *ret_pitch = pitch; } - return 1; + return 1; } @@ -7767,9 +7962,9 @@ STBIRDEF unsigned char * stbir_resize_uint8_linear( const unsigned char *input_p if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, sizeof( unsigned char ), output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) ) return 0; - stbir_resize_init( &resize, - input_pixels, input_w, input_h, input_stride_in_bytes, - (optr) ? optr : output_pixels, output_w, output_h, opitch, + stbir_resize_init( &resize, + input_pixels, input_w, input_h, input_stride_in_bytes, + (optr) ? optr : output_pixels, output_w, output_h, opitch, pixel_layout, STBIR_TYPE_UINT8 ); if ( !stbir_resize_extended( &resize ) ) @@ -7793,9 +7988,9 @@ STBIRDEF unsigned char * stbir_resize_uint8_srgb( const unsigned char *input_pix if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, sizeof( unsigned char ), output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) ) return 0; - stbir_resize_init( &resize, - input_pixels, input_w, input_h, input_stride_in_bytes, - (optr) ? optr : output_pixels, output_w, output_h, opitch, + stbir_resize_init( &resize, + input_pixels, input_w, input_h, input_stride_in_bytes, + (optr) ? optr : output_pixels, output_w, output_h, opitch, pixel_layout, STBIR_TYPE_UINT8_SRGB ); if ( !stbir_resize_extended( &resize ) ) @@ -7820,9 +8015,9 @@ STBIRDEF float * stbir_resize_float_linear( const float *input_pixels , int inpu if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, sizeof( float ), output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) ) return 0; - stbir_resize_init( &resize, - input_pixels, input_w, input_h, input_stride_in_bytes, - (optr) ? optr : output_pixels, output_w, output_h, opitch, + stbir_resize_init( &resize, + input_pixels, input_w, input_h, input_stride_in_bytes, + (optr) ? optr : output_pixels, output_w, output_h, opitch, pixel_layout, STBIR_TYPE_FLOAT ); if ( !stbir_resize_extended( &resize ) ) @@ -7838,7 +8033,7 @@ STBIRDEF float * stbir_resize_float_linear( const float *input_pixels , int inpu STBIRDEF void * stbir_resize( const void *input_pixels , int input_w , int input_h, int input_stride_in_bytes, void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_pixel_layout pixel_layout, stbir_datatype data_type, + stbir_pixel_layout pixel_layout, stbir_datatype data_type, stbir_edge edge, stbir_filter filter ) { STBIR_RESIZE resize; @@ -7848,9 +8043,9 @@ STBIRDEF void * stbir_resize( const void *input_pixels , int input_w , int input if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, stbir__type_size[data_type], output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) ) return 0; - stbir_resize_init( &resize, - input_pixels, input_w, input_h, input_stride_in_bytes, - (optr) ? optr : output_pixels, output_w, output_h, output_stride_in_bytes, + stbir_resize_init( &resize, + input_pixels, input_w, input_h, input_stride_in_bytes, + (optr) ? optr : output_pixels, output_w, output_h, output_stride_in_bytes, pixel_layout, data_type ); resize.horizontal_edge = edge; @@ -7958,7 +8153,7 @@ STBIRDEF void stbir_resize_extended_profile_info( STBIR_PROFILE_INFO * info, STB #else // STB_IMAGE_RESIZE_HORIZONTALS&STB_IMAGE_RESIZE_DO_VERTICALS // we reinclude the header file to define all the horizontal functions -// specializing each function for the number of coeffs is 20-40% faster *OVERALL* +// specializing each function for the number of coeffs is 20-40% faster *OVERALL* // by including the header file again this way, we can still debug the functions @@ -7991,16 +8186,16 @@ STBIRDEF void stbir_resize_extended_profile_info( STBIR_PROFILE_INFO * info, STB #define stbir__encode_order2 2 #define stbir__encode_order3 3 #define stbir__decode_simdf8_flip(reg) -#define stbir__decode_simdf4_flip(reg) +#define stbir__decode_simdf4_flip(reg) #define stbir__encode_simdf8_unflip(reg) -#define stbir__encode_simdf4_unflip(reg) +#define stbir__encode_simdf4_unflip(reg) #endif #ifdef STBIR_SIMD8 #define stbir__encode_simdfX_unflip stbir__encode_simdf8_unflip #else #define stbir__encode_simdfX_unflip stbir__encode_simdf4_unflip -#endif +#endif static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * decodep, int width_times_channels, void const * inputp ) { @@ -8013,6 +8208,7 @@ static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * deco if ( width_times_channels >= 16 ) { decode_end -= 16; + STBIR_NO_UNROLL_LOOP_START_INF_FOR for(;;) { #ifdef STBIR_SIMD8 @@ -8054,7 +8250,7 @@ static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * deco #endif decode += 16; input += 16; - if ( decode <= decode_end ) + if ( decode <= decode_end ) continue; if ( decode == ( decode_end + 16 ) ) break; @@ -8068,6 +8264,7 @@ static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * deco // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four decode += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( decode <= decode_end ) { STBIR_SIMD_NO_UNROLL(decode); @@ -8083,6 +8280,7 @@ static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * deco // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( decode < decode_end ) { STBIR_NO_UNROLL(decode); @@ -8109,6 +8307,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outpu { float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2; end_output -= stbir__simdfX_float_count*2; + STBIR_NO_UNROLL_LOOP_START_INF_FOR for(;;) { stbir__simdfX e0, e1; @@ -8119,15 +8318,15 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outpu stbir__encode_simdfX_unflip( e0 ); stbir__encode_simdfX_unflip( e1 ); #ifdef STBIR_SIMD8 - stbir__simdf8_pack_to_16bytes( i, e0, e1 ); + stbir__simdf8_pack_to_16bytes( i, e0, e1 ); stbir__simdi_store( output, i ); #else - stbir__simdf_pack_to_8bytes( i, e0, e1 ); + stbir__simdf_pack_to_8bytes( i, e0, e1 ); stbir__simdi_store2( output, i ); #endif encode += stbir__simdfX_float_count*2; output += stbir__simdfX_float_count*2; - if ( output <= end_output ) + if ( output <= end_output ) continue; if ( output == ( end_output + stbir__simdfX_float_count*2 ) ) break; @@ -8140,6 +8339,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outpu // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_NO_UNROLL_LOOP_START while( output <= end_output ) { stbir__simdf e0; @@ -8158,9 +8358,10 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outpu // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( output < end_output ) { - stbir__simdf e0; + stbir__simdf e0; STBIR_NO_UNROLL(encode); stbir__simdf_madd1_mem( e0, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint8_as_float), encode+stbir__encode_order0 ); output[0] = stbir__simdf_convert_float_to_uint8( e0 ); #if stbir__coder_min_num >= 2 @@ -8173,7 +8374,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outpu encode += stbir__coder_min_num; } #endif - + #else // try to do blocks of 4 when you can @@ -8194,6 +8395,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outpu // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( output < end_output ) { float f; @@ -8223,6 +8425,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_linear)( float * decodep, int if ( width_times_channels >= 16 ) { decode_end -= 16; + STBIR_NO_UNROLL_LOOP_START_INF_FOR for(;;) { #ifdef STBIR_SIMD8 @@ -8258,7 +8461,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_linear)( float * decodep, int #endif decode += 16; input += 16; - if ( decode <= decode_end ) + if ( decode <= decode_end ) continue; if ( decode == ( decode_end + 16 ) ) break; @@ -8272,6 +8475,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_linear)( float * decodep, int // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four decode += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( decode <= decode_end ) { STBIR_SIMD_NO_UNROLL(decode); @@ -8287,6 +8491,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_linear)( float * decodep, int // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( decode < decode_end ) { STBIR_NO_UNROLL(decode); @@ -8313,6 +8518,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear )( void * outputp, int { float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2; end_output -= stbir__simdfX_float_count*2; + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { stbir__simdfX e0, e1; @@ -8323,15 +8529,15 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear )( void * outputp, int stbir__encode_simdfX_unflip( e0 ); stbir__encode_simdfX_unflip( e1 ); #ifdef STBIR_SIMD8 - stbir__simdf8_pack_to_16bytes( i, e0, e1 ); + stbir__simdf8_pack_to_16bytes( i, e0, e1 ); stbir__simdi_store( output, i ); #else - stbir__simdf_pack_to_8bytes( i, e0, e1 ); + stbir__simdf_pack_to_8bytes( i, e0, e1 ); stbir__simdi_store2( output, i ); #endif encode += stbir__simdfX_float_count*2; output += stbir__simdfX_float_count*2; - if ( output <= end_output ) + if ( output <= end_output ) continue; if ( output == ( end_output + stbir__simdfX_float_count*2 ) ) break; @@ -8344,6 +8550,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear )( void * outputp, int // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_NO_UNROLL_LOOP_START while( output <= end_output ) { stbir__simdf e0; @@ -8382,6 +8589,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear )( void * outputp, int // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( output < end_output ) { float f; @@ -8422,6 +8630,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_srgb)( float * decodep, int wi // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( decode < decode_end ) { STBIR_NO_UNROLL(decode); @@ -8441,7 +8650,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_srgb)( float * decodep, int wi #define stbir__min_max_shift20( i, f ) \ stbir__simdf_max( f, f, stbir_simdf_casti(STBIR__CONSTI( STBIR_almost_zero )) ); \ stbir__simdf_min( f, f, stbir_simdf_casti(STBIR__CONSTI( STBIR_almost_one )) ); \ - stbir__simdi_32shr( i, stbir_simdi_castf( f ), 20 ); + stbir__simdi_32shr( i, stbir_simdi_castf( f ), 20 ); #define stbir__scale_and_convert( i, f ) \ stbir__simdf_madd( f, STBIR__CONSTF( STBIR_simd_point5 ), STBIR__CONSTF( STBIR_max_uint8_as_float ), f ); \ @@ -8468,7 +8677,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_srgb)( float * decodep, int wi temp1.m128i_u32[0] = table[temp1.m128i_i32[0]]; temp1.m128i_u32[1] = table[temp1.m128i_i32[1]]; temp1.m128i_u32[2] = table[temp1.m128i_i32[2]]; temp1.m128i_u32[3] = table[temp1.m128i_i32[3]]; \ v0 = temp0.m128i_i128; \ v1 = temp1.m128i_i128; \ -} +} #define stbir__simdi_table_lookup3( v0,v1,v2, table ) \ { \ @@ -8499,7 +8708,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_srgb)( float * decodep, int wi v1 = temp1.m128i_i128; \ v2 = temp2.m128i_i128; \ v3 = temp3.m128i_i128; \ -} +} static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int width_times_channels, float const * encode ) { @@ -8507,16 +8716,16 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int w unsigned char * end_output = ( (unsigned char*) output ) + width_times_channels; #ifdef STBIR_SIMD - stbir_uint32 const * to_srgb = fp32_to_srgb8_tab4 - (127-13)*8; if ( width_times_channels >= 16 ) { float const * end_encode_m16 = encode + width_times_channels - 16; end_output -= 16; + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { stbir__simdf f0, f1, f2, f3; - stbir__simdi i0, i1, i2, i3; + stbir__simdi i0, i1, i2, i3; STBIR_SIMD_NO_UNROLL(encode); stbir__simdf_load4_transposed( f0, f1, f2, f3, encode ); @@ -8525,9 +8734,9 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int w stbir__min_max_shift20( i1, f1 ); stbir__min_max_shift20( i2, f2 ); stbir__min_max_shift20( i3, f3 ); - - stbir__simdi_table_lookup4( i0, i1, i2, i3, to_srgb ); - + + stbir__simdi_table_lookup4( i0, i1, i2, i3, ( fp32_to_srgb8_tab4 - (127-13)*8 ) ); + stbir__linear_to_srgb_finish( i0, f0 ); stbir__linear_to_srgb_finish( i1, f1 ); stbir__linear_to_srgb_finish( i2, f2 ); @@ -8537,7 +8746,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int w encode += 16; output += 16; - if ( output <= end_output ) + if ( output <= end_output ) continue; if ( output == ( end_output + 16 ) ) break; @@ -8551,6 +8760,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int w // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while ( output <= end_output ) { STBIR_SIMD_NO_UNROLL(encode); @@ -8568,7 +8778,8 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int w // do the remnants #if stbir__coder_min_num < 4 - while( output < end_output ) + STBIR_NO_UNROLL_LOOP_START + while( output < end_output ) { STBIR_NO_UNROLL(encode); output[0] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order0] ); @@ -8608,12 +8819,12 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb4_linearalpha )( void * o unsigned char * end_output = ( (unsigned char*) output ) + width_times_channels; #ifdef STBIR_SIMD - stbir_uint32 const * to_srgb = fp32_to_srgb8_tab4 - (127-13)*8; if ( width_times_channels >= 16 ) { float const * end_encode_m16 = encode + width_times_channels - 16; end_output -= 16; + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { stbir__simdf f0, f1, f2, f3; @@ -8625,10 +8836,10 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb4_linearalpha )( void * o stbir__min_max_shift20( i0, f0 ); stbir__min_max_shift20( i1, f1 ); stbir__min_max_shift20( i2, f2 ); - stbir__scale_and_convert( i3, f3 ); - - stbir__simdi_table_lookup3( i0, i1, i2, to_srgb ); - + stbir__scale_and_convert( i3, f3 ); + + stbir__simdi_table_lookup3( i0, i1, i2, ( fp32_to_srgb8_tab4 - (127-13)*8 ) ); + stbir__linear_to_srgb_finish( i0, f0 ); stbir__linear_to_srgb_finish( i1, f1 ); stbir__linear_to_srgb_finish( i2, f2 ); @@ -8638,7 +8849,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb4_linearalpha )( void * o output += 16; encode += 16; - if ( output <= end_output ) + if ( output <= end_output ) continue; if ( output == ( end_output + 16 ) ) break; @@ -8649,9 +8860,10 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb4_linearalpha )( void * o } #endif + STBIR_SIMD_NO_UNROLL_LOOP_START do { float f; - STBIR_SIMD_NO_UNROLL(encode); + STBIR_SIMD_NO_UNROLL(encode); output[stbir__decode_order0] = stbir__linear_to_srgb_uchar( encode[0] ); output[stbir__decode_order1] = stbir__linear_to_srgb_uchar( encode[1] ); @@ -8686,7 +8898,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_srgb2_linearalpha)( float * de decode += 4; } decode -= 4; - if( decode < decode_end ) + if( decode < decode_end ) { decode[0] = stbir__srgb_uchar_to_linear_float[ stbir__decode_order0 ]; decode[1] = ( (float) input[stbir__decode_order1] ) * stbir__max_uint8_as_float_inverted; @@ -8699,16 +8911,16 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb2_linearalpha )( void * o unsigned char * end_output = ( (unsigned char*) output ) + width_times_channels; #ifdef STBIR_SIMD - stbir_uint32 const * to_srgb = fp32_to_srgb8_tab4 - (127-13)*8; if ( width_times_channels >= 16 ) { float const * end_encode_m16 = encode + width_times_channels - 16; end_output -= 16; + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { stbir__simdf f0, f1, f2, f3; - stbir__simdi i0, i1, i2, i3; + stbir__simdi i0, i1, i2, i3; STBIR_SIMD_NO_UNROLL(encode); stbir__simdf_load4_transposed( f0, f1, f2, f3, encode ); @@ -8717,9 +8929,9 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb2_linearalpha )( void * o stbir__scale_and_convert( i1, f1 ); stbir__min_max_shift20( i2, f2 ); stbir__scale_and_convert( i3, f3 ); - - stbir__simdi_table_lookup2( i0, i2, to_srgb ); - + + stbir__simdi_table_lookup2( i0, i2, ( fp32_to_srgb8_tab4 - (127-13)*8 ) ); + stbir__linear_to_srgb_finish( i0, f0 ); stbir__linear_to_srgb_finish( i2, f2 ); @@ -8727,7 +8939,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb2_linearalpha )( void * o output += 16; encode += 16; - if ( output <= end_output ) + if ( output <= end_output ) continue; if ( output == ( end_output + 16 ) ) break; @@ -8738,6 +8950,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb2_linearalpha )( void * o } #endif + STBIR_SIMD_NO_UNROLL_LOOP_START do { float f; STBIR_SIMD_NO_UNROLL(encode); @@ -8766,6 +8979,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear_scaled)( float * decod if ( width_times_channels >= 8 ) { decode_end -= 8; + STBIR_NO_UNROLL_LOOP_START_INF_FOR for(;;) { #ifdef STBIR_SIMD8 @@ -8793,9 +9007,9 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear_scaled)( float * decod stbir__simdf_store( decode + 0, of0 ); stbir__simdf_store( decode + 4, of1 ); #endif - decode += 8; + decode += 8; input += 8; - if ( decode <= decode_end ) + if ( decode <= decode_end ) continue; if ( decode == ( decode_end + 8 ) ) break; @@ -8809,6 +9023,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear_scaled)( float * decod // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four decode += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( decode <= decode_end ) { STBIR_SIMD_NO_UNROLL(decode); @@ -8824,6 +9039,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear_scaled)( float * decod // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( decode < decode_end ) { STBIR_NO_UNROLL(decode); @@ -8852,6 +9068,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * output { float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2; end_output -= stbir__simdfX_float_count*2; + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { stbir__simdfX e0, e1; @@ -8865,7 +9082,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * output stbir__simdiX_store( output, i ); encode += stbir__simdfX_float_count*2; output += stbir__simdfX_float_count*2; - if ( output <= end_output ) + if ( output <= end_output ) continue; if ( output == ( end_output + stbir__simdfX_float_count*2 ) ) break; @@ -8879,6 +9096,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * output // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_NO_UNROLL_LOOP_START while( output <= end_output ) { stbir__simdf e; @@ -8897,6 +9115,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * output // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( output < end_output ) { stbir__simdf e; @@ -8912,12 +9131,13 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * output encode += stbir__coder_min_num; } #endif - + #else // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( output <= end_output ) { float f; @@ -8934,6 +9154,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * output // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( output < end_output ) { float f; @@ -8963,6 +9184,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear)( float * decodep, int if ( width_times_channels >= 8 ) { decode_end -= 8; + STBIR_NO_UNROLL_LOOP_START_INF_FOR for(;;) { #ifdef STBIR_SIMD8 @@ -8989,7 +9211,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear)( float * decodep, int #endif decode += 8; input += 8; - if ( decode <= decode_end ) + if ( decode <= decode_end ) continue; if ( decode == ( decode_end + 8 ) ) break; @@ -9003,6 +9225,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear)( float * decodep, int // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four decode += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( decode <= decode_end ) { STBIR_SIMD_NO_UNROLL(decode); @@ -9018,6 +9241,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear)( float * decodep, int // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( decode < decode_end ) { STBIR_NO_UNROLL(decode); @@ -9045,6 +9269,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int { float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2; end_output -= stbir__simdfX_float_count*2; + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { stbir__simdfX e0, e1; @@ -9058,7 +9283,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int stbir__simdiX_store( output, i ); encode += stbir__simdfX_float_count*2; output += stbir__simdfX_float_count*2; - if ( output <= end_output ) + if ( output <= end_output ) continue; if ( output == ( end_output + stbir__simdfX_float_count*2 ) ) break; @@ -9072,6 +9297,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_NO_UNROLL_LOOP_START while( output <= end_output ) { stbir__simdf e; @@ -9093,6 +9319,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( output <= end_output ) { float f; @@ -9111,6 +9338,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( output < end_output ) { float f; @@ -9139,6 +9367,7 @@ static void STBIR__CODER_NAME(stbir__decode_half_float_linear)( float * decodep, { stbir__FP16 const * end_input_m8 = input + width_times_channels - 8; decode_end -= 8; + STBIR_NO_UNROLL_LOOP_START_INF_FOR for(;;) { STBIR_NO_UNROLL(decode); @@ -9166,7 +9395,7 @@ static void STBIR__CODER_NAME(stbir__decode_half_float_linear)( float * decodep, #endif decode += 8; input += 8; - if ( decode <= decode_end ) + if ( decode <= decode_end ) continue; if ( decode == ( decode_end + 8 ) ) break; @@ -9180,6 +9409,7 @@ static void STBIR__CODER_NAME(stbir__decode_half_float_linear)( float * decodep, // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four decode += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( decode <= decode_end ) { STBIR_SIMD_NO_UNROLL(decode); @@ -9195,6 +9425,7 @@ static void STBIR__CODER_NAME(stbir__decode_half_float_linear)( float * decodep, // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( decode < decode_end ) { STBIR_NO_UNROLL(decode); @@ -9221,6 +9452,7 @@ static void STBIR__CODER_NAME( stbir__encode_half_float_linear )( void * outputp { float const * end_encode_m8 = encode + width_times_channels - 8; end_output -= 8; + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { STBIR_SIMD_NO_UNROLL(encode); @@ -9247,7 +9479,7 @@ static void STBIR__CODER_NAME( stbir__encode_half_float_linear )( void * outputp #endif encode += 8; output += 8; - if ( output <= end_output ) + if ( output <= end_output ) continue; if ( output == ( end_output + 8 ) ) break; @@ -9261,6 +9493,7 @@ static void STBIR__CODER_NAME( stbir__encode_half_float_linear )( void * outputp // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( output <= end_output ) { STBIR_SIMD_NO_UNROLL(output); @@ -9276,6 +9509,7 @@ static void STBIR__CODER_NAME( stbir__encode_half_float_linear )( void * outputp // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( output < end_output ) { STBIR_NO_UNROLL(output); @@ -9304,6 +9538,7 @@ static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int { float const * end_input_m16 = input + width_times_channels - 16; decode_end -= 16; + STBIR_NO_UNROLL_LOOP_START_INF_FOR for(;;) { STBIR_NO_UNROLL(decode); @@ -9338,7 +9573,7 @@ static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int #endif decode += 16; input += 16; - if ( decode <= decode_end ) + if ( decode <= decode_end ) continue; if ( decode == ( decode_end + 16 ) ) break; @@ -9352,6 +9587,7 @@ static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four decode += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( decode <= decode_end ) { STBIR_SIMD_NO_UNROLL(decode); @@ -9367,6 +9603,7 @@ static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( decode < decode_end ) { STBIR_NO_UNROLL(decode); @@ -9383,10 +9620,10 @@ static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int #endif #else - + if ( (void*)decodep != inputp ) STBIR_MEMCPY( decodep, inputp, width_times_channels * sizeof( float ) ); - + #endif } @@ -9426,6 +9663,7 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int { float const * end_encode_m8 = encode + width_times_channels - ( stbir__simdfX_float_count * 2 ); end_output -= ( stbir__simdfX_float_count * 2 ); + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { stbir__simdfX e0, e1; @@ -9435,18 +9673,18 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int #ifdef STBIR_FLOAT_HIGH_CLAMP stbir__simdfX_min( e0, e0, high_clamp ); stbir__simdfX_min( e1, e1, high_clamp ); -#endif +#endif #ifdef STBIR_FLOAT_LOW_CLAMP stbir__simdfX_max( e0, e0, low_clamp ); stbir__simdfX_max( e1, e1, low_clamp ); -#endif +#endif stbir__encode_simdfX_unflip( e0 ); stbir__encode_simdfX_unflip( e1 ); stbir__simdfX_store( output, e0 ); stbir__simdfX_store( output+stbir__simdfX_float_count, e1 ); encode += stbir__simdfX_float_count * 2; output += stbir__simdfX_float_count * 2; - if ( output < end_output ) + if ( output < end_output ) continue; if ( output == ( end_output + ( stbir__simdfX_float_count * 2 ) ) ) break; @@ -9459,6 +9697,7 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_NO_UNROLL_LOOP_START while( output <= end_output ) { stbir__simdf e0; @@ -9466,10 +9705,10 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int stbir__simdf_load( e0, encode ); #ifdef STBIR_FLOAT_HIGH_CLAMP stbir__simdf_min( e0, e0, high_clamp ); -#endif +#endif #ifdef STBIR_FLOAT_LOW_CLAMP stbir__simdf_max( e0, e0, low_clamp ); -#endif +#endif stbir__encode_simdf4_unflip( e0 ); stbir__simdf_store( output-4, e0 ); output += 4; @@ -9483,6 +9722,7 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( output <= end_output ) { float e; @@ -9502,6 +9742,7 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( output < end_output ) { float e; @@ -9517,18 +9758,18 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int encode += stbir__coder_min_num; } #endif - + #endif } -#undef stbir__decode_suffix +#undef stbir__decode_suffix #undef stbir__decode_simdf8_flip #undef stbir__decode_simdf4_flip -#undef stbir__decode_order0 +#undef stbir__decode_order0 #undef stbir__decode_order1 #undef stbir__decode_order2 #undef stbir__decode_order3 -#undef stbir__encode_order0 +#undef stbir__encode_order0 #undef stbir__encode_order1 #undef stbir__encode_order2 #undef stbir__encode_order3 @@ -9612,7 +9853,8 @@ static void STBIR_chans( stbir__vertical_scatter_with_,_coeffs)( float ** output stbIF5(stbir__simdfX c5 = stbir__simdf_frepX( c5s ); ) stbIF6(stbir__simdfX c6 = stbir__simdf_frepX( c6s ); ) stbIF7(stbir__simdfX c7 = stbir__simdf_frepX( c7s ); ) - while ( ( (char*)input_end - (char*) input ) >= (16*stbir__simdfX_float_count) ) + STBIR_SIMD_NO_UNROLL_LOOP_START + while ( ( (char*)input_end - (char*) input ) >= (16*stbir__simdfX_float_count) ) { stbir__simdfX o0, o1, o2, o3, r0, r1, r2, r3; STBIR_SIMD_NO_UNROLL(output0); @@ -9621,52 +9863,53 @@ static void STBIR_chans( stbir__vertical_scatter_with_,_coeffs)( float ** output #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE stbIF0( stbir__simdfX_load( o0, output0 ); stbir__simdfX_load( o1, output0+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output0+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output0+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c0 ); stbir__simdfX_madd( o1, o1, r1, c0 ); stbir__simdfX_madd( o2, o2, r2, c0 ); stbir__simdfX_madd( o3, o3, r3, c0 ); + stbir__simdfX_madd( o0, o0, r0, c0 ); stbir__simdfX_madd( o1, o1, r1, c0 ); stbir__simdfX_madd( o2, o2, r2, c0 ); stbir__simdfX_madd( o3, o3, r3, c0 ); stbir__simdfX_store( output0, o0 ); stbir__simdfX_store( output0+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output0+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output0+(3*stbir__simdfX_float_count), o3 ); ) stbIF1( stbir__simdfX_load( o0, output1 ); stbir__simdfX_load( o1, output1+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output1+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output1+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c1 ); stbir__simdfX_madd( o1, o1, r1, c1 ); stbir__simdfX_madd( o2, o2, r2, c1 ); stbir__simdfX_madd( o3, o3, r3, c1 ); + stbir__simdfX_madd( o0, o0, r0, c1 ); stbir__simdfX_madd( o1, o1, r1, c1 ); stbir__simdfX_madd( o2, o2, r2, c1 ); stbir__simdfX_madd( o3, o3, r3, c1 ); stbir__simdfX_store( output1, o0 ); stbir__simdfX_store( output1+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output1+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output1+(3*stbir__simdfX_float_count), o3 ); ) stbIF2( stbir__simdfX_load( o0, output2 ); stbir__simdfX_load( o1, output2+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output2+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output2+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c2 ); stbir__simdfX_madd( o1, o1, r1, c2 ); stbir__simdfX_madd( o2, o2, r2, c2 ); stbir__simdfX_madd( o3, o3, r3, c2 ); + stbir__simdfX_madd( o0, o0, r0, c2 ); stbir__simdfX_madd( o1, o1, r1, c2 ); stbir__simdfX_madd( o2, o2, r2, c2 ); stbir__simdfX_madd( o3, o3, r3, c2 ); stbir__simdfX_store( output2, o0 ); stbir__simdfX_store( output2+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output2+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output2+(3*stbir__simdfX_float_count), o3 ); ) stbIF3( stbir__simdfX_load( o0, output3 ); stbir__simdfX_load( o1, output3+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output3+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output3+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c3 ); stbir__simdfX_madd( o1, o1, r1, c3 ); stbir__simdfX_madd( o2, o2, r2, c3 ); stbir__simdfX_madd( o3, o3, r3, c3 ); + stbir__simdfX_madd( o0, o0, r0, c3 ); stbir__simdfX_madd( o1, o1, r1, c3 ); stbir__simdfX_madd( o2, o2, r2, c3 ); stbir__simdfX_madd( o3, o3, r3, c3 ); stbir__simdfX_store( output3, o0 ); stbir__simdfX_store( output3+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output3+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output3+(3*stbir__simdfX_float_count), o3 ); ) stbIF4( stbir__simdfX_load( o0, output4 ); stbir__simdfX_load( o1, output4+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output4+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output4+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c4 ); stbir__simdfX_madd( o1, o1, r1, c4 ); stbir__simdfX_madd( o2, o2, r2, c4 ); stbir__simdfX_madd( o3, o3, r3, c4 ); + stbir__simdfX_madd( o0, o0, r0, c4 ); stbir__simdfX_madd( o1, o1, r1, c4 ); stbir__simdfX_madd( o2, o2, r2, c4 ); stbir__simdfX_madd( o3, o3, r3, c4 ); stbir__simdfX_store( output4, o0 ); stbir__simdfX_store( output4+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output4+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output4+(3*stbir__simdfX_float_count), o3 ); ) stbIF5( stbir__simdfX_load( o0, output5 ); stbir__simdfX_load( o1, output5+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output5+(2*stbir__simdfX_float_count)); stbir__simdfX_load( o3, output5+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c5 ); stbir__simdfX_madd( o1, o1, r1, c5 ); stbir__simdfX_madd( o2, o2, r2, c5 ); stbir__simdfX_madd( o3, o3, r3, c5 ); + stbir__simdfX_madd( o0, o0, r0, c5 ); stbir__simdfX_madd( o1, o1, r1, c5 ); stbir__simdfX_madd( o2, o2, r2, c5 ); stbir__simdfX_madd( o3, o3, r3, c5 ); stbir__simdfX_store( output5, o0 ); stbir__simdfX_store( output5+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output5+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output5+(3*stbir__simdfX_float_count), o3 ); ) stbIF6( stbir__simdfX_load( o0, output6 ); stbir__simdfX_load( o1, output6+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output6+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output6+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c6 ); stbir__simdfX_madd( o1, o1, r1, c6 ); stbir__simdfX_madd( o2, o2, r2, c6 ); stbir__simdfX_madd( o3, o3, r3, c6 ); + stbir__simdfX_madd( o0, o0, r0, c6 ); stbir__simdfX_madd( o1, o1, r1, c6 ); stbir__simdfX_madd( o2, o2, r2, c6 ); stbir__simdfX_madd( o3, o3, r3, c6 ); stbir__simdfX_store( output6, o0 ); stbir__simdfX_store( output6+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output6+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output6+(3*stbir__simdfX_float_count), o3 ); ) stbIF7( stbir__simdfX_load( o0, output7 ); stbir__simdfX_load( o1, output7+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output7+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output7+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c7 ); stbir__simdfX_madd( o1, o1, r1, c7 ); stbir__simdfX_madd( o2, o2, r2, c7 ); stbir__simdfX_madd( o3, o3, r3, c7 ); + stbir__simdfX_madd( o0, o0, r0, c7 ); stbir__simdfX_madd( o1, o1, r1, c7 ); stbir__simdfX_madd( o2, o2, r2, c7 ); stbir__simdfX_madd( o3, o3, r3, c7 ); stbir__simdfX_store( output7, o0 ); stbir__simdfX_store( output7+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output7+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output7+(3*stbir__simdfX_float_count), o3 ); ) #else - stbIF0( stbir__simdfX_mult( o0, r0, c0 ); stbir__simdfX_mult( o1, r1, c0 ); stbir__simdfX_mult( o2, r2, c0 ); stbir__simdfX_mult( o3, r3, c0 ); + stbIF0( stbir__simdfX_mult( o0, r0, c0 ); stbir__simdfX_mult( o1, r1, c0 ); stbir__simdfX_mult( o2, r2, c0 ); stbir__simdfX_mult( o3, r3, c0 ); stbir__simdfX_store( output0, o0 ); stbir__simdfX_store( output0+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output0+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output0+(3*stbir__simdfX_float_count), o3 ); ) - stbIF1( stbir__simdfX_mult( o0, r0, c1 ); stbir__simdfX_mult( o1, r1, c1 ); stbir__simdfX_mult( o2, r2, c1 ); stbir__simdfX_mult( o3, r3, c1 ); + stbIF1( stbir__simdfX_mult( o0, r0, c1 ); stbir__simdfX_mult( o1, r1, c1 ); stbir__simdfX_mult( o2, r2, c1 ); stbir__simdfX_mult( o3, r3, c1 ); stbir__simdfX_store( output1, o0 ); stbir__simdfX_store( output1+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output1+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output1+(3*stbir__simdfX_float_count), o3 ); ) - stbIF2( stbir__simdfX_mult( o0, r0, c2 ); stbir__simdfX_mult( o1, r1, c2 ); stbir__simdfX_mult( o2, r2, c2 ); stbir__simdfX_mult( o3, r3, c2 ); + stbIF2( stbir__simdfX_mult( o0, r0, c2 ); stbir__simdfX_mult( o1, r1, c2 ); stbir__simdfX_mult( o2, r2, c2 ); stbir__simdfX_mult( o3, r3, c2 ); stbir__simdfX_store( output2, o0 ); stbir__simdfX_store( output2+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output2+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output2+(3*stbir__simdfX_float_count), o3 ); ) - stbIF3( stbir__simdfX_mult( o0, r0, c3 ); stbir__simdfX_mult( o1, r1, c3 ); stbir__simdfX_mult( o2, r2, c3 ); stbir__simdfX_mult( o3, r3, c3 ); + stbIF3( stbir__simdfX_mult( o0, r0, c3 ); stbir__simdfX_mult( o1, r1, c3 ); stbir__simdfX_mult( o2, r2, c3 ); stbir__simdfX_mult( o3, r3, c3 ); stbir__simdfX_store( output3, o0 ); stbir__simdfX_store( output3+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output3+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output3+(3*stbir__simdfX_float_count), o3 ); ) - stbIF4( stbir__simdfX_mult( o0, r0, c4 ); stbir__simdfX_mult( o1, r1, c4 ); stbir__simdfX_mult( o2, r2, c4 ); stbir__simdfX_mult( o3, r3, c4 ); + stbIF4( stbir__simdfX_mult( o0, r0, c4 ); stbir__simdfX_mult( o1, r1, c4 ); stbir__simdfX_mult( o2, r2, c4 ); stbir__simdfX_mult( o3, r3, c4 ); stbir__simdfX_store( output4, o0 ); stbir__simdfX_store( output4+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output4+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output4+(3*stbir__simdfX_float_count), o3 ); ) - stbIF5( stbir__simdfX_mult( o0, r0, c5 ); stbir__simdfX_mult( o1, r1, c5 ); stbir__simdfX_mult( o2, r2, c5 ); stbir__simdfX_mult( o3, r3, c5 ); + stbIF5( stbir__simdfX_mult( o0, r0, c5 ); stbir__simdfX_mult( o1, r1, c5 ); stbir__simdfX_mult( o2, r2, c5 ); stbir__simdfX_mult( o3, r3, c5 ); stbir__simdfX_store( output5, o0 ); stbir__simdfX_store( output5+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output5+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output5+(3*stbir__simdfX_float_count), o3 ); ) - stbIF6( stbir__simdfX_mult( o0, r0, c6 ); stbir__simdfX_mult( o1, r1, c6 ); stbir__simdfX_mult( o2, r2, c6 ); stbir__simdfX_mult( o3, r3, c6 ); + stbIF6( stbir__simdfX_mult( o0, r0, c6 ); stbir__simdfX_mult( o1, r1, c6 ); stbir__simdfX_mult( o2, r2, c6 ); stbir__simdfX_mult( o3, r3, c6 ); stbir__simdfX_store( output6, o0 ); stbir__simdfX_store( output6+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output6+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output6+(3*stbir__simdfX_float_count), o3 ); ) - stbIF7( stbir__simdfX_mult( o0, r0, c7 ); stbir__simdfX_mult( o1, r1, c7 ); stbir__simdfX_mult( o2, r2, c7 ); stbir__simdfX_mult( o3, r3, c7 ); + stbIF7( stbir__simdfX_mult( o0, r0, c7 ); stbir__simdfX_mult( o1, r1, c7 ); stbir__simdfX_mult( o2, r2, c7 ); stbir__simdfX_mult( o3, r3, c7 ); stbir__simdfX_store( output7, o0 ); stbir__simdfX_store( output7+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output7+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output7+(3*stbir__simdfX_float_count), o3 ); ) #endif input += (4*stbir__simdfX_float_count); stbIF0( output0 += (4*stbir__simdfX_float_count); ) stbIF1( output1 += (4*stbir__simdfX_float_count); ) stbIF2( output2 += (4*stbir__simdfX_float_count); ) stbIF3( output3 += (4*stbir__simdfX_float_count); ) stbIF4( output4 += (4*stbir__simdfX_float_count); ) stbIF5( output5 += (4*stbir__simdfX_float_count); ) stbIF6( output6 += (4*stbir__simdfX_float_count); ) stbIF7( output7 += (4*stbir__simdfX_float_count); ) } - while ( ( (char*)input_end - (char*) input ) >= 16 ) + STBIR_SIMD_NO_UNROLL_LOOP_START + while ( ( (char*)input_end - (char*) input ) >= 16 ) { stbir__simdf o0, r0; STBIR_SIMD_NO_UNROLL(output0); @@ -9692,13 +9935,14 @@ static void STBIR_chans( stbir__vertical_scatter_with_,_coeffs)( float ** output stbIF6( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c6 ) ); stbir__simdf_store( output6, o0 ); ) stbIF7( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c7 ) ); stbir__simdf_store( output7, o0 ); ) #endif - + input += 4; stbIF0( output0 += 4; ) stbIF1( output1 += 4; ) stbIF2( output2 += 4; ) stbIF3( output3 += 4; ) stbIF4( output4 += 4; ) stbIF5( output5 += 4; ) stbIF6( output6 += 4; ) stbIF7( output7 += 4; ) } } #else - while ( ( (char*)input_end - (char*) input ) >= 16 ) + STBIR_NO_UNROLL_LOOP_START + while ( ( (char*)input_end - (char*) input ) >= 16 ) { float r0, r1, r2, r3; STBIR_NO_UNROLL(input); @@ -9729,7 +9973,8 @@ static void STBIR_chans( stbir__vertical_scatter_with_,_coeffs)( float ** output stbIF0( output0 += 4; ) stbIF1( output1 += 4; ) stbIF2( output2 += 4; ) stbIF3( output3 += 4; ) stbIF4( output4 += 4; ) stbIF5( output5 += 4; ) stbIF6( output6 += 4; ) stbIF7( output7 += 4; ) } #endif - while ( input < input_end ) + STBIR_NO_UNROLL_LOOP_START + while ( input < input_end ) { float r = input[0]; STBIR_NO_UNROLL(output0); @@ -9779,7 +10024,7 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, STBIR_MEMCPY( output, input0, (char*)input0_end - (char*)input0 ); return; } -#endif +#endif #ifdef STBIR_SIMD { @@ -9791,14 +10036,15 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, stbIF5(stbir__simdfX c5 = stbir__simdf_frepX( c5s ); ) stbIF6(stbir__simdfX c6 = stbir__simdf_frepX( c6s ); ) stbIF7(stbir__simdfX c7 = stbir__simdf_frepX( c7s ); ) - - while ( ( (char*)input0_end - (char*) input0 ) >= (16*stbir__simdfX_float_count) ) + + STBIR_SIMD_NO_UNROLL_LOOP_START + while ( ( (char*)input0_end - (char*) input0 ) >= (16*stbir__simdfX_float_count) ) { stbir__simdfX o0, o1, o2, o3, r0, r1, r2, r3; STBIR_SIMD_NO_UNROLL(output); // prefetch four loop iterations ahead (doesn't affect much for small resizes, but helps with big ones) - stbIF0( stbir__prefetch( input0 + (16*stbir__simdfX_float_count) ); ) + stbIF0( stbir__prefetch( input0 + (16*stbir__simdfX_float_count) ); ) stbIF1( stbir__prefetch( input1 + (16*stbir__simdfX_float_count) ); ) stbIF2( stbir__prefetch( input2 + (16*stbir__simdfX_float_count) ); ) stbIF3( stbir__prefetch( input3 + (16*stbir__simdfX_float_count) ); ) @@ -9836,7 +10082,8 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, stbIF0( input0 += (4*stbir__simdfX_float_count); ) stbIF1( input1 += (4*stbir__simdfX_float_count); ) stbIF2( input2 += (4*stbir__simdfX_float_count); ) stbIF3( input3 += (4*stbir__simdfX_float_count); ) stbIF4( input4 += (4*stbir__simdfX_float_count); ) stbIF5( input5 += (4*stbir__simdfX_float_count); ) stbIF6( input6 += (4*stbir__simdfX_float_count); ) stbIF7( input7 += (4*stbir__simdfX_float_count); ) } - while ( ( (char*)input0_end - (char*) input0 ) >= 16 ) + STBIR_SIMD_NO_UNROLL_LOOP_START + while ( ( (char*)input0_end - (char*) input0 ) >= 16 ) { stbir__simdf o0, r0; STBIR_SIMD_NO_UNROLL(output); @@ -9860,7 +10107,8 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, } } #else - while ( ( (char*)input0_end - (char*) input0 ) >= 16 ) + STBIR_NO_UNROLL_LOOP_START + while ( ( (char*)input0_end - (char*) input0 ) >= 16 ) { float o0, o1, o2, o3; STBIR_NO_UNROLL(output); @@ -9881,7 +10129,8 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, stbIF0( input0 += 4; ) stbIF1( input1 += 4; ) stbIF2( input2 += 4; ) stbIF3( input3 += 4; ) stbIF4( input4 += 4; ) stbIF5( input5 += 4; ) stbIF6( input6 += 4; ) stbIF7( input7 += 4; ) } #endif - while ( input0 < input0_end ) + STBIR_NO_UNROLL_LOOP_START + while ( input0 < input0_end ) { float o0; STBIR_NO_UNROLL(output); @@ -9897,7 +10146,7 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, stbIF5( o0 += input5[0] * c5s; ) stbIF6( o0 += input6[0] * c6s; ) stbIF7( o0 += input7[0] * c7s; ) - output[0] = o0; + output[0] = o0; ++output; stbIF0( ++input0; ) stbIF1( ++input1; ) stbIF2( ++input2; ) stbIF3( ++input3; ) stbIF4( ++input4; ) stbIF5( ++input5; ) stbIF6( ++input6; ) stbIF7( ++input7; ) } @@ -9928,25 +10177,25 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, #ifndef stbir__2_coeff_only #define stbir__2_coeff_only() \ stbir__1_coeff_only(); \ - stbir__1_coeff_remnant(1); + stbir__1_coeff_remnant(1); #endif #ifndef stbir__2_coeff_remnant #define stbir__2_coeff_remnant( ofs ) \ stbir__1_coeff_remnant(ofs); \ - stbir__1_coeff_remnant((ofs)+1); + stbir__1_coeff_remnant((ofs)+1); #endif - + #ifndef stbir__3_coeff_only #define stbir__3_coeff_only() \ stbir__2_coeff_only(); \ - stbir__1_coeff_remnant(2); + stbir__1_coeff_remnant(2); #endif - + #ifndef stbir__3_coeff_remnant #define stbir__3_coeff_remnant( ofs ) \ stbir__2_coeff_remnant(ofs); \ - stbir__1_coeff_remnant((ofs)+2); + stbir__1_coeff_remnant((ofs)+2); #endif #ifndef stbir__3_coeff_setup @@ -9956,13 +10205,13 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, #ifndef stbir__4_coeff_start #define stbir__4_coeff_start() \ stbir__2_coeff_only(); \ - stbir__2_coeff_remnant(2); + stbir__2_coeff_remnant(2); #endif - + #ifndef stbir__4_coeff_continue_from_4 #define stbir__4_coeff_continue_from_4( ofs ) \ stbir__2_coeff_remnant(ofs); \ - stbir__2_coeff_remnant((ofs)+2); + stbir__2_coeff_remnant((ofs)+2); #endif #ifndef stbir__store_output_tiny @@ -9973,8 +10222,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_1_coeff)( floa { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__1_coeff_only(); stbir__store_output_tiny(); @@ -9985,8 +10235,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_2_coeffs)( flo { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__2_coeff_only(); stbir__store_output_tiny(); @@ -9997,8 +10248,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_3_coeffs)( flo { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__3_coeff_only(); stbir__store_output_tiny(); @@ -10009,8 +10261,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_4_coeffs)( flo { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); stbir__store_output(); @@ -10021,8 +10274,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_5_coeffs)( flo { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); stbir__1_coeff_remnant(4); @@ -10034,8 +10288,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_6_coeffs)( flo { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); stbir__2_coeff_remnant(4); @@ -10048,10 +10303,11 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_7_coeffs)( flo float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; stbir__3_coeff_setup(); + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; - + stbir__4_coeff_start(); stbir__3_coeff_remnant(4); stbir__store_output(); @@ -10062,8 +10318,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_8_coeffs)( flo { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); stbir__4_coeff_continue_from_4(4); @@ -10075,8 +10332,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_9_coeffs)( flo { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); stbir__4_coeff_continue_from_4(4); @@ -10089,8 +10347,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_10_coeffs)( fl { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); stbir__4_coeff_continue_from_4(4); @@ -10104,8 +10363,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_11_coeffs)( fl float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; stbir__3_coeff_setup(); + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); stbir__4_coeff_continue_from_4(4); @@ -10118,8 +10378,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_12_coeffs)( fl { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); stbir__4_coeff_continue_from_4(4); @@ -10132,12 +10393,14 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod0 { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 4 + 3 ) >> 2; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 4 + 3 ) >> 2; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); + STBIR_SIMD_NO_UNROLL_LOOP_START do { hc += 4; decode += STBIR__horizontal_channels * 4; @@ -10152,19 +10415,21 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod1 { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 5 + 3 ) >> 2; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 5 + 3 ) >> 2; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); + STBIR_SIMD_NO_UNROLL_LOOP_START do { hc += 4; decode += STBIR__horizontal_channels * 4; stbir__4_coeff_continue_from_4( 0 ); --n; } while ( n > 0 ); - stbir__1_coeff_remnant( 4 ); + stbir__1_coeff_remnant( 4 ); stbir__store_output(); } while ( output < output_end ); } @@ -10173,19 +10438,21 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod2 { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 6 + 3 ) >> 2; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 6 + 3 ) >> 2; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); + STBIR_SIMD_NO_UNROLL_LOOP_START do { hc += 4; decode += STBIR__horizontal_channels * 4; stbir__4_coeff_continue_from_4( 0 ); --n; } while ( n > 0 ); - stbir__2_coeff_remnant( 4 ); + stbir__2_coeff_remnant( 4 ); stbir__store_output(); } while ( output < output_end ); @@ -10196,19 +10463,21 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod3 float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; stbir__3_coeff_setup(); + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 7 + 3 ) >> 2; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 7 + 3 ) >> 2; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); + STBIR_SIMD_NO_UNROLL_LOOP_START do { hc += 4; decode += STBIR__horizontal_channels * 4; stbir__4_coeff_continue_from_4( 0 ); --n; } while ( n > 0 ); - stbir__3_coeff_remnant( 4 ); + stbir__3_coeff_remnant( 4 ); stbir__store_output(); } while ( output < output_end ); @@ -10216,26 +10485,26 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod3 static stbir__horizontal_gather_channels_func * STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_funcs)[4]= { - STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod0), - STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod1), - STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod2), - STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod3), + STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod0), + STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod1), + STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod2), + STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod3), }; static stbir__horizontal_gather_channels_func * STBIR_chans(stbir__horizontal_gather_,_channels_funcs)[12]= { - STBIR_chans(stbir__horizontal_gather_,_channels_with_1_coeff), - STBIR_chans(stbir__horizontal_gather_,_channels_with_2_coeffs), + STBIR_chans(stbir__horizontal_gather_,_channels_with_1_coeff), + STBIR_chans(stbir__horizontal_gather_,_channels_with_2_coeffs), STBIR_chans(stbir__horizontal_gather_,_channels_with_3_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_4_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_5_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_6_coeffs), + STBIR_chans(stbir__horizontal_gather_,_channels_with_4_coeffs), + STBIR_chans(stbir__horizontal_gather_,_channels_with_5_coeffs), + STBIR_chans(stbir__horizontal_gather_,_channels_with_6_coeffs), STBIR_chans(stbir__horizontal_gather_,_channels_with_7_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_8_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_9_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_10_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_11_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_12_coeffs), + STBIR_chans(stbir__horizontal_gather_,_channels_with_8_coeffs), + STBIR_chans(stbir__horizontal_gather_,_channels_with_9_coeffs), + STBIR_chans(stbir__horizontal_gather_,_channels_with_10_coeffs), + STBIR_chans(stbir__horizontal_gather_,_channels_with_11_coeffs), + STBIR_chans(stbir__horizontal_gather_,_channels_with_12_coeffs), }; #undef STBIR__horizontal_channels @@ -10266,38 +10535,38 @@ This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------ ALTERNATIVE A - MIT License Copyright (c) 2017 Sean Barrett -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 +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 +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 +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. ------------------------------------------------------------------------------ ALTERNATIVE B - Public Domain (www.unlicense.org) This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. -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 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 +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 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. ------------------------------------------------------------------------------ */ diff --git a/src/minshell.html b/src/minshell.html index 38f3672b9..4068ca36c 100644 --- a/src/minshell.html +++ b/src/minshell.html @@ -34,8 +34,12 @@