h-raylib 5.5.0.0 → 5.5.1.0
raw patch · 84 files changed
+23340/−23783 lines, 84 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Raylib.Core.Textures: c'loadImageSvg :: CString -> CInt -> CInt -> IO (Ptr Image)
- Raylib.Core.Textures: loadImageSvg :: String -> Int -> Int -> IO Image
- Raylib.Types.Util.GUI: Icon228 :: GuiIconName
+ Raylib.Core: c'makeDirectory :: CString -> IO CInt
+ Raylib.Core: makeDirectory :: String -> IO Bool
+ Raylib.Core: setTraceLogCallback :: TraceLogCallback -> IO ()
+ Raylib.Core.Models: c'drawModelPoints :: Ptr Model -> Ptr Vector3 -> CFloat -> Ptr Color -> IO ()
+ Raylib.Core.Models: c'drawModelPointsEx :: Ptr Model -> Ptr Vector3 -> Ptr Vector3 -> CFloat -> Ptr Vector3 -> Ptr Color -> IO ()
+ Raylib.Core.Models: c'updateModelAnimationBoneMatrices :: Ptr Model -> Ptr ModelAnimation -> CInt -> IO ()
+ Raylib.Core.Models: drawModelPoints :: Model -> Vector3 -> Float -> Color -> IO ()
+ Raylib.Core.Models: drawModelPointsEx :: Model -> Vector3 -> Vector3 -> Float -> Vector3 -> Color -> IO ()
+ Raylib.Core.Models: updateModelAnimationBoneMatrices :: Model -> ModelAnimation -> Int -> IO ()
+ Raylib.Core.Textures: c'colorLerp :: Ptr Color -> Ptr Color -> CFloat -> IO (Ptr Color)
+ Raylib.Core.Textures: colorLerp :: Color -> Color -> Float -> Color
+ Raylib.Types.Core: type C'TraceLogCallback = FunPtr CInt -> CString -> IO ()
+ Raylib.Types.Core: type TraceLogCallback = TraceLogLevel -> String -> IO ()
+ Raylib.Types.Core.Models: DefaultShaderAttribLocationBoneIds :: DefaultShaderAttributeLocation
+ Raylib.Types.Core.Models: DefaultShaderAttribLocationBoneWeights :: DefaultShaderAttributeLocation
+ Raylib.Types.Core.Models: DefaultShaderAttribLocationColor :: DefaultShaderAttributeLocation
+ Raylib.Types.Core.Models: DefaultShaderAttribLocationIndices :: DefaultShaderAttributeLocation
+ Raylib.Types.Core.Models: DefaultShaderAttribLocationNormal :: DefaultShaderAttributeLocation
+ Raylib.Types.Core.Models: DefaultShaderAttribLocationPosition :: DefaultShaderAttributeLocation
+ Raylib.Types.Core.Models: DefaultShaderAttribLocationTangent :: DefaultShaderAttributeLocation
+ Raylib.Types.Core.Models: DefaultShaderAttribLocationTexcoord :: DefaultShaderAttributeLocation
+ Raylib.Types.Core.Models: DefaultShaderAttribLocationTexcoord2 :: DefaultShaderAttributeLocation
+ Raylib.Types.Core.Models: ShaderLocBoneMatrices :: ShaderLocationIndex
+ Raylib.Types.Core.Models: ShaderLocVertexBoneIds :: ShaderLocationIndex
+ Raylib.Types.Core.Models: ShaderLocVertexBoneWeights :: ShaderLocationIndex
+ Raylib.Types.Core.Models: [mesh'boneCount] :: Mesh -> Int
+ Raylib.Types.Core.Models: [mesh'boneMatrices] :: Mesh -> Maybe [Matrix]
+ Raylib.Types.Core.Models: data DefaultShaderAttributeLocation
+ Raylib.Types.Core.Models: instance GHC.Classes.Eq Raylib.Types.Core.Models.DefaultShaderAttributeLocation
+ Raylib.Types.Core.Models: instance GHC.Enum.Enum Raylib.Types.Core.Models.DefaultShaderAttributeLocation
+ Raylib.Types.Core.Models: instance GHC.Show.Show Raylib.Types.Core.Models.DefaultShaderAttributeLocation
+ Raylib.Types.Util.GUI: DropdownRollUp :: GuiDropdownBoxProperty
+ Raylib.Types.Util.GUI: IconHot :: GuiIconName
+ Raylib.Types.Util.RLGL: RLShaderUniformUIVec2 :: RLShaderUniformDataType
+ Raylib.Types.Util.RLGL: RLShaderUniformUIVec3 :: RLShaderUniformDataType
+ Raylib.Types.Util.RLGL: RLShaderUniformUIVec4 :: RLShaderUniformDataType
+ Raylib.Types.Util.RLGL: RLShaderUniformUInt :: RLShaderUniformDataType
+ Raylib.Util.Lenses: _mesh'boneCount :: Lens' Mesh Int
+ Raylib.Util.Lenses: _mesh'boneMatrices :: Lens' Mesh (Maybe [Matrix])
+ Raylib.Util.RLGL: c'rlSetUniformMatrices :: CInt -> Ptr Matrix -> CInt -> IO ()
+ Raylib.Util.RLGL: rlSetUniformMatrices :: Int -> [Matrix] -> IO ()
- Raylib.Core: setLoadFileDataCallback :: LoadFileDataCallback -> IO C'LoadFileDataCallback
+ Raylib.Core: setLoadFileDataCallback :: LoadFileDataCallback -> IO ()
- Raylib.Core: setLoadFileTextCallback :: LoadFileTextCallback -> IO C'LoadFileTextCallback
+ Raylib.Core: setLoadFileTextCallback :: LoadFileTextCallback -> IO ()
- Raylib.Core: setSaveFileDataCallback :: Storable a => SaveFileDataCallback a -> IO C'SaveFileDataCallback
+ Raylib.Core: setSaveFileDataCallback :: Storable a => SaveFileDataCallback a -> IO ()
- Raylib.Core: setSaveFileTextCallback :: SaveFileTextCallback -> IO C'SaveFileTextCallback
+ Raylib.Core: setSaveFileTextCallback :: SaveFileTextCallback -> IO ()
- Raylib.Types.Core: type C'LoadFileDataCallback = FunPtr (CString -> Ptr CUInt -> IO (Ptr CUChar))
+ Raylib.Types.Core: type C'LoadFileDataCallback = FunPtr CString -> Ptr CUInt -> IO Ptr CUChar
- Raylib.Types.Core: type C'LoadFileTextCallback = FunPtr (CString -> IO CString)
+ Raylib.Types.Core: type C'LoadFileTextCallback = FunPtr CString -> IO CString
- Raylib.Types.Core: type C'SaveFileDataCallback = FunPtr (CString -> Ptr () -> CUInt -> IO CInt)
+ Raylib.Types.Core: type C'SaveFileDataCallback = FunPtr CString -> Ptr () -> CUInt -> IO CInt
- Raylib.Types.Core: type C'SaveFileTextCallback = FunPtr (CString -> CString -> IO CInt)
+ Raylib.Types.Core: type C'SaveFileTextCallback = FunPtr CString -> CString -> IO CInt
- Raylib.Types.Core.Audio: type C'AudioCallback = FunPtr (Ptr () -> CUInt -> IO ())
+ Raylib.Types.Core.Audio: type C'AudioCallback = FunPtr Ptr () -> CUInt -> IO ()
- Raylib.Types.Core.Models: Mesh :: Int -> Int -> [Vector3] -> [Vector2] -> Maybe [Vector2] -> [Vector3] -> Maybe [Vector4] -> Maybe [Color] -> Maybe [Word16] -> Maybe [Vector3] -> Maybe [Vector3] -> Maybe [Word8] -> Maybe [Float] -> Integer -> Maybe [Integer] -> Mesh
+ Raylib.Types.Core.Models: Mesh :: Int -> Int -> [Vector3] -> [Vector2] -> Maybe [Vector2] -> [Vector3] -> Maybe [Vector4] -> Maybe [Color] -> Maybe [Word16] -> Maybe [Vector3] -> Maybe [Vector3] -> Maybe [Word8] -> Maybe [Float] -> Maybe [Matrix] -> Int -> Integer -> Maybe [Integer] -> Mesh
Files
- CHANGELOG.md +15/−0
- CONTRIBUTING.md +5/−5
- README.md +2/−2
- default.nix +1/−1
- examples/basic-callbacks/src/Main.hs +4/−3
- flake.nix +4/−4
- h-raylib.cabal +16/−11
- lib/rl_bindings.c +44/−7
- lib/rl_bindings.h +14/−2
- lib/rlgl_bindings.c +5/−0
- lib/rlgl_bindings.h +2/−0
- raygui/src/raygui.h +92/−34
- raygui/styles/amber/style_amber.h +590/−593
- raylib/examples/audio/audio_mixed_processor.c +1/−1
- raylib/examples/core/core_automation_events.c +36/−34
- raylib/examples/core/core_input_gamepad_info.c +9/−9
- raylib/examples/core/core_input_virtual_controls.c +123/−0
- raylib/examples/core/core_vr_simulator.c +1/−1
- raylib/examples/models/models_box_collisions.c +1/−1
- raylib/examples/models/models_gpu_skinning.c +119/−0
- raylib/examples/models/models_point_rendering.c +182/−0
- raylib/examples/models/models_yaw_pitch_roll.c +1/−0
- raylib/examples/shaders/shaders_basic_pbr.c +1/−1
- raylib/examples/shaders/shaders_lightmap.c +2/−0
- raylib/examples/shaders/shaders_texture_drawing.c +1/−0
- raylib/examples/shaders/shaders_vertex_displacement.c +119/−0
- raylib/examples/shapes/raygui.h +433/−235
- raylib/examples/shapes/shapes_bouncing_ball.c +1/−1
- raylib/examples/shapes/shapes_draw_circle_sector.c +4/−4
- raylib/examples/shapes/shapes_draw_rectangle_rounded.c +5/−5
- raylib/examples/shapes/shapes_draw_ring.c +5/−5
- raylib/examples/text/text_input_box.c +1/−1
- raylib/examples/text/text_writing_anim.c +1/−1
- raylib/examples/textures/textures_blend_modes.c +3/−0
- raylib/examples/textures/textures_image_drawing.c +1/−1
- raylib/examples/textures/textures_image_rotate.c +2/−0
- raylib/examples/textures/textures_logo_raylib.c +2/−0
- raylib/examples/textures/textures_raw_data.c +2/−0
- raylib/examples/textures/textures_sprite_explosion.c +2/−2
- raylib/examples/textures/textures_svg_loading.c +0/−72
- raylib/examples/textures/textures_to_image.c +2/−0
- raylib/parser/raylib_parser.c +2/−2
- raylib/src/config.h +21/−7
- raylib/src/external/RGFW.h +8935/−6575
- raylib/src/external/glfw/src/mappings.h +1/−0
- raylib/src/external/jar_xm.h +5/−5
- raylib/src/external/miniaudio.h too large to diff
- raylib/src/external/nanosvg.h +0/−3053
- raylib/src/external/nanosvgrast.h +0/−1458
- raylib/src/external/par_shapes.h +1/−1
- raylib/src/external/stb_image_resize2.h +10569/−10300
- raylib/src/platforms/rcore_android.c +29/−14
- raylib/src/platforms/rcore_desktop_glfw.c +53/−25
- raylib/src/platforms/rcore_desktop_rgfw.c +39/−41
- raylib/src/platforms/rcore_desktop_sdl.c +29/−4
- raylib/src/platforms/rcore_drm.c +12/−4
- raylib/src/platforms/rcore_template.c +7/−1
- raylib/src/platforms/rcore_web.c +18/−12
- raylib/src/raudio.c +3/−1
- raylib/src/raylib.h +25/−16
- raylib/src/rcamera.h +29/−24
- raylib/src/rcore.c +151/−47
- raylib/src/rlgl.h +111/−19
- raylib/src/rmodels.c +448/−142
- raylib/src/rshapes.c +15/−19
- raylib/src/rtext.c +24/−19
- raylib/src/rtextures.c +41/−118
- raylib/src/utils.c +0/−1
- src/Raylib/Core.hs +228/−222
- src/Raylib/Core/Audio.hs +66/−66
- src/Raylib/Core/Camera.hs +2/−2
- src/Raylib/Core/Models.hs +91/−73
- src/Raylib/Core/Shapes.hs +78/−78
- src/Raylib/Core/Text.hs +29/−29
- src/Raylib/Core/Textures.hs +115/−115
- src/Raylib/Internal.hs +10/−10
- src/Raylib/Internal/TH.hs +7/−7
- src/Raylib/Types/Core.hs +6/−0
- src/Raylib/Types/Core/Models.hs +41/−11
- src/Raylib/Types/Util/GUI.hs +7/−3
- src/Raylib/Types/Util/RLGL.hs +8/−0
- src/Raylib/Util/GUI.hs +57/−57
- src/Raylib/Util/GUI/Styles.hs +12/−12
- src/Raylib/Util/RLGL.hs +161/−154
CHANGELOG.md view
@@ -1,5 +1,20 @@ # h-raylib changelog +## Changelog guidelines (apply to `5.5.0.0` onward)++Changes ported from the upstream raylib code are not mentioned unless they are breaking changes. Changes and bug fixes in the h-raylib API are mentioned, breaking and non-breaking. Internal changes that do not change the API or affect functionality are not mentioned (e.g. performance improvements).++### Versioning scheme++h-raylib's version numbers do not follow the usual format. The first two numbers in the version track the underlying C raylib version. For example, `5.1.x.x` versions use raylib 5.1 under the hood. The third number represents breaking changes (renamed/deleted functions or modules). The last number represents non-breaking changes (new functions or modules, bug fixes, etc). The safest version bound format to use is `h-raylib >=x.y.z.w && <x.y.(z+1)` (instead of the usual `^>=` bound).++## Version 5.5.1.0+_11 October 2024_++- **BREAKING CHANGE**: `set*Callback` functions are no longer managed and do not return `IO C'*Callback` values+- **BREAKING CHANGE**: Removed `loadImageSvg` (upstream change in raylib)+- \[[#58](https://github.com/Anut-py/h-raylib/issues/58)\] Added support for `setTraceLogCallback`+ ## Version 5.5.0.0 _12 July 2024_
CONTRIBUTING.md view
@@ -12,27 +12,27 @@ [DOCUMENTATION.md](https://github.com/Anut-py/h-raylib/blob/master/DOCUMENTATION.md) has information that is specific to h-raylib. -# h-raylib roadmap+## h-raylib roadmap This is a list of features that may be added to this project. Contributors are welcome to help implement these. -## Pending+### Pending Items which have not yet been worked on. Feel free to work on one of these. - Bind `rgestures` -## In progress+### In progress - Add web build support \[[#4](https://github.com/Anut-py/h-raylib/issues/4)\] -## Implemented+### Implemented Items which have been completed but not published to hackage. (none) -## Published+### Published Items which have been published to hackage.
README.md view
@@ -1,6 +1,6 @@ # h-raylib: Haskell bindings for Raylib -[](https://github.com/Anut-py/h-raylib/actions/workflows/cabal-build.yml) [](https://github.com/Anut-py/h-raylib/actions/workflows/nix-build.yml) +[](https://github.com/Anut-py/h-raylib/actions/workflows/cabal-build.yml) [](https://github.com/Anut-py/h-raylib/actions/workflows/nix-build.yml) [](https://hackage.haskell.org/package/h-raylib) This library includes Haskell bindings to the [Raylib](https://www.raylib.com/) library.@@ -109,7 +109,7 @@ - When I try to compile an h-raylib program I get the error `Missing (or bad) C libraries: gcc_eh` - See [#36](https://github.com/Anut-py/h-raylib/issues/36) -If you find a bug, please [create an issue on GitHub](https://github.com/Anut-py/h-raylib/issues).+If you find a bug, please [create an issue on GitHub](https://github.com/Anut-py/h-raylib/issues). There are probably some bindings that are incomplete or do not work properly, so if something seems wrong then it is most likely a bug. If you have a question about the library that is not related to a bug, ask it on [GitHub discussions](https://github.com/Anut-py/h-raylib/discussions) or in the [Haskell GameDev Discord server](https://discord.gg/aKHNgxc59t).
default.nix view
@@ -3,7 +3,7 @@ }: mkDerivation { pname = "h-raylib";- version = "5.5.0.0";+ version = "5.5.1.0"; src = ./.; isLibrary = true; isExecutable = buildExamples;
examples/basic-callbacks/src/Main.hs view
@@ -2,9 +2,9 @@ module Main where import Paths_h_raylib (getDataFileName)-import Raylib.Core (clearBackground, initWindow, setTargetFPS, windowShouldClose, closeWindow, setLoadFileTextCallback, loadFileText)+import Raylib.Core (clearBackground, initWindow, setTargetFPS, windowShouldClose, closeWindow, setLoadFileTextCallback, setTraceLogCallback, loadFileText) import Raylib.Core.Text (drawText)-import Raylib.Util (drawing, raylibApplication, WindowResources, managed)+import Raylib.Util (drawing, raylibApplication, WindowResources) import Raylib.Util.Colors (black, rayWhite) filePath :: String@@ -14,9 +14,10 @@ startup :: IO AppState startup = do+ setTraceLogCallback (\logLevel text -> putStrLn (show logLevel ++ ": " ++ text)) window <- initWindow 600 450 "raylib [core] example - basic callbacks" setTargetFPS 60- _ <- managed window $ setLoadFileTextCallback (\s -> putStrLn ("opening file: " ++ s) >> readFile s)+ setLoadFileTextCallback (\s -> putStrLn ("opening file: " ++ s) >> readFile s) text <- loadFileText =<< getDataFileName filePath return (text, window)
flake.nix view
@@ -9,10 +9,10 @@ forAllSystems' = nixpkgs.lib.genAttrs; forAllSystems = forAllSystems' supportedSystems; - raylibRev = "8d5374a443509036063a350d1649408e009425e7";- raylibHash = "sha256-kYuqEUkyw8dngy5yBneNn+Br0xQr6NagP/s2CPM+q44=";- rayguiRev = "3fb9d77a67243497e10ae0448374a52a2a65e26f";- rayguiHash = "sha256-aWfXimbGU7RYqqOd44GmH3jPN8gcN4D/ygB71jIEr2c=";+ raylibRev = "f5328a9bb63a0e0eca7dead15cfa01a3ec1417c2";+ raylibHash = "sha256-gAv1jfMdbKWnlIqqBddVn+WE0BOIARMmagpK61bxVnU=";+ rayguiRev = "1e03efca48c50c5ea4b4a053d5bf04bad58d3e43";+ rayguiHash = "sha256-PzQZxCz63EPd7sVFBYY0T1s9jA5kOAxF9K4ojRoIMz4="; pkgsForSystem = system:
h-raylib.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: h-raylib-version: 5.5.0.0+version: 5.5.1.0 synopsis: Raylib bindings for Haskell category: graphics description:@@ -17,6 +17,10 @@ DOCUMENTATION.md README.md +-- Requires >= 9.6.5 on Mac because this bug fix is required: https://gitlab.haskell.org/ghc/ghc/-/merge_requests/12079+-- Works with >= 9.2.8 on Windows+tested-with: GHC >= 9.6.5+ extra-source-files: default.nix flake.nix@@ -108,15 +112,14 @@ , base , h-raylib - other-modules: Paths_h_raylib- autogen-modules: Paths_h_raylib-+ other-modules: Paths_h_raylib+ autogen-modules: Paths_h_raylib other-extensions: BangPatterns TemplateHaskell- - ghc-options: -Wall + ghc-options: -Wall+ if flag(platform-web) ghc-options: -no-hs-main -optl-mexec-model=reactor@@ -257,9 +260,9 @@ ScopedTypeVariables TemplateHaskell TemplateHaskellQuotes- - ghc-options: -Wall + ghc-options: -Wall+ if (flag(platform-windows) || (flag(detect-platform) && os(windows))) if flag(mingw-cross) extra-libraries:@@ -310,8 +313,8 @@ else - -- Unsupported OS, do nothing. If you can get it working on an- -- OS that isn't listed here, please add it here.+ -- Unsupported OS, do nothing. If you can get it working on an+ -- OS that isn't listed here, please add it here. if flag(platform-nixos) extra-libraries: raylib @@ -322,7 +325,9 @@ c-sources: lib/web.c else- cc-options: -DPLATFORM_DESKTOP_GLFW -Wno-int-to-void-pointer-cast+ cc-options:+ -DPLATFORM_DESKTOP_GLFW -Wno-int-to-void-pointer-cast+ c-sources: lib/rgui_bindings.c lib/rl_bindings.c
lib/rl_bindings.c view
@@ -3,6 +3,7 @@ */ #include "rl_bindings.h"+#include <stdio.h> RLBIND void SetWindowIcon_(Image *a) {@@ -642,13 +643,6 @@ return ptr; } -RLBIND Image *LoadImageSvg_(char *a, int b, int c)-{- Image *ptr = (Image *)malloc(sizeof(Image));- *ptr = LoadImageSvg(a, b, c);- return ptr;-}- RLBIND Image *LoadImageAnim_(char *a, int *b) { Image *ptr = (Image *)malloc(sizeof(Image));@@ -1144,6 +1138,13 @@ return ptr; } +RLBIND Color *ColorLerp_(Color *a, Color *b, float c)+{+ Color *ptr = (Color *)malloc(sizeof(Color));+ *ptr = ColorLerp(*a, *b, c);+ return ptr;+}+ RLBIND Color *GetColor_(unsigned int a) { Color *ptr = (Color *)malloc(sizeof(Color));@@ -1443,6 +1444,16 @@ DrawModelWiresEx(*a, *b, *c, d, *e, *f); } +RLBIND void DrawModelPoints_(Model *a, Vector3 *b, float c, Color *d)+{+ DrawModelPoints(*a, *b, c, *d);+}++RLBIND void DrawModelPointsEx_(Model *a, Vector3 *b, Vector3 *c, float d, Vector3 *e, Color *f)+{+ DrawModelPointsEx(*a, *b, *c, d, *e, *f);+}+ RLBIND void DrawBoundingBox_(BoundingBox *a, Color *b) { DrawBoundingBox(*a, *b);@@ -1614,6 +1625,11 @@ return IsModelAnimationValid(*a, *b); } +RLBIND void UpdateModelAnimationBoneMatrices_(Model *a, ModelAnimation *b, int c)+{+ UpdateModelAnimationBoneMatrices(*a, *b, c);+}+ RLBIND bool CheckCollisionSpheres_(Vector3 *a, float b, Vector3 *c, float d) { return CheckCollisionSpheres(*a, b, *c, d);@@ -2362,6 +2378,22 @@ OpenURL(a); } +TraceLogCallback_ customCallback;++void CustomCallback(int logLevel, const char *text, va_list args)+{+ size_t n = vsnprintf(NULL, 0, text, args) + 1;+ char *buffer = malloc(n);+ vsnprintf(buffer, n, text, args);+ customCallback(logLevel, buffer);+}++RLBIND void SetTraceLogCallback_(TraceLogCallback_ a)+{+ customCallback = a;+ SetTraceLogCallback(&CustomCallback);+}+ RLBIND void SetLoadFileDataCallback_(LoadFileDataCallback a) { SetLoadFileDataCallback(a);@@ -2470,6 +2502,11 @@ RLBIND const char *GetApplicationDirectory_() { return GetApplicationDirectory();+}++RLBIND int MakeDirectory_(const char *a)+{+ return MakeDirectory(a); } RLBIND bool ChangeDirectory_(const char *a)
lib/rl_bindings.h view
@@ -10,6 +10,8 @@ #include "rl_common.h" +typedef void (*TraceLogCallback_)(int logLevel, char *text);+ void SetWindowIcon_(Image *a); Vector2 *GetMonitorPosition_(int a);@@ -238,8 +240,6 @@ Image *LoadImageRaw_(char *a, int b, int c, int d, int e); -Image *LoadImageSvg_(char *a, int b, int c);- Image *LoadImageAnim_(char *a, int *b); Image *LoadImageAnimFromMemory_(char *a, unsigned char *b, int c, int *d);@@ -404,6 +404,8 @@ Color *ColorAlphaBlend_(Color *a, Color *b, Color *c); +Color *ColorLerp_(Color *a, Color *b, float c);+ Color *GetColor_(unsigned int a); Color *GetPixelColor_(void *a, int b);@@ -510,6 +512,10 @@ void DrawModelWiresEx_(Model *a, Vector3 *b, Vector3 *c, float d, Vector3 *e, Color *f); +void DrawModelPoints_(Model *a, Vector3 *b, float c, Color *d);++void DrawModelPointsEx_(Model *a, Vector3 *b, Vector3 *c, float d, Vector3 *e, Color *f);+ void DrawBoundingBox_(BoundingBox *a, Color *b); void DrawBillboard_(Camera3D *a, Texture *b, Vector3 *c, float d, Color *e);@@ -568,6 +574,8 @@ bool IsModelAnimationValid_(Model *a, ModelAnimation *b); +void UpdateModelAnimationBoneMatrices_(Model *a, ModelAnimation *b, int c);+ bool CheckCollisionSpheres_(Vector3 *a, float b, Vector3 *c, float d); bool CheckCollisionBoxes_(BoundingBox *a, BoundingBox *b);@@ -856,6 +864,8 @@ void OpenURL_(const char *a); +void SetTraceLogCallback_(TraceLogCallback_ a);+ void SetLoadFileDataCallback_(LoadFileDataCallback a); void SetSaveFileDataCallback_(SaveFileDataCallback a);@@ -899,6 +909,8 @@ const char *GetWorkingDirectory_(); const char *GetApplicationDirectory_();++int MakeDirectory_(const char *a); bool ChangeDirectory_(const char *a);
lib/rlgl_bindings.c view
@@ -21,6 +21,11 @@ rlSetUniformMatrix(locIndex, *mat); } +RLBIND void rlSetUniformMatrices_(int locIndex, const Matrix *mat, int count)+{+ rlSetUniformMatrices(locIndex, mat, count);+}+ RLBIND Matrix *rlGetMatrixProjectionStereo_(int eye) { Matrix *ptr = (Matrix *)malloc(sizeof(Matrix));
lib/rlgl_bindings.h view
@@ -12,6 +12,8 @@ void rlSetUniformMatrix_(int locIndex, Matrix *mat); +void rlSetUniformMatrices_(int locIndex, const Matrix *mat, int count);+ Matrix *rlGetMatrixProjectionStereo_(int eye); Matrix *rlGetMatrixViewOffsetStereo_(int eye);
raygui/src/raygui.h view
@@ -1,6 +1,6 @@ /******************************************************************************************* *-* raygui v4.1-dev - 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@@ -141,8 +141,23 @@ * Draw text bounds rectangles for debug * * VERSIONS HISTORY:-* 4.1-dev (2024) Current dev version...+* 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()@@ -317,9 +332,9 @@ #define RAYGUI_H #define RAYGUI_VERSION_MAJOR 4-#define RAYGUI_VERSION_MINOR 1+#define RAYGUI_VERSION_MINOR 5 #define RAYGUI_VERSION_PATCH 0-#define RAYGUI_VERSION "4.1-dev"+#define RAYGUI_VERSION "4.5-dev" #if !defined(RAYGUI_STANDALONE) #include "raylib.h"@@ -617,7 +632,8 @@ typedef enum { ARROW_PADDING = 16, // DropdownBox arrow separation from border and items DROPDOWN_ITEMS_SPACING, // DropdownBox items separation- DROPDOWN_ARROW_HIDDEN // DropdownBox arrow hidden+ DROPDOWN_ARROW_HIDDEN, // DropdownBox arrow hidden+ DROPDOWN_ROLL_UP // DropdownBox roll up flag (default rolls down) } GuiDropdownBoxProperty; // TextBox/TextBoxMulti/ValueBox/Spinner@@ -977,12 +993,12 @@ ICON_WARNING = 220, ICON_HELP_BOX = 221, ICON_INFO_BOX = 222,- ICON_223 = 223,- ICON_224 = 224,- ICON_225 = 225,- ICON_226 = 226,- ICON_227 = 227,- ICON_228 = 228,+ ICON_PRIORITY = 223,+ ICON_LAYERS_ISO = 224,+ ICON_LAYERS2 = 225,+ ICON_MLAYERS = 226,+ ICON_MAPS = 227,+ ICON_HOT = 228, ICON_229 = 229, ICON_230 = 230, ICON_231 = 231,@@ -1029,6 +1045,7 @@ #if defined(RAYGUI_IMPLEMENTATION) +#include <ctype.h> // required for: isspace() [GuiTextBox()] #include <stdio.h> // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()] #include <stdlib.h> // Required for: malloc(), calloc(), free() [GuiLoadStyle(), GuiLoadIcons()] #include <string.h> // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy()@@ -1300,7 +1317,7 @@ 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+ 0x04200000, 0x1cf00c60, 0x11f019f0, 0x0f3807b8, 0x1e3c0f3c, 0x1c1c1e1c, 0x1e3c1c1c, 0x00000f70, // ICON_HOT 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_229 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_230 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_231@@ -1623,9 +1640,9 @@ // Draw control //--------------------------------------------------------------------- GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)));- GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, RAYGUI_GROUPBOX_LINE_THICK }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)));- GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)));+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)));+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, RAYGUI_GROUPBOX_LINE_THICK }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)));+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR))); GuiLine(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y - GuiGetStyle(DEFAULT, TEXT_SIZE)/2, bounds.width, (float)GuiGetStyle(DEFAULT, TEXT_SIZE) }, text); //--------------------------------------------------------------------@@ -1646,7 +1663,7 @@ int result = 0; GuiState state = guiState; - Color color = GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR));+ Color color = GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)); // Draw control //--------------------------------------------------------------------@@ -1694,7 +1711,7 @@ //-------------------------------------------------------------------- if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar - GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED: LINE_COLOR)),+ GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED: (int)LINE_COLOR)), GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BASE_COLOR_DISABLED : BACKGROUND_COLOR))); //-------------------------------------------------------------------- @@ -2335,12 +2352,16 @@ 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; @@ -2367,7 +2388,8 @@ 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)) {@@ -2411,7 +2433,8 @@ 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) {@@ -2434,7 +2457,7 @@ 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 },+ 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 }@@ -2581,24 +2604,59 @@ } } - // Delete codepoint from text, before current cursor position- if ((textLength > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))))+ // Delete related codepoints from text, before current cursor position+ if ((textLength > 0) && IsKeyPressed(KEY_BACKSPACE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL))) {- autoCursorDelayCounter++;+ int i = textBoxCursorIndex - 1;+ int accCodepointSize = 0; - if (IsKeyPressed(KEY_BACKSPACE) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames+ // Move cursor to the end of word if on space already+ while ((i > 0) && isspace(text[i])) { int prevCodepointSize = 0;- GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);+ GetCodepointPrevious(text + i, &prevCodepointSize);+ i -= prevCodepointSize;+ accCodepointSize += prevCodepointSize;+ } - // Move backward text from cursor position- for (int i = (textBoxCursorIndex - prevCodepointSize); i < textLength; i++) text[i] = text[i + prevCodepointSize];+ // Move cursor to the start of the word+ while ((i > 0) && !isspace(text[i]))+ {+ int prevCodepointSize = 0;+ GetCodepointPrevious(text + i, &prevCodepointSize);+ i -= prevCodepointSize;+ accCodepointSize += prevCodepointSize;+ } - // TODO Check: >= cursor+codepointsize and <= length-codepointsize+ // Move forward text from cursor position+ for (int j = (textBoxCursorIndex - accCodepointSize); j < textLength; j++) text[j] = text[j + accCodepointSize]; + // Prevent cursor index from decrementing past 0+ if (textBoxCursorIndex > 0)+ {+ textBoxCursorIndex -= accCodepointSize;+ textLength -= accCodepointSize;+ }++ // Make sure text last character is EOL+ text[textLength] = '\0';+ } + else if ((textLength > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))))+ {+ autoCursorDelayCounter++;++ if (IsKeyPressed(KEY_BACKSPACE) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames+ {+ int prevCodepointSize = 0;+ // Prevent cursor index from decrementing past 0 if (textBoxCursorIndex > 0) {+ GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);++ // Move backward text from cursor position+ for (int i = (textBoxCursorIndex - prevCodepointSize); i < textLength; i++) text[i] = text[i + prevCodepointSize];+ textBoxCursorIndex -= codepointSize; textLength -= codepointSize; }@@ -2616,7 +2674,7 @@ if (IsKeyPressed(KEY_LEFT) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames { int prevCodepointSize = 0;- GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);+ if (textBoxCursorIndex > 0) GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize); if (textBoxCursorIndex >= prevCodepointSize) textBoxCursorIndex -= prevCodepointSize; }@@ -2903,7 +2961,7 @@ //if (*value > maxValue) *value = maxValue; //else if (*value < minValue) *value = minValue; - if (IsKeyPressed(KEY_ENTER) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))+ 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;@@ -3019,7 +3077,7 @@ if (valueHasChanged) *value = TextToFloat(textValue); - 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))) result = 1; } else {@@ -3404,7 +3462,7 @@ // Draw control //--------------------------------------------------------------------- GuiDrawRectangle(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background+ GuiDrawRectangle(bounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background // Draw visible items for (int i = 0; ((i < visibleItems) && (text != NULL)); i++)@@ -3859,7 +3917,7 @@ buttonBounds.width = (bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount; buttonBounds.height = RAYGUI_MESSAGEBOX_BUTTON_HEIGHT; - int textWidth = GetTextWidth(message) + 2;+ //int textWidth = GetTextWidth(message) + 2; Rectangle textBounds = { 0 }; textBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING;@@ -4463,7 +4521,7 @@ // NOTE: All DEFAULT properties should be defined first in the file GuiSetStyle(0, (int)propertyId, propertyValue); - if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int i = 1; i < RAYGUI_MAX_CONTROLS; i++) GuiSetStyle(i, (int)propertyId, propertyValue);+ if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue); } else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); }
raygui/styles/amber/style_amber.h view
@@ -7,599 +7,596 @@ // more info and bugs-report: github.com/raysan5/raygui // // feedback and support: ray[at]raylibtech.com // // //-// Copyright (c) 2020-2023 raylib technologies (@raylibtech) //-// //-//////////////////////////////////////////////////////////////////////////////////--#define AMBER_STYLE_PROPS_COUNT 17--// Custom style name: Amber-static const GuiStyleProp amberStyleProps[AMBER_STYLE_PROPS_COUNT] = {- { 0, 0, 0x898988ff }, // DEFAULT_BORDER_COLOR_NORMAL - { 0, 1, 0x292929ff }, // DEFAULT_BASE_COLOR_NORMAL - { 0, 2, 0xd4d4d4ff }, // DEFAULT_TEXT_COLOR_NORMAL - { 0, 3, 0xf1850dff }, // DEFAULT_BORDER_COLOR_FOCUSED - { 0, 4, 0x292929ff }, // DEFAULT_BASE_COLOR_FOCUSED - { 0, 5, 0xffffffff }, // DEFAULT_TEXT_COLOR_FOCUSED - { 0, 6, 0xf1850dff }, // DEFAULT_BORDER_COLOR_PRESSED - { 0, 7, 0xf1850dff }, // DEFAULT_BASE_COLOR_PRESSED - { 0, 8, 0xffffffff }, // DEFAULT_TEXT_COLOR_PRESSED - { 0, 9, 0x6a6a6aff }, // DEFAULT_BORDER_COLOR_DISABLED - { 0, 10, 0x818181ff }, // DEFAULT_BASE_COLOR_DISABLED - { 0, 11, 0x606060ff }, // DEFAULT_TEXT_COLOR_DISABLED - { 0, 16, 0x00000010 }, // DEFAULT_TEXT_SIZE - { 0, 18, 0xf1850dff }, // DEFAULT_LINE_COLOR - { 0, 19, 0x333333ff }, // DEFAULT_BACKGROUND_COLOR - { 0, 20, 0x00000018 }, // DEFAULT_TEXT_LINE_SPACING - { 10, 7, 0x202020ff }, // VALUEBOX_BASE_COLOR_PRESSED -};--// WARNING: This style uses a custom font: "Inter-Regular.ttf" (size: 16, spacing: 1)--#define AMBER_STYLE_FONT_ATLAS_COMP_SIZE 6417--// Font atlas image pixels data: DEFLATE compressed-static unsigned char amberFontData[AMBER_STYLE_FONT_ATLAS_COMP_SIZE] = { 0xed,- 0x9d, 0x07, 0x78, 0x15, 0xc5, 0xda, 0xc7, 0x4f, 0x1a, 0x3d, 0x20, 0x4d, 0x10, 0x41, 0x45, 0xa5, 0x89, 0x8a, 0x7a, 0x45,- 0xb0, 0x60, 0x47, 0x51, 0xb0, 0xe3, 0xc5, 0x02, 0x36, 0x14, 0x95, 0x0b, 0x28, 0x88, 0x5c, 0xf1, 0x43, 0x6c, 0x20, 0xd2,- 0x14, 0x15, 0xb1, 0x80, 0xc1, 0x02, 0xd8, 0x50, 0x14, 0x51, 0x41, 0x91, 0x2e, 0x1d, 0x2e, 0xc5, 0x84, 0x2e, 0xed, 0x86,- 0x16, 0x02, 0x84, 0x10, 0x02, 0x21, 0xe4, 0xf7, 0x3d, 0x3b, 0x67, 0xcf, 0xc9, 0x81, 0xf3, 0xce, 0x9e, 0x9c, 0x18, 0x10,- 0xb8, 0x2f, 0xbf, 0xe7, 0x21, 0xc9, 0xce, 0xd6, 0xf9, 0xcf, 0xce, 0xcc, 0xee, 0xfe, 0xdf, 0x19, 0x7c, 0x8a, 0xa2, 0x28,- 0x8a, 0xa2, 0x28, 0x87, 0xf0, 0x1c, 0xf7, 0x84, 0x2d, 0x7b, 0x94, 0x07, 0x68, 0xca, 0x0b, 0xe2, 0xfa, 0x75, 0xe9, 0x62,- 0x7e, 0xf6, 0xe3, 0x24, 0xeb, 0x3e, 0x63, 0x48, 0xb0, 0xa4, 0xc4, 0xd2, 0x93, 0x71, 0xb4, 0x72, 0xff, 0x2a, 0xc1, 0x3b,- 0x54, 0xb0, 0xac, 0xd9, 0x84, 0x21, 0x0c, 0xe4, 0x74, 0x4b, 0xaa, 0x73, 0x86, 0xd2, 0xf2, 0x8b, 0x29, 0x19, 0xb6, 0xac,- 0x02, 0xe7, 0x58, 0xcf, 0xf4, 0x64, 0xba, 0x5b, 0xd3, 0xea, 0xf0, 0x1f, 0x6b, 0x5a, 0x23, 0x2e, 0x0f, 0x5b, 0x56, 0x86,- 0x11, 0x2e, 0xa7, 0x84, 0xa5, 0x75, 0xa0, 0x85, 0x65, 0x4f, 0xa5, 0x29, 0x21, 0x2e, 0xbf, 0x84, 0xf7, 0xf9, 0x8a, 0xb6,- 0xd6, 0x7c, 0x7c, 0x8a, 0x24, 0xce, 0x2c, 0x02, 0xfd, 0x27, 0xd1, 0x2f, 0x6c, 0xd9, 0x07, 0x0c, 0xe2, 0x71, 0xa6, 0x89,- 0xeb, 0xb7, 0x65, 0x08, 0x3e, 0x8a, 0x91, 0x41, 0xac, 0x75, 0x9f, 0xb5, 0xf8, 0xc4, 0x92, 0x72, 0x2f, 0x13, 0xb9, 0x90,- 0x54, 0x4e, 0x35, 0x7f, 0x0d, 0x10, 0x8e, 0x1d, 0x28, 0x65, 0x99, 0x74, 0x64, 0x28, 0x6b, 0x88, 0x11, 0xd3, 0x9d, 0x33,- 0x0c, 0x5f, 0x7a, 0x35, 0xa9, 0xc4, 0x87, 0x2d, 0x3d, 0x95, 0x3d, 0x54, 0x13, 0xd6, 0x2e, 0xce, 0xd3, 0xd4, 0xe4, 0x57,- 0x6a, 0xd2, 0x5a, 0x3c, 0xc6, 0xb9, 0xa4, 0x59, 0xaf, 0x70, 0x22, 0x3d, 0xc3, 0x96, 0x95, 0xa0, 0xa3, 0x4b, 0xf9, 0xb0,- 0xb4, 0x05, 0x0c, 0xb5, 0xec, 0x69, 0x2a, 0xb7, 0x8b, 0xe5, 0x2b, 0x8b, 0x89, 0xf4, 0x63, 0x3f, 0xbd, 0x85, 0xd4, 0xca,- 0x8c, 0x67, 0x11, 0x79, 0x34, 0x2a, 0x02, 0xfd, 0x7f, 0xa5, 0x4f, 0xd8, 0xb2, 0x37, 0x79, 0x8d, 0x36, 0x8c, 0x17, 0xd7,- 0x1f, 0x40, 0x07, 0x93, 0x37, 0x0b, 0xad, 0x7b, 0x6c, 0xca, 0xe7, 0x6c, 0xe0, 0x15, 0xf1, 0xde, 0x7d, 0xc9, 0xd4, 0x2a,- 0x93, 0x69, 0x82, 0x8f, 0xab, 0x58, 0x44, 0x71, 0xcb, 0x3e, 0xfe, 0xcd, 0x38, 0x7c, 0x54, 0x23, 0xcf, 0x52, 0x3f, 0x38,- 0x67, 0x18, 0xbe, 0xf4, 0x07, 0x5e, 0x16, 0xd7, 0xfe, 0x56, 0x5c, 0x3b, 0x91, 0xfe, 0x2c, 0x61, 0x33, 0x0b, 0x69, 0x19,- 0x96, 0xd6, 0x90, 0x66, 0x3c, 0xce, 0x2e, 0x9a, 0xd1, 0x8c, 0xb3, 0x84, 0x6d, 0x37, 0xd2, 0x38, 0xaa, 0x5c, 0x8e, 0xb7,- 0x94, 0xe3, 0x32, 0xec, 0xa5, 0x9c, 0xb0, 0x7c, 0x20, 0xef, 0x99, 0x2d, 0xae, 0xe2, 0xbf, 0x42, 0xea, 0xc3, 0x0c, 0xa1,- 0x04, 0x07, 0x8b, 0x44, 0xff, 0xf1, 0xf4, 0x0a, 0x5b, 0xd6, 0x9b, 0x1e, 0xb4, 0xe4, 0xdb, 0xb0, 0xe5, 0x67, 0x90, 0x4d,- 0x2e, 0xfb, 0xc9, 0x66, 0x3f, 0x07, 0xc9, 0x16, 0xca, 0xb9, 0x8f, 0x27, 0x49, 0x67, 0x18, 0xb3, 0xf9, 0x8e, 0x2d, 0x42,- 0xfd, 0xd4, 0x9c, 0xf9, 0xb4, 0x62, 0x13, 0x15, 0x48, 0x64, 0x05, 0x17, 0x58, 0xcf, 0xea, 0x5a, 0x76, 0x70, 0x36, 0xdf,- 0x58, 0xca, 0xa0, 0xff, 0x0c, 0x0f, 0x5f, 0x56, 0x8a, 0x7d, 0x34, 0x10, 0xd7, 0x6e, 0x4d, 0xb2, 0xb0, 0x34, 0x8e, 0xd6,- 0x2c, 0x25, 0x93, 0xef, 0x39, 0x4f, 0xc8, 0xff, 0x49, 0xcc, 0x21, 0x87, 0x49, 0x4c, 0xa2, 0x8d, 0x50, 0x72, 0xd2, 0x89,- 0x2b, 0x92, 0xd6, 0xb7, 0x39, 0x33, 0xc5, 0xe5, 0xf3, 0xb8, 0xcd, 0x3d, 0xc7, 0x3d, 0x9c, 0x2d, 0x5c, 0xa9, 0xf3, 0x7f,- 0xd1, 0xe8, 0xff, 0x23, 0x2f, 0x85, 0x2d, 0x4b, 0x20, 0x81, 0x38, 0xe1, 0xde, 0x8c, 0x21, 0x9e, 0xf5, 0x54, 0x27, 0x9e,- 0x57, 0xe8, 0x21, 0xd4, 0xb4, 0x0e, 0x2b, 0x78, 0xd4, 0xad, 0xff, 0xbf, 0xe0, 0x61, 0x51, 0x8b, 0x41, 0xa6, 0xed, 0x1c,- 0xc6, 0xf3, 0x9e, 0xe7, 0xf5, 0x2d, 0x39, 0x4c, 0xa0, 0xac, 0x25, 0x35, 0x41, 0xe8, 0x61, 0xdc, 0x48, 0x9a, 0xa5, 0x4d,- 0x3a, 0x95, 0x3c, 0xa1, 0x05, 0xa8, 0xc0, 0x50, 0x2e, 0xe0, 0x17, 0xae, 0xb5, 0xd4, 0x1a, 0xf6, 0xfa, 0xbf, 0x0c, 0x57,- 0x16, 0x51, 0xef, 0x6b, 0x90, 0x78, 0xec, 0xb2, 0xe4, 0x52, 0xdd, 0xfd, 0x7d, 0x06, 0x8f, 0x58, 0xb6, 0x2d, 0x1a, 0xfd,- 0xc7, 0x5a, 0xfa, 0x79, 0xb6, 0x2b, 0x4f, 0x37, 0x3f, 0xbf, 0xe2, 0x0e, 0x6b, 0x7b, 0xd6, 0xc3, 0xa3, 0xfd, 0x0f, 0x70,- 0x0b, 0x33, 0x89, 0x23, 0x96, 0x3a, 0x96, 0x16, 0xe0, 0x16, 0x32, 0x58, 0xcb, 0x87, 0xf8, 0x38, 0x85, 0xf3, 0x0b, 0x78,- 0x6e, 0x4f, 0xf3, 0x9b, 0x35, 0x6d, 0x1b, 0xd7, 0x59, 0x4a, 0xc6, 0x87, 0xd6, 0x6d, 0xbc, 0xda, 0xff, 0xa2, 0x22, 0xd9,- 0xb4, 0x84, 0x87, 0x53, 0x93, 0x3c, 0x4a, 0x07, 0xf5, 0x79, 0xee, 0x88, 0xea, 0x3f, 0x9c, 0xa7, 0x0a, 0xbc, 0x6e, 0x7b,- 0xbe, 0x65, 0x07, 0xc3, 0x19, 0xce, 0x36, 0xc6, 0x72, 0xb7, 0xb8, 0xce, 0x75, 0x6c, 0x65, 0x3e, 0x53, 0xac, 0x3d, 0x77,- 0x87, 0x4a, 0xac, 0xa1, 0x16, 0x09, 0xcc, 0x60, 0x12, 0x6b, 0x85, 0x35, 0xab, 0xb0, 0x87, 0x7b, 0xa9, 0xce, 0x26, 0x3a,- 0xf2, 0x1c, 0x1f, 0x17, 0xf0, 0xec, 0xfa, 0x32, 0xd2, 0x9a, 0xb6, 0xc4, 0xd2, 0xc7, 0xf3, 0xa2, 0x1c, 0x77, 0x1d, 0x61,- 0xf5, 0x4f, 0x65, 0xb7, 0xe5, 0x49, 0xe9, 0xbf, 0xc1, 0xe7, 0x8b, 0x8d, 0x62, 0x09, 0x29, 0x3a, 0xfd, 0xa3, 0xe1, 0x5a,- 0x86, 0x32, 0x9e, 0x7b, 0x68, 0x43, 0x36, 0xf7, 0x50, 0xd7, 0x5a, 0x47, 0xbc, 0xcc, 0x6e, 0x0e, 0xf0, 0x99, 0xb5, 0x77,- 0x37, 0x9a, 0x7f, 0x99, 0x27, 0x9c, 0x39, 0xf8, 0x78, 0x83, 0xce, 0x61, 0xe9, 0xd7, 0xb3, 0xdb, 0xd4, 0xe4, 0x97, 0xb0,- 0x9b, 0xf5, 0x3c, 0x5e, 0xc0, 0xb3, 0xeb, 0xc3, 0x28, 0x6b, 0xda, 0x52, 0xee, 0x3b, 0x06, 0x9f, 0xbd, 0x1f, 0x64, 0xac,- 0x25, 0x65, 0x94, 0x7b, 0x57, 0x56, 0x25, 0xdb, 0x9a, 0x8b, 0x45, 0xa3, 0x7f, 0x7b, 0x9a, 0x47, 0xb1, 0xf6, 0xeb, 0x3c,- 0x8d, 0x8f, 0x7a, 0x2c, 0xf1, 0x5c, 0xcb, 0xa9, 0xff, 0xcf, 0x24, 0x99, 0x17, 0x2d, 0xbd, 0xb1, 0x09, 0xa6, 0x6f, 0xdb,- 0x90, 0xb9, 0xa6, 0x05, 0xec, 0x14, 0xb6, 0xc6, 0x49, 0xec, 0xa3, 0x1d, 0x09, 0x34, 0x66, 0x1e, 0x50, 0xbf, 0x80, 0xe7,- 0xf6, 0x08, 0xf3, 0xac, 0x4f, 0xcb, 0x7b, 0xb9, 0xf8, 0x18, 0xd4, 0x7f, 0x84, 0x70, 0xed, 0x7e, 0xda, 0xb1, 0x95, 0xd6,- 0x9c, 0xcb, 0x74, 0x8f, 0x36, 0xad, 0x68, 0xf4, 0xb7, 0x3f, 0x99, 0xca, 0xbd, 0x85, 0x1b, 0xf1, 0x71, 0x17, 0x5f, 0x58,- 0xd2, 0xcb, 0xd3, 0x8b, 0x8a, 0x6e, 0xfb, 0x3f, 0x98, 0xaf, 0x84, 0x35, 0xaa, 0xf3, 0xa7, 0xdb, 0xb7, 0x49, 0x60, 0x0a,- 0xb3, 0x59, 0xe3, 0xbe, 0x0b, 0x38, 0xbc, 0x06, 0x58, 0x45, 0x16, 0x39, 0x8c, 0xe4, 0x0d, 0x52, 0xc4, 0x27, 0x24, 0xe9,- 0x8d, 0x91, 0xed, 0x9d, 0xc4, 0x99, 0x60, 0xed, 0x49, 0xfe, 0x7d, 0xc4, 0xb0, 0x99, 0x7a, 0x96, 0xb4, 0x38, 0x06, 0x91,- 0x45, 0x2e, 0x33, 0x83, 0xfd, 0xc0, 0x23, 0xa5, 0xbf, 0xed, 0xc9, 0xb4, 0xb0, 0x4c, 0x67, 0x04, 0x4d, 0xf8, 0x8c, 0xe6,- 0xec, 0xa2, 0x5d, 0xc4, 0xb5, 0x4f, 0xb7, 0x3c, 0x45, 0xf8, 0xcb, 0x52, 0xb1, 0xa8, 0x8e, 0x5c, 0x9c, 0xcd, 0xdc, 0x64,- 0x79, 0xc7, 0x39, 0xe5, 0x18, 0xbc, 0xfb, 0xcf, 0x67, 0xa3, 0x67, 0x7a, 0xc2, 0x31, 0x58, 0x66, 0x23, 0x73, 0x1e, 0x5f,- 0x90, 0x45, 0x1e, 0xdb, 0x78, 0xa9, 0x88, 0x4b, 0x56, 0x64, 0x7a, 0x0a, 0xef, 0x2c, 0x9c, 0xfb, 0x6c, 0x95, 0xf5, 0x69,- 0xe5, 0xef, 0xa4, 0x0b, 0xc3, 0x4f, 0xd0, 0x6f, 0x0a, 0xe7, 0xf1, 0xb5, 0xc7, 0xdb, 0xe1, 0x23, 0xc7, 0xc9, 0xcc, 0x24,- 0x51, 0x38, 0x9b, 0x5f, 0x8a, 0xe8, 0x6d, 0x4d, 0xd1, 0x72, 0x13, 0x17, 0x9e, 0xa0, 0xfa, 0x97, 0xe3, 0x1a, 0xfd, 0xb2,- 0xa6, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0x72, 0x54, 0xb9, 0x8d, 0x8f,- 0xf9, 0xd4, 0xc3, 0xd7, 0x72, 0x2b, 0x1f, 0xf1, 0x25, 0x8f, 0x79, 0x7e, 0xb9, 0xa9, 0x49, 0x92, 0xe8, 0x19, 0x68, 0x40,- 0x92, 0x4b, 0x4f, 0xcb, 0x96, 0xb5, 0x79, 0x83, 0x31, 0x3c, 0x27, 0x3a, 0xde, 0x2f, 0x0b, 0x6e, 0x9d, 0x24, 0x38, 0x92,- 0xfd, 0x9e, 0xb0, 0x24, 0x3e, 0xe7, 0x11, 0xeb, 0xb9, 0xb5, 0x34, 0xe7, 0xde, 0x52, 0x4c, 0xfb, 0x84, 0x6e, 0xc2, 0xd2,- 0xee, 0x24, 0x79, 0x7e, 0x7f, 0x2b, 0x2d, 0x38, 0x6f, 0x7f, 0x08, 0xd2, 0x50, 0x78, 0xef, 0xed, 0x9d, 0xfb, 0x67, 0x31,- 0x88, 0x31, 0x74, 0xb7, 0x3a, 0x3a, 0x02, 0xfe, 0x99, 0xcb, 0x38, 0x2d, 0xe2, 0x17, 0x96, 0x24, 0x2e, 0x8b, 0x5a, 0xfd,- 0x27, 0xd8, 0xc2, 0x8b, 0xbc, 0xc0, 0x66, 0x3a, 0x8a, 0xe9, 0x9d, 0xd9, 0x4c, 0x67, 0x9e, 0xe1, 0x4f, 0xfa, 0x7b, 0x3a,- 0x86, 0x0f, 0x8a, 0x51, 0x13, 0x8f, 0xb1, 0x8a, 0x67, 0x0d, 0x6d, 0x2c, 0x9e, 0xfe, 0x6d, 0xcc, 0xa6, 0x33, 0x0b, 0x99,- 0x28, 0xa4, 0xd6, 0x77, 0xb7, 0x7d, 0x96, 0xc9, 0xc6, 0x17, 0x12, 0x9e, 0xf3, 0xdb, 0x79, 0xd9, 0x9c, 0x9b, 0x1c, 0x33,- 0xd0, 0x8d, 0x74, 0x9e, 0xa7, 0x1b, 0x9b, 0x44, 0xbf, 0xdc, 0x30, 0x37, 0x6a, 0xe5, 0x50, 0x9e, 0xe5, 0x03, 0xeb, 0x57,- 0xf1, 0x87, 0x58, 0x2d, 0x78, 0xbc, 0xff, 0xc1, 0x03, 0x41, 0xaa, 0x0b, 0xdf, 0x99, 0xa7, 0x72, 0xb5, 0xc7, 0xd7, 0xa9,- 0x34, 0x3e, 0xe6, 0x21, 0xe6, 0x32, 0xda, 0xea, 0x08, 0x78, 0x81, 0x85, 0xac, 0xe7, 0x07, 0x16, 0xb1, 0x99, 0x6e, 0x1e,- 0x5f, 0xad, 0xde, 0x61, 0x1d, 0x5f, 0x46, 0xad, 0xff, 0x62, 0xe3, 0xdd, 0x77, 0xdc, 0x25, 0x29, 0x16, 0xcf, 0xed, 0x0d,- 0xe6, 0xe7, 0xdd, 0xa4, 0x5b, 0xef, 0xb2, 0xfb, 0x49, 0xe6, 0x67, 0x51, 0xff, 0x5e, 0x1e, 0xfe, 0x3b, 0xff, 0x3d, 0xf8,- 0xbe, 0xd9, 0x6b, 0x55, 0x66, 0x0b, 0x9e, 0xe6, 0xfc, 0x28, 0x8a, 0x8d, 0xdc, 0x2f, 0xfa, 0x0a, 0x7a, 0xba, 0x77, 0xf9,- 0x76, 0xe1, 0xdc, 0xe2, 0xc9, 0x74, 0xbf, 0xfd, 0x37, 0x62, 0x8f, 0xe8, 0x4b, 0x2f, 0x38, 0x71, 0x3c, 0xc0, 0x2a, 0xfe,- 0xa0, 0xb5, 0x87, 0x37, 0x41, 0xe6, 0x24, 0xfe, 0x8f, 0x6d, 0x4c, 0xb6, 0xb8, 0x83, 0x9b, 0x31, 0xd1, 0xec, 0xb1, 0x11,- 0x39, 0x42, 0x94, 0x92, 0xa3, 0xfe, 0x3b, 0x4c, 0x0d, 0x46, 0x1b, 0x54, 0x66, 0x8c, 0xd5, 0x1d, 0x96, 0x40, 0x1a, 0x77,- 0xb0, 0xd7, 0x23, 0x02, 0xcb, 0xe6, 0x37, 0x2c, 0xe6, 0xe6, 0xe1, 0x4a, 0xcf, 0xf5, 0x9e, 0xb2, 0xfa, 0xbb, 0x2a, 0xb2,- 0x85, 0x2b, 0xf8, 0x5e, 0xd4, 0xff, 0x53, 0xfa, 0x50, 0x9f, 0x8b, 0x2d, 0xa5, 0x36, 0x8e, 0x6c, 0x5a, 0x50, 0x81, 0xc6,- 0x96, 0x78, 0xa7, 0x00, 0x1d, 0x59, 0x26, 0xee, 0xe1, 0x73, 0xde, 0x71, 0xe3, 0x0b, 0x16, 0x8b, 0x2d, 0x0b, 0xee, 0x97,- 0xdf, 0x58, 0xb2, 0xb9, 0xe2, 0x2f, 0xa8, 0x7f, 0x0f, 0x2b, 0x98, 0xcd, 0x6d, 0x96, 0xf2, 0xdf, 0x83, 0xd4, 0x20, 0xd7,- 0x8b, 0x6b, 0x94, 0xa2, 0x13, 0xeb, 0x99, 0xe8, 0xe1, 0x37, 0xbb, 0x97, 0xad, 0xe2, 0xde, 0xbb, 0x32, 0x8f, 0xb2, 0x24,- 0xd0, 0x94, 0x27, 0x39, 0x9b, 0xdb, 0x88, 0x65, 0xb6, 0x78, 0x27, 0x38, 0xad, 0xf4, 0x3a, 0x62, 0x58, 0xc8, 0x63, 0x85,- 0xba, 0xc2, 0x92, 0x2c, 0xe6, 0x19, 0x6b, 0xea, 0xa3, 0x8c, 0x64, 0x05, 0xd7, 0x5a, 0x52, 0x93, 0x78, 0x1f, 0x9f, 0x45,- 0xff, 0x29, 0xa4, 0xb1, 0x92, 0x6d, 0x6c, 0x15, 0xe3, 0x3a, 0x9c, 0x58, 0x9e, 0xde, 0x64, 0xf0, 0x27, 0x59, 0xd6, 0x58,- 0x38, 0xe7, 0xdc, 0x52, 0x2d, 0x4e, 0xcd, 0x3a, 0xcc, 0xe1, 0x5b, 0x86, 0xb3, 0x4c, 0xbc, 0xbb, 0xe2, 0xc9, 0x70, 0x23,- 0x26, 0x6e, 0x04, 0x4b, 0xfb, 0x53, 0x30, 0x26, 0xb3, 0x89, 0x5b, 0xac, 0xb5, 0x5f, 0x55, 0xce, 0x0d, 0x92, 0x68, 0xbd,- 0x86, 0xce, 0xe4, 0x08, 0x51, 0x15, 0x01, 0xf5, 0x77, 0xf3, 0x90, 0xe5, 0xc8, 0x4e, 0xa9, 0x1b, 0xc5, 0x34, 0xde, 0x67,- 0x0d, 0xbb, 0xf0, 0xd1, 0x42, 0x6c, 0x29, 0x1d, 0xf7, 0xfd, 0x00, 0xd3, 0xda, 0x4c, 0x2f, 0xc4, 0xf5, 0xc5, 0x32, 0x9a,- 0x09, 0x1e, 0x35, 0xdb, 0xab, 0xfc, 0xce, 0x2a, 0x8b, 0xb7, 0xfb, 0x1a, 0x52, 0x4d, 0x9d, 0x23, 0xeb, 0x5f, 0xcf, 0x38,- 0x35, 0x63, 0x79, 0x83, 0x75, 0x62, 0xef, 0x10, 0x26, 0x98, 0x7b, 0xbf, 0x35, 0xd9, 0xd6, 0xa8, 0xcf, 0xa7, 0x48, 0xb1,- 0xd4, 0x1f, 0xb7, 0xb0, 0x81, 0x29, 0x8c, 0x64, 0xbd, 0xdb, 0x86, 0x85, 0x6f, 0x99, 0x41, 0x7f, 0x06, 0x92, 0x4c, 0x6a,- 0x30, 0xbe, 0x34, 0x52, 0xfc, 0xa5, 0x14, 0xc5, 0x19, 0xcb, 0x3f, 0xf9, 0x83, 0x25, 0xdc, 0x17, 0x75, 0xed, 0xef, 0xef,- 0x01, 0x3e, 0xc7, 0x16, 0x7e, 0xe2, 0x12, 0x4b, 0xfa, 0xa5, 0xec, 0xa3, 0x99, 0xa5, 0xc7, 0xe1, 0x44, 0x29, 0x5e, 0xcc,- 0x12, 0x73, 0xdc, 0x3b, 0x8c, 0xfe, 0xa7, 0xb2, 0x4d, 0x6c, 0x65, 0xb2, 0x4d, 0xed, 0x72, 0x1a, 0x07, 0xc5, 0xd8, 0x34,- 0x6f, 0xde, 0x63, 0x71, 0x44, 0x5f, 0xd9, 0x55, 0xe4, 0x52, 0x55, 0x68, 0x99, 0x57, 0xd0, 0x86, 0x92, 0x94, 0xe4, 0x07,- 0x7a, 0x7a, 0xf4, 0x61, 0xcb, 0x73, 0x90, 0x5a, 0x42, 0xef, 0x87, 0x60, 0xbd, 0xbc, 0xd6, 0xbd, 0x57, 0xc3, 0xef, 0x9c,- 0xcd, 0x42, 0x34, 0xb2, 0xff, 0xd8, 0xbb, 0xdd, 0xda, 0xee, 0x5c, 0x72, 0x2d, 0xae, 0xc9, 0x1b, 0x79, 0xcb, 0xc4, 0x9e,- 0xec, 0x13, 0xea, 0x7f, 0xd9, 0xe5, 0x3a, 0xd1, 0xf2, 0xa4, 0x12, 0xcb, 0x3d, 0xa4, 0xb0, 0x9a, 0x9a, 0x51, 0xe6, 0xed,- 0xad, 0xec, 0x64, 0xbc, 0x67, 0x64, 0x60, 0x37, 0x7e, 0xb4, 0xa4, 0xd4, 0x33, 0x5a, 0x3f, 0xe2, 0x9e, 0x67, 0x35, 0x57,- 0xff, 0x4c, 0xb1, 0x86, 0xce, 0x63, 0x1a, 0x53, 0x99, 0xca, 0x3e, 0x6b, 0x2d, 0x63, 0xa3, 0x17, 0x2b, 0x05, 0x65, 0x03,- 0x51, 0x6d, 0x1d, 0xa9, 0xe8, 0xf6, 0x2f, 0x76, 0x09, 0xf7, 0xcb, 0xa5, 0x84, 0xfe, 0x9b, 0x25, 0x44, 0x06, 0x9f, 0xe5,- 0x2a, 0x9d, 0x27, 0x7a, 0x7a, 0x77, 0xb9, 0xbd, 0xcb, 0x18, 0xd2, 0x2c, 0xd1, 0x38, 0x5d, 0xf8, 0xc3, 0xe2, 0x1b, 0xab,- 0x05, 0xd4, 0x70, 0xef, 0x93, 0x74, 0xee, 0x0c, 0x4b, 0x2f, 0x46, 0x17, 0xaa, 0x04, 0x5d, 0xc0, 0x89, 0x05, 0x74, 0xb9,- 0x7a, 0x45, 0x71, 0xc6, 0x71, 0x9f, 0x50, 0x8a, 0xbd, 0x69, 0x16, 0xf1, 0x99, 0xac, 0xac, 0xb5, 0x6f, 0x5a, 0x89, 0xfd,- 0xc4, 0x73, 0x3d, 0x93, 0xdc, 0xb2, 0x9c, 0x61, 0x1c, 0xf2, 0x2b, 0xc4, 0x08, 0xab, 0xe1, 0xdc, 0x6e, 0x18, 0xc0, 0xea,- 0xa8, 0x3c, 0x96, 0x4f, 0x93, 0xc6, 0x3f, 0xa8, 0x64, 0x88, 0x15, 0xfa, 0x9f, 0x6b, 0x18, 0x45, 0x0d, 0xaa, 0xd0, 0x87,- 0x2c, 0xa1, 0x6f, 0x19, 0x47, 0x69, 0x97, 0x9f, 0x78, 0x51, 0xe8, 0xc1, 0x7e, 0xcd, 0x64, 0x6a, 0x52, 0x89, 0x51, 0xcc,- 0x16, 0x8f, 0xfe, 0x32, 0x8b, 0xa9, 0x45, 0x39, 0x06, 0x92, 0xea, 0x46, 0x30, 0x1e, 0xde, 0x73, 0xda, 0xc2, 0x3f, 0xad,- 0x4f, 0x46, 0xeb, 0xf9, 0x88, 0x1a, 0x54, 0xa4, 0x27, 0xfb, 0xa9, 0x24, 0x3e, 0x1f, 0x8c, 0xa6, 0x1a, 0x37, 0x93, 0xcc,- 0xc0, 0x02, 0xe6, 0x46, 0xd1, 0x45, 0x71, 0x46, 0xf3, 0xfe, 0xc5, 0xee, 0x89, 0xde, 0x4e, 0x5d, 0x4a, 0xb3, 0x82, 0x97,- 0x68, 0xc3, 0x34, 0x72, 0x68, 0xc1, 0x68, 0xde, 0x12, 0x62, 0x70, 0xf3, 0x82, 0xf5, 0x5f, 0x79, 0xb1, 0xae, 0xb3, 0xfb,- 0xcd, 0xf3, 0x42, 0xee, 0xdf, 0xd3, 0xc5, 0xbb, 0x6c, 0x06, 0x39, 0x1c, 0x60, 0xb1, 0xb5, 0xfd, 0x0a, 0x44, 0x01, 0x74,- 0x17, 0x9f, 0x0d, 0xc6, 0x99, 0xd8, 0xe0, 0x5f, 0xa8, 0x6c, 0xa9, 0xdd, 0xdf, 0x27, 0x87, 0xfd, 0xcc, 0xb1, 0xd4, 0xdf,- 0x5d, 0x59, 0xea, 0x39, 0xa6, 0xc0, 0xef, 0xe4, 0x90, 0x43, 0xb2, 0xe5, 0x8a, 0x4f, 0x65, 0x1a, 0x07, 0xd8, 0xcb, 0x87,- 0xd6, 0xb1, 0x27, 0x8e, 0x5c, 0x14, 0x67, 0xc1, 0xf9, 0xd4, 0x12, 0xef, 0xeb, 0x1f, 0xd3, 0xe0, 0x13, 0x73, 0x9d, 0x83,- 0xf8, 0x92, 0xab, 0x78, 0x84, 0xa9, 0x0c, 0x11, 0x5a, 0xea, 0xff, 0x3b, 0x64, 0x54, 0x8a, 0x6f, 0x3d, 0xe2, 0x17, 0x0b,- 0x47, 0x09, 0x6b, 0xbf, 0xb6, 0x60, 0x5b, 0x97, 0x8a, 0xe0, 0xd1, 0x4f, 0x3c, 0x82, 0xe7, 0x96, 0x18, 0x65, 0xc4, 0xc0,- 0xdf, 0x11, 0xf3, 0x61, 0xaf, 0x71, 0x2a, 0xb0, 0x95, 0x67, 0x8e, 0x49, 0xa7, 0xb2, 0x72, 0x74, 0xa8, 0xc5, 0xaf, 0x2c,- 0x65, 0x30, 0x4f, 0xf1, 0x2c, 0x5f, 0x58, 0x9e, 0xc1, 0x94, 0x13, 0x9b, 0x7f, 0xd0, 0x9a, 0x97, 0x79, 0x81, 0x3b, 0x8e,- 0xcb, 0xe8, 0x1f, 0x45, 0x51, 0x14, 0x45, 0x51, 0x14, 0x45, 0x51, 0x14, 0x45, 0x51, 0x14, 0x45, 0x51, 0x14, 0xe5, 0xe8,- 0xd3, 0xdb, 0x78, 0xeb, 0x3f, 0xa0, 0xa3, 0xe8, 0xce, 0xf0, 0x7f, 0xa1, 0xbd, 0x8b, 0x0f, 0xf8, 0x9c, 0xa7, 0xc4, 0xaf,- 0x78, 0xfe, 0xed, 0xdf, 0xa4, 0xa5, 0xeb, 0xb4, 0x90, 0xd3, 0xfd, 0xc4, 0x7b, 0xa4, 0x0e, 0xb5, 0xf8, 0x26, 0xef, 0x66,- 0x28, 0x23, 0xe8, 0x20, 0x7a, 0x63, 0x9d, 0xed, 0xaf, 0x0c, 0xf1, 0xd0, 0x3d, 0xe9, 0x99, 0x2e, 0x6d, 0xdd, 0xc4, 0x63,- 0x8b, 0x26, 0x24, 0x09, 0x8e, 0x64, 0xaf, 0x3d, 0xf6, 0x66, 0x68, 0x88, 0x03, 0xaa, 0x2c, 0x49, 0xc2, 0x78, 0xd4, 0xbd,- 0x43, 0xdc, 0x39, 0xd7, 0x59, 0xc6, 0x42, 0x74, 0x72, 0xfc, 0x7d, 0x3e, 0xe6, 0x7e, 0x4b, 0xec, 0x80, 0x3f, 0xd7, 0x86,- 0xd0, 0xd6, 0xea, 0xda, 0x89, 0xb4, 0x87, 0x7c, 0x52, 0x18, 0x4d, 0x37, 0x5e, 0xe4, 0x77, 0x36, 0x8a, 0x25, 0x20, 0x9e,- 0x71, 0xac, 0xa6, 0x1f, 0xdd, 0x59, 0xc0, 0x22, 0x61, 0x0e, 0x03, 0xff, 0xf6, 0x43, 0xd8, 0x49, 0x96, 0xf8, 0x0d, 0xde,- 0x9f, 0xee, 0x27, 0xce, 0x23, 0xb5, 0xab, 0xe8, 0x68, 0x1e, 0xcf, 0x2a, 0xfa, 0xd2, 0x97, 0xd5, 0x2c, 0x10, 0x8e, 0xed,- 0x6c, 0x9f, 0x3f, 0x17, 0xc2, 0x9b, 0xc2, 0xc8, 0x82, 0x29, 0xd6, 0xb9, 0x12, 0xfc, 0xa9, 0x8f, 0x58, 0xb7, 0xb8, 0x90,- 0x5d, 0x62, 0x74, 0x88, 0xd7, 0x1e, 0x53, 0xc8, 0x0d, 0x71, 0x19, 0xb6, 0xe3, 0x80, 0xe0, 0x79, 0x49, 0x21, 0x2f, 0xe8,- 0x54, 0xea, 0xc8, 0x7c, 0x31, 0xc7, 0x7f, 0x60, 0x35, 0xfd, 0x79, 0x85, 0xa5, 0xcc, 0x11, 0xa2, 0x4d, 0x9c, 0x7d, 0x7c,- 0xc5, 0xb3, 0xf4, 0x66, 0x19, 0x6b, 0xc5, 0x98, 0x90, 0xc8, 0x7b, 0x08, 0xbf, 0x9e, 0x18, 0x92, 0xcd, 0xf8, 0xab, 0x87,- 0xd3, 0x9f, 0xe5, 0xae, 0x2f, 0x33, 0x81, 0x49, 0xc6, 0x61, 0x2a, 0x6f, 0x5f, 0x92, 0xae, 0xec, 0x14, 0xbc, 0x71, 0x91,- 0x14, 0xf0, 0x4a, 0x1d, 0xc8, 0x32, 0xd7, 0x19, 0x55, 0x8a, 0x95, 0xbc, 0x7d, 0x14, 0xf5, 0xaf, 0xcd, 0x56, 0x4b, 0xbc,- 0x91, 0xb7, 0xfe, 0x93, 0xf9, 0x35, 0xf8, 0xd7, 0x6c, 0x26, 0x8b, 0xfa, 0x7f, 0x49, 0xaa, 0x7b, 0x57, 0xca, 0xfa, 0xf7,- 0x0d, 0xe6, 0x78, 0x09, 0x66, 0x8a, 0xa3, 0xd7, 0xe6, 0x9f, 0xc3, 0x42, 0x71, 0x26, 0x88, 0xc8, 0x7b, 0x08, 0xdf, 0x57,- 0x3c, 0x6b, 0x79, 0x42, 0x48, 0x0f, 0x1d, 0x25, 0xaf, 0xae, 0xe0, 0xc3, 0xcc, 0x3f, 0x97, 0x04, 0x76, 0x08, 0x7b, 0xf8,- 0x2b, 0xfa, 0xaf, 0x0e, 0x39, 0x76, 0x7d, 0xee, 0x3d, 0x6a, 0xfa, 0x57, 0x63, 0x9d, 0x1b, 0x95, 0x12, 0xad, 0xfe, 0x9d,- 0xc8, 0x75, 0xef, 0x81, 0xfa, 0x64, 0xd1, 0x4d, 0xd4, 0xbf, 0x0d, 0xd3, 0x79, 0xcf, 0x43, 0xff, 0x95, 0x21, 0x57, 0x7d,- 0x09, 0x99, 0x62, 0xad, 0x19, 0x38, 0x87, 0xb7, 0xf9, 0xa6, 0x50, 0x7b, 0x08, 0xdd, 0xd7, 0x27, 0x3c, 0xc6, 0xd3, 0x4c,- 0x61, 0xb4, 0xd0, 0xbe, 0x57, 0x20, 0x2f, 0x42, 0xd4, 0x59, 0x68, 0x7e, 0x8c, 0xe0, 0x23, 0xcb, 0xfe, 0x1d, 0x9a, 0x89,- 0x5b, 0xf7, 0xe5, 0x4a, 0x43, 0xcd, 0x42, 0x1c, 0xdb, 0xd9, 0xfe, 0xeb, 0x60, 0xeb, 0x32, 0xbd, 0x88, 0xf4, 0xef, 0xc8,- 0x22, 0x0f, 0xcf, 0x99, 0xb7, 0xfe, 0x2d, 0x99, 0xc4, 0xab, 0x6e, 0xdd, 0x35, 0x8a, 0x0e, 0xa2, 0xfe, 0x8f, 0x72, 0xbe,- 0xeb, 0xd0, 0x93, 0xf4, 0x3f, 0xf4, 0xaa, 0x8b, 0x93, 0x23, 0xcc, 0x43, 0x11, 0x38, 0x87, 0x04, 0x96, 0x09, 0x5e, 0xe5,- 0x82, 0xec, 0x21, 0x74, 0x5f, 0x33, 0xf9, 0x94, 0x11, 0x2c, 0x65, 0x9a, 0x10, 0xbb, 0x76, 0x76, 0x30, 0x82, 0xa6, 0x20,- 0xfa, 0xf7, 0x17, 0x46, 0xda, 0x4c, 0x61, 0x21, 0x63, 0x0c, 0x3d, 0xc4, 0xad, 0x37, 0xb1, 0xcc, 0xd0, 0xd5, 0xe3, 0xd8,- 0xfd, 0x49, 0x36, 0x94, 0x10, 0xb6, 0x9f, 0x61, 0x46, 0x9e, 0x77, 0x48, 0x2e, 0x22, 0xfd, 0xd3, 0xf8, 0x89, 0xbd, 0xdc,- 0x5a, 0x48, 0xfd, 0xef, 0x65, 0x23, 0x71, 0x14, 0x33, 0x73, 0x0b, 0xc8, 0xfa, 0x3b, 0x8e, 0xf5, 0xd7, 0x48, 0xa1, 0xb8,- 0xa8, 0xff, 0xa1, 0x39, 0x1e, 0xc3, 0x4e, 0x21, 0x76, 0x30, 0x85, 0x5f, 0x78, 0x83, 0x24, 0xd2, 0x58, 0xec, 0x7a, 0xb3,- 0xbd, 0x34, 0x4b, 0xb7, 0xc6, 0xed, 0x1c, 0xda, 0xfe, 0x8f, 0xe0, 0x6b, 0xc1, 0x99, 0xb6, 0x33, 0xa4, 0x8f, 0x1c, 0x2b,- 0xf8, 0xfb, 0x43, 0xf3, 0x63, 0x85, 0x30, 0x7b, 0x47, 0xe1, 0xeb, 0xff, 0xfc, 0x63, 0xd7, 0xe1, 0x0a, 0x3a, 0x45, 0xa8,- 0x09, 0x0b, 0x5e, 0xff, 0x57, 0x0d, 0xc6, 0x77, 0xc8, 0xfa, 0x8f, 0x23, 0x81, 0x0e, 0xa4, 0x89, 0xfd, 0xcd, 0xc8, 0xfa,- 0x17, 0x67, 0x3b, 0x37, 0x71, 0x87, 0x99, 0xa3, 0xca, 0xae, 0x7f, 0x09, 0x56, 0xd2, 0x93, 0x0e, 0x82, 0xfe, 0x31, 0xec,- 0x08, 0xc9, 0xf1, 0x9a, 0x1c, 0x14, 0x1c, 0x3f, 0xce, 0x39, 0x3a, 0x73, 0xdd, 0xdc, 0x44, 0x19, 0x31, 0xdf, 0xfc, 0x7b,- 0x88, 0x31, 0x75, 0xd8, 0x29, 0x20, 0x3a, 0xa3, 0xc3, 0xaf, 0xe7, 0x21, 0x31, 0xfe, 0x73, 0x7c, 0xc8, 0x93, 0x59, 0x7f,- 0x21, 0x4e, 0x21, 0x7f, 0xfb, 0x73, 0x41, 0x2c, 0xab, 0x85, 0x6f, 0xff, 0x27, 0x84, 0xb4, 0x27, 0xaf, 0x32, 0xa1, 0x88,- 0xda, 0xff, 0xab, 0xc8, 0x30, 0x8e, 0xd0, 0x38, 0xd2, 0xcc, 0xb8, 0xe5, 0xd2, 0x16, 0x31, 0xfc, 0xe8, 0x8e, 0x47, 0x1f,- 0xad, 0xfe, 0xce, 0xdc, 0x05, 0x9f, 0xf0, 0x85, 0xb9, 0x13, 0xec, 0xfa, 0x3b, 0x51, 0x53, 0x59, 0xf4, 0x12, 0xdb, 0xff,- 0x9f, 0x19, 0x16, 0xfc, 0xfd, 0x25, 0x96, 0x46, 0x9d, 0x6b, 0x81, 0x3d, 0x54, 0x60, 0x1d, 0x2d, 0xe9, 0xc9, 0xb2, 0x08,- 0xf5, 0xf7, 0xd3, 0x9c, 0x4c, 0x35, 0x6e, 0x67, 0x89, 0x18, 0xf7, 0x5c, 0x9b, 0x34, 0x06, 0x50, 0x8f, 0xaa, 0x74, 0x61,- 0x8f, 0x30, 0x82, 0xab, 0x7f, 0xfb, 0x2b, 0x19, 0x4e, 0xa6, 0xd8, 0x17, 0xf5, 0xa7, 0xfb, 0x89, 0x8d, 0xf2, 0x4a, 0x9c,- 0x63, 0xbf, 0xc9, 0xb9, 0x9c, 0x4a, 0x27, 0xf6, 0x8a, 0xb1, 0x5a, 0x85, 0xd1, 0x3f, 0x96, 0x75, 0x74, 0x35, 0x71, 0x2d,- 0x9b, 0x84, 0x37, 0x12, 0x81, 0x2d, 0xaa, 0xb0, 0x55, 0x8c, 0x0e, 0xcf, 0xbf, 0x9e, 0x0a, 0x16, 0xfd, 0xeb, 0xb1, 0x9d,- 0x1d, 0x66, 0x66, 0x21, 0x2f, 0xfd, 0x7d, 0x7c, 0xc4, 0x76, 0x51, 0xff, 0x5a, 0x6c, 0xe3, 0x0d, 0xce, 0xa1, 0x26, 0xdd,- 0xc9, 0x14, 0x47, 0x73, 0x8f, 0xa4, 0x7f, 0x60, 0x0f, 0x2d, 0xc8, 0x20, 0x2b, 0xc2, 0x9c, 0x64, 0x29, 0xc6, 0xf7, 0x7f,- 0x90, 0x15, 0xbc, 0x67, 0x79, 0xc7, 0xd2, 0x90, 0x1f, 0xd9, 0x43, 0x2e, 0x8b, 0xc5, 0x28, 0x76, 0xff, 0xf6, 0xdb, 0xf8,- 0x4e, 0x7c, 0x7a, 0x08, 0xa4, 0xfb, 0xff, 0x55, 0x8e, 0xfa, 0x4a, 0x2e, 0x61, 0x9c, 0x99, 0x35, 0x64, 0x3e, 0xb7, 0x44,- 0xac, 0x3f, 0x0a, 0xde, 0xff, 0x6f, 0x6e, 0xa2, 0x02, 0x7e, 0x17, 0xe3, 0xcd, 0xf2, 0xb7, 0x68, 0x4e, 0xb6, 0x10, 0xb3,- 0x9a, 0x7f, 0x3d, 0xcb, 0x2c, 0xfa, 0xfb, 0x98, 0xe6, 0xc6, 0x68, 0x7b, 0xeb, 0x5f, 0x9e, 0x2d, 0xa2, 0xfe, 0xce, 0x7c,- 0x95, 0xe3, 0xc8, 0x64, 0x1f, 0xbf, 0xb9, 0xb1, 0x51, 0xd1, 0xe6, 0x5a, 0x60, 0x0f, 0x07, 0x59, 0xc7, 0x8a, 0x08, 0xe3,- 0x4a, 0x14, 0x8c, 0x62, 0x62, 0x4b, 0x73, 0x74, 0x48, 0x38, 0x22, 0xc7, 0x2e, 0x73, 0x8c, 0xbf, 0x97, 0x2d, 0x16, 0x21,- 0x66, 0xa2, 0x20, 0x7b, 0x48, 0x24, 0x86, 0x2f, 0xa2, 0x9a, 0xc9, 0x4b, 0x51, 0x14, 0x45, 0x51, 0x14, 0x45, 0x51, 0x14,- 0x45, 0x51, 0x14, 0x45, 0x51, 0x14, 0x45, 0x51, 0x14, 0x45, 0x39, 0x31, 0xfc, 0xff, 0x43, 0x68, 0x67, 0xf5, 0xff, 0x3b,- 0xf3, 0xae, 0xbf, 0xcb, 0xf7, 0xbc, 0x2a, 0xce, 0x3a, 0x1e, 0x3a, 0x42, 0xbf, 0x13, 0x07, 0xe0, 0xe5, 0x97, 0x6f, 0x25,- 0x38, 0x8c, 0x5b, 0xf1, 0x6c, 0xc8, 0x5f, 0x6d, 0x85, 0x35, 0x5a, 0xd3, 0xde, 0xfd, 0xed, 0x1c, 0x92, 0x38, 0xdf, 0xfd,- 0xfd, 0x71, 0x61, 0xbc, 0xdc, 0x33, 0x48, 0xe2, 0x4c, 0xf7, 0xf7, 0x93, 0xf9, 0x88, 0xba, 0xc2, 0x97, 0xdf, 0xb7, 0x83,- 0xdf, 0xfc, 0x13, 0x18, 0x2c, 0xf8, 0x3f, 0xce, 0x3c, 0xe4, 0x7a, 0xc2, 0x67, 0x34, 0xa8, 0x41, 0x43, 0x1a, 0x0a, 0x4e,- 0x86, 0x44, 0xeb, 0x77, 0xd6, 0xd2, 0x66, 0x8b, 0x8a, 0x62, 0xda, 0x85, 0x96, 0x31, 0x2f, 0x43, 0xff, 0x49, 0x23, 0x63,- 0x97, 0xb3, 0x8e, 0x43, 0x5b, 0x8d, 0xa6, 0xe2, 0x48, 0xcb, 0xf6, 0xef, 0xff, 0x8e, 0x97, 0xbc, 0x17, 0x0b, 0x49, 0xb5,- 0x8c, 0xbf, 0xde, 0x8e, 0xed, 0xbc, 0x45, 0x7b, 0x7e, 0x60, 0x8b, 0xe0, 0xd2, 0xac, 0x6f, 0xbc, 0x97, 0x23, 0x8d, 0x5b,- 0xbe, 0x9b, 0xa0, 0x5e, 0xe8, 0xb7, 0xea, 0x01, 0x82, 0x5b, 0xf5, 0x6a, 0xb2, 0x83, 0x31, 0x0a, 0xb1, 0xa4, 0xf2, 0xb0,- 0xa0, 0x7f, 0x60, 0xe4, 0xe0, 0xe7, 0xc9, 0xe5, 0xe5, 0xa0, 0x2f, 0x59, 0xfa, 0x06, 0x3e, 0x92, 0xa9, 0xae, 0x36, 0xdf,- 0xf3, 0x9d, 0x90, 0x7e, 0x92, 0x99, 0xcb, 0xc0, 0xff, 0xfb, 0xb3, 0x6c, 0x14, 0xbc, 0x8d, 0xa7, 0x04, 0xfd, 0xa4, 0xaf,- 0x91, 0xc7, 0xcd, 0x61, 0xe9, 0xfd, 0xd8, 0xcc, 0x2c, 0x61, 0x44, 0xb9, 0x01, 0xa2, 0xfb, 0xc5, 0x67, 0xfc, 0x20, 0xb3,- 0xc8, 0x10, 0x47, 0x9f, 0x2e, 0xce, 0x06, 0xd2, 0x85, 0x52, 0xea, 0x78, 0x77, 0xf2, 0x91, 0x5c, 0x48, 0x5f, 0xf2, 0xba,- 0x78, 0xac, 0x1e, 0x64, 0x33, 0x9f, 0x5d, 0x8c, 0x2f, 0xf0, 0x98, 0x77, 0xf9, 0xfa, 0xcc, 0xa1, 0xaf, 0x65, 0x8d, 0x7f,- 0xb9, 0xea, 0x8c, 0xb6, 0x8c, 0x51, 0xed, 0xe3, 0x9f, 0x6c, 0x28, 0x80, 0xc3, 0x4b, 0xd2, 0xdf, 0x71, 0xe3, 0x04, 0x5c,- 0x78, 0x8e, 0x27, 0x2a, 0xdc, 0xed, 0x56, 0x85, 0x3c, 0x77, 0x0c, 0xd9, 0xdf, 0xf8, 0x91, 0x19, 0xe6, 0xb7, 0xd3, 0x82,- 0x23, 0xbf, 0x1e, 0x4a, 0x79, 0x36, 0x1a, 0x7d, 0x1f, 0x61, 0x0b, 0x27, 0x8b, 0xe7, 0x73, 0x0f, 0xbb, 0x4d, 0x4d, 0x77,- 0x1a, 0x7b, 0x22, 0xcc, 0xff, 0xfe, 0x1d, 0x9f, 0x09, 0x4b, 0xfb, 0x09, 0xa3, 0x6f, 0xfa, 0xcc, 0xd8, 0xac, 0x73, 0x3d,- 0xf6, 0x35, 0x49, 0xd4, 0xff, 0x31, 0x7e, 0xa4, 0x3b, 0x1f, 0x17, 0xa2, 0xd6, 0x3e, 0x99, 0xc9, 0x42, 0xbd, 0x50, 0x8a,- 0xe1, 0xe6, 0xde, 0x2f, 0x43, 0x86, 0xc7, 0x8c, 0x13, 0x36, 0x7d, 0xde, 0x15, 0xfc, 0x33, 0x3e, 0x33, 0xb2, 0x6c, 0xcf,- 0x88, 0x7b, 0x29, 0xbc, 0xfe, 0xce, 0xe8, 0xc3, 0x81, 0xf1, 0xcc, 0x3f, 0xb0, 0xc4, 0x2a, 0x2c, 0x32, 0x9e, 0x99, 0x92,- 0x64, 0x73, 0x2d, 0x39, 0xc6, 0xb9, 0xf1, 0xa0, 0x65, 0xae, 0x0a, 0x1f, 0x37, 0xb0, 0x87, 0x46, 0xec, 0xb2, 0xf8, 0x85,- 0xfc, 0x8e, 0x46, 0xe7, 0x3a, 0xbf, 0xe1, 0x7b, 0xcf, 0x2b, 0x7a, 0x90, 0x54, 0x71, 0x3c, 0x72, 0x9b, 0xfe, 0xa5, 0xc8,- 0xb2, 0x8e, 0x5f, 0x2e, 0xeb, 0x1f, 0xc7, 0x6a, 0xae, 0xa1, 0x3c, 0xe9, 0x9c, 0x51, 0x84, 0xed, 0x79, 0x49, 0x2e, 0xe0,- 0x6e, 0xb6, 0x78, 0x8c, 0x28, 0x2b, 0xeb, 0x53, 0x97, 0x54, 0x3a, 0x89, 0x6b, 0x5c, 0xc7, 0x56, 0x7e, 0xa3, 0x83, 0x38,- 0x36, 0x6c, 0x51, 0xe8, 0x5f, 0x9b, 0x5c, 0x73, 0x47, 0x26, 0xb0, 0x5d, 0xa8, 0x6f, 0xfd, 0x79, 0xee, 0x94, 0x8b, 0xa6,- 0xac, 0x35, 0xf5, 0xfe, 0xcd, 0x66, 0xd6, 0x90, 0x41, 0xd6, 0x73, 0x19, 0xcc, 0x1e, 0xcf, 0xf1, 0x4f, 0xcf, 0x34, 0x91,- 0x19, 0x99, 0x9e, 0xb1, 0x05, 0xd5, 0xd9, 0x69, 0x99, 0x8f, 0xc0, 0xa6, 0xbf, 0x53, 0x3b, 0xb5, 0x8c, 0x4a, 0xff, 0xc6,- 0x7c, 0x6a, 0x7e, 0x76, 0x8d, 0xe8, 0xe6, 0x2a, 0xb8, 0xe3, 0x67, 0x18, 0xbb, 0x98, 0xcb, 0x27, 0xac, 0xe1, 0xf1, 0x02,- 0xeb, 0xbf, 0x91, 0x25, 0xac, 0x03, 0x86, 0x5b, 0x1d, 0x47, 0x65, 0xe8, 0x62, 0x1c, 0x73, 0x9f, 0x59, 0xfb, 0x38, 0x7f,- 0x45, 0x7f, 0x1f, 0xb3, 0xcc, 0xcc, 0x13, 0xcd, 0xd9, 0x62, 0xe9, 0xd5, 0x34, 0x65, 0x33, 0x31, 0xbc, 0x6e, 0x9c, 0xc8,- 0x43, 0xcc, 0x48, 0xce, 0x1b, 0x2c, 0x25, 0xc5, 0xdf, 0x06, 0xe6, 0x0a, 0xfd, 0xd0, 0x50, 0xba, 0x83, 0xc7, 0x5c, 0x17,- 0x8e, 0xfb, 0xf7, 0x67, 0x86, 0x5b, 0xd2, 0xec, 0xfa, 0x77, 0xb7, 0xce, 0x1b, 0x64, 0xab, 0xff, 0x8b, 0x9a, 0xdb, 0x82,- 0xad, 0xde, 0xc2, 0x28, 0xf4, 0x1f, 0xc8, 0xf5, 0xdc, 0xcf, 0x41, 0x61, 0xe6, 0xaa, 0xc3, 0xef, 0x9b, 0x64, 0x4b, 0xbc,- 0xaa, 0x97, 0xfe, 0x4b, 0x43, 0x7c, 0xa1, 0x83, 0x2c, 0x2d, 0xcc, 0x93, 0xcc, 0x33, 0xa3, 0x20, 0xdb, 0x54, 0x2b, 0xc1,- 0x5e, 0xce, 0x61, 0xae, 0x19, 0x07, 0xfc, 0x0e, 0x16, 0x70, 0x36, 0xfb, 0xac, 0x51, 0x8d, 0x17, 0x93, 0xc5, 0x9d, 0x64,- 0x0b, 0x4e, 0xe5, 0xd0, 0xe7, 0x04, 0x8c, 0x3f, 0xd7, 0x46, 0x5b, 0x36, 0x5a, 0x67, 0xd1, 0xb1, 0xeb, 0x7f, 0x31, 0x6b,- 0xfe, 0x66, 0xfd, 0xaf, 0x67, 0x07, 0x55, 0x88, 0xe1, 0x76, 0x72, 0xa3, 0xd0, 0xdf, 0x7f, 0x7f, 0x8e, 0x62, 0xb2, 0x98,- 0x7e, 0x12, 0xbd, 0x82, 0xfd, 0xf3, 0x81, 0xd6, 0xd9, 0xa5, 0xec, 0xfa, 0x7f, 0x1a, 0xe2, 0x66, 0x9f, 0x21, 0x8e, 0x10,- 0xee, 0xf4, 0x76, 0xf7, 0x51, 0x8b, 0x5d, 0x5c, 0xe4, 0x11, 0x09, 0xd0, 0x85, 0xfd, 0xe6, 0x19, 0xaa, 0x1c, 0xfb, 0xe8,- 0xe4, 0x8e, 0x87, 0x2f, 0xb5, 0xc2, 0xcb, 0x4c, 0x19, 0xed, 0xc1, 0x3a, 0x8f, 0x91, 0x52, 0xbd, 0xf5, 0x3f, 0x8d, 0x5d,- 0xc2, 0x73, 0x61, 0x64, 0xfd, 0x63, 0xd9, 0x6e, 0x9d, 0x79, 0xe3, 0xe8, 0xe8, 0x9f, 0xc0, 0x08, 0x0e, 0x90, 0xce, 0x8f,- 0x4c, 0x8f, 0x5a, 0xff, 0xb3, 0xd8, 0x2f, 0xce, 0xdf, 0xe7, 0xe4, 0xfd, 0x50, 0xca, 0x11, 0xc7, 0x35, 0x6c, 0xe6, 0xd1,- 0xa8, 0xf5, 0xbf, 0x91, 0x7d, 0x74, 0xa4, 0x32, 0x35, 0xe8, 0xcb, 0x6e, 0xf1, 0x59, 0xc7, 0xe7, 0xf6, 0xc6, 0x92, 0x3d,- 0xce, 0xf2, 0x19, 0x96, 0x9b, 0x3a, 0xc2, 0xe1, 0x77, 0x56, 0x8a, 0xb3, 0xb9, 0xf9, 0xdb, 0xfe, 0x39, 0xa6, 0x0d, 0x89,- 0x67, 0xb6, 0xb5, 0x06, 0xf7, 0xd6, 0x3f, 0x86, 0x5f, 0x18, 0x46, 0x25, 0xd7, 0xe3, 0x5f, 0x3a, 0x0a, 0xfd, 0x9d, 0x19,- 0x78, 0x9e, 0xf8, 0x5b, 0xf5, 0xf7, 0xdf, 0xaf, 0x55, 0xa2, 0x5a, 0x3f, 0xbf, 0x7d, 0x1e, 0xcc, 0x52, 0x31, 0x52, 0xb4,- 0x1e, 0xa3, 0x48, 0x67, 0x1f, 0x69, 0xf4, 0xb0, 0xce, 0x2b, 0x61, 0xd7, 0xdf, 0xc7, 0xed, 0x24, 0x73, 0x90, 0x03, 0xcc,- 0xf3, 0x98, 0xfd, 0xea, 0x36, 0xb0, 0x6a, 0xea, 0x70, 0x3e, 0xf0, 0x5a, 0x30, 0x26, 0x06, 0x4b, 0x4d, 0x71, 0x13, 0x7b,- 0xa8, 0x13, 0xec, 0x55, 0xee, 0xb1, 0xcc, 0x27, 0xe3, 0xad, 0x7f, 0x9d, 0x43, 0xde, 0xbd, 0xf4, 0x89, 0x4a, 0xff, 0xc7,- 0xac, 0x73, 0xf8, 0x1d, 0x3d, 0xfd, 0x8f, 0x0c, 0xf1, 0x9e, 0xed, 0x65, 0x41, 0x4a, 0x65, 0xe9, 0x13, 0xe4, 0x7d, 0xa9,- 0x97, 0xfe, 0x35, 0xd9, 0x61, 0x89, 0xb5, 0x3e, 0xde, 0xf5, 0x57, 0x42, 0x9f, 0x45, 0x2f, 0xb0, 0xd6, 0x83, 0xab, 0x84,- 0x39, 0x52, 0x4a, 0x71, 0x01, 0x73, 0x55, 0xff, 0x13, 0x84, 0xa7, 0x98, 0xcf, 0x7c, 0xeb, 0xdb, 0xd5, 0x16, 0xc1, 0xef,- 0x13, 0xf9, 0x9c, 0x63, 0xb6, 0xb8, 0x59, 0xf3, 0x4e, 0x51, 0x14, 0x45, 0x51, 0x14, 0x45, 0x51, 0x14, 0x45, 0x51, 0x14,- 0x45, 0x51, 0x14, 0x45, 0x39, 0x8a, 0x0c, 0x15, 0x7d, 0xb4, 0x87, 0x7e, 0x11, 0x6f, 0x10, 0xfc, 0xaa, 0x6a, 0xc3, 0x19,- 0xeb, 0xbe, 0x8c, 0x65, 0xeb, 0x0b, 0x69, 0x68, 0x75, 0xab, 0xfb, 0xdd, 0x3d, 0x31, 0x96, 0x6f, 0x8e, 0x97, 0x52, 0x8b,- 0x58, 0x1a, 0x0b, 0x73, 0xb7, 0x7b, 0x9d, 0x75, 0x05, 0xfe, 0x10, 0x47, 0xa2, 0xaf, 0xc4, 0x1f, 0xc1, 0x91, 0x3f, 0x0b,- 0x7a, 0xfd, 0x52, 0x6a, 0x23, 0x4a, 0x50, 0x8b, 0xcb, 0xcc, 0x59, 0x9f, 0xc1, 0x0d, 0xe2, 0x08, 0xfb, 0xce, 0x3a, 0x55,- 0xb9, 0xc4, 0xfa, 0x9d, 0xc8, 0xc9, 0xd3, 0x73, 0x2c, 0x69, 0xce, 0xb6, 0xa7, 0xd3, 0xc4, 0x63, 0xdc, 0xb6, 0x04, 0x93,- 0x33, 0x71, 0x34, 0x16, 0xf2, 0xd5, 0xd9, 0xba, 0x76, 0x84, 0x99, 0xfa, 0x43, 0xc9, 0xa1, 0x81, 0x67, 0x7a, 0x2d, 0x36,- 0xb0, 0x96, 0xff, 0x92, 0x62, 0x9d, 0x6b, 0xc0, 0xef, 0x47, 0x96, 0x47, 0x19, 0xad, 0xc3, 0x46, 0x52, 0x48, 0x67, 0x89,- 0x25, 0x97, 0xcb, 0x32, 0x9e, 0x83, 0xa2, 0xef, 0xfc, 0x22, 0xd2, 0x59, 0x4d, 0x06, 0xaf, 0x83, 0xe0, 0x68, 0xf0, 0x3a,- 0xeb, 0x04, 0x7a, 0x8a, 0xb1, 0x2c, 0xce, 0xf2, 0x6a, 0x51, 0x5e, 0xbf, 0x94, 0x9a, 0x43, 0x3f, 0x96, 0xb1, 0x93, 0xe1,- 0x74, 0x67, 0x2d, 0x1b, 0x59, 0x27, 0x1c, 0x2d, 0x87, 0x1e, 0x6c, 0x61, 0x2b, 0xab, 0xa9, 0x65, 0xcd, 0xd3, 0x54, 0x56,- 0x88, 0xe7, 0x99, 0x43, 0x1f, 0xb2, 0x48, 0x61, 0x0f, 0xd7, 0x8b, 0xe7, 0xe4, 0xe4, 0xcc, 0x2a, 0x76, 0xd3, 0x5b, 0xcc,- 0xf3, 0x1c, 0x86, 0x92, 0xe1, 0xe1, 0x8e, 0x95, 0xae, 0xd0, 0xab, 0xb4, 0x2d, 0xe7, 0x15, 0x62, 0x88, 0xe1, 0x5d, 0xfa,- 0x79, 0x94, 0x45, 0x59, 0xff, 0x18, 0x96, 0x9b, 0xd8, 0x9d, 0x52, 0x7c, 0x23, 0x8c, 0x0c, 0xed, 0x70, 0xbf, 0x99, 0x75,- 0xa2, 0xb8, 0xe0, 0xa5, 0xda, 0x60, 0xbc, 0x62, 0xe5, 0x19, 0x63, 0xd5, 0xbf, 0x9a, 0xf5, 0xfe, 0x6a, 0x64, 0x71, 0xb2,- 0x4a, 0xcb, 0x03, 0x0a, 0xd7, 0xa1, 0x5e, 0x81, 0xf5, 0x7f, 0xd3, 0x9c, 0x59, 0x26, 0xa3, 0x89, 0x25, 0x96, 0xd5, 0x74,- 0x10, 0xd6, 0x19, 0x49, 0x02, 0xc5, 0x98, 0x28, 0x7a, 0xe7, 0x03, 0x79, 0xfa, 0x0e, 0x33, 0xc5, 0x63, 0xce, 0x30, 0xe5,- 0xf4, 0x61, 0x76, 0x08, 0xf1, 0x29, 0x81, 0x9c, 0xa9, 0xc8, 0x0f, 0x16, 0xfd, 0x47, 0x59, 0xc6, 0xf1, 0xb4, 0xe9, 0x3f,- 0xc8, 0xa3, 0xb4, 0x9d, 0xc9, 0x01, 0x31, 0xfe, 0xe8, 0xf0, 0xb2, 0xf8, 0x86, 0x78, 0x2e, 0x8e, 0xd3, 0xba, 0x21, 0x17,- 0x71, 0x11, 0xed, 0xd9, 0x21, 0x46, 0x3f, 0xbd, 0xc5, 0x4c, 0x1a, 0x0b, 0xe3, 0x82, 0xd6, 0x61, 0xbf, 0x5b, 0xeb, 0xdf,- 0x6c, 0xd1, 0xbf, 0xaf, 0xc7, 0xfd, 0x65, 0xbb, 0xa7, 0x73, 0x45, 0x35, 0x9d, 0x65, 0xb7, 0x92, 0x26, 0xfa, 0x5f, 0x65,- 0xfd, 0x1b, 0xbb, 0xf1, 0x32, 0x7e, 0xe7, 0xd4, 0x30, 0xc1, 0xb7, 0x9a, 0xe3, 0xc6, 0x75, 0xb5, 0x67, 0xba, 0x47, 0x9e,- 0x56, 0x22, 0xcf, 0x9d, 0xdf, 0xe2, 0xd0, 0x6d, 0x03, 0x2e, 0xb2, 0xcd, 0xc2, 0x5c, 0x33, 0xb5, 0xc9, 0x71, 0xbf, 0x3e,- 0xdf, 0x6e, 0xd1, 0xff, 0xf2, 0xa8, 0xda, 0x7f, 0xef, 0xd2, 0x76, 0x03, 0xa9, 0x1e, 0xdb, 0x46, 0x2a, 0x8b, 0x37, 0xb0,- 0x9f, 0xd9, 0x41, 0xc2, 0x1d, 0x40, 0xa3, 0x59, 0xc7, 0x4e, 0x66, 0x0a, 0xbe, 0xc3, 0xa6, 0xa4, 0xb9, 0xf7, 0xf6, 0x59,- 0x16, 0xfd, 0x47, 0x79, 0xdc, 0x5f, 0xd1, 0xea, 0xdf, 0x8c, 0x34, 0x2e, 0x8d, 0xa2, 0xfe, 0x6f, 0xe0, 0xea, 0xff, 0xa0,- 0xf9, 0xf9, 0xa1, 0x50, 0xdb, 0x06, 0xd6, 0x79, 0x40, 0x88, 0x0a, 0x0a, 0xcd, 0xd3, 0x2c, 0xc1, 0x13, 0x97, 0x13, 0x1c,- 0xff, 0x7b, 0xbe, 0x10, 0x6f, 0x75, 0x63, 0x70, 0xeb, 0xb3, 0x2d, 0xfa, 0x37, 0x88, 0x52, 0x7f, 0xaf, 0xd2, 0x56, 0x8d,- 0x83, 0x6e, 0xff, 0x26, 0x51, 0xd0, 0x2f, 0x52, 0x59, 0xac, 0xce, 0x41, 0xcf, 0xa8, 0x11, 0xc7, 0xd7, 0xf9, 0x93, 0xb8,- 0xbc, 0x0a, 0xb8, 0x51, 0x8c, 0x6d, 0x2d, 0xfa, 0x07, 0xee, 0xaf, 0x19, 0x7f, 0x59, 0xff, 0x2e, 0xec, 0xb4, 0xce, 0xe9,- 0x74, 0x24, 0xf4, 0xcf, 0xcf, 0xd3, 0x1a, 0xe4, 0x0a, 0xb9, 0x9a, 0xe3, 0xce, 0x3b, 0x14, 0xcf, 0x2e, 0xa1, 0x1f, 0x77,- 0x5a, 0x70, 0x44, 0xf8, 0x36, 0x45, 0xa4, 0xbf, 0x57, 0x69, 0xf3, 0x31, 0x9d, 0x8f, 0x29, 0x4b, 0x79, 0xbe, 0x13, 0xa2,- 0x1b, 0x22, 0x95, 0x45, 0xc7, 0xab, 0xfb, 0xa9, 0x69, 0xdf, 0xdf, 0x76, 0x67, 0x3c, 0x29, 0xa8, 0xfe, 0x3e, 0xc6, 0xb2,- 0x88, 0x56, 0x3c, 0xc1, 0x42, 0xcf, 0xfe, 0xdf, 0x03, 0xe2, 0x08, 0xca, 0xd1, 0xe9, 0xbf, 0xd9, 0x44, 0x0c, 0x1c, 0x3d,- 0xfd, 0x03, 0x79, 0x5a, 0x81, 0x6f, 0xc5, 0x18, 0xb4, 0x1c, 0xf3, 0xfc, 0x52, 0x82, 0xbe, 0xfc, 0x29, 0xb6, 0xbd, 0x0b,- 0xcc, 0xb3, 0xd6, 0x05, 0xcc, 0x2a, 0x22, 0xfd, 0xbd, 0x4a, 0x9b, 0xd3, 0x46, 0x4d, 0x24, 0x93, 0x0c, 0xc6, 0x08, 0xcf,- 0x77, 0x91, 0xca, 0xa2, 0xb3, 0xf5, 0x2f, 0x64, 0x91, 0xc1, 0x74, 0x4b, 0xb4, 0x95, 0x5d, 0xff, 0x52, 0x0c, 0x64, 0x21,- 0x13, 0xb8, 0xea, 0x88, 0xeb, 0x7f, 0x25, 0x0f, 0x90, 0x61, 0x71, 0xa6, 0x1f, 0x19, 0xfd, 0xfd, 0x79, 0x9a, 0xc9, 0x58,- 0x71, 0x6e, 0x95, 0x1c, 0x9e, 0x66, 0x07, 0x7b, 0x59, 0xca, 0xb9, 0x96, 0xf8, 0x84, 0xb9, 0xec, 0x65, 0x0f, 0xed, 0x8b,- 0x48, 0xff, 0xa5, 0x9e, 0xa5, 0xcd, 0x5f, 0xf7, 0xdb, 0x7a, 0x94, 0x81, 0xb2, 0x38, 0xd3, 0x63, 0x96, 0x89, 0x52, 0x1e,- 0x33, 0xc8, 0xd8, 0xf5, 0x2f, 0xeb, 0xc6, 0x71, 0x37, 0x21, 0x5b, 0x38, 0xaf, 0xa2, 0xd4, 0xbf, 0x81, 0x89, 0x2a, 0x5b,- 0x66, 0xd1, 0xa2, 0xc1, 0x11, 0x7a, 0xef, 0x92, 0x68, 0x8d, 0xb6, 0x73, 0x8e, 0x19, 0x6f, 0x89, 0x5e, 0x0e, 0x50, 0x91,- 0x62, 0xd6, 0x67, 0x6e, 0x5f, 0x94, 0xfa, 0xb7, 0xf3, 0x2c, 0x6d, 0xde, 0x04, 0xca, 0xe2, 0x43, 0x85, 0x3c, 0x17, 0xbb,- 0xfe, 0x3f, 0x33, 0x82, 0x2b, 0xb8, 0x93, 0xd9, 0x8c, 0xf1, 0xd0, 0xa5, 0xa8, 0xf4, 0x2f, 0xc6, 0x2c, 0xbe, 0x11, 0x9e,- 0x26, 0x8f, 0x9c, 0xfe, 0x85, 0x7f, 0x23, 0x13, 0xe9, 0x9d, 0x4b, 0x61, 0xdc, 0xfd, 0x27, 0xff, 0x85, 0xad, 0x2b, 0x16,- 0x78, 0xac, 0x81, 0x68, 0xf4, 0xaf, 0x44, 0x6f, 0xa6, 0x30, 0x95, 0x5e, 0x9e, 0xcf, 0x9f, 0xd1, 0x50, 0x9c, 0x83, 0xe2,- 0xd3, 0xe2, 0xb1, 0xc6, 0x18, 0x61, 0x94, 0x0d, 0x9f, 0x38, 0x06, 0xc8, 0x58, 0x8f, 0x18, 0x37, 0xe5, 0xf0, 0x08, 0x94,- 0x0f, 0x58, 0xa5, 0xf9, 0xf0, 0x3f, 0xcb, 0x69, 0xf4, 0x13, 0xdf, 0xf0, 0x29, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a,- 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0xca, 0x89, 0x4a, 0x15, 0xae, 0x16, 0x7c, 0x88, 0x7e, 0x26, 0x72, 0x9f,- 0xa7, 0x97, 0xb6, 0x32, 0xe7, 0x09, 0x0e, 0xc7, 0x5a, 0xc1, 0xaf, 0xdc, 0x8d, 0x85, 0xb1, 0xf2, 0x6b, 0xb8, 0x6e, 0x8b,- 0xc4, 0xa0, 0x83, 0xfd, 0x22, 0x61, 0x7c, 0xfc, 0x4a, 0x34, 0x72, 0xbf, 0xc8, 0xd6, 0x0d, 0x8e, 0xea, 0x2f, 0x1d, 0xa3,- 0x8c, 0x78, 0x0c, 0xc7, 0x1d, 0x1f, 0xa0, 0x92, 0x47, 0xac, 0xc0, 0xe1, 0x4b, 0x2e, 0xe5, 0x95, 0xb0, 0x65, 0x25, 0x3d,- 0x1c, 0xb5, 0x31, 0xc7, 0xbd, 0xfa, 0x9d, 0xc9, 0x60, 0x0a, 0x69, 0xc2, 0x75, 0x3b, 0x0e, 0xdd, 0x3f, 0x78, 0x55, 0x9c,- 0x4f, 0xc0, 0xeb, 0x0b, 0xfc, 0x43, 0xac, 0x75, 0xf3, 0xa5, 0x0b, 0x0b, 0x85, 0x6d, 0x5b, 0xba, 0xa3, 0x05, 0x3e, 0x0a,- 0xc6, 0x7d, 0x56, 0x91, 0x5c, 0x21, 0xc2, 0xa4, 0x1c, 0xeb, 0xcd, 0xc8, 0xf0, 0x75, 0xc8, 0x14, 0x9c, 0x49, 0xf9, 0xc7,- 0xe8, 0x2c, 0x1e, 0x23, 0x91, 0x55, 0x86, 0xf5, 0xc0, 0x5d, 0x56, 0xef, 0xc2, 0xd4, 0xb0, 0xa5, 0xb7, 0x31, 0x2e, 0x6c,- 0xd9, 0x39, 0x6c, 0x63, 0xb0, 0xb8, 0x8f, 0x16, 0xa4, 0xb1, 0xc9, 0xdc, 0x21, 0x6d, 0xe9, 0x7a, 0x5c, 0xaa, 0x9f, 0x40,- 0x26, 0xd7, 0x9a, 0x3a, 0x60, 0xb0, 0xe0, 0xc3, 0x1f, 0x4d, 0x26, 0xab, 0xc4, 0x51, 0x7b, 0xbd, 0xf4, 0x2f, 0xc3, 0x6e,- 0xd7, 0x55, 0xb8, 0x80, 0x8e, 0xa2, 0x36, 0xfb, 0x4c, 0xf4, 0xcb, 0x57, 0x2c, 0x30, 0xa5, 0xae, 0x15, 0xcb, 0xc5, 0x73,- 0xbb, 0x9e, 0xed, 0x54, 0x66, 0xb2, 0x38, 0xb3, 0x42, 0x19, 0x32, 0x3d, 0x8f, 0x11, 0x60, 0x30, 0xbf, 0x59, 0xc6, 0xe4,- 0xeb, 0xc0, 0x48, 0xe1, 0xee, 0x95, 0xf4, 0x77, 0xdc, 0x48, 0x19, 0xe2, 0xe8, 0xee, 0xb3, 0x79, 0x82, 0xcb, 0x59, 0xc3,- 0x64, 0x76, 0x58, 0x47, 0x9b, 0x3c, 0xd6, 0xf9, 0x0f, 0x5f, 0x70, 0xb1, 0x25, 0x8f, 0x9c, 0x2b, 0x7c, 0xc8, 0xd3, 0xa5,- 0x22, 0x3b, 0x70, 0x86, 0xf1, 0xbe, 0xb9, 0x6f, 0xf6, 0x59, 0xe6, 0x3d, 0x99, 0x40, 0x67, 0xe2, 0x48, 0xe3, 0x0e, 0x66,- 0xe1, 0x23, 0x89, 0xfe, 0x96, 0xa3, 0xbf, 0xcb, 0x42, 0x96, 0x58, 0xfc, 0x25, 0x49, 0xe6, 0x18, 0xf5, 0xd9, 0xe7, 0x31,- 0xee, 0x7e, 0x6b, 0x52, 0xad, 0xe3, 0xa1, 0x8e, 0x14, 0xe2, 0x36, 0x6c, 0xfa, 0x3b, 0x6e, 0x3f, 0x69, 0x4c, 0xe0, 0xda,- 0xe6, 0x9e, 0x49, 0xa4, 0x95, 0xc5, 0x3f, 0x7e, 0x3c, 0x50, 0x83, 0x21, 0x6c, 0x25, 0x35, 0x38, 0xcb, 0x4e, 0x51, 0xe8,- 0x7f, 0x39, 0xe9, 0x14, 0xe3, 0x35, 0xeb, 0x78, 0xd1, 0xff, 0xe2, 0x27, 0x2e, 0x61, 0x1e, 0xc5, 0xd8, 0x49, 0x59, 0x36,- 0x5a, 0xfd, 0xd7, 0x57, 0x82, 0xb5, 0x5e, 0x6d, 0x62, 0x8e, 0xd1, 0xc7, 0x7a, 0x0c, 0x1f, 0xe7, 0xb1, 0x2b, 0xe8, 0x6e,- 0x0e, 0x47, 0x1e, 0xad, 0xd7, 0xa6, 0xff, 0xef, 0x96, 0xf9, 0x00, 0x4e, 0x0c, 0x62, 0xf8, 0x37, 0x79, 0xa2, 0x3b, 0xca,- 0xa6, 0xff, 0x56, 0x9a, 0x9a, 0x9f, 0xaf, 0x8a, 0xfa, 0x3b, 0x91, 0x5f, 0x2d, 0x58, 0x43, 0x33, 0xab, 0x1b, 0x63, 0x37,- 0xcf, 0xf3, 0xaa, 0x99, 0x65, 0xa5, 0x13, 0xdb, 0x2d, 0xb5, 0x4f, 0x09, 0x92, 0x79, 0x99, 0x34, 0x4b, 0x0c, 0x41, 0x0c,- 0x2b, 0x69, 0xc1, 0x9f, 0xd6, 0xb1, 0xba, 0xcb, 0xb1, 0xf2, 0x90, 0xb9, 0xa5, 0x0e, 0x6f, 0xf7, 0x96, 0x8b, 0xae, 0x6f,- 0x9b, 0xfe, 0x63, 0x82, 0x33, 0x0f, 0x9d, 0x58, 0x54, 0x66, 0xbd, 0x89, 0x41, 0xb9, 0x8c, 0x03, 0xd4, 0x8e, 0x42, 0xff,- 0x0f, 0x19, 0xcb, 0x29, 0x5c, 0x4a, 0xb2, 0xa8, 0xbf, 0x8f, 0x7f, 0x33, 0x9d, 0x8d, 0xd6, 0x56, 0xc5, 0x99, 0xd3, 0xe5,- 0x4f, 0x2e, 0x33, 0xf3, 0x78, 0xad, 0x75, 0xe7, 0xc1, 0x08, 0x67, 0x20, 0x93, 0x89, 0xa1, 0x0f, 0x93, 0x85, 0xfe, 0xbd,- 0xcf, 0xcc, 0x07, 0x35, 0x83, 0x0d, 0x96, 0x63, 0xc4, 0xf0, 0x1d, 0x93, 0xa8, 0x4c, 0x25, 0x2a, 0x09, 0x4e, 0xdb, 0xb2,- 0x6c, 0x65, 0x80, 0xd8, 0xab, 0xb7, 0xe9, 0x5f, 0x97, 0xb9, 0x1e, 0x23, 0x8a, 0x1f, 0xcf, 0xb4, 0x27, 0x95, 0x1d, 0xec,- 0xb6, 0xcc, 0x88, 0xf1, 0xb5, 0xb9, 0x4b, 0xc3, 0xa9, 0xcf, 0x78, 0x72, 0x98, 0xcf, 0x93, 0x16, 0xfd, 0x4f, 0xe1, 0x00,- 0xbd, 0x3c, 0x8e, 0xfa, 0x0a, 0xe9, 0x46, 0x39, 0x67, 0x26, 0xa7, 0xbb, 0xc5, 0x35, 0xae, 0x62, 0xb7, 0x19, 0x4f, 0xbf,- 0x04, 0xcb, 0x2d, 0xe7, 0x56, 0x9d, 0x5c, 0xeb, 0x31, 0xce, 0x0f, 0x19, 0xc5, 0xfb, 0x05, 0xc1, 0x0b, 0xfa, 0x3a, 0x2b,- 0x44, 0x9f, 0xa5, 0x4d, 0xff, 0x76, 0x2c, 0xa5, 0xd5, 0x09, 0x5b, 0xff, 0x9f, 0x62, 0xb9, 0xc3, 0x9c, 0x56, 0x76, 0x25,- 0xdb, 0x2c, 0xa9, 0xc5, 0xff, 0xe6, 0xb3, 0xae, 0xca, 0x7e, 0xeb, 0x8c, 0x0b, 0x91, 0x99, 0x14, 0x9c, 0x77, 0xac, 0x20,- 0xfa, 0x4f, 0x16, 0xd7, 0xfe, 0xdf, 0x20, 0xf1, 0x98, 0x3c, 0xab, 0x3b, 0xf9, 0xa5, 0x50, 0x73, 0xa7, 0x05, 0xf8, 0x32,- 0xca, 0xfe, 0x5f, 0x73, 0x7d, 0x53, 0x78, 0x0c, 0x11, 0xcf, 0xd8, 0x90, 0x99, 0x69, 0x0a, 0xc3, 0x10, 0x9e, 0x8f, 0x42,- 0xff, 0x65, 0x34, 0xd2, 0x5c, 0x3f, 0xa1, 0xb8, 0x95, 0xa5, 0xc2, 0x2c, 0x51, 0x92, 0xfe, 0xa5, 0x78, 0x82, 0x34, 0x8f,- 0xbe, 0xac, 0x72, 0x3c, 0x52, 0x9c, 0xb6, 0x42, 0xe4, 0xa6, 0xa4, 0x7f, 0x5d, 0xde, 0x15, 0x47, 0x14, 0x52, 0x4e, 0x3c,- 0x6c, 0xf5, 0xbf, 0xa2, 0xfa, 0x2b, 0xaa, 0xbf, 0x72, 0x62, 0x53, 0xc2, 0xe3, 0x6b, 0x92, 0xa2, 0x28, 0x8a, 0xa2, 0x28,- 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2,- 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a,- 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28,- 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2,- 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a,- 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28,- 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2,- 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a, 0xa2, 0x28, 0x8a,- 0xa2, 0x28, 0x8a, 0xe2, 0xe0, 0xff, 0xa7, 0xf9, 0xa0, 0xfa, 0x2b, 0xff, 0xb3, 0xfa, 0xff, 0x3f };--// Font glyphs rectangles data (on atlas)-static const Rectangle amberFontRecs[95] = {- { 4, 4, 3 , 16 },- { 15, 4, 2 , 11 },- { 25, 4, 4 , 5 },- { 37, 4, 9 , 10 },- { 54, 4, 8 , 14 },- { 70, 4, 11 , 11 },- { 89, 4, 9 , 11 },- { 106, 4, 2 , 5 },- { 116, 4, 4 , 13 },- { 128, 4, 4 , 13 },- { 140, 4, 6 , 6 },- { 154, 4, 7 , 7 },- { 169, 4, 3 , 5 },- { 180, 4, 6 , 2 },- { 194, 4, 2 , 3 },- { 204, 4, 5 , 13 },- { 217, 4, 8 , 11 },- { 233, 4, 5 , 10 },- { 4, 28, 8 , 10 },- { 20, 28, 8 , 11 },- { 36, 28, 8 , 10 },- { 52, 28, 7 , 11 },- { 67, 28, 8 , 11 },- { 83, 28, 7 , 10 },- { 98, 28, 8 , 11 },- { 114, 28, 8 , 11 },- { 130, 28, 2 , 8 },- { 140, 28, 3 , 10 },- { 151, 28, 7 , 8 },- { 166, 28, 7 , 5 },- { 181, 28, 7 , 8 },- { 196, 28, 7 , 11 },- { 211, 28, 12 , 13 },- { 231, 28, 9 , 10 },- { 4, 52, 7 , 10 },- { 19, 52, 9 , 11 },- { 36, 52, 8 , 10 },- { 52, 52, 7 , 10 },- { 67, 52, 6 , 10 },- { 81, 52, 10 , 11 },- { 99, 52, 8 , 10 },- { 115, 52, 2 , 10 },- { 125, 52, 7 , 11 },- { 140, 52, 8 , 10 },- { 156, 52, 6 , 10 },- { 170, 52, 10 , 10 },- { 188, 52, 8 , 10 },- { 204, 52, 10 , 11 },- { 222, 52, 7 , 10 },- { 237, 52, 10 , 11 },- { 4, 76, 8 , 10 },- { 20, 76, 8 , 11 },- { 36, 76, 8 , 10 },- { 52, 76, 8 , 11 },- { 68, 76, 9 , 10 },- { 85, 76, 13 , 10 },- { 106, 76, 9 , 10 },- { 123, 76, 9 , 10 },- { 140, 76, 8 , 10 },- { 156, 76, 4 , 13 },- { 168, 76, 5 , 13 },- { 181, 76, 4 , 13 },- { 193, 76, 6 , 5 },- { 207, 76, 7 , 2 },- { 222, 76, 4 , 3 },- { 234, 76, 7 , 9 },- { 4, 100, 7 , 11 },- { 19, 100, 7 , 9 },- { 34, 100, 8 , 11 },- { 50, 100, 8 , 9 },- { 66, 100, 5 , 11 },- { 79, 100, 8 , 11 },- { 95, 100, 6 , 10 },- { 109, 100, 3 , 10 },- { 120, 100, 4 , 13 },- { 132, 100, 7 , 10 },- { 147, 100, 2 , 10 },- { 157, 100, 10 , 8 },- { 175, 100, 6 , 8 },- { 189, 100, 8 , 9 },- { 205, 100, 7 , 11 },- { 220, 100, 8 , 11 },- { 236, 100, 4 , 8 },- { 4, 124, 7 , 9 },- { 19, 124, 5 , 10 },- { 32, 124, 6 , 9 },- { 46, 124, 8 , 8 },- { 62, 124, 11 , 8 },- { 81, 124, 7 , 8 },- { 96, 124, 8 , 11 },- { 112, 124, 7 , 8 },- { 127, 124, 5 , 13 },- { 140, 124, 2 , 17 },- { 150, 124, 5 , 13 },- { 163, 124, 7 , 4 },-};--// Font glyphs info data-// NOTE: No glyphs.image data provided-static const GlyphInfo amberFontGlyphs[95] = {- { 32, 0, 12, 3, { 0 }},- { 33, 1, 2, 3, { 0 }},- { 34, 1, 2, 6, { 0 }},- { 35, 0, 2, 8, { 0 }},- { 36, 0, 0, 8, { 0 }},- { 37, 1, 2, 12, { 0 }},- { 38, 0, 2, 8, { 0 }},- { 39, 1, 2, 3, { 0 }},- { 40, 1, 1, 4, { 0 }},- { 41, 0, 1, 4, { 0 }},- { 42, 0, 2, 6, { 0 }},- { 43, 1, 5, 8, { 0 }},- { 44, 0, 10, 3, { 0 }},- { 45, 0, 7, 6, { 0 }},- { 46, 1, 10, 3, { 0 }},- { 47, 0, 1, 4, { 0 }},- { 48, 0, 2, 8, { 0 }},- { 49, 0, 2, 5, { 0 }},- { 50, 0, 2, 8, { 0 }},- { 51, 0, 2, 8, { 0 }},- { 52, 0, 2, 8, { 0 }},- { 53, 1, 2, 8, { 0 }},- { 54, 0, 2, 8, { 0 }},- { 55, 0, 2, 7, { 0 }},- { 56, 0, 2, 8, { 0 }},- { 57, 0, 2, 8, { 0 }},- { 58, 1, 5, 3, { 0 }},- { 59, 0, 5, 3, { 0 }},- { 60, 1, 4, 8, { 0 }},- { 61, 1, 6, 8, { 0 }},- { 62, 1, 4, 8, { 0 }},- { 63, 0, 2, 6, { 0 }},- { 64, 0, 2, 12, { 0 }},- { 65, 0, 2, 9, { 0 }},- { 66, 1, 2, 8, { 0 }},- { 67, 0, 2, 9, { 0 }},- { 68, 1, 2, 9, { 0 }},- { 69, 1, 2, 7, { 0 }},- { 70, 1, 2, 7, { 0 }},- { 71, 0, 2, 9, { 0 }},- { 72, 1, 2, 9, { 0 }},- { 73, 1, 2, 3, { 0 }},- { 74, 0, 2, 7, { 0 }},- { 75, 1, 2, 8, { 0 }},- { 76, 1, 2, 7, { 0 }},- { 77, 1, 2, 11, { 0 }},- { 78, 1, 2, 9, { 0 }},- { 79, 0, 2, 10, { 0 }},- { 80, 1, 2, 8, { 0 }},- { 81, 0, 2, 10, { 0 }},- { 82, 1, 2, 8, { 0 }},- { 83, 0, 2, 8, { 0 }},- { 84, 0, 2, 8, { 0 }},- { 85, 1, 2, 9, { 0 }},- { 86, 0, 2, 9, { 0 }},- { 87, 0, 2, 13, { 0 }},- { 88, 0, 2, 9, { 0 }},- { 89, 0, 2, 8, { 0 }},- { 90, 0, 2, 8, { 0 }},- { 91, 1, 1, 4, { 0 }},- { 92, 0, 1, 4, { 0 }},- { 93, 0, 1, 4, { 0 }},- { 94, 0, 2, 6, { 0 }},- { 95, 0, 12, 6, { 0 }},- { 96, 0, 1, 4, { 0 }},- { 97, 0, 4, 7, { 0 }},- { 98, 1, 2, 8, { 0 }},- { 99, 0, 4, 7, { 0 }},- { 100, 0, 2, 8, { 0 }},- { 101, 0, 4, 7, { 0 }},- { 102, 0, 1, 4, { 0 }},- { 103, 0, 4, 8, { 0 }},- { 104, 1, 2, 7, { 0 }},- { 105, 0, 2, 3, { 0 }},- { 106, -1, 2, 3, { 0 }},- { 107, 1, 2, 7, { 0 }},- { 108, 1, 2, 3, { 0 }},- { 109, 1, 4, 11, { 0 }},- { 110, 1, 4, 7, { 0 }},- { 111, 0, 4, 7, { 0 }},- { 112, 1, 4, 8, { 0 }},- { 113, 0, 4, 8, { 0 }},- { 114, 1, 4, 4, { 0 }},- { 115, 0, 4, 6, { 0 }},- { 116, 0, 3, 4, { 0 }},- { 117, 1, 4, 7, { 0 }},- { 118, 0, 4, 7, { 0 }},- { 119, 0, 4, 10, { 0 }},- { 120, 0, 4, 7, { 0 }},- { 121, 0, 4, 7, { 0 }},- { 122, 0, 4, 7, { 0 }},- { 123, 0, 1, 5, { 0 }},- { 124, 1, -1, 4, { 0 }},- { 125, 0, 1, 5, { 0 }},- { 126, 1, 6, 8, { 0 }},-};--// Style loading function: Amber-static void GuiLoadStyleAmber(void)-{- // Load style properties provided- // NOTE: Default properties are propagated- for (int i = 0; i < AMBER_STYLE_PROPS_COUNT; i++)- {- GuiSetStyle(amberStyleProps[i].controlId, amberStyleProps[i].propertyId, amberStyleProps[i].propertyValue);- }-- // Custom font loading- // NOTE: Compressed font image data (DEFLATE), it requires DecompressData() function- int amberFontDataSize = 0;- unsigned char *data = DecompressData(amberFontData, AMBER_STYLE_FONT_ATLAS_COMP_SIZE, &amberFontDataSize);- Image imFont = { data, 256, 256, 1, 2 };-- Font font = { 0 };- font.baseSize = 16;- font.glyphCount = 95;-- // Load texture from image- font.texture = LoadTextureFromImage(imFont);- UnloadImage(imFont); // Uncompressed image data can be unloaded from memory-- // Copy char recs data from global fontRecs- // NOTE: Required to avoid issues if trying to free font- font.recs = (Rectangle *)RAYGUI_MALLOC(font.glyphCount*sizeof(Rectangle));- memcpy(font.recs, amberFontRecs, font.glyphCount*sizeof(Rectangle));-- // Copy font char info data from global fontChars- // NOTE: Required to avoid issues if trying to free font- font.glyphs = (GlyphInfo *)RAYGUI_MALLOC(font.glyphCount*sizeof(GlyphInfo));- memcpy(font.glyphs, amberFontGlyphs, font.glyphCount*sizeof(GlyphInfo));-- GuiSetFont(font);-- // Setup a white rectangle on the font to be used on shapes drawing,- // it makes possible to draw shapes and text (full UI) in a single draw call- Rectangle fontWhiteRec = { 254, 126, 1, 1 };+// Copyright (c) 2020-2024 raylib technologies (@raylibtech) //+// //+//////////////////////////////////////////////////////////////////////////////////++#define AMBER_STYLE_PROPS_COUNT 16++// Custom style name: Amber+static const GuiStyleProp amberStyleProps[AMBER_STYLE_PROPS_COUNT] = {+ { 0, 0, (int)0x898988ff }, // DEFAULT_BORDER_COLOR_NORMAL + { 0, 1, (int)0x292929ff }, // DEFAULT_BASE_COLOR_NORMAL + { 0, 2, (int)0xd4d4d4ff }, // DEFAULT_TEXT_COLOR_NORMAL + { 0, 3, (int)0xeb891dff }, // DEFAULT_BORDER_COLOR_FOCUSED + { 0, 4, (int)0x292929ff }, // DEFAULT_BASE_COLOR_FOCUSED + { 0, 5, (int)0xffffffff }, // DEFAULT_TEXT_COLOR_FOCUSED + { 0, 6, (int)0xf1cf9dff }, // DEFAULT_BORDER_COLOR_PRESSED + { 0, 7, (int)0xf39333ff }, // DEFAULT_BASE_COLOR_PRESSED + { 0, 8, (int)0x282020ff }, // DEFAULT_TEXT_COLOR_PRESSED + { 0, 9, (int)0x6a6a6aff }, // DEFAULT_BORDER_COLOR_DISABLED + { 0, 10, (int)0x818181ff }, // DEFAULT_BASE_COLOR_DISABLED + { 0, 11, (int)0x606060ff }, // DEFAULT_TEXT_COLOR_DISABLED + { 0, 16, (int)0x00000010 }, // DEFAULT_TEXT_SIZE + { 0, 18, (int)0xef922aff }, // DEFAULT_LINE_COLOR + { 0, 19, (int)0x333333ff }, // DEFAULT_BACKGROUND_COLOR + { 0, 20, (int)0x00000018 }, // DEFAULT_TEXT_LINE_SPACING +};++// WARNING: This style uses a custom font: "hello-world.ttf" (size: 16, spacing: 1)++#define AMBER_STYLE_FONT_ATLAS_COMP_SIZE 2605++// Font atlas image pixels data: DEFLATE compressed+static unsigned char amberFontData[AMBER_STYLE_FONT_ATLAS_COMP_SIZE] = { 0xed,+ 0xdd, 0x8b, 0x8e, 0x9c, 0xb8, 0x12, 0x00, 0x50, 0xf8, 0xff, 0x7f, 0x76, 0x5d, 0xe9, 0x66, 0xb3, 0xd2, 0xee, 0x8e, 0x6d,+ 0xaa, 0x30, 0x8f, 0xee, 0x9c, 0x1c, 0x45, 0x91, 0x9a, 0x34, 0x18, 0xdb, 0x85, 0x0d, 0x33, 0x94, 0x63, 0x03, 0x00, 0x00,+ 0x00, 0x88, 0x2d, 0x5a, 0xe7, 0xb3, 0xcc, 0xe7, 0x5b, 0xf7, 0xf3, 0xf6, 0xd7, 0xe7, 0x6d, 0xb0, 0xed, 0xe8, 0xbe, 0xfa,+ 0x65, 0xda, 0x92, 0xfb, 0x89, 0xee, 0x37, 0xe2, 0x87, 0x4f, 0x7e, 0xff, 0xc9, 0xec, 0xa7, 0x77, 0xbe, 0xf9, 0xda, 0xcb,+ 0x6e, 0x19, 0x1f, 0xbd, 0x25, 0x4b, 0x56, 0xff, 0xce, 0xd1, 0x7a, 0xcf, 0xd4, 0xe1, 0xef, 0x3f, 0x2d, 0xb1, 0x97, 0x71,+ 0x79, 0x7e, 0xde, 0xdb, 0x36, 0x39, 0xeb, 0xdc, 0x79, 0xb7, 0xe9, 0x96, 0xda, 0xb7, 0xd6, 0xc4, 0x7f, 0xaf, 0x4d, 0x32,+ 0x9f, 0x6f, 0xdd, 0x7a, 0xfc, 0x15, 0x37, 0xbd, 0xb8, 0xdd, 0x13, 0xfd, 0xa4, 0x17, 0x23, 0xfb, 0x20, 0xca, 0x23, 0xb5,+ 0xff, 0x71, 0x2f, 0x5a, 0x71, 0x4d, 0xed, 0x95, 0xf6, 0xe7, 0xab, 0x4b, 0xff, 0x1b, 0x6d, 0x78, 0xe6, 0xb5, 0x6b, 0x55,+ 0xbf, 0x1e, 0xf7, 0x1f, 0xbe, 0x5b, 0x2b, 0xdb, 0xf1, 0x72, 0x45, 0xba, 0x2d, 0x62, 0xd8, 0x6b, 0xf6, 0xee, 0x35, 0x23,+ 0x77, 0x76, 0x51, 0x38, 0xef, 0x98, 0x6c, 0xd9, 0x52, 0xa3, 0x5a, 0x5b, 0x3c, 0xfe, 0xaf, 0x88, 0xff, 0xf8, 0x7f, 0x2d,+ 0xee, 0xa9, 0xf1, 0x36, 0x92, 0x65, 0xca, 0x47, 0xed, 0xde, 0x39, 0x6e, 0x7f, 0x3c, 0xbf, 0xba, 0x4e, 0x7b, 0xdb, 0xf6,+ 0x42, 0x6d, 0xf4, 0xb6, 0xb4, 0xee, 0x79, 0x6f, 0xe5, 0xab, 0x5e, 0x24, 0xce, 0x26, 0x4e, 0x5f, 0x4b, 0x63, 0xd0, 0xd2,+ 0xe3, 0xb6, 0x8b, 0x74, 0x49, 0xa3, 0xf0, 0x9d, 0xf1, 0x96, 0x6d, 0xe9, 0x77, 0xae, 0x1b, 0xa3, 0xf2, 0xfb, 0x1b, 0xcf,+ 0xbe, 0xa2, 0x18, 0x0f, 0xe7, 0xcb, 0xb9, 0xa7, 0xaf, 0x89, 0x71, 0xf1, 0x3d, 0x55, 0x36, 0xfe, 0xb7, 0x85, 0xf1, 0x1f,+ 0xe9, 0xfa, 0xbe, 0x2f, 0xfe, 0x9f, 0x18, 0xff, 0xb7, 0x49, 0xfc, 0x6f, 0xe2, 0x3f, 0xf5, 0x7f, 0x73, 0xf7, 0x05, 0xe3,+ 0x71, 0x3b, 0x12, 0xf3, 0x99, 0x58, 0x18, 0xcf, 0x71, 0x7b, 0xf4, 0x8f, 0x7a, 0x5b, 0x65, 0x26, 0xd8, 0xbf, 0xdf, 0xea,+ 0xc7, 0xd9, 0xe8, 0x1e, 0x2d, 0xd2, 0x33, 0xce, 0xd1, 0xdd, 0x55, 0xe6, 0x79, 0x49, 0x2c, 0xeb, 0x99, 0x5b, 0x29, 0xfe,+ 0x23, 0xf5, 0xcc, 0x27, 0x26, 0x35, 0x9f, 0x8d, 0xff, 0x18, 0x5c, 0xff, 0x46, 0xfd, 0x28, 0x2e, 0xbd, 0xff, 0xcf, 0xc6,+ 0xff, 0x36, 0x99, 0x95, 0x6d, 0xa9, 0x9e, 0x5a, 0x29, 0x65, 0x7b, 0xd1, 0x13, 0xd5, 0x95, 0xf1, 0x1f, 0xc9, 0xb3, 0x8e,+ 0x03, 0x4f, 0xc3, 0x7a, 0xc7, 0xa8, 0xdc, 0xbd, 0xb5, 0x93, 0xfd, 0x2a, 0x1e, 0x6c, 0x93, 0x33, 0x23, 0x76, 0x7b, 0x7c,+ 0xfc, 0x8f, 0xc7, 0xe6, 0xff, 0x91, 0x9e, 0x1b, 0x5c, 0x1f, 0xff, 0xf1, 0xf2, 0xe8, 0xaf, 0xcd, 0xff, 0xa3, 0x38, 0x2f,+ 0x8f, 0x45, 0x73, 0xf9, 0xea, 0xdd, 0xcc, 0xbb, 0x5a, 0x64, 0x9b, 0x3e, 0x4f, 0xf8, 0xc4, 0xf9, 0x7f, 0x3c, 0x54, 0x8f,+ 0x51, 0xb8, 0x37, 0x10, 0xff, 0x95, 0xf8, 0xaf, 0xcd, 0x69, 0x67, 0x4f, 0x37, 0x63, 0xe9, 0x95, 0xe9, 0xb3, 0xe3, 0xbf,+ 0x1e, 0xb1, 0xe2, 0xff, 0xe8, 0xdc, 0x36, 0x86, 0xcf, 0x65, 0x63, 0x49, 0x1b, 0x7e, 0xc6, 0x58, 0xb3, 0x2e, 0xfe, 0xe3,+ 0xc4, 0x5d, 0xc3, 0x9f, 0x18, 0xff, 0xdb, 0x8d, 0xf1, 0x1f, 0x5f, 0x3b, 0xff, 0xaf, 0xdc, 0xff, 0xc7, 0xf0, 0x27, 0xd2,+ 0xb1, 0x68, 0x06, 0xf0, 0xfe, 0xd1, 0xbf, 0xf2, 0xb4, 0x67, 0xfc, 0x9b, 0x47, 0x91, 0xfe, 0xb9, 0x40, 0xe5, 0x69, 0xd3,+ 0x6c, 0xee, 0xbc, 0xa5, 0xcb, 0xf6, 0xe9, 0xe3, 0x7f, 0xfe, 0xbc, 0x63, 0xba, 0x25, 0x0a, 0xfd, 0xe8, 0x6d, 0xd7, 0xd7,+ 0x78, 0x7c, 0x64, 0x05, 0xbe, 0x97, 0xf8, 0x07, 0x57, 0x00, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,+ 0x00, 0x00, 0xc0, 0x77, 0x6a, 0xff, 0xfa, 0xf7, 0x9f, 0xdb, 0xda, 0x8f, 0xd9, 0x8c, 0x5b, 0x77, 0x4b, 0x6f, 0x5f, 0xad,+ 0x70, 0xfc, 0x7c, 0xc9, 0x56, 0xe7, 0x60, 0xdf, 0x06, 0x67, 0x5a, 0xaf, 0x83, 0xeb, 0xb7, 0x8c, 0x4b, 0x9d, 0x69, 0x9b,+ 0x7e, 0xbd, 0x6c, 0xa9, 0x77, 0x92, 0x73, 0x79, 0x02, 0xdb, 0xe4, 0x0d, 0xd7, 0xec, 0xba, 0x0e, 0xb3, 0x1c, 0x86, 0x99,+ 0xcc, 0x87, 0xed, 0x50, 0x34, 0xcd, 0x3f, 0xcf, 0x96, 0x67, 0x1b, 0x66, 0xc5, 0x8c, 0x72, 0xde, 0xbf, 0x5a, 0xee, 0xe9,+ 0x3d, 0x99, 0xf9, 0x69, 0xf4, 0x3e, 0x7a, 0x4b, 0x67, 0x67, 0xbe, 0x2b, 0x07, 0xfb, 0xa8, 0x3e, 0xf7, 0x74, 0xf6, 0x8b,+ 0xca, 0x96, 0xbd, 0xbb, 0xae, 0xca, 0x2c, 0xd7, 0xc3, 0x7e, 0xb8, 0x15, 0x46, 0x39, 0x92, 0xf7, 0x6e, 0x1e, 0xf1, 0x5c,+ 0x5f, 0x5b, 0x95, 0xfb, 0x3e, 0xa6, 0x25, 0x8e, 0xe4, 0x77, 0xda, 0xf0, 0x38, 0x71, 0xd9, 0x3b, 0x65, 0x91, 0xac, 0xad,+ 0xed, 0xef, 0x1c, 0x1b, 0xb9, 0xba, 0x3c, 0x13, 0xff, 0x95, 0xfc, 0xd2, 0x5b, 0x3a, 0x03, 0xea, 0xde, 0xc9, 0x4b, 0xff,+ 0xfb, 0x7a, 0x76, 0x57, 0xa6, 0x95, 0x6c, 0x5b, 0xdf, 0x11, 0xff, 0xf3, 0xdc, 0x69, 0x91, 0x1a, 0x07, 0xf3, 0x7d, 0xf1,+ 0x89, 0xdc, 0x0d, 0x77, 0xe5, 0x23, 0x3f, 0xd3, 0x8a, 0x57, 0xc6, 0x7f, 0x3e, 0x4f, 0x6c, 0x3d, 0xf3, 0xcf, 0xfa, 0xf8,+ 0xcf, 0xe7, 0xab, 0x8a, 0x6e, 0x3e, 0x15, 0xf1, 0x5f, 0x8d, 0xff, 0xf8, 0x80, 0xf8, 0x5f, 0x99, 0x49, 0x7b, 0xb6, 0xb7,+ 0x48, 0x65, 0x3e, 0x9f, 0x65, 0xf9, 0x69, 0x83, 0xb9, 0xec, 0xb1, 0xbb, 0x8f, 0x38, 0x30, 0xff, 0xb8, 0x27, 0xfe, 0x67,+ 0x99, 0x7b, 0x73, 0xfd, 0xab, 0xba, 0x9f, 0x55, 0x6b, 0x30, 0xcc, 0x7a, 0x4e, 0xb6, 0x45, 0x23, 0xb9, 0x52, 0xe0, 0xea,+ 0xf8, 0x1f, 0x47, 0x6d, 0xad, 0x6c, 0xdb, 0xd2, 0x11, 0xf7, 0xec, 0x08, 0x18, 0x4b, 0xef, 0x0c, 0xee, 0xb9, 0x8a, 0xef,+ 0xa7, 0x57, 0x8f, 0x8b, 0xe1, 0x1d, 0xe6, 0xba, 0xbe, 0x75, 0xef, 0xf8, 0x1f, 0x8b, 0xf3, 0xa9, 0xc7, 0x8d, 0x99, 0x56,+ 0xf3, 0xab, 0x5c, 0x64, 0xeb, 0xb3, 0x92, 0x23, 0x35, 0x9f, 0x55, 0xf9, 0x5b, 0xe2, 0xff, 0xfa, 0x2d, 0xeb, 0x23, 0x2d,+ 0x17, 0xff, 0x71, 0xc3, 0xdc, 0xf2, 0x13, 0xe6, 0xff, 0xdb, 0x30, 0x5f, 0xfd, 0x5d, 0xf1, 0x5f, 0x6d, 0x8d, 0x6b, 0xe3,+ 0x3f, 0x0a, 0xf3, 0xf6, 0x95, 0xf3, 0xfc, 0x67, 0xe6, 0xff, 0xe3, 0x31, 0x26, 0xd2, 0xf5, 0x5e, 0xcd, 0x61, 0x7a, 0x65,+ 0xfc, 0xc7, 0x2d, 0xf7, 0x96, 0xf7, 0xc7, 0xff, 0xda, 0xb8, 0x5c, 0x1b, 0xff, 0x2b, 0xd7, 0xab, 0x10, 0xff, 0xf7, 0xcf,+ 0x0c, 0xd6, 0x7e, 0xa7, 0x72, 0x77, 0xf0, 0xe4, 0xf8, 0x7f, 0x7f, 0x5d, 0x3f, 0x1f, 0xff, 0x2b, 0xe7, 0xff, 0xf1, 0x70,+ 0xfc, 0x57, 0xd6, 0xff, 0xba, 0x67, 0x96, 0x2f, 0xfe, 0x9f, 0x88, 0xff, 0x37, 0xd4, 0x7a, 0x7e, 0xde, 0x34, 0x7f, 0x5a,+ 0x98, 0x5b, 0x35, 0xb1, 0xf6, 0x54, 0x3c, 0x8a, 0x2b, 0x87, 0x47, 0xa1, 0xd4, 0x95, 0x99, 0xe3, 0xb6, 0xe4, 0x5e, 0xbe,+ 0x76, 0x35, 0xa9, 0x64, 0x8e, 0xaf, 0xae, 0x33, 0x76, 0xe7, 0x7d, 0xc1, 0x35, 0xdf, 0xca, 0xb5, 0x62, 0x4c, 0xeb, 0x7e,+ 0xc5, 0x75, 0x64, 0x7b, 0x61, 0x16, 0x7f, 0x3e, 0x5d, 0xdc, 0xf4, 0x1d, 0xd4, 0x22, 0xe2, 0x1f, 0xb5, 0xc8, 0x9b, 0x7a,+ 0x61, 0x24, 0xef, 0xa9, 0xcd, 0x42, 0xd7, 0xd4, 0xba, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,+ 0x00, 0x56, 0xfd, 0x7e, 0x72, 0x36, 0xa7, 0xf8, 0x28, 0x6f, 0x62, 0x7e, 0x7f, 0xb3, 0x2c, 0x68, 0xed, 0xc1, 0x2d, 0xa3,+ 0x5a, 0x68, 0x07, 0xcf, 0xa6, 0x25, 0xf3, 0xbc, 0xf5, 0xeb, 0xa4, 0x9f, 0x5f, 0xbe, 0x25, 0xb7, 0xb5, 0xc9, 0x1e, 0x8f,+ 0xee, 0xfd, 0x78, 0x1b, 0xf7, 0xb3, 0xa8, 0xe5, 0xea, 0xbd, 0x9f, 0x99, 0xbf, 0x25, 0x57, 0x2c, 0x98, 0xd5, 0xe8, 0x96,+ 0x68, 0xc9, 0x23, 0xbd, 0x69, 0xb4, 0xd6, 0xc4, 0xd1, 0x76, 0x38, 0x7a, 0x0e, 0x71, 0xf0, 0xad, 0xa3, 0x59, 0xae, 0xc5,+ 0xd1, 0x96, 0x4c, 0x56, 0xa3, 0x33, 0xb9, 0x27, 0x56, 0xe6, 0xd2, 0x5d, 0x95, 0x4b, 0x3f, 0x97, 0xbb, 0x71, 0x1f, 0xb6,+ 0x51, 0x9c, 0xbc, 0x52, 0xb7, 0xc1, 0x31, 0x5a, 0x21, 0xef, 0xc3, 0xf1, 0xbd, 0x1f, 0x6f, 0xe3, 0x3d, 0x9d, 0xdd, 0x64,+ 0x65, 0xfe, 0xfd, 0x96, 0xce, 0xd8, 0xb9, 0x27, 0x57, 0xc4, 0x38, 0x9e, 0x4f, 0x62, 0x4f, 0x67, 0xae, 0x98, 0xf5, 0xc3,+ 0xfd, 0xc4, 0x15, 0xe0, 0xce, 0xfc, 0x3b, 0x6f, 0x88, 0xff, 0x55, 0xb9, 0xb4, 0xaf, 0xce, 0xca, 0xd3, 0xba, 0xa5, 0x6f,+ 0x17, 0xd7, 0x6d, 0x3d, 0xe2, 0x62, 0x98, 0x01, 0x23, 0xca, 0x63, 0xd4, 0xd1, 0x63, 0x8c, 0x22, 0x67, 0xb4, 0x62, 0xd1,+ 0xf1, 0xeb, 0x66, 0x2c, 0x88, 0xff, 0x33, 0x6f, 0x03, 0x1f, 0x1f, 0x5b, 0x8e, 0xd6, 0xef, 0x7d, 0x19, 0xf3, 0xc7, 0x39,+ 0xd8, 0x73, 0x59, 0xd8, 0x57, 0x67, 0xcc, 0x59, 0x17, 0xe7, 0xab, 0xf2, 0xe8, 0xe4, 0xa2, 0x25, 0xd2, 0xf3, 0xf1, 0x4c,+ 0xfc, 0xc7, 0xe1, 0xd9, 0x7f, 0x36, 0x9f, 0x4d, 0x3e, 0x1a, 0x62, 0xf1, 0x1b, 0xb5, 0xfd, 0xf2, 0xb6, 0x8b, 0xc6, 0xff,+ 0xd5, 0xf1, 0xbf, 0x9d, 0x88, 0xfe, 0x7b, 0x57, 0xcc, 0xd8, 0x8a, 0xeb, 0x52, 0x5c, 0x9d, 0x4b, 0x33, 0x0a, 0x65, 0x7b,+ 0x2e, 0xfe, 0xb3, 0x2b, 0x18, 0x8c, 0x8e, 0xd0, 0x0e, 0x97, 0xa4, 0x5d, 0x14, 0x9b, 0x51, 0xec, 0xd5, 0xf1, 0x48, 0x66,+ 0x8e, 0x73, 0xe3, 0xff, 0x76, 0x3a, 0xfe, 0xd7, 0xd7, 0xab, 0xf8, 0xaf, 0xcf, 0x67, 0xee, 0x8d, 0xff, 0xad, 0xb0, 0x4e,+ 0x4b, 0x14, 0x66, 0x5d, 0xf5, 0x2b, 0xc0, 0x5d, 0xfd, 0xfa, 0xed, 0xcf, 0xd3, 0x67, 0xfd, 0xe0, 0x5d, 0xe7, 0x30, 0xeb,+ 0x21, 0x99, 0x7e, 0x15, 0x93, 0xa3, 0xe4, 0xef, 0x8d, 0x2b, 0x7d, 0x7e, 0x2b, 0x66, 0x88, 0xaf, 0xe4, 0x2d, 0x3d, 0x7f,+ 0xbf, 0x70, 0xfe, 0x2a, 0x52, 0x5d, 0xbf, 0x2b, 0x4e, 0xf7, 0x91, 0x4c, 0x7b, 0xad, 0xed, 0xaf, 0xef, 0xbd, 0x0e, 0xcc,+ 0xb3, 0xc6, 0x7e, 0x46, 0x3e, 0xa0, 0xb8, 0xed, 0x5a, 0xfc, 0x96, 0xfa, 0x88, 0x45, 0x77, 0x8e, 0x57, 0x8d, 0xff, 0x6b,+ 0x9f, 0xad, 0x66, 0xe3, 0xe8, 0xfb, 0xb2, 0x58, 0xc5, 0x25, 0xd7, 0x92, 0x58, 0x7a, 0xbf, 0x23, 0xfe, 0xc5, 0xff, 0x15,+ 0xf1, 0x7f, 0xfc, 0x18, 0xf1, 0xb5, 0xf1, 0xff, 0x44, 0x2f, 0x12, 0xff, 0x67, 0xe6, 0x97, 0x6f, 0x9a, 0x51, 0x5e, 0x1b,+ 0xff, 0xeb, 0xc6, 0xb1, 0xca, 0x7d, 0xd7, 0x9b, 0x5a, 0x47, 0xfc, 0xf3, 0x49, 0xed, 0xfc, 0x9e, 0x75, 0x34, 0x00, 0xf1,+ 0x0f, 0x5c, 0x33, 0xef, 0x3e, 0xf6, 0x93, 0x7b, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,+ 0xc0, 0x59, 0xad, 0x9b, 0x59, 0x3c, 0xba, 0x59, 0xcc, 0xff, 0xf9, 0xef, 0xcf, 0x5b, 0x9f, 0x3d, 0x9f, 0x2d, 0x55, 0xb6,+ 0x36, 0xcc, 0xf8, 0xde, 0x1e, 0x2e, 0xf5, 0x95, 0x47, 0x68, 0xb7, 0x9d, 0xe1, 0xda, 0x5a, 0xe9, 0xbd, 0x47, 0xdb, 0x6e,+ 0xa8, 0xc9, 0x5a, 0x7b, 0xb5, 0xe1, 0xb6, 0x96, 0xee, 0xb3, 0xb5, 0x2d, 0xff, 0xfd, 0x9f, 0xfb, 0xb0, 0x86, 0xf7, 0x64,+ 0x5e, 0xde, 0xda, 0x9b, 0xd1, 0xb5, 0x6c, 0x5a, 0x3f, 0x6f, 0xdb, 0xff, 0xfa, 0xdb, 0xdb, 0x96, 0xa9, 0x83, 0x71, 0xee,+ 0xfb, 0x95, 0xe7, 0x33, 0x2a, 0xf5, 0x9a, 0x0c, 0xc4, 0x3f, 0x1f, 0x21, 0x06, 0x67, 0x18, 0xa5, 0x6c, 0x66, 0x77, 0xb5,+ 0x65, 0x6f, 0x4d, 0x86, 0xbd, 0xb0, 0xda, 0xca, 0x1d, 0xed, 0x15, 0xa5, 0xf5, 0x1b, 0xb6, 0x49, 0xdf, 0xcc, 0xf5, 0xe7,+ 0x4c, 0xdd, 0x8f, 0xf2, 0xcd, 0x8e, 0xce, 0xb3, 0x7f, 0xe4, 0xfe, 0x99, 0xec, 0xc9, 0x33, 0xf9, 0xf5, 0xf9, 0x9e, 0xbc,+ 0x96, 0xb6, 0xc1, 0x3c, 0xa7, 0xf2, 0xd6, 0xee, 0xca, 0xf3, 0x19, 0x8d, 0xc3, 0xfd, 0x3a, 0xc8, 0x1f, 0xe3, 0x78, 0x5b,+ 0x8e, 0xea, 0xf8, 0xf9, 0xb6, 0x1c, 0xf5, 0xcc, 0x48, 0x47, 0x52, 0xbe, 0xcc, 0xfd, 0xbe, 0xde, 0xdb, 0xdb, 0x6c, 0x3d,+ 0x9d, 0x67, 0xde, 0x11, 0x9f, 0xc5, 0x7f, 0xa4, 0xe3, 0x7f, 0xbc, 0x0a, 0xcc, 0xf1, 0x4f, 0x47, 0x57, 0xd9, 0x7d, 0x30,+ 0x96, 0xf7, 0x6a, 0xb9, 0x0d, 0xeb, 0xbf, 0xf6, 0xd6, 0xfe, 0xaa, 0xf3, 0xa9, 0x1c, 0x67, 0x4f, 0xd7, 0x59, 0x2e, 0x2b,+ 0xea, 0x3e, 0x3c, 0x93, 0x67, 0xdb, 0x72, 0xd4, 0x9b, 0xdb, 0x20, 0x4b, 0xff, 0xea, 0xf6, 0x8a, 0xc4, 0xde, 0xaa, 0x6b,+ 0xd6, 0x8c, 0xd6, 0xe0, 0xcb, 0x6e, 0xe9, 0x45, 0x79, 0x65, 0xf6, 0x97, 0x9d, 0x13, 0xe7, 0xc7, 0xe5, 0xea, 0x58, 0xbe,+ 0xa5, 0xb3, 0x96, 0xcf, 0x56, 0xc9, 0xc8, 0x8c, 0xd8, 0x95, 0x2d, 0x51, 0xb8, 0x37, 0x6c, 0xe9, 0x27, 0x16, 0xa3, 0x9c,+ 0xe2, 0x91, 0x1c, 0xe3, 0x9e, 0x6d, 0xcb, 0xd9, 0x68, 0x96, 0x39, 0x9b, 0xca, 0x96, 0xd1, 0xac, 0xa9, 0xff, 0x9d, 0xfc,+ 0xca, 0x98, 0x67, 0x56, 0xe7, 0x6b, 0x97, 0xcd, 0xff, 0xe7, 0x39, 0xb6, 0xd7, 0x8c, 0xcb, 0xd5, 0xb1, 0x7c, 0x2b, 0xac,+ 0x5a, 0x10, 0x97, 0xdf, 0x31, 0x56, 0x57, 0x47, 0xdb, 0xbb, 0xf7, 0xc6, 0xb9, 0xcf, 0xab, 0x6b, 0x1f, 0xc4, 0x0b, 0xdb,+ 0x32, 0x1f, 0xff, 0xd7, 0xac, 0x73, 0xb1, 0x76, 0x6d, 0xbc, 0x76, 0x5b, 0x9f, 0x3a, 0x3e, 0xca, 0xaf, 0x5e, 0xe5, 0xee,+ 0xfa, 0x5a, 0xae, 0xe5, 0xf2, 0x7f, 0x3a, 0xfe, 0x63, 0xe1, 0x8a, 0x02, 0xab, 0xe2, 0xbf, 0xbd, 0x24, 0x62, 0xfe, 0x94,+ 0xf8, 0xcf, 0xad, 0xc2, 0x11, 0xa5, 0x95, 0x3b, 0x32, 0x31, 0x9e, 0x7f, 0x96, 0xff, 0x9e, 0x5a, 0xfe, 0x9e, 0xf1, 0xff,+ 0xb9, 0xf8, 0x8f, 0x0f, 0x8c, 0xff, 0xf7, 0x96, 0xf9, 0xf9, 0xb1, 0xf1, 0xd9, 0xf8, 0xaf, 0x8c, 0xcb, 0xf5, 0x75, 0x79,+ 0xd6, 0xc6, 0x7f, 0x24, 0x46, 0xec, 0xf5, 0x99, 0xb8, 0x9f, 0x8a, 0xff, 0xf7, 0x8e, 0xa5, 0xb3, 0xba, 0x7a, 0xb2, 0x64,+ 0xb3, 0x55, 0xe6, 0xdf, 0x15, 0xff, 0xd5, 0x15, 0x55, 0x23, 0x39, 0x93, 0x7d, 0xff, 0xf8, 0x1f, 0xa9, 0x35, 0xf7, 0xbe,+ 0x67, 0xfc, 0x8f, 0xc9, 0xda, 0xbc, 0x9f, 0x37, 0xff, 0x8f, 0x47, 0x63, 0x2c, 0x4a, 0x2b, 0xc9, 0x66, 0x57, 0xda, 0x5b,+ 0x35, 0xff, 0xbf, 0xf3, 0xe7, 0x8c, 0x9f, 0x36, 0x9b, 0x3c, 0xf7, 0xa4, 0xe3, 0x33, 0xe2, 0x7f, 0x3e, 0x92, 0x7e, 0x5e,+ 0x8b, 0x3d, 0x3d, 0xc6, 0xca, 0xf6, 0xfc, 0x4d, 0xf1, 0xbf, 0xdd, 0x32, 0xfe, 0x57, 0x57, 0x3a, 0xcd, 0xfe, 0xfe, 0xd9,+ 0x27, 0xc5, 0xff, 0xca, 0x95, 0x87, 0xee, 0x2c, 0x99, 0xf8, 0x7f, 0xdb, 0x3d, 0xce, 0x8a, 0x92, 0xdf, 0xf5, 0x13, 0x99,+ 0xbb, 0xc7, 0xf9, 0xf7, 0x5e, 0xb1, 0xdf, 0xdb, 0xff, 0xaa, 0xbf, 0xe7, 0x2e, 0xfe, 0x3f, 0x2f, 0xfe, 0xb3, 0x23, 0x76,+ 0x65, 0xcb, 0xfc, 0x48, 0xe7, 0x3f, 0x5f, 0xd7, 0x62, 0xeb, 0x9f, 0x7e, 0xde, 0x71, 0xb7, 0x7a, 0x5f, 0xc9, 0xc4, 0x3f,+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xad, 0x36, 0xcc, 0xe4, 0x9f, 0xcd, 0x4a, 0x3e, 0xca, 0x0c,+ 0x18, 0xb7, 0xe4, 0x38, 0xaf, 0xe6, 0xff, 0x3f, 0xfe, 0x79, 0xbe, 0xc6, 0x2a, 0x65, 0x5a, 0x7b, 0xee, 0x6d, 0xd2, 0x66,+ 0x3f, 0x7f, 0xde, 0x0a, 0xab, 0x3c, 0xdc, 0xd1, 0x62, 0xad, 0xd4, 0x9f, 0xf9, 0xa9, 0xb6, 0xf6, 0x85, 0xb5, 0x35, 0x5b,+ 0x33, 0xe0, 0x99, 0x1c, 0xe7, 0xb3, 0xe3, 0xb4, 0x45, 0xc7, 0x18, 0x67, 0xb8, 0xce, 0x95, 0xa9, 0x72, 0xee, 0xeb, 0xdb,+ 0xb2, 0x5f, 0x8a, 0x7b, 0x5a, 0xac, 0xf9, 0x0d, 0xfb, 0x47, 0xdf, 0xd9, 0xa9, 0x64, 0x18, 0x8e, 0x64, 0xf6, 0xa3, 0xfb,+ 0x4a, 0xbd, 0xee, 0x08, 0xfd, 0xab, 0xd8, 0xfe, 0xd2, 0xb1, 0x67, 0x9c, 0x7b, 0x76, 0x94, 0x15, 0xb1, 0xdd, 0xf4, 0x66,+ 0x58, 0x4b, 0xbf, 0xcb, 0xd3, 0x16, 0xed, 0x4d, 0x94, 0xaf, 0xca, 0x3d, 0xbc, 0x4d, 0xf3, 0x72, 0xad, 0xba, 0xce, 0xe4,+ 0x4b, 0xbd, 0x0d, 0xf6, 0x95, 0xfb, 0x7c, 0x4b, 0xe6, 0x6a, 0x89, 0xc5, 0x59, 0xdc, 0xd7, 0xd6, 0xca, 0x36, 0xb9, 0x8e,+ 0x47, 0x22, 0xc6, 0xce, 0x6c, 0xc9, 0x1f, 0xe7, 0x6d, 0x6b, 0x69, 0x7c, 0xee, 0x7b, 0xb9, 0xfb, 0xa2, 0xdc, 0xc3, 0xf5,+ 0x4c, 0x9a, 0xab, 0x72, 0x9c, 0xd7, 0x32, 0xb3, 0xac, 0xcb, 0xa4, 0xb7, 0x77, 0xfb, 0xf1, 0xda, 0x33, 0xbc, 0xbe, 0x56,+ 0x3e, 0x21, 0x97, 0xee, 0x1b, 0xdf, 0x0c, 0xff, 0xec, 0xf7, 0xf3, 0x8f, 0x8c, 0x67, 0xdb, 0x74, 0xce, 0xf8, 0x64, 0xfb,+ 0x5f, 0x9f, 0x49, 0x67, 0xfb, 0xc8, 0x0c, 0x87, 0x5b, 0x39, 0x03, 0x98, 0xf8, 0xff, 0xf6, 0xf9, 0x7f, 0xdc, 0x90, 0x17,+ 0x69, 0x76, 0x2d, 0x59, 0x9b, 0xff, 0x77, 0x13, 0xff, 0x27, 0xa3, 0xe2, 0xf9, 0x5c, 0x9a, 0xf3, 0xab, 0xfc, 0x26, 0xfe,+ 0x17, 0x8d, 0xfb, 0xdf, 0x96, 0x49, 0xd3, 0xf8, 0x7f, 0x5d, 0x54, 0x7c, 0xea, 0x5a, 0x1a, 0x6c, 0x85, 0xb1, 0x7c, 0x65,+ 0x86, 0xe1, 0xb8, 0xe1, 0x0a, 0x54, 0xc9, 0xcc, 0x98, 0xff, 0xfc, 0xd3, 0xa2, 0x7c, 0x65, 0x8e, 0xad, 0x6b, 0xca, 0xb6,+ 0x26, 0xfe, 0xdf, 0x99, 0xfd, 0xfa, 0x13, 0xe7, 0xff, 0xf7, 0x3c, 0x63, 0xd8, 0x6e, 0xce, 0xcc, 0x16, 0x4b, 0x3e, 0xdf,+ 0x92, 0x77, 0x38, 0x2b, 0xef, 0x97, 0x9e, 0xcf, 0xa4, 0x77, 0x5f, 0x56, 0xfa, 0xda, 0x5d, 0x9e, 0xf1, 0x1f, 0xbe, 0xfb,+ 0xd9, 0xb4, 0xf8, 0x07, 0xf1, 0x6f, 0xf6, 0x0f, 0xee, 0x4c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xc7, 0xaf, 0x3f, 0xea, 0x01, 0xc4, 0x3f, 0xf0, 0xc7,+ 0xc5, 0xff, 0xff, 0x00 };++// Font glyphs rectangles data (on atlas)+static const Rectangle amberFontRecs[189] = {+ { 4, 4, 5 , 16 },+ { 17, 4, 2 , 10 },+ { 27, 4, 4 , 4 },+ { 39, 4, 5 , 10 },+ { 52, 4, 5 , 11 },+ { 65, 4, 5 , 10 },+ { 78, 4, 5 , 10 },+ { 91, 4, 2 , 4 },+ { 101, 4, 4 , 13 },+ { 113, 4, 5 , 13 },+ { 126, 4, 4 , 4 },+ { 138, 4, 5 , 6 },+ { 151, 4, 3 , 2 },+ { 162, 4, 5 , 2 },+ { 175, 4, 2 , 1 },+ { 185, 4, 5 , 10 },+ { 198, 4, 5 , 10 },+ { 211, 4, 4 , 10 },+ { 223, 4, 5 , 10 },+ { 236, 4, 5 , 10 },+ { 249, 4, 5 , 10 },+ { 262, 4, 5 , 10 },+ { 275, 4, 5 , 10 },+ { 288, 4, 5 , 10 },+ { 301, 4, 5 , 10 },+ { 314, 4, 5 , 10 },+ { 327, 4, 2 , 6 },+ { 337, 4, 2 , 6 },+ { 347, 4, 5 , 6 },+ { 360, 4, 5 , 4 },+ { 373, 4, 5 , 6 },+ { 386, 4, 5 , 10 },+ { 399, 4, 5 , 7 },+ { 412, 4, 5 , 10 },+ { 425, 4, 5 , 10 },+ { 438, 4, 5 , 10 },+ { 451, 4, 5 , 10 },+ { 464, 4, 5 , 10 },+ { 477, 4, 5 , 10 },+ { 490, 4, 5 , 10 },+ { 4, 28, 5 , 10 },+ { 17, 28, 4 , 10 },+ { 29, 28, 5 , 10 },+ { 42, 28, 5 , 10 },+ { 55, 28, 5 , 10 },+ { 68, 28, 5 , 10 },+ { 81, 28, 5 , 10 },+ { 94, 28, 5 , 10 },+ { 107, 28, 5 , 10 },+ { 120, 28, 5 , 10 },+ { 133, 28, 5 , 10 },+ { 146, 28, 5 , 10 },+ { 159, 28, 5 , 10 },+ { 172, 28, 5 , 10 },+ { 185, 28, 5 , 10 },+ { 198, 28, 5 , 10 },+ { 211, 28, 5 , 10 },+ { 224, 28, 5 , 10 },+ { 237, 28, 5 , 10 },+ { 250, 28, 3 , 13 },+ { 261, 28, 5 , 10 },+ { 274, 28, 3 , 13 },+ { 285, 28, 4 , 3 },+ { 297, 28, 5 , 1 },+ { 310, 28, 3 , 3 },+ { 321, 28, 5 , 7 },+ { 334, 28, 5 , 10 },+ { 347, 28, 5 , 7 },+ { 360, 28, 5 , 10 },+ { 373, 28, 5 , 7 },+ { 386, 28, 5 , 10 },+ { 399, 28, 5 , 10 },+ { 412, 28, 5 , 10 },+ { 425, 28, 4 , 10 },+ { 437, 28, 3 , 13 },+ { 448, 28, 5 , 10 },+ { 461, 28, 5 , 10 },+ { 474, 28, 5 , 7 },+ { 487, 28, 5 , 7 },+ { 4, 52, 5 , 7 },+ { 17, 52, 5 , 10 },+ { 30, 52, 5 , 10 },+ { 43, 52, 5 , 7 },+ { 56, 52, 5 , 7 },+ { 69, 52, 5 , 10 },+ { 82, 52, 5 , 7 },+ { 95, 52, 5 , 7 },+ { 108, 52, 5 , 7 },+ { 121, 52, 5 , 7 },+ { 134, 52, 5 , 10 },+ { 147, 52, 5 , 7 },+ { 160, 52, 4 , 13 },+ { 172, 52, 2 , 13 },+ { 182, 52, 4 , 13 },+ { 194, 52, 5 , 4 },+ { 207, 52, 2 , 9 },+ { 217, 52, 5 , 7 },+ { 230, 52, 5 , 10 },+ { 243, 52, 5 , 10 },+ { 256, 52, 5 , 10 },+ { 269, 52, 0 , 0 },+ { 277, 52, 5 , 10 },+ { 290, 52, 0 , 0 },+ { 298, 52, 5 , 7 },+ { 311, 52, 3 , 5 },+ { 322, 52, 5 , 5 },+ { 335, 52, 5 , 3 },+ { 348, 52, 5 , 7 },+ { 361, 52, 5 , 2 },+ { 374, 52, 4 , 4 },+ { 386, 52, 5 , 8 },+ { 399, 52, 3 , 5 },+ { 410, 52, 3 , 6 },+ { 421, 52, 0 , 0 },+ { 429, 52, 5 , 10 },+ { 442, 52, 5 , 10 },+ { 455, 52, 2 , 3 },+ { 465, 52, 0 , 0 },+ { 473, 52, 3 , 5 },+ { 484, 52, 4 , 4 },+ { 496, 52, 5 , 5 },+ { 4, 76, 5 , 10 },+ { 17, 76, 5 , 7 },+ { 30, 76, 5 , 10 },+ { 43, 76, 5 , 10 },+ { 56, 76, 5 , 14 },+ { 69, 76, 5 , 14 },+ { 82, 76, 5 , 14 },+ { 95, 76, 5 , 14 },+ { 108, 76, 5 , 12 },+ { 121, 76, 5 , 12 },+ { 134, 76, 5 , 10 },+ { 147, 76, 5 , 13 },+ { 160, 76, 5 , 14 },+ { 173, 76, 5 , 14 },+ { 186, 76, 5 , 14 },+ { 199, 76, 5 , 12 },+ { 212, 76, 4 , 14 },+ { 224, 76, 4 , 14 },+ { 236, 76, 4 , 14 },+ { 248, 76, 4 , 12 },+ { 260, 76, 5 , 10 },+ { 273, 76, 5 , 14 },+ { 286, 76, 5 , 14 },+ { 299, 76, 5 , 14 },+ { 312, 76, 5 , 14 },+ { 325, 76, 5 , 14 },+ { 338, 76, 5 , 12 },+ { 351, 76, 4 , 3 },+ { 363, 76, 5 , 10 },+ { 376, 76, 5 , 14 },+ { 389, 76, 5 , 14 },+ { 402, 76, 5 , 14 },+ { 415, 76, 5 , 12 },+ { 428, 76, 5 , 14 },+ { 441, 76, 5 , 10 },+ { 454, 76, 5 , 10 },+ { 467, 76, 5 , 10 },+ { 480, 76, 5 , 10 },+ { 493, 76, 5 , 10 },+ { 4, 100, 5 , 10 },+ { 17, 100, 5 , 9 },+ { 30, 100, 5 , 9 },+ { 43, 100, 5 , 7 },+ { 56, 100, 5 , 10 },+ { 69, 100, 5 , 10 },+ { 82, 100, 5 , 10 },+ { 95, 100, 5 , 10 },+ { 108, 100, 5 , 9 },+ { 121, 100, 4 , 10 },+ { 133, 100, 4 , 10 },+ { 145, 100, 4 , 10 },+ { 157, 100, 4 , 9 },+ { 169, 100, 5 , 10 },+ { 182, 100, 5 , 10 },+ { 195, 100, 5 , 10 },+ { 208, 100, 5 , 10 },+ { 221, 100, 5 , 10 },+ { 234, 100, 5 , 10 },+ { 247, 100, 5 , 9 },+ { 260, 100, 5 , 6 },+ { 273, 100, 5 , 7 },+ { 286, 100, 5 , 10 },+ { 299, 100, 5 , 10 },+ { 312, 100, 5 , 10 },+ { 325, 100, 5 , 9 },+ { 338, 100, 5 , 13 },+ { 351, 100, 5 , 10 },+ { 364, 100, 5 , 12 },+};++// Font glyphs info data+// NOTE: No glyphs.image data provided+static const GlyphInfo amberFontGlyphs[189] = {+ { 32, 0, 0, 5, { 0 }},+ { 33, 1, 3, 5, { 0 }},+ { 34, 0, 3, 5, { 0 }},+ { 35, 0, 3, 5, { 0 }},+ { 36, 0, 3, 5, { 0 }},+ { 37, 0, 3, 5, { 0 }},+ { 38, 0, 3, 5, { 0 }},+ { 39, 1, 4, 5, { 0 }},+ { 40, 0, 3, 5, { 0 }},+ { 41, 0, 3, 5, { 0 }},+ { 42, 0, 3, 5, { 0 }},+ { 43, 0, 7, 5, { 0 }},+ { 44, 0, 12, 5, { 0 }},+ { 45, 0, 9, 5, { 0 }},+ { 46, 1, 12, 5, { 0 }},+ { 47, 0, 3, 5, { 0 }},+ { 48, 0, 3, 5, { 0 }},+ { 49, 0, 3, 5, { 0 }},+ { 50, 0, 3, 5, { 0 }},+ { 51, 0, 3, 5, { 0 }},+ { 52, 0, 3, 5, { 0 }},+ { 53, 0, 3, 5, { 0 }},+ { 54, 0, 3, 5, { 0 }},+ { 55, 0, 3, 5, { 0 }},+ { 56, 0, 3, 5, { 0 }},+ { 57, 0, 3, 5, { 0 }},+ { 58, 0, 7, 5, { 0 }},+ { 59, 0, 7, 5, { 0 }},+ { 60, 0, 7, 5, { 0 }},+ { 61, 0, 8, 5, { 0 }},+ { 62, 0, 7, 5, { 0 }},+ { 63, 0, 3, 5, { 0 }},+ { 64, 0, 6, 5, { 0 }},+ { 65, 0, 3, 5, { 0 }},+ { 66, 0, 3, 5, { 0 }},+ { 67, 0, 3, 5, { 0 }},+ { 68, 0, 3, 5, { 0 }},+ { 69, 0, 3, 5, { 0 }},+ { 70, 0, 3, 5, { 0 }},+ { 71, 0, 3, 5, { 0 }},+ { 72, 0, 3, 5, { 0 }},+ { 73, 0, 3, 5, { 0 }},+ { 74, 0, 3, 5, { 0 }},+ { 75, 0, 3, 5, { 0 }},+ { 76, 0, 3, 5, { 0 }},+ { 77, 0, 3, 5, { 0 }},+ { 78, 0, 3, 5, { 0 }},+ { 79, 0, 3, 5, { 0 }},+ { 80, 0, 3, 5, { 0 }},+ { 81, 0, 3, 5, { 0 }},+ { 82, 0, 3, 5, { 0 }},+ { 83, 0, 3, 5, { 0 }},+ { 84, 0, 3, 5, { 0 }},+ { 85, 0, 3, 5, { 0 }},+ { 86, 0, 3, 5, { 0 }},+ { 87, 0, 3, 5, { 0 }},+ { 88, 0, 3, 5, { 0 }},+ { 89, 0, 3, 5, { 0 }},+ { 90, 0, 3, 5, { 0 }},+ { 91, 0, 3, 5, { 0 }},+ { 92, 0, 3, 5, { 0 }},+ { 93, 0, 3, 5, { 0 }},+ { 94, 0, 3, 5, { 0 }},+ { 95, 0, 12, 5, { 0 }},+ { 96, 1, 4, 5, { 0 }},+ { 97, 0, 6, 5, { 0 }},+ { 98, 0, 3, 5, { 0 }},+ { 99, 0, 6, 5, { 0 }},+ { 100, 0, 3, 5, { 0 }},+ { 101, 0, 6, 5, { 0 }},+ { 102, 0, 3, 5, { 0 }},+ { 103, 0, 6, 5, { 0 }},+ { 104, 0, 3, 5, { 0 }},+ { 105, 0, 3, 5, { 0 }},+ { 106, 0, 3, 5, { 0 }},+ { 107, 0, 3, 5, { 0 }},+ { 108, 0, 3, 5, { 0 }},+ { 109, 0, 6, 5, { 0 }},+ { 110, 0, 6, 5, { 0 }},+ { 111, 0, 6, 5, { 0 }},+ { 112, 0, 6, 5, { 0 }},+ { 113, 0, 6, 5, { 0 }},+ { 114, 0, 6, 5, { 0 }},+ { 115, 0, 6, 5, { 0 }},+ { 116, 0, 3, 5, { 0 }},+ { 117, 0, 6, 5, { 0 }},+ { 118, 0, 6, 5, { 0 }},+ { 119, 0, 6, 5, { 0 }},+ { 120, 0, 6, 5, { 0 }},+ { 121, 0, 6, 5, { 0 }},+ { 122, 0, 6, 5, { 0 }},+ { 123, 0, 3, 5, { 0 }},+ { 124, 1, 3, 5, { 0 }},+ { 125, 0, 3, 5, { 0 }},+ { 126, 0, 8, 5, { 0 }},+ { 161, 1, 4, 5, { 0 }},+ { 162, 0, 6, 5, { 0 }},+ { 163, 0, 3, 5, { 0 }},+ { 8364, 0, 3, 5, { 0 }},+ { 165, 0, 3, 5, { 0 }},+ { 352, 0, 0, 0, { 0 }},+ { 167, 0, 3, 5, { 0 }},+ { 353, 0, 0, 0, { 0 }},+ { 169, 0, 6, 5, { 0 }},+ { 170, 2, 3, 5, { 0 }},+ { 171, 0, 8, 5, { 0 }},+ { 172, 0, 6, 5, { 0 }},+ { 174, 0, 6, 5, { 0 }},+ { 175, 0, 3, 5, { 0 }},+ { 176, 1, 3, 5, { 0 }},+ { 177, 0, 5, 5, { 0 }},+ { 178, 2, 3, 5, { 0 }},+ { 179, 2, 3, 5, { 0 }},+ { 381, 0, 0, 0, { 0 }},+ { 181, 0, 6, 5, { 0 }},+ { 182, 0, 3, 5, { 0 }},+ { 183, 1, 6, 5, { 0 }},+ { 382, 0, 0, 0, { 0 }},+ { 185, 0, 3, 5, { 0 }},+ { 186, 0, 3, 5, { 0 }},+ { 187, 0, 8, 5, { 0 }},+ { 338, 0, 3, 5, { 0 }},+ { 339, 0, 6, 5, { 0 }},+ { 376, 0, 3, 5, { 0 }},+ { 191, 0, 3, 5, { 0 }},+ { 192, 0, -1, 5, { 0 }},+ { 193, 0, -1, 5, { 0 }},+ { 194, 0, -1, 5, { 0 }},+ { 195, 0, -1, 5, { 0 }},+ { 196, 0, 1, 5, { 0 }},+ { 197, 0, 1, 5, { 0 }},+ { 198, 0, 3, 5, { 0 }},+ { 199, 0, 3, 5, { 0 }},+ { 200, 0, -1, 5, { 0 }},+ { 201, 0, -1, 5, { 0 }},+ { 202, 0, -1, 5, { 0 }},+ { 203, 0, 1, 5, { 0 }},+ { 204, 0, -1, 5, { 0 }},+ { 205, 0, -1, 5, { 0 }},+ { 206, 0, -1, 5, { 0 }},+ { 207, 0, 1, 5, { 0 }},+ { 208, 0, 3, 5, { 0 }},+ { 209, 0, -1, 5, { 0 }},+ { 210, 0, -1, 5, { 0 }},+ { 211, 0, -1, 5, { 0 }},+ { 212, 0, -1, 5, { 0 }},+ { 213, 0, -1, 5, { 0 }},+ { 214, 0, 1, 5, { 0 }},+ { 215, 0, 10, 5, { 0 }},+ { 216, 0, 3, 5, { 0 }},+ { 217, 0, -1, 5, { 0 }},+ { 218, 0, -1, 5, { 0 }},+ { 219, 0, -1, 5, { 0 }},+ { 220, 0, 1, 5, { 0 }},+ { 221, 0, -1, 5, { 0 }},+ { 222, 0, 3, 5, { 0 }},+ { 223, 0, 3, 5, { 0 }},+ { 224, 0, 3, 5, { 0 }},+ { 225, 0, 3, 5, { 0 }},+ { 226, 0, 3, 5, { 0 }},+ { 227, 0, 3, 5, { 0 }},+ { 228, 0, 4, 5, { 0 }},+ { 229, 0, 4, 5, { 0 }},+ { 230, 0, 6, 5, { 0 }},+ { 231, 0, 6, 5, { 0 }},+ { 232, 0, 3, 5, { 0 }},+ { 233, 0, 3, 5, { 0 }},+ { 234, 0, 3, 5, { 0 }},+ { 235, 0, 4, 5, { 0 }},+ { 236, 0, 3, 5, { 0 }},+ { 237, 0, 3, 5, { 0 }},+ { 238, 0, 3, 5, { 0 }},+ { 239, 0, 4, 5, { 0 }},+ { 240, 0, 3, 5, { 0 }},+ { 241, 0, 3, 5, { 0 }},+ { 242, 0, 3, 5, { 0 }},+ { 243, 0, 3, 5, { 0 }},+ { 244, 0, 3, 5, { 0 }},+ { 245, 0, 3, 5, { 0 }},+ { 246, 0, 4, 5, { 0 }},+ { 247, 0, 7, 5, { 0 }},+ { 248, 0, 6, 5, { 0 }},+ { 249, 0, 3, 5, { 0 }},+ { 250, 0, 3, 5, { 0 }},+ { 251, 0, 3, 5, { 0 }},+ { 252, 0, 4, 5, { 0 }},+ { 253, 0, 3, 5, { 0 }},+ { 254, 0, 3, 5, { 0 }},+ { 255, 0, 4, 5, { 0 }},+};++// Style loading function: Amber+static void GuiLoadStyleAmber(void)+{+ // Load style properties provided+ // NOTE: Default properties are propagated+ for (int i = 0; i < AMBER_STYLE_PROPS_COUNT; i++)+ {+ GuiSetStyle(amberStyleProps[i].controlId, amberStyleProps[i].propertyId, amberStyleProps[i].propertyValue);+ }++ // Custom font loading+ // NOTE: Compressed font image data (DEFLATE), it requires DecompressData() function+ int amberFontDataSize = 0;+ unsigned char *data = DecompressData(amberFontData, AMBER_STYLE_FONT_ATLAS_COMP_SIZE, &amberFontDataSize);+ Image imFont = { data, 512, 256, 1, 2 };++ Font font = { 0 };+ font.baseSize = 16;+ font.glyphCount = 189;++ // Load texture from image+ font.texture = LoadTextureFromImage(imFont);+ UnloadImage(imFont); // Uncompressed image data can be unloaded from memory++ // Copy char recs data from global fontRecs+ // NOTE: Required to avoid issues if trying to free font+ font.recs = (Rectangle *)RAYGUI_MALLOC(font.glyphCount*sizeof(Rectangle));+ memcpy(font.recs, amberFontRecs, font.glyphCount*sizeof(Rectangle));++ // Copy font char info data from global fontChars+ // NOTE: Required to avoid issues if trying to free font+ font.glyphs = (GlyphInfo *)RAYGUI_MALLOC(font.glyphCount*sizeof(GlyphInfo));+ memcpy(font.glyphs, amberFontGlyphs, font.glyphCount*sizeof(GlyphInfo));++ GuiSetFont(font);++ // Setup a white rectangle on the font to be used on shapes drawing,+ // it makes possible to draw shapes and text (full UI) in a single draw call+ Rectangle fontWhiteRec = { 510, 254, 1, 1 }; SetShapesTexture(font.texture, fontWhiteRec); //-----------------------------------------------------------------
raylib/examples/audio/audio_mixed_processor.c view
@@ -97,7 +97,7 @@ DrawRectangle(199, 199, 402, 34, LIGHTGRAY); for (int i = 0; i < 400; i++) {- DrawLine(201 + i, 232 - (int)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);
raylib/examples/core/core_automation_events.c view
@@ -88,7 +88,7 @@ // Update //---------------------------------------------------------------------------------- float deltaTime = 0.015f;//GetFrameTime();- + // Dropped files logic //---------------------------------------------------------------------------------- if (IsFileDropped())@@ -157,11 +157,6 @@ } 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 @@ } //---------------------------------------------------------------------------------- + // 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 @@ 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 @@ } } }- 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 @@ 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; //----------------------------------------------------------------------------------
raylib/examples/core/core_input_gamepad_info.c view
@@ -47,25 +47,25 @@ 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; } } }
+ raylib/examples/core/core_input_virtual_controls.c view
@@ -0,0 +1,123 @@+/*******************************************************************************************+*+* raylib [core] example - input virtual controls+*+* Example originally created with raylib 5.0, last time updated with raylib 5.0+*+* Example create by GreenSnakeLinux (@GreenSnakeLinux),+* lighter by oblerion (@oblerion) 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 Ramon Santamaria (@raysan5)+*+********************************************************************************************/++#include "raylib.h"+#include <math.h>+//------------------------------------------------------------------------------------+// Program main entry point+//------------------------------------------------------------------------------------+int main(void)+{+ // Initialization+ //--------------------------------------------------------------------------------------+ const int screenWidth = 800;+ const int screenHeight = 450;++ InitWindow(screenWidth, screenHeight, "raylib [core] example - input virtual controls");++ const int dpadX = 90;+ const int dpadY = 300;+ const int dpadRad = 25;//radius of each pad+ Color dpadColor = BLUE;+ int dpadKeydown = -1;//-1 if not down, else 0,1,2,3 ++ + const float dpadCollider[4][2]= // collider array with x,y position+ {+ {dpadX,dpadY-dpadRad*1.5},//up+ {dpadX-dpadRad*1.5,dpadY},//left+ {dpadX+dpadRad*1.5,dpadY},//right+ {dpadX,dpadY+dpadRad*1.5}//down+ };+ const char dpadLabel[4]="XYBA";//label of Dpad++ float playerX=100;+ float playerY=100;++ SetTargetFPS(60);+ //--------------------------------------------------------------------------------------++ // Main game loop+ while (!WindowShouldClose()) // Detect window close button or ESC key+ {+ // Update + //--------------------------------------------------------------------------+ dpadKeydown = -1; //reset+ float inputX=0;+ float inputY=0;+ if(GetTouchPointCount()>0)+ {//use touch pos+ inputX = GetTouchX();+ inputY = GetTouchY();+ }+ else+ {//use mouse pos+ inputX = GetMouseX();+ inputY = GetMouseY();+ }+ for(int i=0;i<4;i++)+ {+ //test distance each collider and input < radius+ if( fabsf(dpadCollider[i][1]-inputY) + fabsf(dpadCollider[i][0]-inputX) < dpadRad)+ {+ dpadKeydown = i;+ break;+ }+ }+ // move player+ switch(dpadKeydown){+ case 0: playerY -= 50*GetFrameTime();+ break;+ case 1: playerX -= 50*GetFrameTime();+ break;+ case 2: playerX += 50*GetFrameTime();+ break;+ case 3: playerY += 50*GetFrameTime();+ default:;+ };+ //--------------------------------------------------------------------------+ + // Draw + //--------------------------------------------------------------------------+ BeginDrawing();+ ClearBackground(RAYWHITE);+ for(int i=0;i<4;i++)+ {+ //draw all pad+ DrawCircle(dpadCollider[i][0],dpadCollider[i][1],dpadRad,dpadColor);+ if(i!=dpadKeydown)+ {+ //draw label+ DrawText(TextSubtext(dpadLabel,i,1),+ dpadCollider[i][0]-5,+ dpadCollider[i][1]-5,16,BLACK);+ }++ }+ DrawText("Player",playerX,playerY,16,BLACK);+ EndDrawing();+ //--------------------------------------------------------------------------+ }++ // De-Initialization+ //--------------------------------------------------------------------------------------+ CloseWindow(); // Close window and OpenGL context+ //--------------------------------------------------------------------------------------++ return 0;+}+
raylib/examples/core/core_vr_simulator.c view
@@ -100,7 +100,7 @@ DisableCursor(); // Limit cursor to relative movement inside the window - SetTargetFPS(90); // Set our game to run at 90 frames-per-second+ SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop
raylib/examples/models/models_box_collisions.c view
@@ -109,7 +109,7 @@ 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);
+ raylib/examples/models/models_gpu_skinning.c view
@@ -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; +}
+ raylib/examples/models/models_point_rendering.c view
@@ -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 <stdlib.h> // Required for: rand()+#include <math.h> // 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;+}
raylib/examples/models/models_yaw_pitch_roll.c view
@@ -114,6 +114,7 @@ // De-Initialization //-------------------------------------------------------------------------------------- UnloadModel(model); // Unload model data+ UnloadTexture(texture); // Unload texture data CloseWindow(); // Close window and OpenGL context //--------------------------------------------------------------------------------------
raylib/examples/shaders/shaders_basic_pbr.c view
@@ -236,7 +236,7 @@ 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++)
raylib/examples/shaders/shaders_lightmap.c view
@@ -164,6 +164,8 @@ //-------------------------------------------------------------------------------------- UnloadMesh(mesh); // Unload the mesh UnloadShader(shader); // Unload shader+ UnloadTexture(texture); // Unload texture+ UnloadTexture(light); // Unload texture CloseWindow(); // Close window and OpenGL context //--------------------------------------------------------------------------------------
raylib/examples/shaders/shaders_texture_drawing.c view
@@ -77,6 +77,7 @@ // De-Initialization //-------------------------------------------------------------------------------------- UnloadShader(shader);+ UnloadTexture(texture); CloseWindow(); // Close window and OpenGL context //--------------------------------------------------------------------------------------
+ raylib/examples/shaders/shaders_vertex_displacement.c view
@@ -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 <Alex ZH> (@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 <Alex ZH> (@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;+}
raylib/examples/shapes/raygui.h view
@@ -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 @@ // 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 @@ 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 @@ // 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 @@ 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 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 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 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 @@ 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 @@ 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 @@ 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 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 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 @@ 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 @@ { #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 @@ }; // 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 @@ #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 @@ } // 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 @@ // Update control //--------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { Vector2 mousePoint = GetMousePosition(); @@ -1997,7 +2015,7 @@ // Update control //--------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { Vector2 mousePoint = GetMousePosition(); @@ -2020,7 +2038,7 @@ 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 @@ // Update control //--------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { Vector2 mousePoint = GetMousePosition(); @@ -2068,7 +2086,7 @@ 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 @@ 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 @@ // Update control //--------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { Vector2 mousePoint = GetMousePosition(); @@ -2256,7 +2274,7 @@ 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 @@ // 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 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 @@ 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 @@ 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 @@ } } - // 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 @@ // 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 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 @@ 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 @@ { 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 @@ 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 @@ 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 @@ // 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 @@ 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 @@ 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 @@ /* // 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 @@ 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 @@ // Update control //--------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { Vector2 mousePoint = GetMousePosition(); @@ -2846,7 +2881,7 @@ // Update control //--------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { Vector2 mousePoint = GetMousePosition(); @@ -2890,7 +2925,13 @@ //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 @@ 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 @@ 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 @@ } // 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 @@ // Update control //--------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { Vector2 mousePoint = GetMousePosition(); @@ -3238,7 +3378,7 @@ // Update control //--------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { Vector2 mousePoint = GetMousePosition(); @@ -3291,6 +3431,8 @@ // 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 @@ 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);-- pickerSelector.x = bounds.x + (float)hsv.y*bounds.width; // HSV: Saturation- pickerSelector.y = bounds.y + (1.0f - (float)hsv.z)*bounds.height; // HSV: Value-- 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)- {- Vector2 mousePoint = GetMousePosition();-- 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) };+ Vector3 prevHsv = hsv; // workaround to see if GuiColorPanelHSV modifies the hsv. - }- else state = STATE_FOCUSED;- }- }- //--------------------------------------------------------------------+ GuiColorPanelHSV(bounds, text, &hsv); - // Draw control- //--------------------------------------------------------------------- if (state != STATE_DISABLED)+ // 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) {- 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));+ Vector3 rgb = ConvertHSVtoRGB(hsv); - // 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));+ // 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 }; }-- GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK);- //--------------------------------------------------------------------- return result; } @@ -3451,11 +3542,11 @@ { 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 @@ } 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 @@ 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 @@ { 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 @@ } 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 @@ 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 @@ // 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 @@ 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 @@ 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 @@ // 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 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 @@ // Update control //--------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { if (CheckCollisionPointRec(mousePoint, bounds)) {@@ -3925,14 +4049,14 @@ // 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 @@ // Set tooltip string void GuiSetTooltip(const char *tooltip) { guiTooltipPtr = tooltip; } - //---------------------------------------------------------------------------------- // Styles loading functions //----------------------------------------------------------------------------------@@ -3967,6 +4090,7 @@ #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 @@ } } - 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 @@ // 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 @@ 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 @@ { // 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 @@ 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 @@ // 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,8 +5030,24 @@ 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 @@ // 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 @@ 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 @@ 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 @@ { 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 @@ } 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 @@ // 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 @@ 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 @@ 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; }@@ -5514,7 +5713,6 @@ codepoint = ptr[0]; *codepointSize = 1; }- return codepoint; }
raylib/examples/shapes/shapes_bouncing_ball.c view
@@ -62,7 +62,7 @@ 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);
raylib/examples/shapes/shapes_draw_circle_sector.c view
@@ -63,11 +63,11 @@ // 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));
raylib/examples/shapes/shapes_draw_rectangle_rounded.c view
@@ -66,11 +66,11 @@ // 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);
raylib/examples/shapes/shapes_draw_ring.c view
@@ -69,13 +69,13 @@ // 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);
raylib/examples/text/text_input_box.c view
@@ -35,7 +35,7 @@ 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
raylib/examples/text/text_writing_anim.c view
@@ -52,7 +52,7 @@ 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(); //----------------------------------------------------------------------------------
raylib/examples/textures/textures_blend_modes.c view
@@ -43,6 +43,9 @@ 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 {
raylib/examples/textures/textures_image_drawing.c view
@@ -47,7 +47,7 @@ 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
raylib/examples/textures/textures_image_rotate.c view
@@ -43,6 +43,8 @@ textures[2] = LoadTextureFromImage(imageNeg90); int currentTexture = 0;++ SetTargetFPS(60); // Set our game to run at 60 frames-per-second //--------------------------------------------------------------------------------------- // Main game loop
raylib/examples/textures/textures_logo_raylib.c view
@@ -27,6 +27,8 @@ // 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
raylib/examples/textures/textures_raw_data.c view
@@ -63,6 +63,8 @@ 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
raylib/examples/textures/textures_sprite_explosion.c view
@@ -48,8 +48,8 @@ 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
− raylib/examples/textures/textures_svg_loading.c
@@ -1,72 +0,0 @@-/*******************************************************************************************-*-* raylib [textures] example - SVG loading and texture creation-*-* NOTE: Images are loaded in CPU memory (RAM); textures are loaded in GPU memory (VRAM)-*-* Example originally created with raylib 4.2, last time updated with raylib 4.2-*-* 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) 2022 Dennis Meinen (@bixxy#4258 on Discord)-*-********************************************************************************************/--#include "raylib.h"--//-------------------------------------------------------------------------------------// Program main entry point-//-------------------------------------------------------------------------------------int main(void)-{- // Initialization- //--------------------------------------------------------------------------------------- const int screenWidth = 800;- const int screenHeight = 450;-- InitWindow(screenWidth, screenHeight, "raylib [textures] example - svg loading");-- // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)-- Image image = LoadImageSvg("resources/test.svg", 400, 350); // Loaded in CPU memory (RAM)- Texture2D texture = LoadTextureFromImage(image); // Image converted to texture, GPU memory (VRAM)- UnloadImage(image); // Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM-- 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- //----------------------------------------------------------------------------------- // TODO: Update your variables here- //------------------------------------------------------------------------------------ // Draw- //----------------------------------------------------------------------------------- BeginDrawing();-- ClearBackground(RAYWHITE);-- DrawTexture(texture, screenWidth/2 - texture.width/2, screenHeight/2 - texture.height/2, WHITE);-- //Red border to illustrate how the SVG is centered within the specified dimensions- DrawRectangleLines((screenWidth / 2 - texture.width / 2) - 1, (screenHeight / 2 - texture.height / 2) - 1, texture.width + 2, texture.height + 2, RED);-- DrawText("this IS a texture loaded from an SVG file!", 300, 410, 10, GRAY);-- EndDrawing();- //----------------------------------------------------------------------------------- }-- // De-Initialization- //--------------------------------------------------------------------------------------- UnloadTexture(texture); // Texture unloading-- CloseWindow(); // Close window and OpenGL context- //---------------------------------------------------------------------------------------- return 0;-}
raylib/examples/textures/textures_to_image.c view
@@ -38,6 +38,8 @@ 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
raylib/parser/raylib_parser.c view
@@ -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 @@ // 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
raylib/src/config.h view
@@ -113,13 +113,23 @@ #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 #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION@@ -170,7 +180,6 @@ //#define SUPPORT_FILEFORMAT_ASTC 1 //#define SUPPORT_FILEFORMAT_PKM 1 //#define SUPPORT_FILEFORMAT_PVR 1-//#define SUPPORT_FILEFORMAT_SVG 1 // Support image export functionality (.png, .bmp, .tga, .jpg, .qoi) #define SUPPORT_IMAGE_EXPORT 1@@ -225,7 +234,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
raylib/src/external/RGFW.h view
@@ -54,6580 +54,8940 @@ #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-*/--/*- Credits :- 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-- GLFW:- certain parts of winapi and X11 are very poorly documented,- GLFW's source code was referenced and used throughout the project (used code is marked in some way),- this mainly includes, code for drag and drops, code for setting the icon to a bitmap and the code for managing the clipboard for X11 (as these parts are not documented very well)-- GLFW Copyright, https::/github.com/GLFW/GLFW-- 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- AICDG (@THISISAGOODNAME) -> vulkan support (example)-*/--#ifndef RGFW_MALLOC-#include <stdlib.h>-#include <time.h>-#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-#endif--/* for windows 95 testing (not that it works well) */-#ifdef RGFW_WIN95-#define RGFW_NO_MONITOR-#define RGFW_NO_PASSTHROUGH-#endif--#ifndef RGFWDEF-#ifdef __APPLE__-#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) (void)(x);-#endif--#ifdef __cplusplus-extern "C" {-#endif-- /* makes sure the header file part is only defined once by default */-#ifndef RGFW_HEADER--#define RGFW_HEADER--#if !defined(u8)- #if defined(_MSC_VER) || defined(__SYMBIAN32__)- 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- #include <stdint.h>-- 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)- typedef u8 b8;-#endif--#if defined(RGFW_X11) && defined(__APPLE__)-#define RGFW_MACOS_X11-#undef __APPLE__-#endif--#if defined(_WIN32) && !defined(RGFW_X11) /* (if you're using X11 on windows some how) */-- /* this name looks better */- /* plus it helps with cross-compiling because RGFW_X11 won't be accidently defined */- -#define RGFW_WINDOWS--#if defined(_WIN32) && !defined(WIN32)-#define WIN32-#endif--#if defined(_WIN64)--#ifndef WIN64-#define WIN64-#endif--#define _AMD64_-#undef _X86_-#else-#undef _AMD64_-#ifndef _X86_-#define _X86_-#endif-#endif--#ifndef RGFW_NO_XINPUT-#ifdef __MINGW32__-#include <xinput.h>-#else-#include <XInput.h>-#endif-#endif--#else -#if defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)-#define RGFW_MACOS_X11-#define RGFW_X11-#include <X11/Xlib.h>-#endif-#endif --#if defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11)-#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-#endif--#if !defined(RGFW_OSMESA) && !defined(RGFW_EGL) && !defined(RGFW_OPENGL) && !defined(RGFW_DIRECTX) && !defined(RGFW_BUFFER) && !defined(RGFW_NO_API)-#define RGFW_OPENGL-#endif--#if defined(RGFW_X11) && (defined(RGFW_OPENGL))-#ifndef GLX_MESA_swap_control-#define GLX_MESA_swap_control-#endif-#include <GL/glx.h> /* GLX defs, xlib.h, gl.h */-#endif--#ifdef RGFW_EGL-#include <EGL/egl.h>-#endif--#ifdef RGFW_OSMESA-#ifndef __APPLE__-#include <GL/osmesa.h>-#else-#include <OpenGL/osmesa.h>-#endif-#endif--#if defined(RGFW_DIRECTX) && defined(RGFW_WINDOWS)-#include <d3d11.h>-#include <dxgi.h>-#include <dxgi.h>-#include <d3dcompiler.h>--#ifndef __cplusplus-#define __uuidof(T) IID_##T-#endif-#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 (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*/-#define RGFW_HIDE_MOUSE (1L<<6) /*! the window should hide the mouse or not (can be toggled later on) using `RGFW_window_mouseShow*/-#define RGFW_FULLSCREEN (1L<<8) /* the window is fullscreen by default or not */-#define RGFW_CENTER (1L<<10) /*! center the window on the screen */-#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)*/---/*! 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 RGFW_HEADER part of this file!!-- 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-*/-#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-*/-#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-*/-#define RGFW_windowMoved 10 /*!< the window was moved (by the user) */-#define RGFW_windowResized 11 /*!< the window was resized (by the user) */--#define RGFW_focusIn 12 /*!< window is in focus now */-#define RGFW_focusOut 13 /*!< window is out of focus now */--#define RGFW_mouseEnter 14 /* mouse entered the window */-#define RGFW_mouseLeave 15 /* mouse left the window */--#define RGFW_windowRefresh 16 /* The window content needs to be refreshed */--/* 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-- 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-*/--/*! mouse button codes (RGFW_Event.button) */-#define RGFW_mouseLeft 1 /*!< left mouse button is pressed*/-#define RGFW_mouseMiddle 2 /*!< mouse-wheel-button is pressed*/-#define RGFW_mouseRight 3 /*!< right mouse button is pressed*/-#define RGFW_mouseScrollUp 4 /*!< mouse wheel is scrolling up*/-#define RGFW_mouseScrollDown 5 /*!< mouse wheel is scrolling down*/--#ifndef RGFW_MAX_PATH-#define RGFW_MAX_PATH 260 /* max length of a path (for dnd) */-#endif-#ifndef RGFW_MAX_DROPS-#define RGFW_MAX_DROPS 260 /* max items you can drop at once */-#endif---/* for RGFW_Event.lockstate */-#define RGFW_CAPSLOCK (1L << 1)-#define RGFW_NUMLOCK (1L << 2)--/*! joystick button codes (based on xbox/playstation), you may need to change these values per controller */-#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;-#endif-- /* 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 */-#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 RGFW_NO_MONITOR- 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 */- } RGFW_monitor;-- /*- 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) */- RGFWDEF RGFW_monitor* RGFW_getMonitors(void);- /* get the primary monitor */- RGFWDEF RGFW_monitor RGFW_getPrimaryMonitor(void);- #endif-- /* NOTE: some parts of the data can represent different things based on the event (read comments in RGFW_Event struct) */- 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;-#else- char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH]; /*!< dropped files*/-#endif- 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 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 keyCode; /*!< keycode of event !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! */-- b8 inFocus; /*if the window is in focus or not (this is always true for MacOS windows due to the api being weird) */-- u8 lockState;-- 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 {-#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 */-#endif-#ifdef RGFW_MACOS- u32 display;- void* displayLink;- void* window;- b8 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_OSMESA- OSMesaContext rSurf;-#endif-#endif--#ifdef RGFW_WINDOWS- RGFW_area maxSize, minSize;-#if defined(RGFW_DIRECTX)- IDXGISwapChain* swapchain;- ID3D11RenderTargetView* renderTargetView;- ID3D11DepthStencilView* pDepthStencilView;-#endif-#endif--#if defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)- void* view; /*apple viewpoint thingy*/-#endif--#ifdef RGFW_EGL- EGLSurface EGL_surface;- EGLDisplay EGL_display;- EGLContext EGL_context;-#endif--#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) -#ifdef RGFW_WINDOWS- HBITMAP bitmap;-#endif-#ifdef RGFW_X11- XImage* bitmap;- GC gc;-#endif-#ifdef RGFW_MACOS- 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-#endif-- 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- b8 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;--#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 */-#endif-- 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 */--#if defined(RGFW_X11) || defined(RGFW_MACOS)- typedef u64 RGFW_thread; /* thread type unix */-#else- typedef void* RGFW_thread; /* thread type for window */-#endif-- /* 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) */-- 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 */-- /* get the size of the screen to an area struct */- RGFWDEF RGFW_area RGFW_getScreenSize(void);-- /*- this function checks an *individual* event (and updates window structure attributes)- this means, using this function without a while loop may cause event lag-- ex.-- while (RGFW_window_checkEvent(win) != NULL) [this keeps checking events until it reaches the last one]-- 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`- */-- RGFW_Event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/-- /* - 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);--- /*! window managment functions*/- RGFWDEF void RGFW_window_close(RGFW_window* win); /*!< close the window and free leftover data */-- RGFWDEF void RGFW_window_move(RGFW_window* win,- RGFW_vector v/* new pos*/- );-- #ifndef RGFW_NO_MONITOR- /* move to a specific monitor */- RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m);- #endif- RGFWDEF void RGFW_window_resize(RGFW_window* win,- RGFW_area a/* new size*/- );-- /* 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);-- 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)*/-- RGFWDEF void RGFW_window_setBorder(RGFW_window* win, b8 border); /* if the window should have a border or not (borderless) based on bool value of `border` */- - RGFWDEF void RGFW_window_setDND(RGFW_window* win, b8 allow); /* turn on / off dnd (RGFW_ALLOW_DND stil must be passed to the window)*/-- #ifndef RGFW_NO_PASSTHROUGH- RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough); /* turn on / off mouse passthrough */- #endif -- RGFWDEF void RGFW_window_setName(RGFW_window* win,- char* name- );-- 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 */-- /*!< 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);-- /*!< 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);-- 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-- this is useful for a 3D camera- */- RGFWDEF void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area);- /* undo hold */- RGFWDEF void RGFW_window_mouseUnhold(RGFW_window* win);-- /* hide the window */- RGFWDEF void RGFW_window_hide(RGFW_window* win);- /* show the window */- RGFWDEF void RGFW_window_show(RGFW_window* win);-- /*- 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);-- /* where the mouse is on the screen */- RGFWDEF RGFW_vector RGFW_getGlobalMousePoint(void);-- /* where the mouse is on the window */- RGFWDEF RGFW_vector RGFW_window_getMousePoint(RGFW_window* win);-- /* 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);-- /* 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);--- #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-- /*!< make the window the current opengl drawing context */- RGFWDEF void RGFW_window_makeCurrent(RGFW_window* win);-- /*error handling*/- RGFWDEF b8 RGFW_Error(void); /* returns true if an error has occurred (doesn't print errors itself) */-- /*!< 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 prev keymap 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)*/-- RGFWDEF b8 RGFW_isClicked(RGFW_window* win, u8 key);-- RGFWDEF b8 RGFW_isMousePressed(RGFW_window* win, u8 button);- RGFWDEF b8 RGFW_isMouseHeld(RGFW_window* win, u8 button);- RGFWDEF b8 RGFW_isMouseReleased(RGFW_window* win, u8 button);- RGFWDEF b8 RGFW_wasMousePressed(RGFW_window* win, u8 button);--/*! clipboard functions*/- 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-- */-- /* 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_vector 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_vector point);- /* RGFW_dnd_init, the window, the point of the drop on the windows */- typedef void (* RGFW_dndInitfunc)(RGFW_window* win, RGFW_vector 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_vector axis[2], u8 axisesCount);- - /* RGFW_dnd, the window that had the drop, the drop data and the amount files dropped */- #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-- RGFWDEF void RGFW_setWindowMoveCallback(RGFW_windowmovefunc func);- RGFWDEF void RGFW_setWindowResizeCallback(RGFW_windowresizefunc func);- RGFWDEF void RGFW_setWindowQuitCallback(RGFW_windowquitfunc func);- RGFWDEF void RGFW_setMousePosCallback(RGFW_mouseposfunc func);- RGFWDEF void RGFW_setWindowRefreshCallback(RGFW_windowrefreshfunc func);- RGFWDEF void RGFW_setFocusCallback(RGFW_focusfunc func);- RGFWDEF void RGFW_setMouseNotifyCallBack(RGFW_mouseNotifyfunc func);- RGFWDEF void RGFW_setDndCallback(RGFW_dndfunc func);- RGFWDEF void RGFW_setDndInitCallback(RGFW_dndInitfunc func);- RGFWDEF void RGFW_setKeyCallback(RGFW_keyfunc func);- RGFWDEF void RGFW_setMouseButtonCallback(RGFW_mousebuttonfunc func);- RGFWDEF void RGFW_setjsButtonCallback(RGFW_jsButtonfunc func);- RGFWDEF void RGFW_setjsAxisCallback(RGFW_jsAxisfunc func);---#ifndef RGFW_NO_THREADS- /*! threading functions*/-- /*! NOTE! (for X11/linux) : if you define a window in a thread, it must be run after the original thread's window is created or else there will be a memory error */- /*- I'd suggest you use sili's threading functions instead- if you're going to use sili- which is a good idea generally- */-- #if defined(__unix__) || defined(__APPLE__) - typedef void* (* RGFW_threadFunc_ptr)(void*);- #else- typedef DWORD (__stdcall *RGFW_threadFunc_ptr) (LPVOID lpThreadParameter); - #endif-- RGFWDEF RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args); /*!< create a thread*/- RGFWDEF void RGFW_cancelThread(RGFW_thread thread); /*!< cancels a thread*/- RGFWDEF void RGFW_joinThread(RGFW_thread thread); /*!< join thread to current thread */- 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);-- RGFWDEF u32 RGFW_isPressedJS(RGFW_window* win, u16 controller, u8 button);-- /*! 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) */-- /*! Set OpenGL version hint */- RGFWDEF void RGFW_setGLVersion(i32 major, i32 minor);- 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 */-#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);- RGFWDEF void RGFW_window_setCPURender(RGFW_window* win, i8 set);-#ifdef RGFW_DIRECTX- typedef struct {- IDXGIFactory* pFactory;- IDXGIAdapter* pAdapter;- ID3D11Device* pDevice;- ID3D11DeviceContext* pDeviceContext;- } RGFW_directXinfo;-- /*- RGFW stores a global instance of RGFW_directXinfo,- you can use this function to get a pointer the instance- */- 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 */-- 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 :-- 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"-- 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- */--#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-#endif-#ifdef RGFW_IMPLEMENTATION--#include <stdio.h>-#include <string.h>-#include <math.h>-#include <assert.h>--/*-RGFW_IMPLEMENTATION starts with generic RGFW defines--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-*/-- u8 RGFW_keycodes[] = {- [RGFW_OS_BASED_VALUE(49, 192, 50)] = RGFW_Backtick,-- [RGFW_OS_BASED_VALUE(19, 0x30, 29)] = RGFW_0,- [RGFW_OS_BASED_VALUE(10, 0x31, 18)] = RGFW_1,- [RGFW_OS_BASED_VALUE(11, 0x32, 19)] = RGFW_2,- [RGFW_OS_BASED_VALUE(12, 0x33, 20)] = RGFW_3,- [RGFW_OS_BASED_VALUE(13, 0x34, 21)] = RGFW_4,- [RGFW_OS_BASED_VALUE(14, 0x35, 23)] = RGFW_5,- [RGFW_OS_BASED_VALUE(15, 0x36, 22)] = RGFW_6,- [RGFW_OS_BASED_VALUE(16, 0x37, 26)] = RGFW_7,- [RGFW_OS_BASED_VALUE(17, 0x38, 28)] = RGFW_8,- [RGFW_OS_BASED_VALUE(18, 0x39, 25)] = RGFW_9,-- [RGFW_OS_BASED_VALUE(65, 0x20, 49)] = RGFW_Space,-- [RGFW_OS_BASED_VALUE(38, 0x41, 0)] = RGFW_a,- [RGFW_OS_BASED_VALUE(56, 0x42, 11)] = RGFW_b,- [RGFW_OS_BASED_VALUE(54, 0x43, 8)] = RGFW_c,- [RGFW_OS_BASED_VALUE(40, 0x44, 2)] = RGFW_d,- [RGFW_OS_BASED_VALUE(26, 0x45, 14)] = RGFW_e,- [RGFW_OS_BASED_VALUE(41, 0x46, 3)] = RGFW_f,- [RGFW_OS_BASED_VALUE(42, 0x47, 5)] = RGFW_g,- [RGFW_OS_BASED_VALUE(43, 0x48, 4)] = RGFW_h,- [RGFW_OS_BASED_VALUE(31, 0x49, 34)] = RGFW_i,- [RGFW_OS_BASED_VALUE(44, 0x4A, 38)] = RGFW_j,- [RGFW_OS_BASED_VALUE(45, 0x4B, 40)] = RGFW_k,- [RGFW_OS_BASED_VALUE(46, 0x4C, 37)] = RGFW_l,- [RGFW_OS_BASED_VALUE(58, 0x4D, 46)] = RGFW_m,- [RGFW_OS_BASED_VALUE(57, 0x4E, 45)] = RGFW_n,- [RGFW_OS_BASED_VALUE(32, 0x4F, 31)] = RGFW_o,- [RGFW_OS_BASED_VALUE(33, 0x50, 35)] = RGFW_p,- [RGFW_OS_BASED_VALUE(24, 0x51, 12)] = RGFW_q,- [RGFW_OS_BASED_VALUE(27, 0x52, 15)] = RGFW_r,- [RGFW_OS_BASED_VALUE(39, 0x53, 1)] = RGFW_s,- [RGFW_OS_BASED_VALUE(28, 0x54, 17)] = RGFW_t,- [RGFW_OS_BASED_VALUE(30, 0x55, 32)] = RGFW_u,- [RGFW_OS_BASED_VALUE(55, 0x56, 9)] = RGFW_v,- [RGFW_OS_BASED_VALUE(25, 0x57, 13)] = RGFW_w,- [RGFW_OS_BASED_VALUE(53, 0x58, 7)] = RGFW_x,- [RGFW_OS_BASED_VALUE(29, 0x59, 16)] = RGFW_y,- [RGFW_OS_BASED_VALUE(52, 0x5A, 6)] = RGFW_z,-- [RGFW_OS_BASED_VALUE(60, 190, 47)] = RGFW_Period,- [RGFW_OS_BASED_VALUE(59, 188, 43)] = RGFW_Comma,- [RGFW_OS_BASED_VALUE(61, 191, 44)] = RGFW_Slash,- [RGFW_OS_BASED_VALUE(34, 219, 33)] = RGFW_Bracket,- [RGFW_OS_BASED_VALUE(35, 221, 30)] = RGFW_CloseBracket,- [RGFW_OS_BASED_VALUE(47, 186, 41)] = RGFW_Semicolon,- [RGFW_OS_BASED_VALUE(48, 222, 39)] = RGFW_Quote,- [RGFW_OS_BASED_VALUE(51, 322, 42)] = RGFW_BackSlash,- - [RGFW_OS_BASED_VALUE(36, 0x0D, 36)] = RGFW_Return,- [RGFW_OS_BASED_VALUE(119, 0x2E, 118)] = RGFW_Delete,- [RGFW_OS_BASED_VALUE(77, 0x90, 72)] = RGFW_Numlock,- [RGFW_OS_BASED_VALUE(106, 0x6F, 82)] = RGFW_KP_Slash,- [RGFW_OS_BASED_VALUE(63, 0x6A, 76)] = RGFW_Multiply,- [RGFW_OS_BASED_VALUE(82, 0x6D, 67)] = RGFW_KP_Minus,- [RGFW_OS_BASED_VALUE(87, 0x61, 84)] = RGFW_KP_1,- [RGFW_OS_BASED_VALUE(88, 0x62, 85)] = RGFW_KP_2,- [RGFW_OS_BASED_VALUE(89, 0x63, 86)] = RGFW_KP_3,- [RGFW_OS_BASED_VALUE(83, 0x64, 87)] = RGFW_KP_4,- [RGFW_OS_BASED_VALUE(84, 0x65, 88)] = RGFW_KP_5,- [RGFW_OS_BASED_VALUE(85, 0x66, 89)] = RGFW_KP_6,- [RGFW_OS_BASED_VALUE(79, 0x67, 90)] = RGFW_KP_7,- [RGFW_OS_BASED_VALUE(80, 0x68, 92)] = RGFW_KP_8,- [RGFW_OS_BASED_VALUE(81, 0x69, 93)] = RGFW_KP_9,- [RGFW_OS_BASED_VALUE(90, 0x60, 83)] = RGFW_KP_0,- [RGFW_OS_BASED_VALUE(91, 0x6E, 65)] = RGFW_KP_Period,- [RGFW_OS_BASED_VALUE(104, 0x92, 77)] = RGFW_KP_Return,- - [RGFW_OS_BASED_VALUE(20, 189, 27)] = RGFW_Minus,- [RGFW_OS_BASED_VALUE(21, 187, 24)] = RGFW_Equals,- [RGFW_OS_BASED_VALUE(22, 8, 51)] = RGFW_BackSpace,- [RGFW_OS_BASED_VALUE(23, 0x09, 48)] = RGFW_Tab,- [RGFW_OS_BASED_VALUE(66, 20, 57)] = RGFW_CapsLock,- [RGFW_OS_BASED_VALUE(50, 0xA0, 56)] = RGFW_ShiftL,- [RGFW_OS_BASED_VALUE(37, 0x11, 59)] = RGFW_ControlL,- [RGFW_OS_BASED_VALUE(64, 164, 58)] = RGFW_AltL,- [RGFW_OS_BASED_VALUE(133, 0x5B, 55)] = RGFW_SuperL,- - #if !defined(RGFW_WINDOWS) && !defined(RGFW_MACOS)- [RGFW_OS_BASED_VALUE(105, 0x11, 59)] = RGFW_ControlR,- [RGFW_OS_BASED_VALUE(135, 0xA4, 55)] = RGFW_SuperR,- #endif-- #if !defined(RGFW_MACOS)- [RGFW_OS_BASED_VALUE(62, 0x5C, 56)] = RGFW_ShiftR,- [RGFW_OS_BASED_VALUE(108, 165, 58)] = RGFW_AltR,- #endif-- [RGFW_OS_BASED_VALUE(67, 0x70, 127)] = RGFW_F1,- [RGFW_OS_BASED_VALUE(68, 0x71, 121)] = RGFW_F2,- [RGFW_OS_BASED_VALUE(69, 0x72, 100)] = RGFW_F3,- [RGFW_OS_BASED_VALUE(70, 0x73, 119)] = RGFW_F4,- [RGFW_OS_BASED_VALUE(71, 0x74, 97)] = RGFW_F5,- [RGFW_OS_BASED_VALUE(72, 0x75, 98)] = RGFW_F6,- [RGFW_OS_BASED_VALUE(73, 0x76, 99)] = RGFW_F7,- [RGFW_OS_BASED_VALUE(74, 0x77, 101)] = RGFW_F8,- [RGFW_OS_BASED_VALUE(75, 0x78, 102)] = RGFW_F9,- [RGFW_OS_BASED_VALUE(76, 0x79, 110)] = RGFW_F10,- [RGFW_OS_BASED_VALUE(95, 0x7A, 104)] = RGFW_F11,- [RGFW_OS_BASED_VALUE(96, 0x7B, 112)] = RGFW_F12,- [RGFW_OS_BASED_VALUE(111, 0x26, 126)] = RGFW_Up,- [RGFW_OS_BASED_VALUE(116, 0x28, 125)] = RGFW_Down,- [RGFW_OS_BASED_VALUE(113, 0x25, 123)] = RGFW_Left,- [RGFW_OS_BASED_VALUE(114, 0x27, 124)] = RGFW_Right,- [RGFW_OS_BASED_VALUE(118, 0x2D, 115)] = RGFW_Insert,- [RGFW_OS_BASED_VALUE(115, 0x23, 120)] = RGFW_End,- [RGFW_OS_BASED_VALUE(112, 336, 117)] = RGFW_PageUp,- [RGFW_OS_BASED_VALUE(117, 325, 122)] = RGFW_PageDown,- [RGFW_OS_BASED_VALUE(9, 0x1B, 53)] = RGFW_Escape,- [RGFW_OS_BASED_VALUE(110, 0x24, 116)] = RGFW_Home,- };-- 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) {- 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;- - size_t i; - for (i = 0; i < len; i++) - RGFW_keyboard[i].prev = 0;- }--/*- this is the end of keycode data-*/---/* - 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_vector point, b8 status) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(status);}- void RGFW_mouseposfuncEMPTY(RGFW_window* win, RGFW_vector point) {RGFW_UNUSED(win); RGFW_UNUSED(point);}- void RGFW_dndInitfuncEMPTY(RGFW_window* win, RGFW_vector 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_vector 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) { while (RGFW_window_checkEvent(win) != NULL && RGFW_window_shouldClose(win) == 0) { if (win->event.type == RGFW_quit) return; }}- - void RGFW_setWindowMoveCallback(RGFW_windowmovefunc func) { RGFW_windowMoveCallback = func; }- void RGFW_setWindowResizeCallback(RGFW_windowresizefunc func) { RGFW_windowResizeCallback = func; }- void RGFW_setWindowQuitCallback(RGFW_windowquitfunc func) { RGFW_windowQuitCallback = func; }- void RGFW_setMousePosCallback(RGFW_mouseposfunc func) { RGFW_mousePosCallback = func; }- void RGFW_setWindowRefreshCallback(RGFW_windowrefreshfunc func) { RGFW_windowRefreshCallback = func; }- void RGFW_setFocusCallback(RGFW_focusfunc func) { RGFW_focusCallback = func; }- void RGFW_setMouseNotifyCallBack(RGFW_mouseNotifyfunc func) { RGFW_mouseNotifyCallBack = func; }- void RGFW_setDndCallback(RGFW_dndfunc func) { RGFW_dndCallback = func; }- void RGFW_setDndInitCallback(RGFW_dndInitfunc func) { RGFW_dndInitCallback = func; }- void RGFW_setKeyCallback(RGFW_keyfunc func) { RGFW_keyCallback = func; }- void RGFW_setMouseButtonCallback(RGFW_mousebuttonfunc func) { RGFW_mouseButtonCallback = func; }- void RGFW_setjsButtonCallback(RGFW_jsButtonfunc func) { RGFW_jsButtonCallback = func; }- void RGFW_setjsAxisCallback(RGFW_jsAxisfunc func) { RGFW_jsAxisCallback = func; }-/* - no more event call back defines-*/--#define RGFW_ASSERT(check, str) {\- if (!(check)) { \- printf(str); \- assert(check); \- } \-}-- b8 RGFW_error = 0;- b8 RGFW_Error() { 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;- }--- RGFWDEF RGFW_window* RGFW_window_basic_init(RGFW_rect rect, u16 args);-- 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 */--#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-- #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;- win->src.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); }- - b8 RGFW_mouseButtons[5] = { 0 };- b8 RGFW_mouseButtons_prev[5];-- b8 RGFW_isMousePressed(RGFW_window* win, u8 button) {- assert(win != NULL);- return RGFW_mouseButtons[button] && (win != NULL) && win->event.inFocus; - }- b8 RGFW_wasMousePressed(RGFW_window* win, u8 button) {- assert(win != NULL); - return RGFW_mouseButtons_prev[button] && (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) {- assert(win != NULL);- return RGFW_keyboard[key].current && win->event.inFocus;- }-- b8 RGFW_wasPressed(RGFW_window* win, u8 key) {- assert(win != NULL);- return RGFW_keyboard[key].prev && 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)); - }- - 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_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_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);- }-- 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_VECTOR(m.rect.x + win->r.x, m.rect.y + win->r.y));- }- #endif-- RGFWDEF void RGFW_clipCursor(RGFW_rect);- - #if !defined(RGFW_WINDOWS) && !defined(RGFW_MACOS) - void RGFW_clipCursor(RGFW_rect r) { RGFW_UNUSED(r) }- #endif-- void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area) {- if (!(win->src.winArgs & RGFW_HOLD_MOUSE)) {- RGFW_clipCursor(win->r);- win->src.winArgs |= RGFW_HOLD_MOUSE;- }- - if (!area.w && !area.h)- area = RGFW_AREA(win->r.w / 2, win->r.h / 2);- - #ifndef RGFW_MACOS- RGFW_window_moveMouse(win, RGFW_VECTOR(win->r.x + (area.w), win->r.y + (area.h)));- #endif- }-- void RGFW_window_mouseUnhold(RGFW_window* win) {- if ((win->src.winArgs & RGFW_HOLD_MOUSE)) {- win->src.winArgs ^= RGFW_HOLD_MOUSE;-- RGFW_clipCursor(RGFW_RECT(0, 0, 0, 0));- }- }-- 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 == 0)- return;- - deltaTime = RGFW_getTimeNS() - win->event.frameTime2;- win->event.fps = round(1e+9 / deltaTime);- win->event.frameTime2 = RGFW_getTimeNS();- }- - u32 RGFW_isPressedJS(RGFW_window* win, u16 c, u8 button) { return win->src.jsPressed[c][button]; }- - #if defined(RGFW_X11) || defined(RGFW_WINDOWS)- void RGFW_window_showMouse(RGFW_window* win, i8 show) {- static u8 RGFW_blk[] = { 0, 0, 0, 0 };- if (show == 0)- RGFW_window_setMouse(win, RGFW_blk, RGFW_AREA(1, 1), 4);- else- RGFW_window_setMouseDefault(win);- }- #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;- }-- #if defined(RGFW_X11) || defined(RGFW_MACOS)- struct timespec;-- 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);-- void RGFW_window_setDND(RGFW_window* win, b8 allow) {- if (allow && !(win->src.winArgs & RGFW_ALLOW_DND))- win->src.winArgs |= RGFW_ALLOW_DND;-- else if (!allow && (win->src.winArgs & RGFW_ALLOW_DND))- win->src.winArgs ^= RGFW_ALLOW_DND;- }- #endif--/*- graphics API spcific code (end of generic code)- starts here -*/---/* - OpenGL defines start here (Normal, EGL, OSMesa)-*/--#if defined(RGFW_OPENGL) || defined(RGFW_EGL) || defined(RGFW_OSMESA)-#ifndef __APPLE__-#include <GL/gl.h>-#else-#ifndef GL_SILENCE_DEPRECATION-#define GL_SILENCE_DEPRECATION-#endif-#include <OpenGL/gl.h>-#include <OpenGL/OpenGL.h>-#endif--/* EGL, normal OpenGL only */-#if !defined(RGFW_OSMESA) - i32 RGFW_majorVersion = 0, RGFW_minorVersion = 0;- - #ifndef RGFW_EGL- i32 RGFW_STENCIL = 8, RGFW_SAMPLES = 4, RGFW_STEREO = GL_FALSE, RGFW_AUX_BUFFERS = 0;- #else- i32 RGFW_STENCIL = 0, RGFW_SAMPLES = 0, RGFW_STEREO = GL_FALSE, RGFW_AUX_BUFFERS = 0;- #endif--- void RGFW_setGLStencil(i32 stencil) { RGFW_STENCIL = stencil; }- 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_setGLVersion(i32 major, i32 minor) {- 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)--#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)-#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-#define WGL_PIXEL_TYPE_ARB 0x2013-#define WGL_TYPE_RGBA_ARB 0x202B--#define WGL_TRANSPARENT_ARB 0x200A-#endif-- static u32* RGFW_initAttribs(u32 useSoftware) {- RGFW_UNUSED(useSoftware);- static u32 attribs[] = {- #ifndef RGFW_MACOS- 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,- RGFW_GL_BLUE_SIZE , 8,- RGFW_GL_DRAW_TYPE , RGFW_GL_USE_RGBA,- #endif -- #ifdef RGFW_X11- GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,- #endif-- #ifdef RGFW_MACOS- 72,- 8, 24,- #endif-- #ifdef RGFW_WINDOWS- WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,- WGL_TRANSPARENT_ARB, TRUE,- WGL_COLOR_BITS_ARB, 32,- #endif-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0- };-- size_t index = (sizeof(attribs) / sizeof(attribs[0])) - 13;--#define RGFW_GL_ADD_ATTRIB(attrib, attVal) \- if (attVal) { \- attribs[index] = attrib;\- attribs[index + 1] = attVal;\- index += 2;\- }-- 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);--#ifndef RGFW_X11- RGFW_GL_ADD_ATTRIB(RGFW_GL_SAMPLES, RGFW_SAMPLES);-#endif --#ifdef RGFW_MACOS- if (useSoftware) {- RGFW_GL_ADD_ATTRIB(70, kCGLRendererGenericFloatID);- } else {- attribs[index] = RGFW_GL_RENDER_TYPE;- index += 1;- }-#endif--#ifdef RGFW_MACOS- 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);-- return attribs;- }--/* EGL only (no OSMesa nor normal OPENGL) */-#elif defined(RGFW_EGL)--#include <EGL/egl.h>--#if defined(RGFW_LINK_EGL)- typedef EGLBoolean(EGLAPIENTRY* PFN_eglInitialize)(EGLDisplay, EGLint*, EGLint*);-- PFNEGLINITIALIZEPROC eglInitializeSource;- PFNEGLGETCONFIGSPROC eglGetConfigsSource;- PFNEGLCHOOSECONFIGPROC eglChooseConfigSource;- PFNEGLCREATEWINDOWSURFACEPROC eglCreateWindowSurfaceSource;- PFNEGLCREATECONTEXTPROC eglCreateContextSource;- PFNEGLMAKECURRENTPROC eglMakeCurrentSource;- PFNEGLGETDISPLAYPROC eglGetDisplaySource;- PFNEGLSWAPBUFFERSPROC eglSwapBuffersSource;- PFNEGLSWAPINTERVALPROC eglSwapIntervalSource;- PFNEGLBINDAPIPROC eglBindAPISource;- PFNEGLDESTROYCONTEXTPROC eglDestroyContextSource;- PFNEGLTERMINATEPROC eglTerminateSource;- PFNEGLDESTROYSURFACEPROC eglDestroySurfaceSource;--#define eglInitialize eglInitializeSource-#define eglGetConfigs eglGetConfigsSource-#define eglChooseConfig eglChooseConfigSource-#define eglCreateWindowSurface eglCreateWindowSurfaceSource-#define eglCreateContext eglCreateContextSource-#define eglMakeCurrent eglMakeCurrentSource-#define eglGetDisplay eglGetDisplaySource-#define eglSwapBuffers eglSwapBuffersSource-#define eglSwapInterval eglSwapIntervalSource-#define eglBindAPI eglBindAPISource-#define eglDestroyContext eglDestroyContextSource-#define eglTerminate eglTerminateSource-#define eglDestroySurface eglDestroySurfaceSource;-#endif---#define EGL_SURFACE_MAJOR_VERSION_KHR 0x3098-#define EGL_SURFACE_MINOR_VERSION_KHR 0x30fb--#ifndef RGFW_GL_ADD_ATTRIB-#define RGFW_GL_ADD_ATTRIB(attrib, attVal) \- if (attVal) { \- attribs[index] = attrib;\- attribs[index + 1] = attVal;\- index += 2;\- }-#endif--- void RGFW_createOpenGLContext(RGFW_window* win) {-#if defined(RGFW_LINK_EGL)- eglInitializeSource = (PFNEGLINITIALIZEPROC) eglGetProcAddress("eglInitialize");- eglGetConfigsSource = (PFNEGLGETCONFIGSPROC) eglGetProcAddress("eglGetConfigs");- eglChooseConfigSource = (PFNEGLCHOOSECONFIGPROC) eglGetProcAddress("eglChooseConfig");- eglCreateWindowSurfaceSource = (PFNEGLCREATEWINDOWSURFACEPROC) eglGetProcAddress("eglCreateWindowSurface");- eglCreateContextSource = (PFNEGLCREATECONTEXTPROC) eglGetProcAddress("eglCreateContext");- eglMakeCurrentSource = (PFNEGLMAKECURRENTPROC) eglGetProcAddress("eglMakeCurrent");- eglGetDisplaySource = (PFNEGLGETDISPLAYPROC) eglGetProcAddress("eglGetDisplay");- eglSwapBuffersSource = (PFNEGLSWAPBUFFERSPROC) eglGetProcAddress("eglSwapBuffers");- eglSwapIntervalSource = (PFNEGLSWAPINTERVALPROC) eglGetProcAddress("eglSwapInterval");- eglBindAPISource = (PFNEGLBINDAPIPROC) eglGetProcAddress("eglBindAPI");- eglDestroyContextSource = (PFNEGLDESTROYCONTEXTPROC) eglGetProcAddress("eglDestroyContext");- eglTerminateSource = (PFNEGLTERMINATEPROC) eglGetProcAddress("eglTerminate");- eglDestroySurfaceSource = (PFNEGLDESTROYSURFACEPROC) eglGetProcAddress("eglDestroySurface");-#endif /* RGFW_LINK_EGL */-- #ifdef RGFW_WINDOWS- win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.hdc);- #else- win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display);- #endif-- EGLint major, minor;-- eglInitialize(win->src.EGL_display, &major, &minor);-- #ifndef EGL_OPENGL_ES1_BIT- #define EGL_OPENGL_ES1_BIT 0x1- #endif-- EGLint egl_config[] = {- EGL_SURFACE_TYPE, EGL_WINDOW_BIT,- EGL_RENDERABLE_TYPE,- #ifdef RGFW_OPENGL_ES1- EGL_OPENGL_ES1_BIT,- #elif defined(RGFW_OPENGL_ES3)- EGL_OPENGL_ES3_BIT,- #elif defined(RGFW_OPENGL_ES2)- EGL_OPENGL_ES2_BIT,- #else- EGL_OPENGL_BIT,- #endif- EGL_NONE, EGL_NONE- };-- EGLConfig config;- EGLint numConfigs;- eglChooseConfig(win->src.EGL_display, egl_config, &config, 1, &numConfigs);--- win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);-- EGLint attribs[] = {- EGL_CONTEXT_CLIENT_VERSION,- #ifdef RGFW_OPENGL_ES1- 1,- #else- 2,- #endif- 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_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 defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3)- eglBindAPI(EGL_OPENGL_ES_API);- #else- eglBindAPI(EGL_OPENGL_API); - #endif-- win->src.EGL_context = eglCreateContext(win->src.EGL_display, config, EGL_NO_CONTEXT, attribs);-- 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);- }-- #ifdef RGFW_APPLE- void* RGFWnsglFramework = NULL;- #elif defined(RGFW_WINDOWS)- static HMODULE wglinstance = NULL;- #endif-- void* RGFW_getProcAddress(const char* procname) { - #if defined(RGFW_WINDOWS)- void* proc = (void*) GetProcAddress(wglinstance, procname); -- if (proc)- return proc;- #endif-- return (void*) eglGetProcAddress(procname); - }-- void RGFW_closeEGL(RGFW_window* win) {- eglDestroySurface(win->src.EGL_display, win->src.EGL_surface);- eglDestroyContext(win->src.EGL_display, win->src.EGL_context);-- eglTerminate(win->src.EGL_display);- }-- void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {- assert(win != NULL);- - eglSwapInterval(win->src.EGL_display, swapInterval);-- win->fpsCap = (swapInterval == 1) ? 0 : swapInterval;-- }-#endif /* RGFW_EGL */--/* - 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-*/---/*---Start of Linux / Unix defines---*/--#ifdef RGFW_X11-#ifndef RGFW_NO_X11_CURSOR-#include <X11/Xcursor/Xcursor.h>-#endif-#include <dlfcn.h>--#ifndef RGFW_NO_DPI-#include <X11/extensions/Xrandr.h>-#include <X11/Xresource.h>-#endif--#include <X11/Xutil.h>-#include <X11/Xatom.h>-#include <X11/keysymdef.h>-#include <unistd.h>--#include <X11/XKBlib.h> /* for converting keycode to string */-#include <X11/cursorfont.h> /* for hiding */-#include <X11/extensions/shapeconst.h>-#include <X11/extensions/shape.h>--#include <limits.h> /* for data limits (mainly used in drag and drop functions) */-#include <fcntl.h>--#ifdef __linux__-#include <linux/joystick.h>-#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;-- Atom wm_delete_window = 0;--#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)- typedef XcursorImage* (*PFN_XcursorImageCreate)(int, int);- typedef void (*PFN_XcursorImageDestroy)(XcursorImage*);- typedef Cursor(*PFN_XcursorImageLoadCursor)(Display*, const XcursorImage*);-#endif-#ifdef RGFW_OPENGL- typedef GLXContext(*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);-#endif--#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)- PFN_XcursorImageLoadCursor XcursorImageLoadCursorSrc = NULL;- PFN_XcursorImageCreate XcursorImageCreateSrc = NULL;- PFN_XcursorImageDestroy XcursorImageDestroySrc = NULL;--#define XcursorImageLoadCursor XcursorImageLoadCursorSrc-#define XcursorImageCreate XcursorImageCreateSrc-#define XcursorImageDestroy XcursorImageDestroySrc-- void* X11Cursorhandle = NULL;-#endif-- u32 RGFW_windowsOpen = 0;--#ifdef RGFW_OPENGL- 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 = RGFW_MALLOC(RGFW_bufferSize.w * RGFW_bufferSize.h * 4);-- #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-- win->src.bitmap = XCreateImage(- win->src.display, vi->visual,- 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- );- }-- 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) {-#if defined(__CYGWIN__)- X11Cursorhandle = dlopen("libXcursor-1.so", RTLD_LAZY | RTLD_LOCAL);-#elif defined(__OpenBSD__) || defined(__NetBSD__)- X11Cursorhandle = dlopen("libXcursor.so", RTLD_LAZY | RTLD_LOCAL);-#else- X11Cursorhandle = dlopen("libXcursor.so.1", RTLD_LAZY | RTLD_LOCAL);-#endif-- XcursorImageCreateSrc = (PFN_XcursorImageCreate) dlsym(X11Cursorhandle, "XcursorImageCreate");- XcursorImageDestroySrc = (PFN_XcursorImageDestroy) dlsym(X11Cursorhandle, "XcursorImageDestroy");- XcursorImageLoadCursorSrc = (PFN_XcursorImageLoadCursor) dlsym(X11Cursorhandle, "XcursorImageLoadCursor");- }-#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 | LeaveWindowMask | EnterWindowMask | ExposureMask; /* X11 events accepted*/--#ifdef RGFW_OPENGL- u32* visual_attribs = RGFW_initAttribs(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");- return NULL;- }-- u32 i;- for (i = 0; i < (u32)fbcount; i++) {- XVisualInfo* vi = glXGetVisualFromFBConfig((Display*) win->src.display, fbc[i]);- 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;- }- }-- if (best_fbc == -1) {- printf("Failed to get a valid GLX visual\n");- return NULL;- }-- GLXFBConfig bestFbc = fbc[best_fbc];-- /* Get a visual */- XVisualInfo* vi = glXGetVisualFromFBConfig((Display*) win->src.display, bestFbc);-- XFree(fbc);-- if (args & RGFW_TRANSPARENT_WINDOW) {- XMatchVisualInfo((Display*) win->src.display, DefaultScreen((Display*) win->src.display), 32, TrueColor, vi); /* for RGBA backgrounds*/- }-#else- XVisualInfo viNorm;-- 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,- 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, DefaultRootWindow((Display*) win->src.display), win->r.x, win->r.y, win->r.w, win->r.h,- 0, vi->depth, InputOutput, vi->visual,- CWColormap | CWBorderPixel | CWBackPixel | CWEventMask, &swa);-- XFreeColors((Display*) win->src.display, cmap, NULL, 0, 0);-- #ifdef RGFW_OPENGL- XFree(vi);- #endif-- // 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 = "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- 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_majorVersion || RGFW_minorVersion) {- context_attribs[2] = GLX_CONTEXT_MAJOR_VERSION_ARB;- context_attribs[3] = RGFW_majorVersion;- context_attribs[4] = GLX_CONTEXT_MINOR_VERSION_ARB;- context_attribs[5] = RGFW_minorVersion;- }-- glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;- glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)- glXGetProcAddressARB((GLubyte*) "glXCreateContextAttribsARB");-- GLXContext ctx = NULL;-- if (RGFW_root != NULL)- ctx = RGFW_root->src.rSurf;-- win->src.rSurf = glXCreateContextAttribsARB((Display*) win->src.display, bestFbc, ctx, True, context_attribs);-#endif- if (RGFW_root == NULL)- RGFW_root = win;-- 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();- sh->flags = (1L << 4) | (1L << 5);- sh->min_width = sh->max_width = win->r.w;- sh->min_height = sh->max_height = win->r.h;-- XSetWMSizeHints((Display*) win->src.display, (Drawable) win->src.window, sh, XA_WM_NORMAL_HINTS);- XFree(sh);- }-- if (args & RGFW_NO_BORDER) {- RGFW_window_setBorder(win, 0);- }-- 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", False);-- XSetWMProtocols((Display*) win->src.display, (Drawable) win->src.window, &wm_delete_window, 1);-- /* connect the context to the window*/-#ifdef RGFW_OPENGL- if ((args & RGFW_NO_INIT_API) == 0)- glXMakeCurrent((Display*) win->src.display, (Drawable) win->src.window, (GLXContext) win->src.rSurf);-#endif-- /* set the background*/- 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*/-- 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;-- XdndAware = XInternAtom((Display*) win->src.display, "XdndAware", False);- XdndTypeList = XInternAtom((Display*) win->src.display, "XdndTypeList", False);- XdndSelection = XInternAtom((Display*) win->src.display, "XdndSelection", False);-- /* client messages */- XdndEnter = XInternAtom((Display*) win->src.display, "XdndEnter", False);- XdndPosition = XInternAtom((Display*) win->src.display, "XdndPosition", False);- XdndStatus = XInternAtom((Display*) win->src.display, "XdndStatus", False);- XdndLeave = XInternAtom((Display*) win->src.display, "XdndLeave", False);- XdndDrop = XInternAtom((Display*) win->src.display, "XdndDrop", False);- XdndFinished = XInternAtom((Display*) win->src.display, "XdndFinished", False);-- /* actions */- XdndActionCopy = XInternAtom((Display*) win->src.display, "XdndActionCopy", False);- XdndActionMove = XInternAtom((Display*) win->src.display, "XdndActionMove", False);- XdndActionLink = XInternAtom((Display*) win->src.display, "XdndActionLink", False);- XdndActionAsk = XInternAtom((Display*) win->src.display, "XdndActionAsk", False);- XdndActionPrivate = XInternAtom((Display*) win->src.display, "XdndActionPrivate", False);- const Atom version = 5;-- XChangeProperty((Display*) win->src.display, (Window) win->src.window,- XdndAware, 4, 32,- PropModeReplace, (u8*) &version, 1); /* turns on drag and drop */- }-- #ifdef RGFW_EGL- if ((args & RGFW_NO_INIT_API) == 0)- RGFW_createOpenGLContext(win);- #endif-- RGFW_window_setMouseDefault(win);-- RGFW_windowsOpen++;-- return win; /*return newly created window*/- }-- RGFW_area RGFW_getScreenSize(void) {- assert(RGFW_root != NULL);-- Screen* scrn = DefaultScreenOfDisplay((Display*) RGFW_root->src.display);- return RGFW_AREA(scrn->width, scrn->height);- }-- RGFW_vector RGFW_getGlobalMousePoint(void) {- assert(RGFW_root != NULL);-- RGFW_vector RGFWMouse;-- i32 x, y;- u32 z;- Window window1, window2;- XQueryPointer((Display*) RGFW_root->src.display, XDefaultRootWindow((Display*) RGFW_root->src.display), &window1, &window2, &RGFWMouse.x, &RGFWMouse.y, &x, &y, &z);- - return RGFWMouse;- }-- RGFW_vector RGFW_window_getMousePoint(RGFW_window* win) {- assert(win != NULL);-- RGFW_vector 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;- }-- typedef struct XDND {- long source, version;- i32 format;- } XDND; /* data structure for xdnd events */- XDND xdnd;-- int xAxis = 0, yAxis = 0;-- 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] == 0)- 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;- RGFW_jsButtonCallback(win, 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 = i;- RGFW_jsAxisCallback(win, i, win->event.axis, win->event.axisesCount);- return &win->event;-- default: break;- }- }- }- }-#endif-- 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)- XNextEvent((Display*) win->src.display, &E);- else {- return NULL;- }-- u32 i;- win->event.type = 0;--- switch (E.type) {- case KeyPress:- case KeyRelease:- /* 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;- }-- /* set event key data */- KeySym sym = 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 = XKeysymToString(sym);- if (str != NULL)- strncpy(win->event.keyName, str, 16);-- 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;-- XKeyboardState keystate;- XGetKeyboardControl((Display*) win->src.display, &keystate);-- 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; // 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_prev[win->event.button] = RGFW_mouseButtons[win->event.button];- RGFW_mouseButtons[win->event.button] = (E.type == ButtonPress);- RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, (E.type == ButtonPress));- break;-- case MotionNotify:- win->event.point.x = E.xmotion.x;- win->event.point.y = E.xmotion.y;- win->event.type = RGFW_mousePosChanged;- RGFW_mousePosCallback(win, win->event.point);- 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;- }- - /* reset DND values */- if (win->event.droppedFilesCount) {- for (i = 0; i < win->event.droppedFilesCount; i++)- win->event.droppedFiles[i][0] = '\0';- }-- win->event.droppedFilesCount = 0;-- /*- much of this event (drag and drop code) is source from glfw- */-- if ((win->src.winArgs & RGFW_ALLOW_DND) == 0)- break;-- if (E.xclient.message_type == XdndEnter) {- u64 count;- Atom* formats;- Atom real_formats[6];-- Bool list = E.xclient.data.l[1] & 1;-- xdnd.source = E.xclient.data.l[0];- xdnd.version = E.xclient.data.l[1] >> 24;- xdnd.format = None;-- if (xdnd.version > 5)- break;-- if (list) {- Atom actualType;- i32 actualFormat;- u64 bytesAfter;-- XGetWindowProperty((Display*) win->src.display,- xdnd.source,- XdndTypeList,- 0,- LONG_MAX,- False,- 4,- &actualType,- &actualFormat,- (unsigned long*) &count,- (unsigned long*) &bytesAfter,- (u8**) &formats);- } else {- count = 0;-- if (E.xclient.data.l[2] != None)- real_formats[count++] = E.xclient.data.l[2];- if (E.xclient.data.l[3] != None)- real_formats[count++] = E.xclient.data.l[3];- if (E.xclient.data.l[4] != None)- real_formats[count++] = E.xclient.data.l[4];- - formats = real_formats;- }-- u32 i;- for (i = 0; i < 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" };- for (; 1; name++) {- u32 j;- for (j = 0; j < 2; j++) {- if (*links[j] != *name) {- links[j] = (char*) (const char*) "\1";- continue;- }-- if (*links[j] == '\0' && *name == '\0')- xdnd.format = formats[i];-- if (*links[j] != '\0' && *links[j] != '\1')- links[j]++;- }-- if (*name == '\0')- break;- }- }-- if (list) {- XFree(formats);- }-- break;- }- if (E.xclient.message_type == XdndPosition) {- const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff;- const i32 yabs = (E.xclient.data.l[2]) & 0xffff;- Window dummy;- i32 xpos, ypos;-- if (xdnd.version > 5)- break;-- XTranslateCoordinates((Display*) win->src.display,- XDefaultRootWindow((Display*) win->src.display),- (Window) win->src.window,- xabs, yabs,- &xpos, &ypos,- &dummy);-- win->event.point.x = xpos;- win->event.point.y = ypos;-- XEvent reply = { ClientMessage };- reply.xclient.window = xdnd.source;- reply.xclient.message_type = XdndStatus;- reply.xclient.format = 32;- reply.xclient.data.l[0] = (long) win->src.window;- reply.xclient.data.l[2] = 0;- reply.xclient.data.l[3] = 0;-- if (xdnd.format) {- reply.xclient.data.l[1] = 1;- if (xdnd.version >= 2)- reply.xclient.data.l[4] = XdndActionCopy;- }-- XSendEvent((Display*) win->src.display, xdnd.source, False, NoEventMask, &reply);- XFlush((Display*) win->src.display);- break;- }-- if (E.xclient.message_type != XdndDrop)- break;-- if (xdnd.version > 5)- break;-- win->event.type = RGFW_dnd_init;-- if (xdnd.format) {- Time time = CurrentTime;-- if (xdnd.version >= 1)- time = E.xclient.data.l[2];-- XConvertSelection((Display*) win->src.display,- XdndSelection,- xdnd.format,- XdndSelection,- (Window) win->src.window,- time);- } else if (xdnd.version >= 2) {- XEvent reply = { ClientMessage };- reply.xclient.window = xdnd.source;- reply.xclient.message_type = XdndFinished;- reply.xclient.format = 32;- reply.xclient.data.l[0] = (long) win->src.window;- reply.xclient.data.l[1] = 0;- reply.xclient.data.l[2] = None;-- XSendEvent((Display*) win->src.display, xdnd.source,- False, NoEventMask, &reply);- XFlush((Display*) win->src.display);- }-- RGFW_dndInitCallback(win, win->event.point);- break;- case SelectionNotify:- /* this is only for checking for xdnd drops */- if (E.xselection.property != XdndSelection || !(win->src.winArgs | RGFW_ALLOW_DND))- break;-- char* data;- u64 result;-- Atom actualType;- i32 actualFormat;- u64 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);-- if (result == 0)- break;-- /*- SOURCED FROM GLFW _glfwParseUriList- Copyright (c) 2002-2006 Marcus Geelnard- Copyright (c) 2006-2019 Camilla Löwy- */-- const char* prefix = "file://";-- char* line;-- win->event.droppedFilesCount = 0;-- win->event.type = RGFW_dnd;-- while ((line = strtok(data, "\r\n"))) {- char path[RGFW_MAX_PATH];-- data = NULL;-- if (line[0] == '#')- continue;-- char* l;- for (l = line; 1; l++) {- if ((l - line) > 7)- break;- else if (*l != prefix[(l - line)])- break;- else if (*l == '\0' && prefix[(l - line)] == '\0') {- line += 7;- while (*line != '/')- line++;- break;- } else if (*l == '\0')- break;- }-- win->event.droppedFilesCount++;-- size_t index = 0;- while (*line) {- if (line[0] == '%' && line[1] && line[2]) {- const char digits[3] = { line[1], line[2], '\0' };- path[index] = (char) strtol(digits, NULL, 16);- line += 2;- } else- path[index] = *line;-- index++;- line++;- }- path[index] = '\0';- strncpy(win->event.droppedFiles[win->event.droppedFilesCount - 1], path, index + 1);- }-- if (data)- XFree(data);-- if (xdnd.version >= 2) {- XEvent reply = { ClientMessage };- reply.xclient.window = xdnd.source;- reply.xclient.message_type = XdndFinished;- reply.xclient.format = 32;- reply.xclient.data.l[0] = (long) win->src.window;- reply.xclient.data.l[1] = result;- reply.xclient.data.l[2] = XdndActionCopy;-- XSendEvent((Display*) win->src.display, xdnd.source, False, NoEventMask, &reply);- XFlush((Display*) win->src.display);- }-- RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);- break;-- case FocusIn:- win->event.inFocus = 1;- win->event.type = RGFW_focusIn;- RGFW_focusCallback(win, 1);- break;-- break;- case FocusOut:- win->event.inFocus = 0;- win->event.type = RGFW_focusOut;- RGFW_focusCallback(win, 0);- break;- - 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;- }-- 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;- }- }-- XFlush((Display*) win->src.display);-- if (win->event.type)- return &win->event;- else- return NULL;- }-- void RGFW_window_move(RGFW_window* win, RGFW_vector v) {- assert(win != NULL);- win->r.x = v.x;- win->r.y = v.y;-- XMoveWindow((Display*) win->src.display, (Window) win->src.window, v.x, v.y);- }--- void RGFW_window_resize(RGFW_window* win, RGFW_area a) {- assert(win != NULL);- win->r.w = a.w;- win->r.h = a.h;-- XResizeWindow((Display*) win->src.display, (Window) win->src.window, a.w, a.h);- }-- 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;-- XSetWMNormalHints(win->src.display, (Window) win->src.window, &hints);- }-- 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;-- XGetWMNormalHints(win->src.display, (Window) win->src.window, &hints, &flags);-- hints.flags |= PMaxSize;-- hints.max_width = a.w;- hints.max_height = a.h;-- XSetWMNormalHints(win->src.display, (Window) win->src.window, &hints);- }--- void RGFW_window_minimize(RGFW_window* win) {- assert(win != NULL);-- XIconifyWindow(win->src.display, (Window) win->src.window, DefaultScreen(win->src.display));- XFlush(win->src.display);- }-- void RGFW_window_restore(RGFW_window* win) {- assert(win != NULL);-- 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- */-- void RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) {- assert(win != NULL);-- i32 longCount = 2 + a.w * a.h;-- u64* X11Icon = (u64*) RGFW_MALLOC(longCount * sizeof(u64));- u64* target = X11Icon;-- *target++ = a.w;- *target++ = a.h;-- u32 i;-- for (i = 0; i < a.w * a.h; i++) {- if (channels == 3)- *target++ = ((icon[i * 3 + 0]) << 16) |- ((icon[i * 3 + 1]) << 8) |- ((icon[i * 3 + 2]) << 0) |- (0xFF << 24);-- else if (channels == 4)- *target++ = ((icon[i * 4 + 0]) << 16) |- ((icon[i * 4 + 1]) << 8) |- ((icon[i * 4 + 2]) << 0) |- ((icon[i * 4 + 3]) << 24);- }-- static Atom NET_WM_ICON = 0;- if (NET_WM_ICON == 0)- NET_WM_ICON = XInternAtom((Display*) win->src.display, "_NET_WM_ICON", False);-- XChangeProperty((Display*) win->src.display, (Window) win->src.window,- NET_WM_ICON,- 6, 32,- PropModeReplace,- (u8*) X11Icon,- longCount);-- RGFW_FREE(X11Icon);-- XFlush((Display*) win->src.display);- }-- void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) {- assert(win != NULL);--#ifndef RGFW_NO_X11_CURSOR- XcursorImage* native = XcursorImageCreate(a.w, a.h);- native->xhot = 0;- native->yhot = 0;-- u8* source = (u8*) image;- XcursorPixel* target = native->pixels;-- u32 i;- for (i = 0; i < a.w * a.h; i++, target++, source += 4) {- u8 alpha = 0xFF;- if (channels == 4)- alpha = source[3];-- *target = (alpha << 24) | (((source[0] * alpha) / 255) << 16) | (((source[1] * alpha) / 255) << 8) | (((source[2] * alpha) / 255) << 0);- }-- 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) {- assert(win != NULL);-- XEvent event;- XQueryPointer(win->src.display, DefaultRootWindow(win->src.display),- &event.xbutton.root, &event.xbutton.window,- &event.xbutton.x_root, &event.xbutton.y_root,- &event.xbutton.x, &event.xbutton.y,- &event.xbutton.state);-- if (event.xbutton.x == v.x && event.xbutton.y == v.y)- return;-- 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) {- RGFW_UNUSED(win);- }-- void RGFW_window_setMouseDefault(RGFW_window* win) {- RGFW_window_setMouseStandard(win, RGFW_MOUSE_ARROW);- }-- void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {- assert(win != NULL);-- if (mouse > (sizeof(RGFW_mouseIconSrc) / sizeof(u8)))- return;- - mouse = RGFW_mouseIconSrc[mouse];-- Cursor cursor = XCreateFontCursor((Display*) win->src.display, mouse);- XDefineCursor((Display*) win->src.display, (Window) win->src.window, (Cursor) cursor);-- XFreeCursor((Display*) win->src.display, (Cursor) cursor);- }-- void RGFW_window_hide(RGFW_window* win) {- XMapWindow(win->src.display, win->src.window);- }-- void RGFW_window_show(RGFW_window* win) {- XUnmapWindow(win->src.display, win->src.window);- }-- /*- the majority function is sourced from GLFW- */- char* RGFW_readClipboard(size_t* size) {- static Atom UTF8 = 0;- if (UTF8 == 0)- UTF8 = XInternAtom(RGFW_root->src.display, "UTF8_STRING", True);-- XEvent event;- int format;- unsigned long N, sizeN;- char* data, * s = NULL;- Atom target;- Atom CLIPBOARD = 0, XSEL_DATA = 0;-- if (CLIPBOARD == 0) {- CLIPBOARD = XInternAtom(RGFW_root->src.display, "CLIPBOARD", 0);- XSEL_DATA = XInternAtom(RGFW_root->src.display, "XSEL_DATA", 0);- }-- XConvertSelection(RGFW_root->src.display, CLIPBOARD, UTF8, XSEL_DATA, RGFW_root->src.window, CurrentTime);- XSync(RGFW_root->src.display, 0);- XNextEvent(RGFW_root->src.display, &event);-- if (event.type != SelectionNotify || event.xselection.selection != CLIPBOARD || event.xselection.property == 0)- return NULL;-- XGetWindowProperty(event.xselection.display, event.xselection.requestor,- event.xselection.property, 0L, (~0L), 0, AnyPropertyType, &target,- &format, &sizeN, &N, (unsigned char**) &data);-- if (target == UTF8 || target == XA_STRING) {- s = (char*)RGFW_MALLOC(sizeof(char) * sizeN);- strncpy(s, data, sizeN);- s[sizeN] = '\0';- XFree(data);- }-- XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property);-- if (s != NULL && size != NULL)- *size = sizeN;-- return s;- }-- /*- almost all of this function is sourced from GLFW- */- void RGFW_writeClipboard(const char* text, u32 textLen) {- static Atom CLIPBOARD = 0,- UTF8_STRING = 0,- SAVE_TARGETS = 0,- TARGETS = 0,- MULTIPLE = 0,- ATOM_PAIR = 0,- CLIPBOARD_MANAGER = 0;-- if (CLIPBOARD == 0) {- CLIPBOARD = XInternAtom((Display*) RGFW_root->src.display, "CLIPBOARD", False);- UTF8_STRING = XInternAtom((Display*) RGFW_root->src.display, "UTF8_STRING", False);- SAVE_TARGETS = XInternAtom((Display*) RGFW_root->src.display, "SAVE_TARGETS", False);- TARGETS = XInternAtom((Display*) RGFW_root->src.display, "TARGETS", False);- MULTIPLE = XInternAtom((Display*) RGFW_root->src.display, "MULTIPLE", False);- 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;-- const XSelectionRequestEvent* request = &event.xselectionrequest;-- XEvent reply = { SelectionNotify };-- 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,- UTF8_STRING,- XA_STRING };-- XChangeProperty((Display*) RGFW_root->src.display,- request->requestor,- request->property,- 4,- 32,- PropModeReplace,- (u8*) targets,- sizeof(targets) / sizeof(targets[0]));-- reply.xselection.property = request->property;- }-- if (request->target == MULTIPLE) {-- Atom* targets;-- Atom actualType;- i32 actualFormat;- u64 count, bytesAfter;-- 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) {- i32 j;-- for (j = 0; j < formatCount; j++) {- if (targets[i] == formats[j])- break;- }-- if (j < formatCount)- {- XChangeProperty((Display*) RGFW_root->src.display,- request->requestor,- targets[i + 1],- targets[i],- 8,- PropModeReplace,- (u8*) selectionString,- textLen);- } else- targets[i + 1] = None;- }-- XChangeProperty((Display*) RGFW_root->src.display,- request->requestor,- request->property,- ATOM_PAIR,- 32,- PropModeReplace,- (u8*) targets,- count);-- XFree(targets);-- reply.xselection.property = request->property;- }-- reply.xselection.display = request->display;- reply.xselection.requestor = request->requestor;- reply.xselection.selection = request->selection;- reply.xselection.target = request->target;- reply.xselection.time = request->time;-- XSendEvent((Display*) RGFW_root->src.display, request->requestor, False, 0, &reply);- }- }-- 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);-- XWindowAttributes windowAttributes;- XGetWindowAttributes(win->src.display, (Window) win->src.window, &windowAttributes);-- /* check if the window is visable */- if (windowAttributes.map_state != IsViewable)- return 0;-- /* check if the window covers the full screen */- return (windowAttributes.x == 0 && windowAttributes.y == 0 &&- windowAttributes.width == XDisplayWidth(win->src.display, DefaultScreen(win->src.display)) &&- windowAttributes.height == XDisplayHeight(win->src.display, DefaultScreen(win->src.display)));- }-- u8 RGFW_window_isHidden(RGFW_window* win) {- assert(win != NULL);-- XWindowAttributes windowAttributes;- XGetWindowAttributes(win->src.display, (Window) win->src.window, &windowAttributes);-- return (windowAttributes.map_state == IsUnmapped && !RGFW_window_isMinimized(win));- }-- u8 RGFW_window_isMinimized(RGFW_window* win) {- assert(win != NULL);-- static Atom prop = 0;- if (prop == 0)- prop = XInternAtom(win->src.display, "WM_STATE", False);-- Atom actual_type;- i32 actual_format;- u64 nitems, bytes_after;- unsigned char* prop_data;-- i16 status = XGetWindowProperty(win->src.display, (Window) win->src.window, prop, 0, 2, False,- AnyPropertyType, &actual_type, &actual_format,- &nitems, &bytes_after, &prop_data);-- if (status == Success && nitems >= 1 && *((int*) prop_data) == IconicState) {- XFree(prop_data);- return 1;- }-- if (prop_data != NULL)- XFree(prop_data);-- return 0;- }-- u8 RGFW_window_isMaximized(RGFW_window* win) {- assert(win != NULL);-- static Atom net_wm_state = 0;- static Atom net_wm_state_maximized_horz = 0;- static Atom net_wm_state_maximized_vert = 0;-- if (net_wm_state == 0) {- net_wm_state = XInternAtom(win->src.display, "_NET_WM_STATE", False);- net_wm_state_maximized_vert = XInternAtom(win->src.display, "_NET_WM_STATE_MAXIMIZED_VERT", False);- net_wm_state_maximized_horz = XInternAtom(win->src.display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);- }-- Atom actual_type;- i32 actual_format;- u64 nitems, bytes_after;- unsigned char* prop_data;-- i16 status = XGetWindowProperty(win->src.display, (Window) win->src.window, net_wm_state, 0, 1024, False,- XA_ATOM, &actual_type, &actual_format,- &nitems, &bytes_after, &prop_data);-- if (status != Success) {- if (prop_data != NULL)- XFree(prop_data);-- return 0;- }-- Atom* atoms = (Atom*) prop_data;- u64 i;- for (i = 0; i < nitems; ++i) {- if (atoms[i] == net_wm_state_maximized_horz ||- atoms[i] == net_wm_state_maximized_vert) {- XFree(prop_data);- return 1;- }- }-- return 0;- }-- static void XGetSystemContentScale(Display* display, float* xscale, float* yscale) {- float xdpi = 96.f, ydpi = 96.f;--#ifndef RGFW_NO_DPI- char* rms = XResourceManagerString(display);- XrmDatabase db = NULL;-- if (rms && db)- db = XrmGetStringDatabase(rms);-- if (db == 0) {- *xscale = xdpi / 96.f;- *yscale = ydpi / 96.f;- return;- }-- XrmValue value;- char* type = NULL;-- if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && strncmp(type, "String", 7) == 0)- xdpi = ydpi = atof(value.addr);- XrmDestroyDatabase(db);-#endif-- * xscale = xdpi / 96.f;- *yscale = ydpi / 96.f;- }-- RGFW_monitor RGFW_XCreateMonitor(i32 screen) {- RGFW_monitor monitor;-- Display* display = XOpenDisplay(NULL);-- monitor.rect = RGFW_RECT(0, 0, DisplayWidth(display, screen), DisplayHeight(display, screen));- monitor.physW = (monitor.rect.w * 25.4f / 96.f);- monitor.physH = (monitor.rect.h * 25.4f / 96.f);-- strncpy(monitor.name, DisplayString(display), 128);-- XGetSystemContentScale(display, &monitor.scaleX, &monitor.scaleY);-- XRRScreenResources* sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen));-- XRRCrtcInfo* ci = NULL;- int crtc = 0;-- if (sr->ncrtc > crtc) {- ci = XRRGetCrtcInfo(display, sr, sr->crtcs[crtc]);- }-- if (ci == NULL) {- XRRFreeScreenResources(sr);- XCloseDisplay(display);- return monitor;- }-- monitor.rect.x = ci->x;- monitor.rect.y = ci->y;-- XRRFreeCrtcInfo(ci);- XRRFreeScreenResources(sr);-- XCloseDisplay(display);-- return monitor;- }-- RGFW_monitor RGFW_monitors[6];- RGFW_monitor* RGFW_getMonitors(void) {- size_t i;- for (i = 0; i < (size_t)ScreenCount(RGFW_root->src.display) && i < 6; i++)- RGFW_monitors[i] = RGFW_XCreateMonitor(i);-- return RGFW_monitors;- }-- RGFW_monitor RGFW_getPrimaryMonitor(void) {- assert(RGFW_root != NULL);-- i32 primary = -1;- Window root = DefaultRootWindow(RGFW_root->src.display);- XRRScreenResources* res = XRRGetScreenResources(RGFW_root->src.display, root);-- for (int i = 0; i < res->noutput; i++) {- XRROutputInfo* output_info = XRRGetOutputInfo(RGFW_root->src.display, res, res->outputs[i]);- if (output_info->connection == RR_Connected && output_info->crtc) {- XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(RGFW_root->src.display, res, output_info->crtc);- if (crtc_info->mode != None && crtc_info->x == 0 && crtc_info->y == 0) {- primary = i;- XRRFreeCrtcInfo(crtc_info);- XRRFreeOutputInfo(output_info);- break;- }- XRRFreeCrtcInfo(crtc_info);- }- XRRFreeOutputInfo(output_info);- }-- XRRFreeScreenResources(res);-- return RGFW_XCreateMonitor(primary);- }-- RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {- return RGFW_XCreateMonitor(DefaultScreen(win->src.display));- }-- #ifdef RGFW_OPENGL- void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {- assert(win != NULL);-- glXMakeCurrent((Display*) win->src.display, (Drawable) win->src.window, (GLXContext) win->src.rSurf);- }- #endif--- 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- 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->src.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- }-- RGFW_window_checkFPS(win);- }-- #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);- #endif-- win->fpsCap = (swapInterval == 1) ? 0 : swapInterval;- }- #endif--- void RGFW_window_close(RGFW_window* win) {- 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.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*/- - 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 (RGFW_libxshape != NULL && RGFW_windowsOpen <= 0) {- dlclose(RGFW_libxshape);- RGFW_libxshape = NULL;- }-- /* 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 */- }-- 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;- }-/* - End of linux / unix defines-*/--#endif /* RGFW_X11 */---/*-- Start of Windows defines---*/--#ifdef RGFW_WINDOWS- #include <processthreadsapi.h>- #include <wchar.h>- #include <locale.h>- #include <windowsx.h>- #include <shellapi.h>- #include <shellscalingapi.h>- #include <windows.h>- #include <winuser.rh>-- #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-#define GL_BACK 0x0405-#define GL_LEFT 0x0406-#define GL_RIGHT 0x0407--#if defined(RGFW_OSMESA) && defined(RGFW_LINK_OSMESA)-- typedef void (GLAPIENTRY* PFN_OSMesaDestroyContext)(OSMesaContext);- typedef i32(GLAPIENTRY* PFN_OSMesaMakeCurrent)(OSMesaContext, void*, int, int, int);- typedef OSMesaContext(GLAPIENTRY* PFN_OSMesaCreateContext)(GLenum, OSMesaContext);-- PFN_OSMesaMakeCurrent OSMesaMakeCurrentSource;- PFN_OSMesaCreateContext OSMesaCreateContextSource;- PFN_OSMesaDestroyContext OSMesaDestroyContextSource;--#define OSMesaCreateContext OSMesaCreateContextSource-#define OSMesaMakeCurrent OSMesaMakeCurrentSource-#define OSMesaDestroyContext OSMesaDestroyContextSource-#endif-- typedef int (*PFN_wglGetSwapIntervalEXT)(void);- PFN_wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc = NULL;-#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 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_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_COLOR_BITS_ARB 0x2014-#define WGL_RED_BITS_ARB 0x2015-#define WGL_RED_SHIFT_ARB 0x2016-#define WGL_GREEN_BITS_ARB 0x2017-#define WGL_GREEN_SHIFT_ARB 0x2018-#define WGL_BLUE_BITS_ARB 0x2019-#define WGL_BLUE_SHIFT_ARB 0x201a-#define WGL_ALPHA_BITS_ARB 0x201b-#define WGL_ALPHA_SHIFT_ARB 0x201c-#define WGL_ACCUM_BITS_ARB 0x201d-#define WGL_ACCUM_RED_BITS_ARB 0x201e-#define WGL_ACCUM_GREEN_BITS_ARB 0x201f-#define WGL_ACCUM_BLUE_BITS_ARB 0x2020-#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021-#define WGL_DEPTH_BITS_ARB 0x2022-#define WGL_AUX_BUFFERS_ARB 0x2024-#define WGL_STEREO_ARB 0x2012-#define WGL_DEPTH_BITS_ARB 0x2022-#define WGL_STENCIL_BITS_ARB 0x2023-#define WGL_FULL_ACCELERATION_ARB 0x2027-#define WGL_CONTEXT_FLAGS_ARB 0x2094-#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126-#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002-#define WGL_SAMPLE_BUFFERS_ARB 0x2041-#define WGL_SAMPLES_ARB 0x2042-#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9--#ifndef RGFW_EGL-static HMODULE wglinstance = NULL;-#endif--#ifdef RGFW_WGL_LOAD- typedef HGLRC(WINAPI* PFN_wglCreateContext)(HDC);- typedef BOOL(WINAPI* PFN_wglDeleteContext)(HGLRC);- typedef PROC(WINAPI* PFN_wglGetProcAddress)(LPCSTR);- typedef BOOL(WINAPI* PFN_wglMakeCurrent)(HDC, HGLRC);- typedef HDC(WINAPI* PFN_wglGetCurrentDC)();- typedef HGLRC(WINAPI* PFN_wglGetCurrentContext)();-- PFN_wglCreateContext wglCreateContextSRC;- PFN_wglDeleteContext wglDeleteContextSRC;- PFN_wglGetProcAddress wglGetProcAddressSRC;- PFN_wglMakeCurrent wglMakeCurrentSRC;- PFN_wglGetCurrentDC wglGetCurrentDCSRC;- PFN_wglGetCurrentContext wglGetCurrentContextSRC;-- #define wglCreateContext wglCreateContextSRC- #define wglDeleteContext wglDeleteContextSRC- #define wglGetProcAddress wglGetProcAddressSRC- #define wglMakeCurrent wglMakeCurrentSRC-- #define wglGetCurrentDC wglGetCurrentDCSRC- #define wglGetCurrentContext wglGetCurrentContextSRC-#endif--#ifdef RGFW_OPENGL- void* RGFW_getProcAddress(const char* procname) { - void* proc = (void*) wglGetProcAddress(procname);- if (proc)- return proc;-- return (void*) GetProcAddress(wglinstance, procname); - }-- typedef HRESULT (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats);- static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;-#endif-- RGFW_window RGFW_eventWindow;-- LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {- switch (message) {- case WM_MOVE:- RGFW_eventWindow.r.x = LOWORD(lParam);- RGFW_eventWindow.r.y = HIWORD(lParam);- RGFW_eventWindow.src.window = hWnd;- return DefWindowProcA(hWnd, message, wParam, lParam);- case WM_SIZE:- RGFW_eventWindow.r.w = LOWORD(lParam);- RGFW_eventWindow.r.h = HIWORD(lParam);- RGFW_eventWindow.src.window = hWnd;- return DefWindowProcA(hWnd, message, wParam, lParam); // Call DefWindowProc after handling- default:- return DefWindowProcA(hWnd, message, wParam, lParam);- }- }- - #ifndef RGFW_NO_DPI- static HMODULE RGFW_Shcore_dll = NULL;- 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[] = { - "xinput1_4.dll",- "xinput1_3.dll",- "xinput9_1_0.dll",- "xinput1_2.dll",- "xinput1_1.dll"- };-- for (i = 0; i < sizeof(names) / sizeof(const char*); i++) {- RGFW_XInput_dll = LoadLibraryA(names[i]);-- if (RGFW_XInput_dll) {- 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.rSurf = OSMesaCreateContext(OSMESA_RGBA, NULL);- OSMesaMakeCurrent(win->src.rSurf, 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_clipCursor(RGFW_rect rect) {- if (!rect.x && !rect.y && rect.w && !rect.h) {- ClipCursor(NULL);- return;- }-- RECT r = {rect.x, rect.y, rect.x + rect.w, rect.y + rect.h};- ClipCursor(&r);- }-- 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)(void*)GetProcAddress(RGFW_Shcore_dll, "GetDpiForMonitor");- }- #endif-- if (wglinstance == NULL) {- wglinstance = LoadLibraryA("opengl32.dll");-#ifdef RGFW_WGL_LOAD- wglCreateContextSRC = (PFN_wglCreateContext) GetProcAddress(wglinstance, "wglCreateContext");- wglDeleteContextSRC = (PFN_wglDeleteContext) GetProcAddress(wglinstance, "wglDeleteContext");- wglGetProcAddressSRC = (PFN_wglGetProcAddress) GetProcAddress(wglinstance, "wglGetProcAddress");- wglMakeCurrentSRC = (PFN_wglMakeCurrent) GetProcAddress(wglinstance, "wglMakeCurrent");- wglGetCurrentDCSRC = (PFN_wglGetCurrentDC) GetProcAddress(wglinstance, "wglGetCurrentDC");- wglGetCurrentContextSRC = (PFN_wglGetCurrentContext) GetProcAddress(wglinstance, "wglGetCurrentContext");-#endif- }-- timeBeginPeriod(1);-- if (name[0] == 0) name = (char*) " ";-- RGFW_eventWindow.r = RGFW_RECT(-1, -1, -1, -1);- RGFW_eventWindow.src.window = NULL;-- RGFW_window* win = RGFW_window_basic_init(rect, args);-- 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. */- Class.lpszClassName = name;- Class.hInstance = inh;- Class.hCursor = LoadCursor(NULL, IDC_ARROW);- Class.lpfnWndProc = WndProc;-- RegisterClassA(&Class);-- DWORD window_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;-- RECT windowRect, clientRect;-- if (!(args & RGFW_NO_BORDER)) {- window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_VISIBLE | WS_MINIMIZEBOX;-- if (!(args & RGFW_NO_RESIZE))- window_style |= WS_SIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;- } else- window_style |= WS_POPUP | WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX;-- HWND dummyWin = CreateWindowA(Class.lpszClassName, name, window_style, win->r.x, win->r.y, win->r.w, win->r.h, 0, 0, inh, 0);-- GetWindowRect(dummyWin, &windowRect);- GetClientRect(dummyWin, &clientRect);-- 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_ALLOW_DND) {- win->src.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);-- if (FAILED(RGFW_dxInfo.pFactory->lpVtbl->EnumAdapters(RGFW_dxInfo.pFactory, 0, &RGFW_dxInfo.pAdapter))) {- fprintf(stderr, "Failed to enumerate DXGI adapters\n");- RGFW_dxInfo.pFactory->lpVtbl->Release(RGFW_dxInfo.pFactory);- return NULL;- }-- D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0 };-- if (FAILED(D3D11CreateDevice(RGFW_dxInfo.pAdapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, featureLevels, 1, D3D11_SDK_VERSION, &RGFW_dxInfo.pDevice, NULL, &RGFW_dxInfo.pDeviceContext))) {- fprintf(stderr, "Failed to create Direct3D device\n");- RGFW_dxInfo.pAdapter->lpVtbl->Release(RGFW_dxInfo.pAdapter);- RGFW_dxInfo.pFactory->lpVtbl->Release(RGFW_dxInfo.pFactory);- return NULL;- }-- DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 };- swapChainDesc.BufferCount = 1;- swapChainDesc.BufferDesc.Width = win->r.w;- swapChainDesc.BufferDesc.Height = win->r.h;- swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;- swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;- swapChainDesc.OutputWindow = win->src.window;- swapChainDesc.SampleDesc.Count = 1;- swapChainDesc.SampleDesc.Quality = 0;- swapChainDesc.Windowed = TRUE;- RGFW_dxInfo.pFactory->lpVtbl->CreateSwapChain(RGFW_dxInfo.pFactory, (IUnknown*) RGFW_dxInfo.pDevice, &swapChainDesc, &win->src.swapchain);-- ID3D11Texture2D* pBackBuffer;- win->src.swapchain->lpVtbl->GetBuffer(win->src.swapchain, 0, &__uuidof(ID3D11Texture2D), (LPVOID*) &pBackBuffer);- RGFW_dxInfo.pDevice->lpVtbl->CreateRenderTargetView(RGFW_dxInfo.pDevice, (ID3D11Resource*) pBackBuffer, NULL, &win->src.renderTargetView);- pBackBuffer->lpVtbl->Release(pBackBuffer);-- D3D11_TEXTURE2D_DESC depthStencilDesc = { 0 };- depthStencilDesc.Width = win->r.w;- depthStencilDesc.Height = win->r.h;- depthStencilDesc.MipLevels = 1;- depthStencilDesc.ArraySize = 1;- depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;- depthStencilDesc.SampleDesc.Count = 1;- depthStencilDesc.SampleDesc.Quality = 0;- depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;- depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;-- ID3D11Texture2D* pDepthStencilTexture = NULL;- RGFW_dxInfo.pDevice->lpVtbl->CreateTexture2D(RGFW_dxInfo.pDevice, &depthStencilDesc, NULL, &pDepthStencilTexture);-- D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc = { 0 };- depthStencilViewDesc.Format = depthStencilDesc.Format;- depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;- depthStencilViewDesc.Texture2D.MipSlice = 0;-- RGFW_dxInfo.pDevice->lpVtbl->CreateDepthStencilView(RGFW_dxInfo.pDevice, (ID3D11Resource*) pDepthStencilTexture, &depthStencilViewDesc, &win->src.pDepthStencilView);-- pDepthStencilTexture->lpVtbl->Release(pDepthStencilTexture);-- RGFW_dxInfo.pDeviceContext->lpVtbl->OMSetRenderTargets(RGFW_dxInfo.pDeviceContext, 1, &win->src.renderTargetView, win->src.pDepthStencilView);-#endif--#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 = 24,- .cAlphaBits = 8,- .iLayerType = PFD_MAIN_PLANE,- .cDepthBits = 32,- .cStencilBits = 8,- };-- int pixel_format = ChoosePixelFormat(dummy_dc, &pfd);- SetPixelFormat(dummy_dc, pixel_format, &pfd);-- HGLRC dummy_context = wglCreateContext(dummy_dc);- wglMakeCurrent(dummy_dc, dummy_context);-- if (wglChoosePixelFormatARB == NULL) {- wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) (void*) wglGetProcAddress("wglCreateContextAttribsARB");- wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC) (void*)wglGetProcAddress("wglChoosePixelFormatARB");- }-- wglMakeCurrent(dummy_dc, 0);- wglDeleteContext(dummy_context);- ReleaseDC(dummyWin, dummy_dc);-- 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};-- 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);-- 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");- }-- 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");- }- }-- 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);- }-- 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);- }-- SET_ATTRIB(0, 0);-- win->src.rSurf = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs);- } else {- 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);- }- - wglMakeCurrent(win->src.hdc, win->src.rSurf);-#endif- }--#ifdef RGFW_OSMESA-#ifdef RGFW_LINK_OSM ESA- OSMesaMakeCurrentSource = (PFN_OSMesaMakeCurrent) GetProcAddress(win->src.hdc, "OSMesaMakeCurrent");- OSMesaCreateContextSource = (PFN_OSMesaCreateContext) GetProcAddress(win->src.hdc, "OSMesaCreateContext");- OSMesaDestroyContextSource = (PFN_OSMesaDestroyContext) GetProcAddress(win->src.hdc, "OSMesaDestroyContext");-#endif-#endif--#ifdef RGFW_OPENGL- 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.rSurf);- }-#endif-- DestroyWindow(dummyWin);- RGFW_init_buffer(win);--- #ifndef RGFW_NO_MONITOR- if (args & RGFW_SCALE_TO_MONITOR)- RGFW_window_scaleToMonitor(win);- #endif--#ifdef RGFW_EGL- 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.rSurf, win->src.rSurf);- #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) {- POINT p;- GetCursorPos(&p);-- return RGFW_VECTOR(p.x, p.y);- }-- RGFW_vector RGFW_window_getMousePoint(RGFW_window* win) {- POINT p;- GetCursorPos(&p);- ScreenToClient(win->src.window, &p);-- return RGFW_VECTOR(p.x, p.y);- }-- void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {- assert(win != NULL);- win->src.minSize = a;- }-- void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {- assert(win != NULL);- win->src.maxSize = a;- }--- void RGFW_window_minimize(RGFW_window* win) {- assert(win != NULL);-- ShowWindow(win->src.window, SW_MINIMIZE);- }-- void RGFW_window_restore(RGFW_window* win) {- assert(win != NULL);-- ShowWindow(win->src.window, SW_RESTORE);- }--- 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) {- 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];- win->src.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;-#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 &&- state.Gamepad.sThumbLX > -INPUT_DEADZONE) &&- (state.Gamepad.sThumbLY < INPUT_DEADZONE &&- state.Gamepad.sThumbLY > -INPUT_DEADZONE))- {- state.Gamepad.sThumbLX = 0;- state.Gamepad.sThumbLY = 0;- }-- if ((state.Gamepad.sThumbRX < INPUT_DEADZONE &&- state.Gamepad.sThumbRX > -INPUT_DEADZONE) &&- (state.Gamepad.sThumbRY < INPUT_DEADZONE &&- state.Gamepad.sThumbRY > -INPUT_DEADZONE))- {- state.Gamepad.sThumbRX = 0;- state.Gamepad.sThumbRY = 0;- }-- 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);-- 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;-- e->axis[0] = axis1;- e->axis[1] = axis2;-- return 1;- }-- e->axis[0] = axis1;- e->axis[1] = axis2;- }-- return 0;- }-- 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);- }-- 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, &win->event))- return &win->event;-- 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_ACTIVATE:- win->event.inFocus = (LOWORD(msg.wParam) == WA_INACTIVE);-- 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->src.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;- 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);-- 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) & 0x8000) {- ToAscii((UINT) msg.wParam, MapVirtualKey((UINT) msg.wParam, MAPVK_VK_TO_CHAR),- keyboardState, (LPWORD) win->event.keyName, 0);- }-- win->event.type = RGFW_keyPressed;- 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.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->src.winArgs & RGFW_MOUSE_LEFT) {- win->src.winArgs ^= RGFW_MOUSE_LEFT;- win->event.type = RGFW_mouseEnter;- RGFW_mouseNotifyCallBack(win, win->event.point, 1);- }-- break;-- case WM_LBUTTONDOWN:- win->event.button = RGFW_mouseLeft;- RGFW_mouseButtons_prev[win->event.button] = RGFW_mouseButtons[win->event.button];- RGFW_mouseButtons[win->event.button] = 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_prev[win->event.button] = RGFW_mouseButtons[win->event.button];- RGFW_mouseButtons[win->event.button] = 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_prev[win->event.button] = RGFW_mouseButtons[win->event.button];- RGFW_mouseButtons[win->event.button] = 1;- RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);- break;-- case WM_MOUSEWHEEL:- if (msg.wParam > 0)- win->event.button = RGFW_mouseScrollUp;- else- win->event.button = RGFW_mouseScrollDown;-- RGFW_mouseButtons_prev[win->event.button] = RGFW_mouseButtons[win->event.button];- RGFW_mouseButtons[win->event.button] = 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_prev[win->event.button] = RGFW_mouseButtons[win->event.button];- RGFW_mouseButtons[win->event.button] = 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_prev[win->event.button] = RGFW_mouseButtons[win->event.button];- RGFW_mouseButtons[win->event.button] = 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_prev[win->event.button] = RGFW_mouseButtons[win->event.button];- RGFW_mouseButtons[win->event.button] = 0;- RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);- break;-- /*- much of this event is source from glfw- */- case WM_DROPFILES: { - win->event.type = RGFW_dnd_init;-- drop = (HDROP) msg.wParam;- POINT pt;-- /* Move the mouse to the position of the drop */- DragQueryPoint(drop, &pt);-- win->event.point.x = pt.x;- win->event.point.y = pt.y;-- RGFW_dndInitCallback(win, win->event.point);- }- break;- case WM_GETMINMAXINFO:- {- if (win->src.maxSize.w == 0 && win->src.maxSize.h == 0)- break;-- MINMAXINFO* mmi = (MINMAXINFO*) msg.lParam;- mmi->ptMinTrackSize.x = win->src.minSize.w;- mmi->ptMinTrackSize.y = win->src.minSize.h;- mmi->ptMaxTrackSize.x = win->src.maxSize.w;- mmi->ptMaxTrackSize.y = win->src.maxSize.h;- return 0;- }- default:- win->event.type = 0;- break;- }-- TranslateMessage(&msg);- DispatchMessageA(&msg);- }-- else- win->event.type = 0;-- if (!IsWindow(win->src.window)) {- win->event.type = RGFW_quit;- RGFW_windowQuitCallback(win);- }-- if (win->event.type)- return &win->event;- else- return NULL;- }-- u8 RGFW_window_isFullscreen(RGFW_window* win) {- assert(win != NULL);-- WINDOWPLACEMENT placement = { 0 };- GetWindowPlacement(win->src.window, &placement);- return placement.showCmd == SW_SHOWMAXIMIZED;- }-- u8 RGFW_window_isHidden(RGFW_window* win) {- assert(win != NULL);-- return IsWindowVisible(win->src.window) == 0 && !RGFW_window_isMinimized(win);- }-- u8 RGFW_window_isMinimized(RGFW_window* win) {- assert(win != NULL);-- WINDOWPLACEMENT placement = { 0 };- GetWindowPlacement(win->src.window, &placement);- return placement.showCmd == SW_SHOWMINIMIZED;- }-- u8 RGFW_window_isMaximized(RGFW_window* win) {- assert(win != NULL);-- WINDOWPLACEMENT placement = { 0 };- GetWindowPlacement(win->src.window, &placement);- return placement.showCmd == SW_SHOWMAXIMIZED;- }-- typedef struct { int iIndex; HMONITOR hMonitor; } RGFW_mInfo;- BOOL CALLBACK GetMonitorByHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {- RGFW_UNUSED(hdcMonitor)- RGFW_UNUSED(lprcMonitor)-- RGFW_mInfo* info = (RGFW_mInfo*) dwData;- if (info->hMonitor == hMonitor)- return FALSE;-- info->iIndex++;- return TRUE;- }- - #ifndef RGFW_NO_MONITOR- RGFW_monitor win32CreateMonitor(HMONITOR src) {- RGFW_monitor monitor;- MONITORINFO monitorInfo;-- monitorInfo.cbSize = sizeof(MONITORINFO);- GetMonitorInfoA(src, &monitorInfo);-- RGFW_mInfo info;- info.iIndex = 0;- info.hMonitor = src;-- /* get the monitor's index */- if (EnumDisplayMonitors(NULL, NULL, GetMonitorByHandle, (LPARAM) &info)) {- DISPLAY_DEVICEA dd;- dd.cb = sizeof(dd);-- /* loop through the devices until you find a device with the monitor's index */- size_t deviceIndex;- for (deviceIndex = 0; EnumDisplayDevicesA(0, (DWORD) deviceIndex, &dd, 0); deviceIndex++) {- char* deviceName = dd.DeviceName;- if (EnumDisplayDevicesA(deviceName, info.iIndex, &dd, 0)) {- strncpy(monitor.name, dd.DeviceString, 128); /* copy the monitor's name */- break;- }- }- }-- monitor.rect.x = monitorInfo.rcWork.left;- monitor.rect.y = monitorInfo.rcWork.top;- monitor.rect.w = monitorInfo.rcWork.right - monitorInfo.rcWork.left;- monitor.rect.h = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;--#ifndef RGFW_NO_DPI- if (GetDpiForMonitor != NULL) {- u32 x, y;- GetDpiForMonitor(src, MDT_ANGULAR_DPI, &x, &y);- monitor.scaleX = (float) (x) / (float) USER_DEFAULT_SCREEN_DPI;- monitor.scaleY = (float) (y) / (float) USER_DEFAULT_SCREEN_DPI;- }-#endif-- HDC hdc = GetDC(NULL);- /* get pixels per inch */- i32 ppiX = GetDeviceCaps(hdc, LOGPIXELSX);- i32 ppiY = GetDeviceCaps(hdc, LOGPIXELSY);- ReleaseDC(NULL, hdc);-- /* Calculate physical height in inches */- monitor.physW = GetSystemMetrics(SM_CYSCREEN) / (float) ppiX;- monitor.physH = GetSystemMetrics(SM_CXSCREEN) / (float) ppiY;-- 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)- RGFW_UNUSED(lprcMonitor)-- RGFW_mInfo* info = (RGFW_mInfo*) dwData;-- if (info->iIndex >= 6)- return FALSE;-- RGFW_monitors[info->iIndex] = win32CreateMonitor(hMonitor);- info->iIndex++;-- return TRUE;- }-- RGFW_monitor RGFW_getPrimaryMonitor(void) {- return win32CreateMonitor(MonitorFromPoint((POINT) { 0, 0 }, MONITOR_DEFAULTTOPRIMARY));- }-- RGFW_monitor* RGFW_getMonitors(void) {- RGFW_mInfo info;- info.iIndex = 0;- while (EnumDisplayMonitors(NULL, NULL, GetMonitorHandle, (LPARAM) &info));-- return RGFW_monitors;- }-- RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {- HMONITOR src = MonitorFromWindow(win->src.window, MONITOR_DEFAULTTOPRIMARY);- return win32CreateMonitor(src);- }- #endif-- HICON RGFW_loadHandleImage(RGFW_window* win, u8* src, RGFW_area a, BOOL icon) {- assert(win != NULL);-- u32 i;- HDC dc;- HICON handle;- HBITMAP color, mask;- BITMAPV5HEADER bi;- ICONINFO ii;- u8* target = NULL;- u8* source = src;-- ZeroMemory(&bi, sizeof(bi));- bi.bV5Size = sizeof(bi);- bi.bV5Width = a.w;- bi.bV5Height = -((LONG) a.h);- bi.bV5Planes = 1;- bi.bV5BitCount = 32;- bi.bV5Compression = BI_BITFIELDS;- bi.bV5RedMask = 0x00ff0000;- bi.bV5GreenMask = 0x0000ff00;- bi.bV5BlueMask = 0x000000ff;- bi.bV5AlphaMask = 0xff000000;-- dc = GetDC(NULL);- color = CreateDIBSection(dc,- (BITMAPINFO*) &bi,- DIB_RGB_COLORS,- (void**) &target,- NULL,- (DWORD) 0);- ReleaseDC(NULL, dc);-- mask = CreateBitmap(a.w, a.h, 1, 1, NULL);-- for (i = 0; i < a.w * a.h; i++) {- target[0] = source[2];- target[1] = source[1];- target[2] = source[0];- target[3] = source[3];- target += 4;- source += 4;- }-- ZeroMemory(&ii, sizeof(ii));- ii.fIcon = icon;- ii.xHotspot = 0;- ii.yHotspot = 0;- ii.hbmMask = mask;- ii.hbmColor = color;-- handle = CreateIconIndirect(&ii);-- DeleteObject(color);- DeleteObject(mask);-- return handle;- }-- void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) {- assert(win != NULL);- RGFW_UNUSED(channels)-- HCURSOR cursor = (HCURSOR) RGFW_loadHandleImage(win, image, a, FALSE);- SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) cursor);- SetCursor(cursor);- DestroyCursor(cursor);- }-- void RGFW_window_setMouseDefault(RGFW_window* win) {- RGFW_window_setMouseStandard(win, RGFW_MOUSE_ARROW);- }-- void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {- assert(win != NULL);-- 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));- }-- void RGFW_window_hide(RGFW_window* win) {- ShowWindow(win->src.window, SW_HIDE);- }-- void RGFW_window_show(RGFW_window* win) {- ShowWindow(win->src.window, SW_RESTORE);- }-- void RGFW_window_close(RGFW_window* win) {- assert(win != NULL);--#ifdef RGFW_EGL- RGFW_closeEGL(win);-#endif-- if (win == RGFW_root) {-#ifdef RGFW_DIRECTX- RGFW_dxInfo.pDeviceContext->lpVtbl->Release(RGFW_dxInfo.pDeviceContext);- RGFW_dxInfo.pDevice->lpVtbl->Release(RGFW_dxInfo.pDevice);- RGFW_dxInfo.pAdapter->lpVtbl->Release(RGFW_dxInfo.pAdapter);- RGFW_dxInfo.pFactory->lpVtbl->Release(RGFW_dxInfo.pFactory);-#endif- - if (RGFW_XInput_dll != NULL) {- FreeLibrary(RGFW_XInput_dll);- RGFW_XInput_dll = NULL;- }-- #ifndef RGFW_NO_DPI- if (RGFW_Shcore_dll != NULL) {- FreeLibrary(RGFW_Shcore_dll);- RGFW_Shcore_dll = NULL;- }- #endif-- if (wglinstance != NULL) {- FreeLibrary(wglinstance);- wglinstance = NULL;- }-- RGFW_root = NULL;- }--#ifdef RGFW_DIRECTX- win->src.swapchain->lpVtbl->Release(win->src.swapchain);- win->src.renderTargetView->lpVtbl->Release(win->src.renderTargetView);- win->src.pDepthStencilView->lpVtbl->Release(win->src.pDepthStencilView);-#endif--#ifdef RGFW_BUFFER- DeleteDC(win->src.hdcMem);- DeleteObject(win->src.bitmap);-#endif--#ifdef RGFW_OPENGL- wglDeleteContext((HGLRC) win->src.rSurf); /* delete opengl context */-#endif- DeleteDC(win->src.hdc); /* delete device context */- DestroyWindow(win->src.window); /* delete window */--#if defined(RGFW_OSMESA)- if (win->buffer != NULL)- RGFW_FREE(win->buffer);-#endif--#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_FREE(win);- }-- void RGFW_window_move(RGFW_window* win, RGFW_vector v) {- assert(win != NULL);-- win->r.x = v.x;- win->r.y = v.y;- SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, 0, 0, SWP_NOSIZE);- }-- void RGFW_window_resize(RGFW_window* win, RGFW_area a) {- assert(win != NULL);-- win->r.w = a.w;- win->r.h = a.h;- SetWindowPos(win->src.window, HWND_TOP, 0, 0, win->r.w, win->r.h + win->src.hOffset, SWP_NOMOVE);- }--- void RGFW_window_setName(RGFW_window* win, char* name) {- assert(win != 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);-- 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) {- /* Open the clipboard */- if (OpenClipboard(NULL) == 0)- return (char*) "";-- /* Get the clipboard data as a Unicode string */- HANDLE hData = GetClipboardData(CF_UNICODETEXT);- if (hData == NULL) {- CloseClipboard();- return (char*) "";- }-- wchar_t* wstr = (wchar_t*) GlobalLock(hData);-- char* text;-- {- setlocale(LC_ALL, "en_US.UTF-8");-- size_t textLen = wcstombs(NULL, wstr, 0);- if (textLen == 0)- return (char*) "";-- 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 */- GlobalUnlock(hData);- CloseClipboard();-- return text;- }-- void RGFW_writeClipboard(const char* text, u32 textLen) {- HANDLE object;- WCHAR* buffer;-- object = GlobalAlloc(GMEM_MOVEABLE, (1 + textLen) * sizeof(WCHAR));- if (!object)- return;-- buffer = (WCHAR*) GlobalLock(object);- if (!buffer) {- GlobalFree(object);- return;- }-- MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, textLen);- GlobalUnlock(object);-- if (!OpenClipboard(RGFW_root->src.window)) {- GlobalFree(object);- return;- }-- EmptyClipboard();- SetClipboardData(CF_UNICODETEXT, object);- CloseClipboard();- }-- u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber) {- assert(win != NULL);-- RGFW_UNUSED(jsNumber)-- return RGFW_registerJoystickF(win, (char*) "");- }-- u16 RGFW_registerJoystickF(RGFW_window* win, char* file) {- assert(win != NULL);- RGFW_UNUSED(file)-- return win->src.joystickCount - 1;- }-- void RGFW_window_moveMouse(RGFW_window* win, RGFW_vector p) {- assert(win != NULL);-- SetCursorPos(p.x, p.y);- }-- #ifdef RGFW_OPENGL- void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {- assert(win != NULL);- wglMakeCurrent(win->src.hdc, (HGLRC) win->src.rSurf);- }- #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");- 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-- win->fpsCap = (swapInterval == 1) ? 0 : swapInterval;-- }- #endif-- 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- 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->src.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- }-- RGFW_window_checkFPS(win);- }-- char* createUTF8FromWideStringWin32(const WCHAR* source) {- char* target;- i32 size;-- size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL);- if (!size) {- return NULL;- }-- target = (char*) RGFW_CALLOC(size, 1);-- if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL)) {- RGFW_FREE(target);- return NULL;- }-- return target;- }-- u64 RGFW_getTimeNS(void) {- LARGE_INTEGER frequency;- QueryPerformanceFrequency(&frequency);-- LARGE_INTEGER counter;- QueryPerformanceCounter(&counter);-- return (u64) (counter.QuadPart * 1e9 / frequency.QuadPart);- }-- u64 RGFW_getTime(void) {- LARGE_INTEGER frequency;- QueryPerformanceFrequency(&frequency);-- 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); }- void RGFW_cancelThread(RGFW_thread thread) { CloseHandle((HANDLE) thread); }- void RGFW_joinThread(RGFW_thread thread) { WaitForSingleObject((HANDLE) thread, INFINITE); }- void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { SetThreadPriority((HANDLE) thread, priority); }-#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 <CoreVideo/CVDisplayLink.h>-#include <ApplicationServices/ApplicationServices.h>-#include <objc/runtime.h>-#include <objc/message.h>-#include <mach/mach_time.h>-- 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_void_SEL ((void (*)(id, SEL, SEL))objc_msgSend)-#define objc_msgSend_id ((id (*)(id, SEL))objc_msgSend)-- 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 */- 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- };-- 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;--#ifdef RGFW_OPENGL- void* RGFW_getProcAddress(const char* procname) {- if (RGFWnsglFramework == NULL)- RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));-- CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII);-- void* symbol = CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName);-- CFRelease(symbolName);-- return symbol;- }-#endif-- CVReturn displayCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* inNow, const CVTimeStamp* inOutputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) { - RGFW_UNUSED(displayLink) RGFW_UNUSED(inNow) RGFW_UNUSED(inOutputTime) RGFW_UNUSED(flagsIn) RGFW_UNUSED(flagsOut) RGFW_UNUSED(displayLinkContext)- return kCVReturnSuccess; - }-- id NSWindow_delegate(RGFW_window* win) {- return (id) objc_msgSend_id(win->src.window, sel_registerName("delegate"));- }-- u32 RGFW_OnClose(void* self) {- 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;- }-- /* NOTE(EimaMei): Fixes the constant clicking when the app is running under a terminal. */- bool acceptsFirstResponder(void) { return true; }- bool performKeyEquivalent(NSEvent* event) { RGFW_UNUSED(event); return true; }-- NSDragOperation draggingEntered(id self, SEL sel, id sender) { - RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); -- printf("hi\n");- return NSDragOperationCopy; - }- NSDragOperation draggingUpdated(id self, SEL sel, id sender) { - RGFW_UNUSED(sel); -- RGFW_window* win = NULL;- object_getInstanceVariable(self, "RGFW_window", (void*)&win);- if (win == NULL)- return true;- - if (!(win->src.winArgs & RGFW_ALLOW_DND)) {- return false;- }-- 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_VECTOR((u32) p.x, (u32) (win->r.h - p.y));- RGFW_dndInitCallback(win, win->event.point);-- return NSDragOperationCopy; - }- bool prepareForDragOperation(id self) {- RGFW_window* win = NULL;- object_getInstanceVariable(self, "RGFW_window", (void*)&win);- if (win == NULL)- return true;- - if (!(win->src.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; }-- /* NOTE(EimaMei): Usually, you never need 'id self, SEL cmd' for C -> Obj-C methods. This isn't the case. */- bool performDragOperation(id self, SEL sel, id sender) {- RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); -- RGFW_window* win = NULL;- object_getInstanceVariable(self, "RGFW_window", (void*)&win);- if (win == NULL)- return true;-- //NSWindow* window = objc_msgSend_id(sender, sel_registerName("draggingDestinationWindow"));- u32 i;- bool found = 0;-- if (!found)- i = 0;-- Class array[] = { objc_getClass("NSURL"), NULL };- NSPasteboard* pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard"));- - char** droppedFiles = (char**) NSPasteboard_readObjectsForClasses(pasteBoard, array, 1, NULL);-- win->event.droppedFilesCount = si_array_len(droppedFiles);-- u32 y;-- for (y = 0; y < win->event.droppedFilesCount; y++) {- strncpy(win->event.droppedFiles[y], droppedFiles[y], RGFW_MAX_PATH);-- win->event.droppedFiles[y][RGFW_MAX_PATH - 1] = '\0';- }-- win->event.type = RGFW_dnd;- win->src.dndPassed = 0;-- NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));- win->event.point = RGFW_VECTOR((u32) p.x, (u32) (win->r.h - p.y));-- RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);- return true;- }--- NSApplication* NSApp = NULL;-- static void NSMoveToResourceDir(void) {- /* sourced from glfw */- char resourcesPath[255];-- CFBundleRef bundle = CFBundleGetMainBundle();- if (!bundle)- return;-- CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);- CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);-- if (- CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo ||- CFURLGetFileSystemRepresentation(resourcesURL, true, (u8*) resourcesPath, 255) == 0- ) {- CFRelease(last);- CFRelease(resourcesURL);- return;- }-- CFRelease(last);- CFRelease(resourcesURL);-- chdir(resourcesPath);- }--- NSSize RGFW__osxWindowResize(void* self, SEL sel, NSSize frameSize) {- RGFW_UNUSED(sel); -- 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); -- 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;-- win->event.type = RGFW_windowMoved;- RGFW_windowMoveCallback(win, win->r);- }-- 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.rSurf = OSMesaCreateContext(OSMESA_RGBA, NULL);- OSMesaMakeCurrent(win->src.rSurf, 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";-- RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) {- static u8 RGFW_loaded = 0;-- /* NOTE(EimaMei): Why does Apple hate good code? Like wtf, who thought of methods being a great idea???- Imagine a universe, where MacOS had a proper system API (we would probably have like 20% better performance).- */- si_func_to_SEL_with_name("NSObject", "windowShouldClose", RGFW_OnClose);-- /* NOTE(EimaMei): Fixes the 'Boop' sfx from constantly playing each time you click a key. Only a problem when running in the terminal. */- si_func_to_SEL("NSWindow", acceptsFirstResponder);- si_func_to_SEL("NSWindow", performKeyEquivalent);-- if (NSApp == NULL) {- NSApp = objc_msgSend_id((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication"));-- ((void (*)(id, SEL, NSUInteger))objc_msgSend)- (NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular);- }-- RGFW_window* win = RGFW_window_basic_init(rect, args);- - RGFW_window_setMouseDefault(win);-- NSRect windowRect;- windowRect.origin.x = win->r.x;- windowRect.origin.y = win->r.y;- windowRect.size.width = win->r.w;- windowRect.size.height = win->r.h;-- NSBackingStoreType macArgs = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled;-- if (!(args & RGFW_NO_RESIZE))- macArgs |= NSWindowStyleMaskResizable;- if (!(args & RGFW_NO_BORDER))- macArgs |= NSWindowStyleMaskTitled;- else- macArgs = NSWindowStyleMaskBorderless;- {- void* nsclass = objc_getClass("NSWindow");- void* func = sel_registerName("initWithContentRect:styleMask:backing:defer:");-- win->src.window = ((id(*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend)- (NSAlloc(nsclass), func, windowRect, macArgs, macArgs, false);- }-- NSString* str = NSString_stringWithUTF8String(name);- objc_msgSend_void_id(win->src.window, sel_registerName("setTitle:"), str);--#ifdef RGFW_OPENGL- if ((args & RGFW_NO_INIT_API) == 0) {- void* attrs = RGFW_initAttribs(args & RGFW_OPENGL_SOFTWARE);- void* format = NSOpenGLPixelFormat_initWithAttributes(attrs);-- if (format == NULL) {- printf("Failed to load pixel format ");-- void* attrs = RGFW_initAttribs(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((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-#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);- }-- void* contentView = NSWindow_contentView(win->src.window);- objc_msgSend_void_bool(contentView, sel_registerName("setWantsLayer:"), true);-- objc_msgSend_void_id(win->src.window, sel_registerName("setContentView:"), win->src.view);--#ifdef RGFW_OPENGL- if ((args & RGFW_NO_INIT_API) == 0)- objc_msgSend_void(win->src.rSurf, sel_registerName("makeCurrentContext"));-#endif- if (args & RGFW_TRANSPARENT_WINDOW) {-#ifdef RGFW_OPENGL- if ((args & RGFW_NO_INIT_API) == 0) {- i32 opacity = 0;- #define NSOpenGLCPSurfaceOpacity 236- NSOpenGLContext_setValues(win->src.rSurf, &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));- }-- win->src.display = CGMainDisplayID();- CVDisplayLinkCreateWithCGDisplay(win->src.display, (CVDisplayLinkRef*)&win->src.displayLink);- CVDisplayLinkSetOutputCallback(win->src.displayLink, displayCallback, win);- CVDisplayLinkStart(win->src.displayLink);-- RGFW_init_buffer(win);-- #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);-- if (args & RGFW_COCOA_MOVE_TO_RESOURCE_DIR)- 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@:@");- class_addMethod(delegateClass, sel_registerName("draggingUpdated:"), (IMP)draggingUpdated, "l@:@");- class_addMethod(delegateClass, sel_registerName("draggingExited:"), (IMP)RGFW__osxDraggingEnded, "v@:@");- class_addMethod(delegateClass, sel_registerName("draggingEnded:"), (IMP)RGFW__osxDraggingEnded, "v@:@");- class_addMethod(delegateClass, sel_registerName("prepareForDragOperation:"), (IMP)prepareForDragOperation, "B@:@");- class_addMethod(delegateClass, sel_registerName("performDragOperation:"), (IMP)performDragOperation, "B@:@");-- id delegate = objc_msgSend_id(NSAlloc(delegateClass), sel_registerName("init"));-- object_setInstanceVariable(delegate, "RGFW_window", win);-- objc_msgSend_void_id(win->src.window, sel_registerName("setDelegate:"), delegate);-- if (args & RGFW_ALLOW_DND) {- win->src.winArgs |= RGFW_ALLOW_DND;-- NSPasteboardType types[] = {NSPasteboardTypeURL, NSPasteboardTypeFileURL, NSPasteboardTypeString};- NSregisterForDraggedTypes(win->src.window, types, 3);- }-- // Show the window- ((id(*)(id, SEL, SEL))objc_msgSend)(win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL);- objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true);-- if (!RGFW_loaded) {- objc_msgSend_void(win->src.window, sel_registerName("makeMainWindow"));-- RGFW_loaded = 1;- }-- objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow"));-- objc_msgSend_void(NSApp, sel_registerName("finishLaunching"));-- if (RGFW_root == NULL)- RGFW_root = win;-- NSRetain(win->src.window);- NSRetain(NSApp);-- return win;- }-- void RGFW_window_setBorder(RGFW_window* win, u8 border) {- NSBackingStoreType storeType = NSWindowStyleMaskBorderless;- if (!border) {- storeType = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;- }- if (!(win->src.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;-- if (display == 0)- display = CGMainDisplayID();-- return RGFW_AREA(CGDisplayPixelsWide(display), CGDisplayPixelsHigh(display));- }-- RGFW_vector 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 */- }-- RGFW_vector RGFW_window_getMousePoint(RGFW_window* win) {- NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(win->src.window, sel_registerName("mouseLocationOutsideOfEventStream"));-- return RGFW_VECTOR((u32) p.x, (u32) (win->r.h - p.y));- }-- u32 RGFW_keysPressed[10]; /*10 keys at a time*/- typedef NS_ENUM(u32, NSEventType) { /* various types of events */- NSEventTypeLeftMouseDown = 1,- NSEventTypeLeftMouseUp = 2,- NSEventTypeRightMouseDown = 3,- NSEventTypeRightMouseUp = 4,- NSEventTypeMouseMoved = 5,- NSEventTypeLeftMouseDragged = 6,- NSEventTypeRightMouseDragged = 7,- NSEventTypeMouseEntered = 8,- NSEventTypeMouseExited = 9,- NSEventTypeKeyDown = 10,- NSEventTypeKeyUp = 11,- NSEventTypeFlagsChanged = 12,- NSEventTypeAppKitDefined = 13,- NSEventTypeSystemDefined = 14,- NSEventTypeApplicationDefined = 15,- NSEventTypePeriodic = 16,- NSEventTypeCursorUpdate = 17,- NSEventTypeScrollWheel = 22,- NSEventTypeTabletPoint = 23,- NSEventTypeTabletProximity = 24,- NSEventTypeOtherMouseDown = 25,- NSEventTypeOtherMouseUp = 26,- NSEventTypeOtherMouseDragged = 27,- /* The following event types are available on some hardware on 10.5.2 and later */- NSEventTypeGesture API_AVAILABLE(macos(10.5)) = 29,- NSEventTypeMagnify API_AVAILABLE(macos(10.5)) = 30,- NSEventTypeSwipe API_AVAILABLE(macos(10.5)) = 31,- NSEventTypeRotate API_AVAILABLE(macos(10.5)) = 18,- NSEventTypeBeginGesture API_AVAILABLE(macos(10.5)) = 19,- NSEventTypeEndGesture API_AVAILABLE(macos(10.5)) = 20,-- NSEventTypeSmartMagnify API_AVAILABLE(macos(10.8)) = 32,- NSEventTypeQuickLook API_AVAILABLE(macos(10.8)) = 33,-- NSEventTypePressure API_AVAILABLE(macos(10.10.3)) = 34,- NSEventTypeDirectTouch API_AVAILABLE(macos(10.10)) = 37,-- NSEventTypeChangeMode API_AVAILABLE(macos(10.15)) = 38,- };-- typedef NS_ENUM(unsigned long long, NSEventMask) { /* masks for the types of events */- NSEventMaskLeftMouseDown = 1ULL << NSEventTypeLeftMouseDown,- NSEventMaskLeftMouseUp = 1ULL << NSEventTypeLeftMouseUp,- NSEventMaskRightMouseDown = 1ULL << NSEventTypeRightMouseDown,- NSEventMaskRightMouseUp = 1ULL << NSEventTypeRightMouseUp,- NSEventMaskMouseMoved = 1ULL << NSEventTypeMouseMoved,- NSEventMaskLeftMouseDragged = 1ULL << NSEventTypeLeftMouseDragged,- NSEventMaskRightMouseDragged = 1ULL << NSEventTypeRightMouseDragged,- NSEventMaskMouseEntered = 1ULL << NSEventTypeMouseEntered,- NSEventMaskMouseExited = 1ULL << NSEventTypeMouseExited,- NSEventMaskKeyDown = 1ULL << NSEventTypeKeyDown,- NSEventMaskKeyUp = 1ULL << NSEventTypeKeyUp,- NSEventMaskFlagsChanged = 1ULL << NSEventTypeFlagsChanged,- NSEventMaskAppKitDefined = 1ULL << NSEventTypeAppKitDefined,- NSEventMaskSystemDefined = 1ULL << NSEventTypeSystemDefined,- NSEventMaskApplicationDefined = 1ULL << NSEventTypeApplicationDefined,- NSEventMaskPeriodic = 1ULL << NSEventTypePeriodic,- NSEventMaskCursorUpdate = 1ULL << NSEventTypeCursorUpdate,- NSEventMaskScrollWheel = 1ULL << NSEventTypeScrollWheel,- NSEventMaskTabletPoint = 1ULL << NSEventTypeTabletPoint,- NSEventMaskTabletProximity = 1ULL << NSEventTypeTabletProximity,- NSEventMaskOtherMouseDown = 1ULL << NSEventTypeOtherMouseDown,- NSEventMaskOtherMouseUp = 1ULL << NSEventTypeOtherMouseUp,- NSEventMaskOtherMouseDragged = 1ULL << NSEventTypeOtherMouseDragged,- /* The following event masks are available on some hardware on 10.5.2 and later */- NSEventMaskGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeGesture,- NSEventMaskMagnify API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeMagnify,- NSEventMaskSwipe API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeSwipe,- NSEventMaskRotate API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeRotate,- NSEventMaskBeginGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeBeginGesture,- NSEventMaskEndGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeEndGesture,-- /* Note: You can only use these event masks on 64 bit. In other words, you cannot setup a local, nor global, event monitor for these event types on 32 bit. Also, you cannot search the event queue for them (nextEventMatchingMask:...) on 32 bit.- */- NSEventMaskSmartMagnify API_AVAILABLE(macos(10.8)) = 1ULL << NSEventTypeSmartMagnify,- NSEventMaskPressure API_AVAILABLE(macos(10.10.3)) = 1ULL << NSEventTypePressure,- NSEventMaskDirectTouch API_AVAILABLE(macos(10.12.2)) = 1ULL << NSEventTypeDirectTouch,-- NSEventMaskChangeMode API_AVAILABLE(macos(10.15)) = 1ULL << NSEventTypeChangeMode,-- NSEventMaskAny = ULONG_MAX,-- };-- typedef enum NSEventModifierFlags {- NSEventModifierFlagCapsLock = 1 << 16,- NSEventModifierFlagShift = 1 << 17,- NSEventModifierFlagControl = 1 << 18,- NSEventModifierFlagOption = 1 << 19,- NSEventModifierFlagCommand = 1 << 20,- NSEventModifierFlagNumericPad = 1 << 21- } NSEventModifierFlags;-- RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) {- assert(win != NULL);- - if (win->event.type == RGFW_quit)- 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;- }-- static void* eventFunc = NULL;- if (eventFunc == NULL)- eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:");- - if ((win->event.type == RGFW_windowMoved || win->event.type == RGFW_windowResized || win->event.type == RGFW_windowRefresh) && win->event.keyCode != 120) {- win->event.keyCode = 120;- return &win->event;- }-- NSEvent* e = (NSEvent*) ((id(*)(id, SEL, NSEventMask, void*, NSString*, bool))objc_msgSend)- (NSApp, eventFunc, ULONG_MAX, NULL, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);-- if (e == NULL)- 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);-- return NULL;- }-- 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 = 0;-- switch (objc_msgSend_uint(e, sel_registerName("type"))) {- case NSEventTypeMouseEntered: {- win->event.type = RGFW_mouseEnter;- NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow"));-- win->event.point = RGFW_VECTOR((u32) p.x, (u32) (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;- 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].current = 1;-- RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 1);- break;- }-- case NSEventTypeKeyUp: {- 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_keyReleased;- 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].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"));- 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 & 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;- }- }-- RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, win->event.type == RGFW_keyPressed);-- break;- }- case NSEventTypeLeftMouseDragged:- case NSEventTypeOtherMouseDragged:- case NSEventTypeRightMouseDragged:- case NSEventTypeMouseMoved:- win->event.type = RGFW_mousePosChanged;- NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow"));- win->event.point = RGFW_VECTOR((u32) p.x, (u32) (win->r.h - p.y));-- if ((win->src.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"));- - p.x = ((win->r.w / 2)) + p.x;- p.y = ((win->r.h / 2)) + p.y;- win->event.point = RGFW_VECTOR((u32) p.x, (u32) (p.y));- }-- RGFW_mousePosCallback(win, win->event.point);- break;-- case NSEventTypeLeftMouseDown:- win->event.button = RGFW_mouseLeft;- win->event.type = RGFW_mouseButtonPressed;- RGFW_mouseButtons_prev[win->event.button] = RGFW_mouseButtons[win->event.button];- RGFW_mouseButtons[win->event.button] = 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_prev[win->event.button] = RGFW_mouseButtons[win->event.button];- RGFW_mouseButtons[win->event.button] = 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_prev[win->event.button] = RGFW_mouseButtons[win->event.button];- RGFW_mouseButtons[win->event.button] = 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_prev[win->event.button] = RGFW_mouseButtons[win->event.button];- RGFW_mouseButtons[win->event.button] = 0;- RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);- break;-- case NSEventTypeOtherMouseUp:- win->event.button = RGFW_mouseMiddle;- RGFW_mouseButtons_prev[win->event.button] = RGFW_mouseButtons[win->event.button];- RGFW_mouseButtons[win->event.button] = 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_prev[win->event.button] = RGFW_mouseButtons[win->event.button];- RGFW_mouseButtons[win->event.button] = 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) {- win->event.button = RGFW_mouseScrollUp;- }- else if (deltaY < 0) {- win->event.button = RGFW_mouseScrollDown;- }-- RGFW_mouseButtons_prev[win->event.button] = RGFW_mouseButtons[win->event.button];- RGFW_mouseButtons[win->event.button] = 1;-- win->event.scroll = deltaY;-- win->event.type = RGFW_mouseButtonPressed;- RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);- break;- }-- default:- break;- }-- objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);-- return &win->event;- }--- void RGFW_window_move(RGFW_window* win, RGFW_vector 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:"), (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) {- assert(win != 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:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true);- }-- void RGFW_window_minimize(RGFW_window* win) {- assert(win != NULL);-- objc_msgSend_void_SEL(win->src.window, sel_registerName("performMiniaturize:"), NULL);- }-- void RGFW_window_restore(RGFW_window* win) {- assert(win != NULL);-- objc_msgSend_void_SEL(win->src.window, sel_registerName("deminiaturize:"), NULL);- }-- void RGFW_window_setName(RGFW_window* win, char* name) {- assert(win != NULL);-- NSString* str = NSString_stringWithUTF8String(name);- 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:"), (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:"), (NSSize){a.w, a.h});- }-- void RGFW_window_setIcon(RGFW_window* win, u8* data, RGFW_area area, i32 channels) {- assert(win != NULL);-- /* code by EimaMei */- // Make a bitmap representation, then copy the loaded image into it.- void* representation = NSBitmapImageRep_initWithBitmapData(NULL, area.w, area.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, area.w * channels, 8 * channels);- memcpy(NSBitmapImageRep_bitmapData(representation), data, area.w * area.h * channels);-- // Add ze representation.- void* dock_image = NSImage_initWithSize((NSSize){area.w, area.h});- NSImage_addRepresentation(dock_image, (void*) representation);-- // Finally, set the dock image to it.- objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), dock_image);- // Free the garbage.- release(dock_image);- release(representation);- }-- NSCursor* NSCursor_arrowStr(char* str) {- void* nclass = objc_getClass("NSCursor");- void* func = sel_registerName(str);- return (NSCursor*) objc_msgSend_id(nclass, func);- }-- void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) {- assert(win != NULL);-- if (image == NULL) {- objc_msgSend_void(NSCursor_arrowStr("arrowCursor"), sel_registerName("set"));- return;- }-- /* NOTE(EimaMei): Code by yours truly. */- // Make a bitmap representation, then copy the loaded image into it.- void* representation = NSBitmapImageRep_initWithBitmapData(NULL, a.w, a.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, a.w * channels, 8 * channels);- memcpy(NSBitmapImageRep_bitmapData(representation), image, a.w * a.h * channels);-- // Add ze representation.- 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, (NSPoint){0.0, 0.0});-- objc_msgSend_void(cursor, sel_registerName("set"));-- // Free the garbage.- release(cursor_image);- release(representation);- }-- void RGFW_window_setMouseDefault(RGFW_window* win) {- RGFW_window_setMouseStandard(win, RGFW_MOUSE_ARROW);- }-- void RGFW_window_showMouse(RGFW_window* win, i8 show) {- RGFW_UNUSED(win);-- if (show) {- CGDisplayShowCursor(kCGDirectMainDisplay);- }- else {- CGDisplayHideCursor(kCGDirectMainDisplay);- }- }-- 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_clipCursor(RGFW_rect r) { - CGWarpMouseCursorPosition(CGPointMake(r.x + (r.w / 2), r.y + (r.h / 2)));- CGAssociateMouseAndMouseCursorPosition((!r.x && !r.y && r.w && !r.h));- }-- void RGFW_window_moveMouse(RGFW_window* win, RGFW_vector v) {- RGFW_UNUSED(win);-- CGWarpMouseCursorPosition(CGPointMake(v.x, v.y)); - }--- void RGFW_window_hide(RGFW_window* win) {- objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), false);- }-- void RGFW_window_show(RGFW_window* win) {- ((id(*)(id, SEL, SEL))objc_msgSend)(win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL);- objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true);- }-- u8 RGFW_window_isFullscreen(RGFW_window* win) {- assert(win != NULL);-- NSWindowStyleMask mask = (NSWindowStyleMask) objc_msgSend_uint(win->src.window, sel_registerName("styleMask"));- return (mask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen;- }-- u8 RGFW_window_isHidden(RGFW_window* win) {- assert(win != NULL);-- bool visible = objc_msgSend_bool(win->src.window, sel_registerName("isVisible"));- return visible == NO && !RGFW_window_isMinimized(win);- }-- u8 RGFW_window_isMinimized(RGFW_window* win) {- assert(win != NULL);-- return objc_msgSend_bool(win->src.window, sel_registerName("isMiniaturized")) == YES;- }-- u8 RGFW_window_isMaximized(RGFW_window* win) {- assert(win != NULL);-- return objc_msgSend_bool(win->src.window, sel_registerName("isZoomed"));- }-- static RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display) {- RGFW_monitor monitor;-- CGRect bounds = CGDisplayBounds(display);- monitor.rect = RGFW_RECT((int) bounds.origin.x, (int) bounds.origin.y, (int) bounds.size.width, (int) bounds.size.height);-- CGSize screenSizeMM = CGDisplayScreenSize(display);- monitor.physW = screenSizeMM.width / 25.4;- monitor.physH = screenSizeMM.height / 25.4;-- monitor.scaleX = (monitor.rect.w / (screenSizeMM.width)) / 2.6;- monitor.scaleY = (monitor.rect.h / (screenSizeMM.height)) / 2.6;-- snprintf(monitor.name, 128, "%i %i %i", CGDisplayModelNumber(display), CGDisplayVendorNumber(display), CGDisplaySerialNumber(display));-- return monitor;- }--- static RGFW_monitor RGFW_monitors[7];-- RGFW_monitor* RGFW_getMonitors(void) {- static CGDirectDisplayID displays[7];- u32 count;-- if (CGGetActiveDisplayList(6, displays, &count) != kCGErrorSuccess)- return NULL;-- for (u32 i = 0; i < count; i++)- RGFW_monitors[i] = RGFW_NSCreateMonitor(displays[i]);-- return RGFW_monitors;- }-- RGFW_monitor RGFW_getPrimaryMonitor(void) {- CGDirectDisplayID primary = CGMainDisplayID();- return RGFW_NSCreateMonitor(primary);- }-- RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {- return RGFW_NSCreateMonitor(win->src.display);- }-- char* RGFW_readClipboard(size_t* size) {- 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 = clip_len;- return str;- }-- void RGFW_writeClipboard(const char* text, u32 textLen) {- RGFW_UNUSED(textLen);-- NSPasteboardType array[] = { NSPasteboardTypeString, NULL };- NSPasteBoard_declareTypes(NSPasteboard_generalPasteboard(), array, 1, NULL);-- NSPasteBoard_setString(NSPasteboard_generalPasteboard(), text, NSPasteboardTypeString);- }-- u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber) {- RGFW_UNUSED(jsNumber);-- assert(win != NULL);-- return RGFW_registerJoystickF(win, (char*) "");- }-- u16 RGFW_registerJoystickF(RGFW_window* win, char* file) {- RGFW_UNUSED(file);-- assert(win != NULL);-- return win->src.joystickCount - 1;- }-- #ifdef RGFW_OPENGL- void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {- assert(win != NULL);- objc_msgSend_void(win->src.rSurf, 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.rSurf, &swapInterval, 222);- #endif-- win->fpsCap = (swapInterval == 1) ? 0 : swapInterval;- }- #endif- - 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- RGFW_OSMesa_reorganize();- #endif-- RGFW_area area = RGFW_bufferSize;- 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}});-- 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- }-- if (!(win->src.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.rSurf, sel_registerName("flushBuffer"));- #endif- }-- RGFW_window_checkFPS(win);- }-- void RGFW_window_close(RGFW_window* win) {- assert(win != NULL);- release(win->src.view);--#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-- if (RGFW_root == win) {- 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);-#endif-- CVDisplayLinkStop(win->src.displayLink);- CVDisplayLinkRelease(win->src.displayLink);-- 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-*/--/* unix (macOS, linux) only stuff */-#if defined(RGFW_X11) || defined(RGFW_MACOS)-/* unix threading */-#ifndef RGFW_NO_THREADS-#include <pthread.h>-- RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) {- RGFW_UNUSED(args);- - RGFW_thread t;- pthread_create((pthread_t*) &t, NULL, *ptr, NULL);- return t;- }- 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-/* unix sleep */- void RGFW_sleep(u64 ms) {- struct timespec time;- time.tv_sec = 0;- time.tv_nsec = ms * 1e+6;-- nanosleep(&time, NULL);- }--#endif /* end of unix / mac stuff*/-#endif /*RGFW_IMPLEMENTATION*/--#ifdef __cplusplus++ #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, siliapp.h -> referencing ++ stb - This project is heavily inspired by the stb single header files++ GLFW:+ certain parts of winapi and X11 are very poorly documented,+ GLFW's source code was referenced and used throughout the project (used code is marked in some way),+ this mainly includes, code for drag and drops, code for setting the icon to a bitmap and the code for managing the clipboard for X11 (as these parts are not documented very well)++ GLFW Copyright, https::/github.com/GLFW/GLFW++ 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 <stdlib.h>++ #ifndef __USE_POSIX199309+ #define __USE_POSIX199309+ #endif++ #include <time.h>+ #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+#endif++#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) (void)(x);+#endif++#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)+ extern "C" {+#endif++ /* makes sure the header file part is only defined once by default */+#ifndef RGFW_HEADER++#define RGFW_HEADER++#if !defined(u8)+ #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 <stdint.h>++ 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 (!(0))+#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 <emscripten/html5.h>+ #include <emscripten/key_codes.h>+#endif++#if defined(RGFW_X11) && defined(__APPLE__)+ #define RGFW_MACOS_X11+ #undef __APPLE__+#endif++#if defined(_WIN32) && !defined(RGFW_X11) && !defined(RGFW_WEBASM) /* (if you're using X11 on windows some how) */+ #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++ #ifndef RGFW_NO_XINPUT+ #ifdef __MINGW32__ /* try to find the right header */+ #include <xinput.h>+ #else+ #include <XInput.h>+ #endif+ #endif++ #if defined(RGFW_DIRECTX)+ #include <d3d11.h>+ #include <dxgi.h>+ #include <dxgi.h>+ #include <d3dcompiler.h>++ #ifndef __cplusplus+ #define __uuidof(T) IID_##T+ #endif+ #endif++#elif defined(RGFW_WAYLAND)+ #if !defined(RGFW_NO_API) && (!defined(RGFW_BUFFER) || defined(RGFW_OPENGL))+ #define RGFW_EGL+ #define RGFW_OPENGL+ #include <wayland-egl.h>+ #endif++ #include <wayland-client.h>+#elif (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)) && !defined(RGFW_WEBASM)+ #define RGFW_MACOS_X11+ #define RGFW_X11+ #include <X11/Xlib.h>+#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_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 <EGL/egl.h>+#elif defined(RGFW_OSMESA)+ #ifndef __APPLE__+ #include <GL/osmesa.h>+ #else+ #include <OpenGL/osmesa.h>+ #endif+#endif++#if defined(RGFW_OPENGL) && defined(RGFW_X11)+ #ifndef GLX_MESA_swap_control+ #define GLX_MESA_swap_control+ #endif+ #include <GL/glx.h> /* GLX defs, xlib.h, gl.h */+#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 (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*/+#define RGFW_HIDE_MOUSE (1L<<6) /*! the window should hide the mouse or not (can be toggled later on) using `RGFW_window_mouseShow*/+#define RGFW_FULLSCREEN (1L<<8) /* the window is fullscreen by default or not */+#define RGFW_CENTER (1L<<10) /*! center the window on the screen */+#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!!++ 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.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.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 */++ /* 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++ 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*/+#define RGFW_mouseMiddle 2 /*!< mouse-wheel-button is pressed*/+#define RGFW_mouseRight 3 /*!< right mouse button is pressed*/+#define RGFW_mouseScrollUp 4 /*!< mouse wheel is scrolling up*/+#define RGFW_mouseScrollDown 5 /*!< mouse wheel is scrolling down*/++#ifndef RGFW_MAX_PATH+#define RGFW_MAX_PATH 260 /* max length of a path (for dnd) */+#endif+#ifndef RGFW_MAX_DROPS+#define RGFW_MAX_DROPS 260 /* max items you can drop at once */+#endif+++/* for RGFW_Event.lockstate */+#define RGFW_CAPSLOCK (1L << 1)+#define RGFW_NUMLOCK (1L << 2)++/*! joystick button codes (based on xbox/playstation), you may need to change these values per controller */+#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_point+ typedef struct { i32 x, y; } RGFW_point;+#endif++/*! 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 */+#ifndef RGFW_area+ typedef struct { u32 w, h; } RGFW_area;+#endif++#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 */+ } RGFW_monitor;++ /*+ 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) */+ RGFWDEF RGFW_monitor* RGFW_getMonitors(void);+ /*! get the primary monitor */+ RGFWDEF RGFW_monitor RGFW_getPrimaryMonitor(void);+#endif++/* 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;+#else+ char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH]; /*!< dropped files*/+#endif+ u32 droppedFilesCount; /*!< house many files were dropped */++ 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) */++ u8 lockState;+ + u8 button; /* !< which mouse button was pressed */+ double scroll; /*!< the raw mouse scroll value */++ 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) */++ u64 frameTime, frameTime2; /*!< this is used for counting the fps */+} RGFW_Event;++/*! 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 */+ #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;+ #elif defined(RGFW_EGL)+ EGLSurface EGL_surface;+ EGLDisplay EGL_display;+ EGLContext EGL_context;+ #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++#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) + void* bitmap; /*!< API's bitmap for storing or managing */+ void* image;+#endif+#elif defined(RGFW_WEBASM)+ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx;+#endif+} RGFW_window_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 */+#endif+ void* userPtr; /* ptr for usr data */+ + RGFW_Event event; /*!< current event */++ 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 */+#else+ typedef void* RGFW_thread; /*!< thread type for window */+#endif++/** * @defgroup Window_management+* @{ */ +++/*! + * the class name for X11 and WinAPI. apps with the same class will be grouped by the WM+ * by default the class name will == the root window's name+*/+RGFWDEF void RGFW_setClassName(char* name);++/*! 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) */++RGFWDEF 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 */++/*! get the size of the screen to an area struct */+RGFWDEF RGFW_area RGFW_getScreenSize(void);++/*!+ this function checks an *individual* event (and updates window structure attributes)+ this means, using this function without a while loop may cause event lag++ ex.++ while (RGFW_window_checkEvent(win) != NULL) [this keeps checking events until it reaches the last one]++ 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`+*/++RGFWDEF RGFW_Event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/++/*!+ 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+};++/*! sleep until RGFW gets an event or the timer ends (defined by OS) */+RGFWDEF void RGFW_window_eventWait(RGFW_window* win, i32 waitMS);++/*!+ 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);++/*! + Tell RGFW_window_eventWait to stop waiting, to be ran from another thread+*/+RGFWDEF void RGFW_stopCheckEvents(void);++/*! window managment functions*/+RGFWDEF void RGFW_window_close(RGFW_window* win); /*!< close the window and free leftover data */++/*! moves window to a given point */+RGFWDEF void RGFW_window_move(RGFW_window* win,+ RGFW_point v/*!< new pos*/+);++#ifndef RGFW_NO_MONITOR+ /*! move to a specific monitor */+ RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m /* monitor */);+#endif++/*! resize window to a current size/area */+RGFWDEF void RGFW_window_resize(RGFW_window* win, /*!< source window */+ RGFW_area a/*!< new size*/+);++/*! 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);++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)*/++/*! 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);++/*! turn on / off dnd (RGFW_ALLOW_DND stil must be passed to the window)*/+RGFWDEF void RGFW_window_setDND(RGFW_window* win, b8 allow);++#ifndef RGFW_NO_PASSTHROUGH+ /*!! turn on / off mouse passthrough */+ RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough);+#endif ++/*! rename window to a given string */+RGFWDEF void RGFW_window_setName(RGFW_window* win,+ char* name+);++RGFWDEF 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 */++/*!< 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);++/*!< 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);++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 ++ 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);++/*! hide the window */+RGFWDEF void RGFW_window_hide(RGFW_window* win);+/*! show the window */+RGFWDEF void RGFW_window_show(RGFW_window* win);++/*+ 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);++/*! where the mouse is on the screen */+RGFWDEF RGFW_point RGFW_getGlobalMousePoint(void);++/*! where the mouse is on the window */+RGFWDEF RGFW_point RGFW_window_getMousePoint(RGFW_window* win);++/*! 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*/++ /*! NOTE! (for X11/linux) : if you define a window in a thread, it must be run after the original thread's window is created or else there will be a memory error */+ /*+ I'd suggest you use sili's threading functions instead+ if you're going to use sili+ which is a good idea generally+ */++ #if defined(__unix__) || defined(__APPLE__) || defined(RGFW_WEBASM) + typedef void* (* RGFW_threadFunc_ptr)(void*);+ #else+ typedef DWORD (__stdcall *RGFW_threadFunc_ptr) (LPVOID lpThreadParameter); + #endif++ RGFWDEF RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args); /*!< create a thread*/+ RGFWDEF void RGFW_cancelThread(RGFW_thread thread); /*!< cancels a thread*/+ RGFWDEF void RGFW_joinThread(RGFW_thread thread); /*!< join thread to current thread */+ RGFWDEF void RGFW_setThreadPriority(RGFW_thread thread, u8 priority); /*!< sets the priority priority */+#endif++/** @} */ ++/** * @defgroup joystick+* @{ */ ++/*! 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);++RGFWDEF u32 RGFW_isPressedJS(RGFW_window* win, u16 controller, u8 button);++/** @} */ ++/** * @defgroup graphics_API+* @{ */ ++/*!< make the window the current opengl drawing context++ 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);++/*< 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);++/* 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);+RGFWDEF void RGFW_window_setCPURender(RGFW_window* win, i8 set);++/*! 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) */++ /*! 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;+ ID3D11Device* pDevice;+ ID3D11DeviceContext* pDeviceContext;+ } RGFW_directXinfo;++ /*+ RGFW stores a global instance of RGFW_directXinfo,+ you can use this function to get a pointer the instance+ */+ RGFWDEF RGFW_directXinfo* RGFW_getDirectXInfo(void);+#endif++/** @} */ ++/** * @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 :++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"++ 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+*/++#ifdef RGFW_X11+ #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 <stdio.h>+#include <string.h>+#include <math.h>+#include <assert.h>++/*+RGFW_IMPLEMENTATION starts with generic RGFW defines++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_WAYLAND+#include <linux/input-event-codes.h>+#endif++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++ 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,++ 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,++ 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++ 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++#undef RGFW_NEXT+#undef RGFW_MAP++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)) { \+ printf(str); \+ assert(check); \+ } \+}++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;+}+++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);++ /* 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 * (float)win->r.w), (u32)(monitor.scaleX * (float)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 */++#ifdef RGFW_MACOS+RGFWDEF void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer);+RGFWDEF void* RGFW_cocoaGetLayer(void);+#endif++char* RGFW_className = NULL;+void RGFW_setClassName(char* name) {+ RGFW_className = name;+}++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)+ void RGFW_window_showMouse(RGFW_window* win, i8 show) {+ static u8 RGFW_blk[] = { 0, 0, 0, 0 };+ if (show == 0)+ RGFW_window_setMouse(win, RGFW_blk, RGFW_AREA(1, 1), 4);+ else+ RGFW_window_setMouseDefault(win);+ }+#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;+}++#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WEBASM) || defined(RGFW_WAYLAND)+ struct timespec;++ 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);++ void RGFW_window_setDND(RGFW_window* win, b8 allow) {+ if (allow && !(win->_winArgs & RGFW_ALLOW_DND))+ win->_winArgs |= RGFW_ALLOW_DND;++ else if (!allow && (win->_winArgs & RGFW_ALLOW_DND))+ win->_winArgs ^= RGFW_ALLOW_DND;+ }+#endif++/*+ graphics API specific code (end of generic code)+ starts here +*/+++/* + OpenGL defines start here (Normal, EGL, OSMesa)+*/++#if defined(RGFW_OPENGL) || defined(RGFW_EGL) || defined(RGFW_OSMESA)+ #ifdef RGFW_WINDOWS+ #define WIN32_LEAN_AND_MEAN+ #define OEMRESOURCE+ #include <windows.h>+ #endif++ #if !defined(__APPLE__) && !defined(RGFW_NO_GL_HEADER)+ #include <GL/gl.h>+ #elif defined(__APPLE__)+ #ifndef GL_SILENCE_DEPRECATION+ #define GL_SILENCE_DEPRECATION+ #endif+ #include <OpenGL/gl.h>+ #include <OpenGL/OpenGL.h>+ #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 = 0, RGFW_AUX_BUFFERS = 0, RGFW_DOUBLE_BUFFER = 1;+ #else+ i32 RGFW_STENCIL = 0, RGFW_SAMPLES = 0, RGFW_STEREO = 0, RGFW_AUX_BUFFERS = 0, RGFW_DOUBLE_BUFFER = 1;+ #endif+++ void RGFW_setGLStencil(i32 stencil) { RGFW_STENCIL = stencil; }+ 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(b8 profile, i32 major, i32 minor) {+ RGFW_profile = profile;+ RGFW_majorVersion = major;+ RGFW_minorVersion = minor;+ }++/* OPENGL normal only (no EGL / OSMesa) */+#ifndef RGFW_EGL++#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, 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_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++ #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[] = {+ #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,+ #if defined(RGFW_X11) || defined(RGFW_WINDOWS)+ RGFW_GL_DRAW, 1,+ RGFW_GL_RED_SIZE , 8,+ RGFW_GL_GREEN_SIZE , 8,+ RGFW_GL_BLUE_SIZE , 8,+ RGFW_GL_DRAW_TYPE , RGFW_GL_USE_RGBA,+ #endif ++ #ifdef RGFW_X11+ GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,+ #endif ++ #ifdef RGFW_MACOS+ 72,+ 8, 24,+ #endif++ #ifdef RGFW_WINDOWS+ WGL_SUPPORT_OPENGL_ARB, 1,+ WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,+ WGL_COLOR_BITS_ARB, 32,+ #endif++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0+ };++ size_t index = (sizeof(attribs) / sizeof(attribs[0])) - 13;++#define RGFW_GL_ADD_ATTRIB(attrib, attVal) \+ if (attVal) { \+ attribs[index] = attrib;\+ attribs[index + 1] = attVal;\+ index += 2;\+ }+ + 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);++#ifndef RGFW_X11+ RGFW_GL_ADD_ATTRIB(RGFW_GL_SAMPLES, RGFW_SAMPLES);+#endif ++#ifdef RGFW_MACOS+ if (useSoftware) {+ RGFW_GL_ADD_ATTRIB(70, kCGLRendererGenericFloatID);+ } else {+ attribs[index] = RGFW_GL_RENDER_TYPE;+ index += 1;+ }+#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);++ return attribs;+ }++/* EGL only (no OSMesa nor normal OPENGL) */+#elif defined(RGFW_EGL)++#include <EGL/egl.h>++#if defined(RGFW_LINK_EGL)+ typedef EGLBoolean(EGLAPIENTRY* PFN_eglInitialize)(EGLDisplay, EGLint*, EGLint*);++ PFNEGLINITIALIZEPROC eglInitializeSource;+ PFNEGLGETCONFIGSPROC eglGetConfigsSource;+ PFNEGLCHOOSECONFIGPROC eglChooseConfigSource;+ PFNEGLCREATEWINDOWSURFACEPROC eglCreateWindowSurfaceSource;+ PFNEGLCREATECONTEXTPROC eglCreateContextSource;+ PFNEGLMAKECURRENTPROC eglMakeCurrentSource;+ PFNEGLGETDISPLAYPROC eglGetDisplaySource;+ PFNEGLSWAPBUFFERSPROC eglSwapBuffersSource;+ PFNEGLSWAPINTERVALPROC eglSwapIntervalSource;+ PFNEGLBINDAPIPROC eglBindAPISource;+ PFNEGLDESTROYCONTEXTPROC eglDestroyContextSource;+ PFNEGLTERMINATEPROC eglTerminateSource;+ PFNEGLDESTROYSURFACEPROC eglDestroySurfaceSource;++#define eglInitialize eglInitializeSource+#define eglGetConfigs eglGetConfigsSource+#define eglChooseConfig eglChooseConfigSource+#define eglCreateWindowSurface eglCreateWindowSurfaceSource+#define eglCreateContext eglCreateContextSource+#define eglMakeCurrent eglMakeCurrentSource+#define eglGetDisplay eglGetDisplaySource+#define eglSwapBuffers eglSwapBuffersSource+#define eglSwapInterval eglSwapIntervalSource+#define eglBindAPI eglBindAPISource+#define eglDestroyContext eglDestroyContextSource+#define eglTerminate eglTerminateSource+#define eglDestroySurface eglDestroySurfaceSource;+#endif+++#define EGL_SURFACE_MAJOR_VERSION_KHR 0x3098+#define EGL_SURFACE_MINOR_VERSION_KHR 0x30fb++#ifndef RGFW_GL_ADD_ATTRIB+#define RGFW_GL_ADD_ATTRIB(attrib, attVal) \+ if (attVal) { \+ attribs[index] = attrib;\+ attribs[index + 1] = attVal;\+ index += 2;\+ }+#endif+++ void RGFW_createOpenGLContext(RGFW_window* win) {+#if defined(RGFW_LINK_EGL)+ eglInitializeSource = (PFNEGLINITIALIZEPROC) eglGetProcAddress("eglInitialize");+ eglGetConfigsSource = (PFNEGLGETCONFIGSPROC) eglGetProcAddress("eglGetConfigs");+ eglChooseConfigSource = (PFNEGLCHOOSECONFIGPROC) eglGetProcAddress("eglChooseConfig");+ eglCreateWindowSurfaceSource = (PFNEGLCREATEWINDOWSURFACEPROC) eglGetProcAddress("eglCreateWindowSurface");+ eglCreateContextSource = (PFNEGLCREATECONTEXTPROC) eglGetProcAddress("eglCreateContext");+ eglMakeCurrentSource = (PFNEGLMAKECURRENTPROC) eglGetProcAddress("eglMakeCurrent");+ eglGetDisplaySource = (PFNEGLGETDISPLAYPROC) eglGetProcAddress("eglGetDisplay");+ eglSwapBuffersSource = (PFNEGLSWAPBUFFERSPROC) eglGetProcAddress("eglSwapBuffers");+ eglSwapIntervalSource = (PFNEGLSWAPINTERVALPROC) eglGetProcAddress("eglSwapInterval");+ eglBindAPISource = (PFNEGLBINDAPIPROC) eglGetProcAddress("eglBindAPI");+ eglDestroyContextSource = (PFNEGLDESTROYCONTEXTPROC) eglGetProcAddress("eglDestroyContext");+ eglTerminateSource = (PFNEGLTERMINATEPROC) eglGetProcAddress("eglTerminate");+ eglDestroySurfaceSource = (PFNEGLDESTROYSURFACEPROC) eglGetProcAddress("eglDestroySurface");+#endif /* RGFW_LINK_EGL */++ #ifdef RGFW_WINDOWS+ win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.hdc);+ #elif defined(RGFW_MACOS)+ win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType)0);+ #else+ win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display);+ #endif++ EGLint major, minor;++ eglInitialize(win->src.EGL_display, &major, &minor);++ #ifndef EGL_OPENGL_ES1_BIT+ #define EGL_OPENGL_ES1_BIT 0x1+ #endif++ EGLint egl_config[] = {+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,+ EGL_RENDERABLE_TYPE,+ #ifdef RGFW_OPENGL_ES1+ EGL_OPENGL_ES1_BIT,+ #elif defined(RGFW_OPENGL_ES3)+ EGL_OPENGL_ES3_BIT,+ #elif defined(RGFW_OPENGL_ES2)+ EGL_OPENGL_ES2_BIT,+ #else+ EGL_OPENGL_BIT,+ #endif+ EGL_NONE, EGL_NONE+ };++ EGLConfig config;+ EGLint numConfigs;+ eglChooseConfig(win->src.EGL_display, egl_config, &config, 1, &numConfigs);++ #if defined(RGFW_MACOS)+ void* layer = RGFW_cocoaGetLayer(); + + RGFW_window_cocoaSetLayer(win, layer);+ + win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) layer, NULL);+ #else+ win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);+ #endif++ EGLint attribs[] = {+ EGL_CONTEXT_CLIENT_VERSION,+ #ifdef RGFW_OPENGL_ES1+ 1,+ #else+ 2,+ #endif+ 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_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)+ eglBindAPI(EGL_OPENGL_ES_API);+ #else+ eglBindAPI(EGL_OPENGL_API); + #endif+ + 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)+ static HMODULE wglinstance = NULL;+ #endif++ void* RGFW_getProcAddress(const char* procname) { + #if defined(RGFW_WINDOWS)+ void* proc = (void*) GetProcAddress(wglinstance, procname); ++ if (proc)+ return proc;+ #endif++ return (void*) eglGetProcAddress(procname); + }++ void RGFW_closeEGL(RGFW_window* win) {+ eglDestroySurface(win->src.EGL_display, win->src.EGL_surface);+ eglDestroyContext(win->src.EGL_display, win->src.EGL_context);++ 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 */++/* + 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 <linux/joystick.h>+ #include <fcntl.h>+ #include <unistd.h>+ + 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 <X11/Xcursor/Xcursor.h>+#endif+#include <dlfcn.h>++#ifndef RGFW_NO_DPI+#include <X11/extensions/Xrandr.h>+#include <X11/Xresource.h>+#endif++#include <X11/Xutil.h>+#include <X11/Xatom.h>+#include <X11/keysymdef.h>+#include <unistd.h>++#include <X11/XKBlib.h> /* for converting keycode to string */+#include <X11/cursorfont.h> /* for hiding */+#include <X11/extensions/shapeconst.h>+#include <X11/extensions/shape.h>+#include <X11/extensions/XInput2.h>++#include <limits.h> /* for data limits (mainly used in drag and drop functions) */+#include <poll.h>+++#ifdef __linux__+#include <linux/joystick.h>+#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, XtextPlain, XtextUriList;++ Atom wm_delete_window = 0;++#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)+ typedef XcursorImage* (*PFN_XcursorImageCreate)(int, int);+ typedef void (*PFN_XcursorImageDestroy)(XcursorImage*);+ typedef Cursor(*PFN_XcursorImageLoadCursor)(Display*, const XcursorImage*);+#endif+#ifdef RGFW_OPENGL+ 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;+ PFN_XcursorImageDestroy XcursorImageDestroySrc = NULL;++#define XcursorImageLoadCursor XcursorImageLoadCursorSrc+#define XcursorImageCreate XcursorImageCreateSrc+#define XcursorImageDestroy XcursorImageDestroySrc++ void* X11Cursorhandle = NULL;+#endif++ u32 RGFW_windowsOpen = 0;++#ifdef RGFW_OPENGL+ 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) {+#if defined(__CYGWIN__)+ X11Cursorhandle = dlopen("libXcursor-1.so", RTLD_LAZY | RTLD_LOCAL);+#elif defined(__OpenBSD__) || defined(__NetBSD__)+ X11Cursorhandle = dlopen("libXcursor.so", RTLD_LAZY | RTLD_LOCAL);+#else+ X11Cursorhandle = dlopen("libXcursor.so.1", RTLD_LAZY | RTLD_LOCAL);+#endif++ XcursorImageCreateSrc = (PFN_XcursorImageCreate) dlsym(X11Cursorhandle, "XcursorImageCreate");+ XcursorImageDestroySrc = (PFN_XcursorImageDestroy) dlsym(X11Cursorhandle, "XcursorImageDestroy");+ XcursorImageLoadCursorSrc = (PFN_XcursorImageLoadCursor) dlsym(X11Cursorhandle, "XcursorImageLoadCursor");+ }+#endif++#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 | LeaveWindowMask | EnterWindowMask | ExposureMask; /*!< X11 events accepted*/++#ifdef RGFW_OPENGL+ 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 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)+ 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;+ }+ }++ if (best_fbc == -1) {+ printf("Failed to get a valid GLX visual\n");+ return NULL;+ }++ GLXFBConfig bestFbc = fbc[best_fbc];++ /* Get a visual */+ XVisualInfo* vi = glXGetVisualFromFBConfig((Display*) win->src.display, bestFbc);+ + XFree(fbc);+ + if (args & RGFW_TRANSPARENT_WINDOW) {+ XMatchVisualInfo((Display*) win->src.display, DefaultScreen((Display*) win->src.display), 32, TrueColor, vi); /*!< for RGBA backgrounds*/+ }+ +#else+ XVisualInfo viNorm;++ 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,+ 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, DefaultRootWindow((Display*) win->src.display), win->r.x, win->r.y, win->r.w, win->r.h,+ 0, vi->depth, InputOutput, vi->visual,+ CWColormap | CWBorderPixel | CWBackPixel | CWEventMask, &swa);++ XFreeColors((Display*) win->src.display, cmap, NULL, 0, 0);++ #ifdef RGFW_OPENGL+ XFree(vi);+ #endif++ // In your .desktop app, if you set the property+ // StartupWMClass=RGFW that will assoicate the launcher icon+ // with your application - robrohan + + if (RGFW_className == NULL)+ RGFW_className = (char*)name;++ XClassHint *hint = XAllocClassHint();+ assert(hint != NULL);+ hint->res_class = (char*)RGFW_className;+ 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;+ 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;+ context_attribs[4] = GLX_CONTEXT_MINOR_VERSION_ARB;+ context_attribs[5] = RGFW_minorVersion;+ }++ glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;+ glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)+ glXGetProcAddressARB((GLubyte*) "glXCreateContextAttribsARB");++ GLXContext ctx = NULL;++ if (RGFW_root != NULL)+ ctx = RGFW_root->src.ctx;++ 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, vi);+ }+ ++ #ifndef RGFW_NO_MONITOR+ if (args & RGFW_SCALE_TO_MONITOR)+ RGFW_window_scaleToMonitor(win);+ #endif++ if (args & RGFW_CENTER) {+ RGFW_area screenR = RGFW_getScreenSize();+ RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));+ }++ if (args & RGFW_NO_RESIZE) { /* make it so the user can't resize the window*/+ XSizeHints* sh = XAllocSizeHints();+ sh->flags = (1L << 4) | (1L << 5);+ sh->min_width = sh->max_width = win->r.w;+ sh->min_height = sh->max_height = win->r.h;++ XSetWMSizeHints((Display*) win->src.display, (Drawable) win->src.window, sh, XA_WM_NORMAL_HINTS);+ XFree(sh);+ }++ if (args & RGFW_NO_BORDER) {+ RGFW_window_setBorder(win, 0);+ }++ 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", False);++ XSetWMProtocols((Display*) win->src.display, (Drawable) win->src.window, &wm_delete_window, 1);++ /* connect the context to the window*/+#ifdef RGFW_OPENGL+ 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*/++ 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*/++ if (args & RGFW_ALLOW_DND) { /* init drag and drop atoms and turn on drag and drop for this window */+ win->_winArgs |= RGFW_ALLOW_DND;++ XdndTypeList = XInternAtom((Display*) win->src.display, "XdndTypeList", False);+ XdndSelection = XInternAtom((Display*) win->src.display, "XdndSelection", False);++ /* client messages */+ XdndEnter = XInternAtom((Display*) win->src.display, "XdndEnter", False);+ XdndPosition = XInternAtom((Display*) win->src.display, "XdndPosition", False);+ XdndStatus = XInternAtom((Display*) win->src.display, "XdndStatus", False);+ XdndLeave = XInternAtom((Display*) win->src.display, "XdndLeave", False);+ XdndDrop = XInternAtom((Display*) win->src.display, "XdndDrop", False);+ XdndFinished = XInternAtom((Display*) win->src.display, "XdndFinished", False);++ /* actions */+ XdndActionCopy = XInternAtom((Display*) win->src.display, "XdndActionCopy", False);++ XtextUriList = XInternAtom((Display*) win->src.display, "text/uri-list", False); + XtextPlain = XInternAtom((Display*) win->src.display, "text/plain", False);++ XdndAware = XInternAtom((Display*) win->src.display, "XdndAware", False);+ const u8 version = 5;++ XChangeProperty((Display*) win->src.display, (Window) win->src.window,+ XdndAware, 4, 32,+ PropModeReplace, &version, 1); /*!< turns on drag and drop */+ }++ #ifdef RGFW_EGL+ if ((args & RGFW_NO_INIT_API) == 0)+ RGFW_createOpenGLContext(win);+ #endif++ RGFW_window_setMouseDefault(win);++ RGFW_windowsOpen++;++ return win; /*return newly created window*/+ }++ RGFW_area RGFW_getScreenSize(void) {+ assert(RGFW_root != NULL);++ Screen* scrn = DefaultScreenOfDisplay((Display*) RGFW_root->src.display);+ return RGFW_AREA(scrn->width, scrn->height);+ }++ RGFW_point RGFW_getGlobalMousePoint(void) {+ assert(RGFW_root != NULL);++ 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, &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;+ }++ int xAxis = 0, yAxis = 0;++ RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) {+ assert(win != NULL);++ static struct {+ long source, version;+ i32 format;+ } xdnd;++ if (win->event.type == 0) + RGFW_resetKey();++ if (win->event.type == RGFW_quit) {+ return NULL;+ }++ win->event.type = 0;++#ifdef __linux__+ RGFW_Event* event = RGFW_linux_updateJoystick(win);+ if (event != NULL)+ return event;+#endif++ XPending(win->src.display);++ XEvent E; /*!< raw X11 event */++ /* if there is no unread qued events, get a new one */+ 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;+ }++ u32 i;+ win->event.type = 0;+++ switch (E.type) {+ case KeyPress:+ 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*/+ win->event.repeat = RGFW_TRUE;+ }++ /* set event key data */+ 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);++ 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;++ XKeyboardState keystate;+ XGetKeyboardControl((Display*) win->src.display, &keystate);++ 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 = 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: + 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;+ }+ + /* reset DND values */+ if (win->event.droppedFilesCount) {+ for (i = 0; i < win->event.droppedFilesCount; i++)+ win->event.droppedFiles[i][0] = '\0';+ }++ win->event.droppedFilesCount = 0;++ if ((win->_winArgs & RGFW_ALLOW_DND) == 0)+ break;++ XEvent reply = { ClientMessage };+ reply.xclient.window = xdnd.source;+ reply.xclient.format = 32;+ reply.xclient.data.l[0] = (long) win->src.window;+ reply.xclient.data.l[1] = 0;+ reply.xclient.data.l[2] = None;++ if (E.xclient.message_type == XdndEnter) {+ unsigned long count;+ Atom* formats;+ Atom real_formats[6];++ Bool list = E.xclient.data.l[1] & 1;++ xdnd.source = E.xclient.data.l[0];+ xdnd.version = E.xclient.data.l[1] >> 24;+ xdnd.format = None;++ if (xdnd.version > 5)+ break;++ if (list) {+ Atom actualType;+ i32 actualFormat;+ unsigned long bytesAfter;++ XGetWindowProperty((Display*) win->src.display,+ xdnd.source,+ XdndTypeList,+ 0,+ LONG_MAX,+ False,+ 4,+ &actualType,+ &actualFormat,+ &count,+ &bytesAfter,+ (u8**) &formats);+ } else {+ count = 0;++ if (E.xclient.data.l[2] != None)+ real_formats[count++] = E.xclient.data.l[2];+ if (E.xclient.data.l[3] != None)+ real_formats[count++] = E.xclient.data.l[3];+ if (E.xclient.data.l[4] != None)+ real_formats[count++] = E.xclient.data.l[4];+ + formats = real_formats;+ }++ unsigned long i;+ for (i = 0; i < count; i++) {+ if (formats[i] == XtextUriList || formats[i] == XtextPlain) {+ xdnd.format = formats[i];+ break;+ }+ }++ if (list) {+ XFree(formats);+ }++ break;+ }+ if (E.xclient.message_type == XdndPosition) {+ const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff;+ const i32 yabs = (E.xclient.data.l[2]) & 0xffff;+ Window dummy;+ i32 xpos, ypos;++ if (xdnd.version > 5)+ break;++ XTranslateCoordinates((Display*) win->src.display,+ XDefaultRootWindow((Display*) win->src.display),+ (Window) win->src.window,+ xabs, yabs,+ &xpos, &ypos,+ &dummy);++ win->event.point.x = xpos;+ win->event.point.y = ypos;++ reply.xclient.window = xdnd.source;+ reply.xclient.message_type = XdndStatus;++ if (xdnd.format) {+ reply.xclient.data.l[1] = 1;+ if (xdnd.version >= 2)+ reply.xclient.data.l[4] = XdndActionCopy;+ }++ XSendEvent((Display*) win->src.display, xdnd.source, False, NoEventMask, &reply);+ XFlush((Display*) win->src.display);+ break;+ }++ if (E.xclient.message_type != XdndDrop)+ break;++ if (xdnd.version > 5)+ break;++ win->event.type = RGFW_dnd_init;++ if (xdnd.format) {+ Time time = CurrentTime;++ if (xdnd.version >= 1)+ time = E.xclient.data.l[2];++ XConvertSelection((Display*) win->src.display,+ XdndSelection,+ xdnd.format,+ XdndSelection,+ (Window) win->src.window,+ time);+ } else if (xdnd.version >= 2) {+ XEvent reply = { ClientMessage };++ XSendEvent((Display*) win->src.display, xdnd.source,+ False, NoEventMask, &reply);+ XFlush((Display*) win->src.display);+ }++ RGFW_dndInitCallback(win, win->event.point);+ break;+ case SelectionNotify: {+ /* this is only for checking for xdnd drops */+ if (E.xselection.property != XdndSelection || !(win->_winArgs | RGFW_ALLOW_DND))+ break;++ char* data;+ unsigned long result;++ Atom actualType;+ i32 actualFormat;+ 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);++ if (result == 0)+ break;++ /*+ SOURCED FROM GLFW _glfwParseUriList+ Copyright (c) 2002-2006 Marcus Geelnard+ Copyright (c) 2006-2019 Camilla Löwy+ */++ const char* prefix = (const char*)"file://";++ char* line;++ win->event.droppedFilesCount = 0;++ win->event.type = RGFW_dnd;++ while ((line = strtok(data, "\r\n"))) {+ char path[RGFW_MAX_PATH];++ data = NULL;++ if (line[0] == '#')+ continue;++ char* l;+ for (l = line; 1; l++) {+ if ((l - line) > 7)+ break;+ else if (*l != prefix[(l - line)])+ break;+ else if (*l == '\0' && prefix[(l - line)] == '\0') {+ line += 7;+ while (*line != '/')+ line++;+ break;+ } else if (*l == '\0')+ break;+ }++ win->event.droppedFilesCount++;++ size_t index = 0;+ while (*line) {+ if (line[0] == '%' && line[1] && line[2]) {+ const char digits[3] = { line[1], line[2], '\0' };+ path[index] = (char) strtol(digits, NULL, 16);+ line += 2;+ } else+ path[index] = *line;++ index++;+ line++;+ }+ path[index] = '\0';+ strncpy(win->event.droppedFiles[win->event.droppedFilesCount - 1], path, index + 1);+ }++ if (data)+ XFree(data);++ if (xdnd.version >= 2) {+ reply.xclient.message_type = XdndFinished;+ reply.xclient.data.l[1] = result;+ reply.xclient.data.l[2] = XdndActionCopy;++ XSendEvent((Display*) win->src.display, xdnd.source, False, NoEventMask, &reply);+ XFlush((Display*) win->src.display);+ }++ RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);+ break;+ }+ case FocusIn:+ win->event.inFocus = 1;+ win->event.type = RGFW_focusIn;+ RGFW_focusCallback(win, 1);+ break;++ break;+ case FocusOut:+ win->event.inFocus = 0;+ win->event.type = RGFW_focusOut;+ RGFW_focusCallback(win, 0);+ break;+ + 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;+ }++ 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;+ }+ }++ XFlush((Display*) win->src.display);++ if (win->event.type)+ return &win->event;+ else+ return NULL;+ }++ void RGFW_window_move(RGFW_window* win, RGFW_point v) {+ assert(win != NULL);+ win->r.x = v.x;+ win->r.y = v.y;++ XMoveWindow((Display*) win->src.display, (Window) win->src.window, v.x, v.y);+ }+++ void RGFW_window_resize(RGFW_window* win, RGFW_area a) {+ assert(win != NULL);+ win->r.w = a.w;+ win->r.h = a.h;++ XResizeWindow((Display*) win->src.display, (Window) win->src.window, a.w, a.h);+ }++ 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;++ XSetWMNormalHints(win->src.display, (Window) win->src.window, &hints);+ }++ 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;++ XGetWMNormalHints(win->src.display, (Window) win->src.window, &hints, &flags);++ hints.flags |= PMaxSize;++ hints.max_width = a.w;+ hints.max_height = a.h;++ XSetWMNormalHints(win->src.display, (Window) win->src.window, &hints);+ }+++ void RGFW_window_minimize(RGFW_window* win) {+ assert(win != NULL);++ XIconifyWindow(win->src.display, (Window) win->src.window, DefaultScreen(win->src.display));+ XFlush(win->src.display);+ }++ void RGFW_window_restore(RGFW_window* win) {+ assert(win != NULL);++ 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+ */++ void RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) {+ assert(win != NULL);++ i32 longCount = 2 + a.w * a.h;++ u64* X11Icon = (u64*) RGFW_MALLOC(longCount * sizeof(u64));+ u64* target = X11Icon;++ *target++ = a.w;+ *target++ = a.h;++ u32 i;++ for (i = 0; i < a.w * a.h; i++) {+ if (channels == 3)+ *target++ = ((icon[i * 3 + 0]) << 16) |+ ((icon[i * 3 + 1]) << 8) |+ ((icon[i * 3 + 2]) << 0) |+ (0xFF << 24);++ else if (channels == 4)+ *target++ = ((icon[i * 4 + 0]) << 16) |+ ((icon[i * 4 + 1]) << 8) |+ ((icon[i * 4 + 2]) << 0) |+ ((icon[i * 4 + 3]) << 24);+ }++ static Atom NET_WM_ICON = 0;+ if (NET_WM_ICON == 0)+ NET_WM_ICON = XInternAtom((Display*) win->src.display, "_NET_WM_ICON", False);++ XChangeProperty((Display*) win->src.display, (Window) win->src.window,+ NET_WM_ICON,+ 6, 32,+ PropModeReplace,+ (u8*) X11Icon,+ longCount);++ RGFW_FREE(X11Icon);++ XFlush((Display*) win->src.display);+ }++ void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) {+ assert(win != NULL);++#ifndef RGFW_NO_X11_CURSOR+ XcursorImage* native = XcursorImageCreate(a.w, a.h);+ native->xhot = 0;+ native->yhot = 0;++ u8* source = (u8*) image;+ XcursorPixel* target = native->pixels;++ u32 i;+ for (i = 0; i < a.w * a.h; i++, target++, source += 4) {+ u8 alpha = 0xFF;+ if (channels == 4)+ alpha = source[3];++ *target = (alpha << 24) | (((source[0] * alpha) / 255) << 16) | (((source[1] * alpha) / 255) << 8) | (((source[2] * alpha) / 255) << 0);+ }++ 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_point v) {+ assert(win != NULL);++ XEvent event;+ XQueryPointer(win->src.display, DefaultRootWindow(win->src.display),+ &event.xbutton.root, &event.xbutton.window,+ &event.xbutton.x_root, &event.xbutton.y_root,+ &event.xbutton.x, &event.xbutton.y,+ &event.xbutton.state);++ if (event.xbutton.x == v.x && event.xbutton.y == v.y)+ return;++ 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) {+ RGFW_UNUSED(win);+ }++ void RGFW_window_setMouseDefault(RGFW_window* win) {+ RGFW_window_setMouseStandard(win, RGFW_MOUSE_ARROW);+ }++ void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {+ assert(win != NULL);+ + if (mouse > (sizeof(RGFW_mouseIconSrc) / sizeof(u8)))+ return;+ + mouse = RGFW_mouseIconSrc[mouse];++ Cursor cursor = XCreateFontCursor((Display*) win->src.display, mouse);+ XDefineCursor((Display*) win->src.display, (Window) win->src.window, (Cursor) cursor);++ XFreeCursor((Display*) win->src.display, (Cursor) cursor);+ }++ void RGFW_window_hide(RGFW_window* win) {+ XMapWindow(win->src.display, win->src.window);+ }++ void RGFW_window_show(RGFW_window* win) {+ XUnmapWindow(win->src.display, win->src.window);+ }++ /*+ the majority function is sourced from GLFW+ */+ char* RGFW_readClipboard(size_t* size) {+ static Atom UTF8 = 0;+ if (UTF8 == 0)+ UTF8 = XInternAtom(RGFW_root->src.display, "UTF8_STRING", True);++ XEvent event;+ int format;+ unsigned long N, sizeN;+ char* data, * s = NULL;+ Atom target;+ Atom CLIPBOARD = 0, XSEL_DATA = 0;++ if (CLIPBOARD == 0) {+ CLIPBOARD = XInternAtom(RGFW_root->src.display, "CLIPBOARD", 0);+ XSEL_DATA = XInternAtom(RGFW_root->src.display, "XSEL_DATA", 0);+ }++ XConvertSelection(RGFW_root->src.display, CLIPBOARD, UTF8, XSEL_DATA, RGFW_root->src.window, CurrentTime);+ XSync(RGFW_root->src.display, 0);+ XNextEvent(RGFW_root->src.display, &event);++ if (event.type != SelectionNotify || event.xselection.selection != CLIPBOARD || event.xselection.property == 0)+ return NULL;++ XGetWindowProperty(event.xselection.display, event.xselection.requestor,+ event.xselection.property, 0L, (~0L), 0, AnyPropertyType, &target,+ &format, &sizeN, &N, (unsigned char**) &data);++ if (target == UTF8 || target == XA_STRING) {+ s = (char*)RGFW_MALLOC(sizeof(char) * sizeN);+ strncpy(s, data, sizeN);+ s[sizeN] = '\0';+ XFree(data);+ }++ XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property);++ if (s != NULL && size != NULL)+ *size = sizeN;++ return s;+ }++ /*+ almost all of this function is sourced from GLFW+ */+ void RGFW_writeClipboard(const char* text, u32 textLen) {+ static Atom CLIPBOARD = 0,+ UTF8_STRING = 0,+ SAVE_TARGETS = 0,+ TARGETS = 0,+ MULTIPLE = 0,+ ATOM_PAIR = 0,+ CLIPBOARD_MANAGER = 0;++ if (CLIPBOARD == 0) {+ CLIPBOARD = XInternAtom((Display*) RGFW_root->src.display, "CLIPBOARD", False);+ UTF8_STRING = XInternAtom((Display*) RGFW_root->src.display, "UTF8_STRING", False);+ SAVE_TARGETS = XInternAtom((Display*) RGFW_root->src.display, "SAVE_TARGETS", False);+ TARGETS = XInternAtom((Display*) RGFW_root->src.display, "TARGETS", False);+ MULTIPLE = XInternAtom((Display*) RGFW_root->src.display, "MULTIPLE", False);+ 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) {+ break;+ }++ const XSelectionRequestEvent* request = &event.xselectionrequest;++ XEvent reply = { SelectionNotify };+ reply.xselection.property = 0;++ if (request->target == TARGETS) {+ const Atom targets[] = { TARGETS,+ MULTIPLE,+ UTF8_STRING,+ XA_STRING };++ XChangeProperty((Display*) RGFW_root->src.display,+ request->requestor,+ request->property,+ 4,+ 32,+ PropModeReplace,+ (u8*) targets,+ sizeof(targets) / sizeof(targets[0]));++ reply.xselection.property = request->property;+ }++ if (request->target == MULTIPLE) {+ Atom* targets = NULL;++ 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);++ unsigned long i;+ for (i = 0; i < (u32)count; i += 2) {+ if (targets[i] == UTF8_STRING || targets[i] == XA_STRING) {+ XChangeProperty((Display*) RGFW_root->src.display,+ request->requestor,+ targets[i + 1],+ targets[i],+ 8,+ PropModeReplace,+ (u8*) text,+ textLen);+ XFlush(RGFW_root->src.display);+ } else {+ targets[i + 1] = None;+ }+ }++ XChangeProperty((Display*) RGFW_root->src.display,+ request->requestor,+ request->property,+ ATOM_PAIR,+ 32,+ PropModeReplace,+ (u8*) targets,+ count);++ XFlush(RGFW_root->src.display);+ XFree(targets);++ reply.xselection.property = request->property;+ }++ reply.xselection.display = request->display;+ reply.xselection.requestor = request->requestor;+ reply.xselection.selection = request->selection;+ reply.xselection.target = request->target;+ reply.xselection.time = request->time;++ XSendEvent((Display*) RGFW_root->src.display, request->requestor, False, 0, &reply);+ XFlush(RGFW_root->src.display);+ }+ }++ u8 RGFW_window_isFullscreen(RGFW_window* win) {+ assert(win != NULL);++ XWindowAttributes windowAttributes;+ XGetWindowAttributes(win->src.display, (Window) win->src.window, &windowAttributes);++ /* check if the window is visable */+ if (windowAttributes.map_state != IsViewable)+ return 0;++ /* check if the window covers the full screen */+ return (windowAttributes.x == 0 && windowAttributes.y == 0 &&+ windowAttributes.width == XDisplayWidth(win->src.display, DefaultScreen(win->src.display)) &&+ windowAttributes.height == XDisplayHeight(win->src.display, DefaultScreen(win->src.display)));+ }++ u8 RGFW_window_isHidden(RGFW_window* win) {+ assert(win != NULL);++ XWindowAttributes windowAttributes;+ XGetWindowAttributes(win->src.display, (Window) win->src.window, &windowAttributes);++ return (windowAttributes.map_state == IsUnmapped && !RGFW_window_isMinimized(win));+ }++ u8 RGFW_window_isMinimized(RGFW_window* win) {+ assert(win != NULL);++ static Atom prop = 0;+ if (prop == 0)+ prop = XInternAtom(win->src.display, "WM_STATE", False);++ Atom actual_type;+ i32 actual_format;+ unsigned long nitems, bytes_after;+ unsigned char* prop_data;++ i16 status = XGetWindowProperty(win->src.display, (Window) win->src.window, prop, 0, 2, False,+ AnyPropertyType, &actual_type, &actual_format,+ &nitems, &bytes_after, &prop_data);++ if (status == Success && nitems >= 1 && *((int*) prop_data) == IconicState) {+ XFree(prop_data);+ return 1;+ }++ if (prop_data != NULL)+ XFree(prop_data);++ return 0;+ }++ u8 RGFW_window_isMaximized(RGFW_window* win) {+ assert(win != NULL);++ static Atom net_wm_state = 0;+ static Atom net_wm_state_maximized_horz = 0;+ static Atom net_wm_state_maximized_vert = 0;++ if (net_wm_state == 0) {+ net_wm_state = XInternAtom(win->src.display, "_NET_WM_STATE", False);+ net_wm_state_maximized_vert = XInternAtom(win->src.display, "_NET_WM_STATE_MAXIMIZED_VERT", False);+ net_wm_state_maximized_horz = XInternAtom(win->src.display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);+ }++ Atom actual_type;+ i32 actual_format;+ 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,+ XA_ATOM, &actual_type, &actual_format,+ &nitems, &bytes_after, &prop_data);++ if (status != Success) {+ if (prop_data != NULL)+ XFree(prop_data);++ return 0;+ }++ Atom* atoms = (Atom*) prop_data;+ u64 i;+ for (i = 0; i < nitems; ++i) {+ if (atoms[i] == net_wm_state_maximized_horz ||+ atoms[i] == net_wm_state_maximized_vert) {+ XFree(prop_data);+ return 1;+ }+ }++ return 0;+ }++ static void XGetSystemContentScale(Display* display, float* xscale, float* yscale) {+ float xdpi = 96.f, ydpi = 96.f;++#ifndef RGFW_NO_DPI+ char* rms = XResourceManagerString(display);+ XrmDatabase db = NULL;++ if (rms && db)+ db = XrmGetStringDatabase(rms);++ if (db == 0) {+ *xscale = xdpi / 96.f;+ *yscale = ydpi / 96.f;+ return;+ }++ XrmValue value;+ char* type = NULL;++ if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && strncmp(type, "String", 7) == 0)+ xdpi = ydpi = atof(value.addr);+ XrmDestroyDatabase(db);+#endif++ * xscale = xdpi / 96.f;+ *yscale = ydpi / 96.f;+ }++ RGFW_monitor RGFW_XCreateMonitor(i32 screen) {+ RGFW_monitor monitor;++ Display* display = XOpenDisplay(NULL);+ + RGFW_area size = RGFW_getScreenSize();++ monitor.rect = RGFW_RECT(0, 0, size.w, size.h);+ monitor.physW = DisplayWidthMM(display, screen);+ monitor.physH = DisplayHeightMM(display, screen);+ + XGetSystemContentScale(display, &monitor.scaleX, &monitor.scaleY);+ XRRScreenResources* sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen));++ XRRCrtcInfo* ci = NULL;+ int crtc = screen;++ if (sr->ncrtc > crtc) {+ ci = XRRGetCrtcInfo(display, sr, sr->crtcs[crtc]);+ }+ + if (ci == NULL) {+ float dpi_width = round((double)monitor.rect.w/(((double)monitor.physW)/25.4));+ float dpi_height = round((double)monitor.rect.h/(((double)monitor.physH)/25.4));+ + monitor.scaleX = (float) (dpi_width) / (float) 96;+ monitor.scaleY = (float) (dpi_height) / (float) 96;+ XRRFreeScreenResources(sr);+ XCloseDisplay(display);+ return monitor;+ }+ + XRROutputInfo* info = XRRGetOutputInfo (display, sr, sr->outputs[screen]);+ monitor.physW = info->mm_width;+ monitor.physH = info->mm_height;++ monitor.rect.x = ci->x;+ monitor.rect.y = ci->y;+ monitor.rect.w = ci->width;+ monitor.rect.h = ci->height;+ + float dpi_width = round((double)monitor.rect.w/(((double)monitor.physW)/25.4));+ float dpi_height = round((double)monitor.rect.h/(((double)monitor.physH)/25.4));++ monitor.scaleX = (float) (dpi_width) / (float) 96;+ monitor.scaleY = (float) (dpi_height) / (float) 96; ++ if (monitor.scaleX > 1 && monitor.scaleX < 1.1)+ monitor.scaleX = 1;++ if (monitor.scaleY > 1 && monitor.scaleY < 1.1)+ monitor.scaleY = 1;++ XRRFreeCrtcInfo(ci);+ XRRFreeScreenResources(sr);++ XCloseDisplay(display);++ return monitor;+ }++ RGFW_monitor RGFW_monitors[6];+ RGFW_monitor* RGFW_getMonitors(void) {+ size_t i;+ for (i = 0; i < (size_t)ScreenCount(RGFW_root->src.display) && i < 6; i++)+ RGFW_monitors[i] = RGFW_XCreateMonitor(i);++ return RGFW_monitors;+ }++ RGFW_monitor RGFW_getPrimaryMonitor(void) {+ assert(RGFW_root != NULL);++ i32 primary = -1;+ Window root = DefaultRootWindow(RGFW_root->src.display);+ XRRScreenResources* res = XRRGetScreenResources(RGFW_root->src.display, root);++ for (int i = 0; i < res->noutput; i++) {+ XRROutputInfo* output_info = XRRGetOutputInfo(RGFW_root->src.display, res, res->outputs[i]);+ if (output_info->connection == RR_Connected && output_info->crtc) {+ XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(RGFW_root->src.display, res, output_info->crtc);+ if (crtc_info->mode != None && crtc_info->x == 0 && crtc_info->y == 0) {+ primary = i;+ XRRFreeCrtcInfo(crtc_info);+ XRRFreeOutputInfo(output_info);+ break;+ }+ XRRFreeCrtcInfo(crtc_info);+ }+ XRRFreeOutputInfo(output_info);+ }++ XRRFreeScreenResources(res);++ return RGFW_XCreateMonitor(primary);+ }++ RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {+ return RGFW_XCreateMonitor(DefaultScreen(win->src.display));+ }++ #ifdef RGFW_OPENGL+ void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {+ if (win == NULL)+ glXMakeCurrent((Display*) NULL, (Drawable)NULL, (GLXContext) NULL);+ else+ 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+ }+ }++ #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 <fcntl.h>+#include <poll.h>+#include <unistd.h>+ 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 <errno.h>+ #include <unistd.h>+ #include <sys/mman.h>+ #include <xkbcommon/xkbcommon.h>+ #include <xkbcommon/xkbcommon-keysyms.h>+ #include <dirent.h>+ #include <linux/kd.h> + #include <wayland-cursor.h>++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];++ 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_CENTER) {+ RGFW_area screenR = RGFW_getScreenSize();+ RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));+ }++ 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 <windows.h>+ + #include <processthreadsapi.h>+ #include <wchar.h>+ #include <locale.h>+ #include <windowsx.h>+ #include <shellapi.h>+ #include <shellscalingapi.h>++ #include <winuser.h>++ __declspec(dllimport) int __stdcall WideCharToMultiByte( UINT CodePage, DWORD dwFlags, const WCHAR* lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar);+ + #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+#define GL_BACK 0x0405+#define GL_LEFT 0x0406+#define GL_RIGHT 0x0407++#if defined(RGFW_OSMESA) && defined(RGFW_LINK_OSMESA)++ typedef void (GLAPIENTRY* PFN_OSMesaDestroyContext)(OSMesaContext);+ typedef i32(GLAPIENTRY* PFN_OSMesaMakeCurrent)(OSMesaContext, void*, int, int, int);+ typedef OSMesaContext(GLAPIENTRY* PFN_OSMesaCreateContext)(GLenum, OSMesaContext);++ PFN_OSMesaMakeCurrent OSMesaMakeCurrentSource;+ PFN_OSMesaCreateContext OSMesaCreateContextSource;+ PFN_OSMesaDestroyContext OSMesaDestroyContextSource;++#define OSMesaCreateContext OSMesaCreateContextSource+#define OSMesaMakeCurrent OSMesaMakeCurrentSource+#define OSMesaDestroyContext OSMesaDestroyContextSource+#endif++ typedef int (*PFN_wglGetSwapIntervalEXT)(void);+ PFN_wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc = NULL;+#define wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc+++ void* RGFWjoystickApi = NULL;++ /* these two wgl functions need to be preloaded */+ 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_DRAW_TO_WINDOW_ARB 0x2001+#define WGL_ACCELERATION_ARB 0x2003+#define WGL_NO_ACCELERATION_ARB 0x2025+#define WGL_DOUBLE_BUFFER_ARB 0x2011+#define WGL_COLOR_BITS_ARB 0x2014+#define WGL_RED_BITS_ARB 0x2015+#define WGL_RED_SHIFT_ARB 0x2016+#define WGL_GREEN_BITS_ARB 0x2017+#define WGL_GREEN_SHIFT_ARB 0x2018+#define WGL_BLUE_BITS_ARB 0x2019+#define WGL_BLUE_SHIFT_ARB 0x201a+#define WGL_ALPHA_BITS_ARB 0x201b+#define WGL_ALPHA_SHIFT_ARB 0x201c+#define WGL_ACCUM_BITS_ARB 0x201d+#define WGL_ACCUM_RED_BITS_ARB 0x201e+#define WGL_ACCUM_GREEN_BITS_ARB 0x201f+#define WGL_ACCUM_BLUE_BITS_ARB 0x2020+#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021+#define WGL_DEPTH_BITS_ARB 0x2022+#define WGL_AUX_BUFFERS_ARB 0x2024+#define WGL_STEREO_ARB 0x2012+#define WGL_DEPTH_BITS_ARB 0x2022+#define WGL_STENCIL_BITS_ARB 0x2023+#define WGL_FULL_ACCELERATION_ARB 0x2027+#define WGL_CONTEXT_FLAGS_ARB 0x2094+#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126+#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002+#define WGL_SAMPLE_BUFFERS_ARB 0x2041+#define WGL_SAMPLES_ARB 0x2042+#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9++#ifndef RGFW_EGL+static HMODULE wglinstance = NULL;+#endif++#ifdef RGFW_WGL_LOAD+ typedef HGLRC(WINAPI* PFN_wglCreateContext)(HDC);+ typedef BOOL(WINAPI* PFN_wglDeleteContext)(HGLRC);+ typedef PROC(WINAPI* PFN_wglGetProcAddress)(LPCSTR);+ typedef BOOL(WINAPI* PFN_wglMakeCurrent)(HDC, HGLRC);+ typedef HDC(WINAPI* PFN_wglGetCurrentDC)();+ typedef HGLRC(WINAPI* PFN_wglGetCurrentContext)();++ PFN_wglCreateContext wglCreateContextSRC;+ PFN_wglDeleteContext wglDeleteContextSRC;+ PFN_wglGetProcAddress wglGetProcAddressSRC;+ PFN_wglMakeCurrent wglMakeCurrentSRC;+ PFN_wglGetCurrentDC wglGetCurrentDCSRC;+ PFN_wglGetCurrentContext wglGetCurrentContextSRC;++ #define wglCreateContext wglCreateContextSRC+ #define wglDeleteContext wglDeleteContextSRC+ #define wglGetProcAddress wglGetProcAddressSRC+ #define wglMakeCurrent wglMakeCurrentSRC++ #define wglGetCurrentDC wglGetCurrentDCSRC+ #define wglGetCurrentContext wglGetCurrentContextSRC+#endif++#ifdef RGFW_OPENGL+ void* RGFW_getProcAddress(const char* procname) { + void* proc = (void*) wglGetProcAddress(procname);+ if (proc)+ return proc;++ return (void*) GetProcAddress(wglinstance, procname); + }++ typedef HRESULT (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats);+ static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;+#endif++ RGFW_window RGFW_eventWindow;++ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {+ switch (message) {+ case WM_MOVE:+ RGFW_eventWindow.r.x = LOWORD(lParam);+ RGFW_eventWindow.r.y = HIWORD(lParam);+ RGFW_eventWindow.src.window = hWnd;+ return DefWindowProcA(hWnd, message, wParam, lParam);+ case WM_SIZE:+ RGFW_eventWindow.r.w = LOWORD(lParam);+ RGFW_eventWindow.r.h = HIWORD(lParam);+ RGFW_eventWindow.src.window = hWnd;+ return DefWindowProcA(hWnd, message, wParam, lParam); // Call DefWindowProc after handling+ default:+ return DefWindowProcA(hWnd, message, wParam, lParam);+ }+ }+ + #ifndef RGFW_NO_DPI+ static HMODULE RGFW_Shcore_dll = NULL;+ 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[] = { + "xinput1_4.dll",+ "xinput1_3.dll",+ "xinput9_1_0.dll",+ "xinput1_2.dll",+ "xinput1_1.dll"+ };++ for (i = 0; i < sizeof(names) / sizeof(const char*); i++) {+ RGFW_XInput_dll = LoadLibraryA(names[i]);++ if (RGFW_XInput_dll) {+ 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) {+ RGFW_UNUSED(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); RGFW_UNUSED(rect);++ 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)(void*)GetProcAddress(RGFW_Shcore_dll, "GetDpiForMonitor");+ SetProcessDPIAware();+ }+ #endif++ if (wglinstance == NULL) {+ wglinstance = LoadLibraryA("opengl32.dll");+#ifdef RGFW_WGL_LOAD+ wglCreateContextSRC = (PFN_wglCreateContext) GetProcAddress(wglinstance, "wglCreateContext");+ wglDeleteContextSRC = (PFN_wglDeleteContext) GetProcAddress(wglinstance, "wglDeleteContext");+ wglGetProcAddressSRC = (PFN_wglGetProcAddress) GetProcAddress(wglinstance, "wglGetProcAddress");+ wglMakeCurrentSRC = (PFN_wglMakeCurrent) GetProcAddress(wglinstance, "wglMakeCurrent");+ wglGetCurrentDCSRC = (PFN_wglGetCurrentDC) GetProcAddress(wglinstance, "wglGetCurrentDC");+ wglGetCurrentContextSRC = (PFN_wglGetCurrentContext) GetProcAddress(wglinstance, "wglGetCurrentContext");+#endif+ }+ + if (name[0] == 0) name = (char*) " ";++ RGFW_eventWindow.r = RGFW_RECT(-1, -1, -1, -1);+ RGFW_eventWindow.src.window = NULL;++ RGFW_window* win = RGFW_window_basic_init(rect, args);++ win->src.maxSize = RGFW_AREA(0, 0);+ win->src.minSize = RGFW_AREA(0, 0);+++ HINSTANCE inh = GetModuleHandleA(NULL);++ #ifndef __cplusplus+ WNDCLASSA Class = { 0 }; /*!< Setup the Window class. */+ #else+ WNDCLASSA Class = { };+ #endif++ if (RGFW_className == NULL)+ RGFW_className = (char*)name;++ Class.lpszClassName = RGFW_className;+ Class.hInstance = inh;+ Class.hCursor = LoadCursor(NULL, IDC_ARROW);+ Class.lpfnWndProc = WndProc;++ RegisterClassA(&Class);++ DWORD window_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;++ RECT windowRect, clientRect;++ if (!(args & RGFW_NO_BORDER)) {+ window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX;++ if (!(args & RGFW_NO_RESIZE))+ window_style |= WS_SIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;+ } else+ window_style |= WS_POPUP | WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX;++ HWND dummyWin = CreateWindowA(Class.lpszClassName, name, window_style, win->r.x, win->r.y, win->r.w, win->r.h, 0, 0, inh, 0);++ GetWindowRect(dummyWin, &windowRect);+ GetClientRect(dummyWin, &clientRect);++ 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_ALLOW_DND) {+ 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);++ if (FAILED(RGFW_dxInfo.pFactory->lpVtbl->EnumAdapters(RGFW_dxInfo.pFactory, 0, &RGFW_dxInfo.pAdapter))) {+ fprintf(stderr, "Failed to enumerate DXGI adapters\n");+ RGFW_dxInfo.pFactory->lpVtbl->Release(RGFW_dxInfo.pFactory);+ return NULL;+ }++ D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0 };++ if (FAILED(D3D11CreateDevice(RGFW_dxInfo.pAdapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, featureLevels, 1, D3D11_SDK_VERSION, &RGFW_dxInfo.pDevice, NULL, &RGFW_dxInfo.pDeviceContext))) {+ fprintf(stderr, "Failed to create Direct3D device\n");+ RGFW_dxInfo.pAdapter->lpVtbl->Release(RGFW_dxInfo.pAdapter);+ RGFW_dxInfo.pFactory->lpVtbl->Release(RGFW_dxInfo.pFactory);+ return NULL;+ }++ DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 };+ swapChainDesc.BufferCount = 1;+ swapChainDesc.BufferDesc.Width = win->r.w;+ swapChainDesc.BufferDesc.Height = win->r.h;+ swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;+ swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;+ swapChainDesc.OutputWindow = win->src.window;+ swapChainDesc.SampleDesc.Count = 1;+ swapChainDesc.SampleDesc.Quality = 0;+ swapChainDesc.Windowed = TRUE;+ RGFW_dxInfo.pFactory->lpVtbl->CreateSwapChain(RGFW_dxInfo.pFactory, (IUnknown*) RGFW_dxInfo.pDevice, &swapChainDesc, &win->src.swapchain);++ ID3D11Texture2D* pBackBuffer;+ win->src.swapchain->lpVtbl->GetBuffer(win->src.swapchain, 0, &__uuidof(ID3D11Texture2D), (LPVOID*) &pBackBuffer);+ RGFW_dxInfo.pDevice->lpVtbl->CreateRenderTargetView(RGFW_dxInfo.pDevice, (ID3D11Resource*) pBackBuffer, NULL, &win->src.renderTargetView);+ pBackBuffer->lpVtbl->Release(pBackBuffer);++ D3D11_TEXTURE2D_DESC depthStencilDesc = { 0 };+ depthStencilDesc.Width = win->r.w;+ depthStencilDesc.Height = win->r.h;+ depthStencilDesc.MipLevels = 1;+ depthStencilDesc.ArraySize = 1;+ depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;+ depthStencilDesc.SampleDesc.Count = 1;+ depthStencilDesc.SampleDesc.Quality = 0;+ depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;+ depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;++ ID3D11Texture2D* pDepthStencilTexture = NULL;+ RGFW_dxInfo.pDevice->lpVtbl->CreateTexture2D(RGFW_dxInfo.pDevice, &depthStencilDesc, NULL, &pDepthStencilTexture);++ D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc = { 0 };+ depthStencilViewDesc.Format = depthStencilDesc.Format;+ depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;+ depthStencilViewDesc.Texture2D.MipSlice = 0;++ RGFW_dxInfo.pDevice->lpVtbl->CreateDepthStencilView(RGFW_dxInfo.pDevice, (ID3D11Resource*) pDepthStencilTexture, &depthStencilViewDesc, &win->src.pDepthStencilView);++ pDepthStencilTexture->lpVtbl->Release(pDepthStencilTexture);++ RGFW_dxInfo.pDeviceContext->lpVtbl->OMSetRenderTargets(RGFW_dxInfo.pDeviceContext, 1, &win->src.renderTargetView, win->src.pDepthStencilView);+#endif++#ifdef RGFW_OPENGL + HDC dummy_dc = GetDC(dummyWin);+ + 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);+ SetPixelFormat(dummy_dc, pixel_format, &pfd);++ HGLRC dummy_context = wglCreateContext(dummy_dc);+ wglMakeCurrent(dummy_dc, dummy_context);++ if (wglChoosePixelFormatARB == NULL) {+ 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 = {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_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 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 WGL pixel format.\n");+ }+ }+ + /* create opengl/WGL context for the specified version */ + u32 index = 0;+ i32 attribs[40];++ if (RGFW_profile == RGFW_GL_CORE) {+ SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_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);+ }++ SET_ATTRIB(0, 0);++ 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.ctx = wglCreateContext(win->src.hdc);+ }+ + wglMakeCurrent(win->src.hdc, win->src.ctx);+#endif+ }++#ifdef RGFW_OSMESA+#ifdef RGFW_LINK_OSM ESA+ OSMesaMakeCurrentSource = (PFN_OSMesaMakeCurrent) GetProcAddress(win->src.hdc, "OSMesaMakeCurrent");+ OSMesaCreateContextSource = (PFN_OSMesaCreateContext) GetProcAddress(win->src.hdc, "OSMesaCreateContext");+ OSMesaDestroyContextSource = (PFN_OSMesaDestroyContext) GetProcAddress(win->src.hdc, "OSMesaDestroyContext");+#endif+#endif++#ifdef RGFW_OPENGL+ 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);+++ #ifndef RGFW_NO_MONITOR+ if (args & RGFW_SCALE_TO_MONITOR)+ RGFW_window_scaleToMonitor(win);+ #endif+ + if (args & RGFW_CENTER) {+ RGFW_area screenR = RGFW_getScreenSize();+ RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));+ }++#ifdef RGFW_EGL+ 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_point RGFW_getGlobalMousePoint(void) {+ POINT p;+ GetCursorPos(&p);++ 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) {+ assert(win != NULL);+ win->src.minSize = a;+ }++ void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {+ assert(win != NULL);+ win->src.maxSize = a;+ }+++ void RGFW_window_minimize(RGFW_window* win) {+ assert(win != NULL);++ ShowWindow(win->src.window, SW_MINIMIZE);+ }++ void RGFW_window_restore(RGFW_window* win) {+ assert(win != NULL);++ ShowWindow(win->src.window, SW_RESTORE);+ }+++ 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;+#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 &&+ state.Gamepad.sThumbLX > -INPUT_DEADZONE) &&+ (state.Gamepad.sThumbLY < INPUT_DEADZONE &&+ state.Gamepad.sThumbLY > -INPUT_DEADZONE))+ {+ state.Gamepad.sThumbLX = 0;+ state.Gamepad.sThumbLY = 0;+ }++ if ((state.Gamepad.sThumbRX < INPUT_DEADZONE &&+ state.Gamepad.sThumbRX > -INPUT_DEADZONE) &&+ (state.Gamepad.sThumbRY < INPUT_DEADZONE &&+ state.Gamepad.sThumbRY > -INPUT_DEADZONE))+ {+ state.Gamepad.sThumbRX = 0;+ state.Gamepad.sThumbRY = 0;+ }++ e->axisesCount = 2;+ 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;++ e->axis[0] = axis1;+ e->axis[1] = axis2;++ return 1;+ }++ e->axis[0] = axis1;+ e->axis[1] = axis2;+ }++ return 0;+ }++ 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);+ }++ 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, &win->event))+ return &win->event;++ 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_ACTIVATE:+ win->event.inFocus = (LOWORD(msg.wParam) == WA_INACTIVE);++ 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;+ 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);++ 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) & 0x8000) {+ ToAscii((UINT) msg.wParam, MapVirtualKey((UINT) msg.wParam, MAPVK_VK_TO_CHAR),+ keyboardState, (LPWORD) win->event.keyName, 0);+ }++ win->event.type = RGFW_keyPressed;+ 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:+ 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:+ if (msg.wParam > 0)+ win->event.button = RGFW_mouseScrollUp;+ 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: { + win->event.type = RGFW_dnd_init;++ drop = (HDROP) msg.wParam;+ POINT pt;++ /* Move the mouse to the position of the drop */+ DragQueryPoint(drop, &pt);++ win->event.point.x = pt.x;+ win->event.point.y = pt.y;++ RGFW_dndInitCallback(win, win->event.point);+ }+ break;+ case WM_GETMINMAXINFO:+ {+ if (win->src.maxSize.w == 0 && win->src.maxSize.h == 0)+ break;++ MINMAXINFO* mmi = (MINMAXINFO*) msg.lParam;+ mmi->ptMinTrackSize.x = win->src.minSize.w;+ mmi->ptMinTrackSize.y = win->src.minSize.h;+ mmi->ptMaxTrackSize.x = win->src.maxSize.w;+ mmi->ptMaxTrackSize.y = win->src.maxSize.h;+ return 0;+ }+ default:+ win->event.type = 0;+ break;+ }++ TranslateMessage(&msg);+ DispatchMessageA(&msg);+ }++ else+ win->event.type = 0;++ if (!IsWindow(win->src.window)) {+ win->event.type = RGFW_quit;+ RGFW_windowQuitCallback(win);+ }++ if (win->event.type)+ return &win->event;+ else+ return 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;+ }++ u8 RGFW_window_isHidden(RGFW_window* win) {+ assert(win != NULL);++ return IsWindowVisible(win->src.window) == 0 && !RGFW_window_isMinimized(win);+ }++ 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;+ }++ 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;+ }++ typedef struct { int iIndex; HMONITOR hMonitor; } RGFW_mInfo;+ BOOL CALLBACK GetMonitorByHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {+ RGFW_UNUSED(hdcMonitor)+ RGFW_UNUSED(lprcMonitor)++ RGFW_mInfo* info = (RGFW_mInfo*) dwData;+ if (info->hMonitor == hMonitor)+ return FALSE;++ info->iIndex++;+ return TRUE;+ }+ + #ifndef RGFW_NO_MONITOR+ RGFW_monitor win32CreateMonitor(HMONITOR src) {+ RGFW_monitor monitor;+ MONITORINFO monitorInfo;++ monitorInfo.cbSize = sizeof(MONITORINFO);+ GetMonitorInfoA(src, &monitorInfo);++ RGFW_mInfo info;+ info.iIndex = 0;+ info.hMonitor = src;++ /* get the monitor's index */+ if (EnumDisplayMonitors(NULL, NULL, GetMonitorByHandle, (LPARAM) &info)) {+ DISPLAY_DEVICEA dd;+ dd.cb = sizeof(dd);++ /* loop through the devices until you find a device with the monitor's index */+ size_t deviceIndex;+ for (deviceIndex = 0; EnumDisplayDevicesA(0, (DWORD) deviceIndex, &dd, 0); deviceIndex++) {+ char* deviceName = dd.DeviceName;+ if (EnumDisplayDevicesA(deviceName, info.iIndex, &dd, 0)) {+ strncpy(monitor.name, dd.DeviceString, 128); /*!< copy the monitor's name */+ break;+ }+ }+ }++ monitor.rect.x = monitorInfo.rcWork.left;+ monitor.rect.y = monitorInfo.rcWork.top;+ monitor.rect.w = monitorInfo.rcWork.right - monitorInfo.rcWork.left;+ 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_EFFECTIVE_DPI, &x, &y);+ + monitor.scaleX = (float) (x) / (float) USER_DEFAULT_SCREEN_DPI;+ monitor.scaleY = (float) (y) / (float) USER_DEFAULT_SCREEN_DPI;+ }+#endif++ HDC hdc = GetDC(NULL);+ /* get pixels per inch */+ i32 ppiX = GetDeviceCaps(hdc, LOGPIXELSX);+ i32 ppiY = GetDeviceCaps(hdc, LOGPIXELSY);+ ReleaseDC(NULL, hdc);++ /* Calculate physical height in inches */+ monitor.physW = GetSystemMetrics(SM_CYSCREEN) / (float) ppiX;+ monitor.physH = GetSystemMetrics(SM_CXSCREEN) / (float) ppiY;+ + 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)+ RGFW_UNUSED(lprcMonitor)++ RGFW_mInfo* info = (RGFW_mInfo*) dwData;++ if (info->iIndex >= 6)+ return FALSE;++ RGFW_monitors[info->iIndex] = win32CreateMonitor(hMonitor);+ info->iIndex++;++ return TRUE;+ }++ 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;+ info.iIndex = 0;+ while (EnumDisplayMonitors(NULL, NULL, GetMonitorHandle, (LPARAM) &info));+ + return RGFW_monitors;+ }++ RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {+ HMONITOR src = MonitorFromWindow(win->src.window, MONITOR_DEFAULTTOPRIMARY);+ return win32CreateMonitor(src);+ }+ #endif++ HICON RGFW_loadHandleImage(RGFW_window* win, u8* src, RGFW_area a, BOOL icon) {+ assert(win != NULL);++ u32 i;+ HDC dc;+ HICON handle;+ HBITMAP color, mask;+ BITMAPV5HEADER bi;+ ICONINFO ii;+ u8* target = NULL;+ u8* source = src;++ ZeroMemory(&bi, sizeof(bi));+ bi.bV5Size = sizeof(bi);+ bi.bV5Width = a.w;+ bi.bV5Height = -((LONG) a.h);+ bi.bV5Planes = 1;+ bi.bV5BitCount = 32;+ bi.bV5Compression = BI_BITFIELDS;+ bi.bV5RedMask = 0x00ff0000;+ bi.bV5GreenMask = 0x0000ff00;+ bi.bV5BlueMask = 0x000000ff;+ bi.bV5AlphaMask = 0xff000000;++ dc = GetDC(NULL);+ color = CreateDIBSection(dc,+ (BITMAPINFO*) &bi,+ DIB_RGB_COLORS,+ (void**) &target,+ NULL,+ (DWORD) 0);+ ReleaseDC(NULL, dc);++ mask = CreateBitmap(a.w, a.h, 1, 1, NULL);++ for (i = 0; i < a.w * a.h; i++) {+ target[0] = source[2];+ target[1] = source[1];+ target[2] = source[0];+ target[3] = source[3];+ target += 4;+ source += 4;+ }++ ZeroMemory(&ii, sizeof(ii));+ ii.fIcon = icon;+ ii.xHotspot = 0;+ ii.yHotspot = 0;+ ii.hbmMask = mask;+ ii.hbmColor = color;++ handle = CreateIconIndirect(&ii);++ DeleteObject(color);+ DeleteObject(mask);++ return handle;+ }++ void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) {+ assert(win != NULL);+ RGFW_UNUSED(channels)++ HCURSOR cursor = (HCURSOR) RGFW_loadHandleImage(win, image, a, FALSE);+ SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) cursor);+ SetCursor(cursor);+ DestroyCursor(cursor);+ }++ void RGFW_window_setMouseDefault(RGFW_window* win) {+ RGFW_window_setMouseStandard(win, RGFW_MOUSE_ARROW);+ }++ void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {+ assert(win != NULL);++ 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));+ }++ void RGFW_window_hide(RGFW_window* win) {+ ShowWindow(win->src.window, SW_HIDE);+ }++ void RGFW_window_show(RGFW_window* win) {+ ShowWindow(win->src.window, SW_RESTORE);+ }++ void RGFW_window_close(RGFW_window* win) {+ assert(win != NULL);++#ifdef RGFW_EGL+ RGFW_closeEGL(win);+#endif++ if (win == RGFW_root) {+#ifdef RGFW_DIRECTX+ RGFW_dxInfo.pDeviceContext->lpVtbl->Release(RGFW_dxInfo.pDeviceContext);+ RGFW_dxInfo.pDevice->lpVtbl->Release(RGFW_dxInfo.pDevice);+ RGFW_dxInfo.pAdapter->lpVtbl->Release(RGFW_dxInfo.pAdapter);+ RGFW_dxInfo.pFactory->lpVtbl->Release(RGFW_dxInfo.pFactory);+#endif+ + if (RGFW_XInput_dll != NULL) {+ FreeLibrary(RGFW_XInput_dll);+ RGFW_XInput_dll = NULL;+ }++ #ifndef RGFW_NO_DPI+ if (RGFW_Shcore_dll != NULL) {+ FreeLibrary(RGFW_Shcore_dll);+ RGFW_Shcore_dll = NULL;+ }+ #endif++ if (wglinstance != NULL) {+ FreeLibrary(wglinstance);+ wglinstance = NULL;+ }++ RGFW_root = NULL;+ }++#ifdef RGFW_DIRECTX+ win->src.swapchain->lpVtbl->Release(win->src.swapchain);+ win->src.renderTargetView->lpVtbl->Release(win->src.renderTargetView);+ win->src.pDepthStencilView->lpVtbl->Release(win->src.pDepthStencilView);+#endif++#ifdef RGFW_BUFFER+ DeleteDC(win->src.hdcMem);+ DeleteObject(win->src.bitmap);+#endif++#ifdef RGFW_OPENGL+ wglDeleteContext((HGLRC) win->src.ctx); /*!< delete opengl context */+#endif+ DeleteDC(win->src.hdc); /*!< delete device context */+ DestroyWindow(win->src.window); /*!< delete window */++#if defined(RGFW_OSMESA)+ if (win->buffer != NULL)+ RGFW_FREE(win->buffer);+#endif++#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_FREE(win);+ }++ void RGFW_window_move(RGFW_window* win, RGFW_point v) {+ assert(win != NULL);++ win->r.x = v.x;+ win->r.y = v.y;+ SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, 0, 0, SWP_NOSIZE);+ }++ void RGFW_window_resize(RGFW_window* win, RGFW_area a) {+ assert(win != NULL);++ win->r.w = a.w;+ win->r.h = a.h;+ SetWindowPos(win->src.window, HWND_TOP, 0, 0, win->r.w, win->r.h + win->src.hOffset, SWP_NOMOVE);+ }+++ void RGFW_window_setName(RGFW_window* win, char* name) {+ assert(win != 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);++ 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) {+ /* Open the clipboard */+ if (OpenClipboard(NULL) == 0)+ return (char*) "";++ /* Get the clipboard data as a Unicode string */+ HANDLE hData = GetClipboardData(CF_UNICODETEXT);+ if (hData == NULL) {+ CloseClipboard();+ return (char*) "";+ }++ wchar_t* wstr = (wchar_t*) GlobalLock(hData);++ char* text;++ {+ setlocale(LC_ALL, "en_US.UTF-8");++ size_t textLen = wcstombs(NULL, wstr, 0);+ if (textLen == 0)+ return (char*) "";++ 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 */+ GlobalUnlock(hData);+ CloseClipboard();++ return text;+ }++ void RGFW_writeClipboard(const char* text, u32 textLen) {+ HANDLE object;+ WCHAR* buffer;++ object = GlobalAlloc(GMEM_MOVEABLE, (1 + textLen) * sizeof(WCHAR));+ if (!object)+ return;++ buffer = (WCHAR*) GlobalLock(object);+ if (!buffer) {+ GlobalFree(object);+ return;+ }++ MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, textLen);+ GlobalUnlock(object);++ if (!OpenClipboard(RGFW_root->src.window)) {+ GlobalFree(object);+ return;+ }++ EmptyClipboard();+ SetClipboardData(CF_UNICODETEXT, object);+ CloseClipboard();+ }++ u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber) {+ assert(win != NULL);++ RGFW_UNUSED(jsNumber)++ return RGFW_registerJoystickF(win, (char*) "");+ }++ u16 RGFW_registerJoystickF(RGFW_window* win, char* file) {+ assert(win != NULL);+ RGFW_UNUSED(file)++ return RGFW_joystickCount - 1;+ }++ 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;++ size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL);+ if (!size) {+ return NULL;+ }++ target = (char*) RGFW_CALLOC(size, 1);++ if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL)) {+ RGFW_FREE(target);+ return 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); }+ void RGFW_cancelThread(RGFW_thread thread) { CloseHandle((HANDLE) thread); }+ void RGFW_joinThread(RGFW_thread thread) { WaitForSingleObject((HANDLE) thread, INFINITE); }+ void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { SetThreadPriority((HANDLE) thread, priority); }+#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 <CoreVideo/CVDisplayLink.h>+#include <ApplicationServices/ApplicationServices.h>+#include <objc/runtime.h>+#include <objc/message.h>+#include <mach/mach_time.h>++ 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;++#ifdef RGFW_OPENGL+ void* RGFW_getProcAddress(const char* procname) {+ if (RGFWnsglFramework == NULL)+ RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));++ CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII);++ void* symbol = CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName);++ CFRelease(symbolName);++ return symbol;+ }+#endif++ CVReturn displayCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* inNow, const CVTimeStamp* inOutputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) { + RGFW_UNUSED(displayLink) RGFW_UNUSED(inNow) RGFW_UNUSED(inOutputTime) RGFW_UNUSED(flagsIn) RGFW_UNUSED(flagsOut) RGFW_UNUSED(displayLinkContext)+ return kCVReturnSuccess; + }++ id NSWindow_delegate(RGFW_window* win) {+ return (id) objc_msgSend_id(win->src.window, sel_registerName("delegate"));+ }++ u32 RGFW_OnClose(void* self) {+ 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;+ }++ /* NOTE(EimaMei): Fixes the constant clicking when the app is running under a terminal. */+ bool acceptsFirstResponder(void) { return true; }+ bool performKeyEquivalent(NSEvent* event) { RGFW_UNUSED(event); return true; }++ 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(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(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; }++ /* NOTE(EimaMei): Usually, you never need 'id self, SEL cmd' for C -> Obj-C methods. This isn't the case. */+ bool performDragOperation(id self, SEL sel, id sender) {+ RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); ++ RGFW_window* win = NULL;+ object_getInstanceVariable(self, "RGFW_window", (void*)&win);++ if (win == NULL)+ return false;++ // 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"));+ 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;+ + 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_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);+ + return false;+ }++ static void NSMoveToResourceDir(void) {+ /* sourced from glfw */+ char resourcesPath[255];++ CFBundleRef bundle = CFBundleGetMainBundle();+ if (!bundle)+ return;++ CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);+ CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);++ if (+ CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo ||+ CFURLGetFileSystemRepresentation(resourcesURL, true, (u8*) resourcesPath, 255) == 0+ ) {+ CFRelease(last);+ CFRelease(resourcesURL);+ return;+ }++ CFRelease(last);+ CFRelease(resourcesURL);++ chdir(resourcesPath);+ }+++ NSSize RGFW__osxWindowResize(void* self, SEL sel, NSSize frameSize) {+ RGFW_UNUSED(sel); ++ 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); ++ 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;++ win->event.type = RGFW_windowMoved;+ RGFW_windowMoveCallback(win, win->r);+ }++ 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+ }+++ void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer) {+ objc_msgSend_void_id(win->src.view, sel_registerName("setLayer"), layer);+ }++ void* RGFW_cocoaGetLayer(void) {+ return objc_msgSend_class(objc_getClass("CAMetalLayer"), sel_registerName("layer"));+ }+++ NSPasteboardType const NSPasteboardTypeURL = "public.url";+ NSPasteboardType const NSPasteboardTypeFileURL = "public.file-url";++ RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) {+ static u8 RGFW_loaded = 0;++ /* NOTE(EimaMei): Why does Apple hate good code? Like wtf, who thought of methods being a great idea???+ Imagine a universe, where MacOS had a proper system API (we would probably have like 20% better performance).+ */+ si_func_to_SEL_with_name("NSObject", "windowShouldClose", RGFW_OnClose);++ /* NOTE(EimaMei): Fixes the 'Boop' sfx from constantly playing each time you click a key. Only a problem when running in the terminal. */+ 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"));++ ((void (*)(id, SEL, NSUInteger))objc_msgSend)+ (NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular);+ }++ RGFW_window* win = RGFW_window_basic_init(rect, args);+ + RGFW_window_setMouseDefault(win);++ NSRect windowRect;+ windowRect.origin.x = win->r.x;+ windowRect.origin.y = win->r.y;+ windowRect.size.width = win->r.w;+ windowRect.size.height = win->r.h;++ NSBackingStoreType macArgs = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled;++ if (!(args & RGFW_NO_RESIZE))+ macArgs |= NSWindowStyleMaskResizable;+ if (!(args & RGFW_NO_BORDER))+ macArgs |= NSWindowStyleMaskTitled;+ else+ macArgs = NSWindowStyleMaskBorderless;+ {+ void* nsclass = objc_getClass("NSWindow");+ void* func = sel_registerName("initWithContentRect:styleMask:backing:defer:");++ win->src.window = ((id(*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend)+ (NSAlloc(nsclass), func, windowRect, macArgs, macArgs, false);+ }++ NSString* str = NSString_stringWithUTF8String(name);+ objc_msgSend_void_id(win->src.window, sel_registerName("setTitle:"), str);++#ifdef RGFW_EGL+ if ((args & RGFW_NO_INIT_API) == 0)+ RGFW_createOpenGLContext(win);+#endif++#ifdef RGFW_OPENGL+ 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 for OpenGL\n");++ 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");+ }+ + /* 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.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);+ }++ void* contentView = NSWindow_contentView(win->src.window);+ objc_msgSend_void_bool(contentView, sel_registerName("setWantsLayer:"), true);++ objc_msgSend_void_id(win->src.window, sel_registerName("setContentView:"), win->src.view);++#ifdef RGFW_OPENGL+ 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;+ #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));+ }++ win->src.display = CGMainDisplayID();+ CVDisplayLinkCreateWithCGDisplay(win->src.display, (CVDisplayLinkRef*)&win->src.displayLink);+ CVDisplayLinkSetOutputCallback(win->src.displayLink, displayCallback, win);+ CVDisplayLinkStart(win->src.displayLink);++ RGFW_init_buffer(win);++ #ifndef RGFW_NO_MONITOR+ if (args & RGFW_SCALE_TO_MONITOR)+ RGFW_window_scaleToMonitor(win);+ #endif++ if (args & RGFW_CENTER) {+ RGFW_area screenR = RGFW_getScreenSize();+ RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));+ }++ if (args & RGFW_HIDE_MOUSE)+ RGFW_window_showMouse(win, 0);++ if (args & RGFW_COCOA_MOVE_TO_RESOURCE_DIR)+ 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@:@");+ class_addMethod(delegateClass, sel_registerName("draggingUpdated:"), (IMP)draggingUpdated, "l@:@");+ class_addMethod(delegateClass, sel_registerName("draggingExited:"), (IMP)RGFW__osxDraggingEnded, "v@:@");+ class_addMethod(delegateClass, sel_registerName("draggingEnded:"), (IMP)RGFW__osxDraggingEnded, "v@:@");+ class_addMethod(delegateClass, sel_registerName("prepareForDragOperation:"), (IMP)prepareForDragOperation, "B@:@");+ class_addMethod(delegateClass, sel_registerName("performDragOperation:"), (IMP)performDragOperation, "B@:@");++ id delegate = objc_msgSend_id(NSAlloc(delegateClass), sel_registerName("init"));++ object_setInstanceVariable(delegate, "RGFW_window", win);++ objc_msgSend_void_id(win->src.window, sel_registerName("setDelegate:"), delegate);++ if (args & 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);++ if (!RGFW_loaded) {+ objc_msgSend_void(win->src.window, sel_registerName("makeMainWindow"));++ RGFW_loaded = 1;+ }++ objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow"));++ objc_msgSend_void(NSApp, sel_registerName("finishLaunching"));++ if (RGFW_root == NULL)+ RGFW_root = win;++ NSRetain(win->src.window);+ NSRetain(NSApp);++ 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;++ if (display == 0)+ display = CGMainDisplayID();++ return RGFW_AREA(CGDisplayPixelsWide(display), CGDisplayPixelsHigh(display));+ }++ RGFW_point RGFW_getGlobalMousePoint(void) {+ assert(RGFW_root != NULL);++ CGEventRef e = CGEventCreate(NULL);+ CGPoint point = CGEventGetLocation(e);+ CFRelease(e);++ 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*/+ typedef NS_ENUM(u32, NSEventType) { /* various types of events */+ NSEventTypeLeftMouseDown = 1,+ NSEventTypeLeftMouseUp = 2,+ NSEventTypeRightMouseDown = 3,+ NSEventTypeRightMouseUp = 4,+ NSEventTypeMouseMoved = 5,+ NSEventTypeLeftMouseDragged = 6,+ NSEventTypeRightMouseDragged = 7,+ NSEventTypeMouseEntered = 8,+ NSEventTypeMouseExited = 9,+ NSEventTypeKeyDown = 10,+ NSEventTypeKeyUp = 11,+ NSEventTypeFlagsChanged = 12,+ NSEventTypeAppKitDefined = 13,+ NSEventTypeSystemDefined = 14,+ NSEventTypeApplicationDefined = 15,+ NSEventTypePeriodic = 16,+ NSEventTypeCursorUpdate = 17,+ NSEventTypeScrollWheel = 22,+ NSEventTypeTabletPoint = 23,+ NSEventTypeTabletProximity = 24,+ NSEventTypeOtherMouseDown = 25,+ NSEventTypeOtherMouseUp = 26,+ NSEventTypeOtherMouseDragged = 27,+ /* The following event types are available on some hardware on 10.5.2 and later */+ NSEventTypeGesture API_AVAILABLE(macos(10.5)) = 29,+ NSEventTypeMagnify API_AVAILABLE(macos(10.5)) = 30,+ NSEventTypeSwipe API_AVAILABLE(macos(10.5)) = 31,+ NSEventTypeRotate API_AVAILABLE(macos(10.5)) = 18,+ NSEventTypeBeginGesture API_AVAILABLE(macos(10.5)) = 19,+ NSEventTypeEndGesture API_AVAILABLE(macos(10.5)) = 20,++ NSEventTypeSmartMagnify API_AVAILABLE(macos(10.8)) = 32,+ NSEventTypeQuickLook API_AVAILABLE(macos(10.8)) = 33,++ NSEventTypePressure API_AVAILABLE(macos(10.10.3)) = 34,+ NSEventTypeDirectTouch API_AVAILABLE(macos(10.10)) = 37,++ NSEventTypeChangeMode API_AVAILABLE(macos(10.15)) = 38,+ };++ typedef NS_ENUM(unsigned long long, NSEventMask) { /* masks for the types of events */+ NSEventMaskLeftMouseDown = 1ULL << NSEventTypeLeftMouseDown,+ NSEventMaskLeftMouseUp = 1ULL << NSEventTypeLeftMouseUp,+ NSEventMaskRightMouseDown = 1ULL << NSEventTypeRightMouseDown,+ NSEventMaskRightMouseUp = 1ULL << NSEventTypeRightMouseUp,+ NSEventMaskMouseMoved = 1ULL << NSEventTypeMouseMoved,+ NSEventMaskLeftMouseDragged = 1ULL << NSEventTypeLeftMouseDragged,+ NSEventMaskRightMouseDragged = 1ULL << NSEventTypeRightMouseDragged,+ NSEventMaskMouseEntered = 1ULL << NSEventTypeMouseEntered,+ NSEventMaskMouseExited = 1ULL << NSEventTypeMouseExited,+ NSEventMaskKeyDown = 1ULL << NSEventTypeKeyDown,+ NSEventMaskKeyUp = 1ULL << NSEventTypeKeyUp,+ NSEventMaskFlagsChanged = 1ULL << NSEventTypeFlagsChanged,+ NSEventMaskAppKitDefined = 1ULL << NSEventTypeAppKitDefined,+ NSEventMaskSystemDefined = 1ULL << NSEventTypeSystemDefined,+ NSEventMaskApplicationDefined = 1ULL << NSEventTypeApplicationDefined,+ NSEventMaskPeriodic = 1ULL << NSEventTypePeriodic,+ NSEventMaskCursorUpdate = 1ULL << NSEventTypeCursorUpdate,+ NSEventMaskScrollWheel = 1ULL << NSEventTypeScrollWheel,+ NSEventMaskTabletPoint = 1ULL << NSEventTypeTabletPoint,+ NSEventMaskTabletProximity = 1ULL << NSEventTypeTabletProximity,+ NSEventMaskOtherMouseDown = 1ULL << NSEventTypeOtherMouseDown,+ NSEventMaskOtherMouseUp = 1ULL << NSEventTypeOtherMouseUp,+ NSEventMaskOtherMouseDragged = 1ULL << NSEventTypeOtherMouseDragged,+ /* The following event masks are available on some hardware on 10.5.2 and later */+ NSEventMaskGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeGesture,+ NSEventMaskMagnify API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeMagnify,+ NSEventMaskSwipe API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeSwipe,+ NSEventMaskRotate API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeRotate,+ NSEventMaskBeginGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeBeginGesture,+ NSEventMaskEndGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeEndGesture,++ /* Note: You can only use these event masks on 64 bit. In other words, you cannot setup a local, nor global, event monitor for these event types on 32 bit. Also, you cannot search the event queue for them (nextEventMatchingMask:...) on 32 bit.+ */+ NSEventMaskSmartMagnify API_AVAILABLE(macos(10.8)) = 1ULL << NSEventTypeSmartMagnify,+ NSEventMaskPressure API_AVAILABLE(macos(10.10.3)) = 1ULL << NSEventTypePressure,+ NSEventMaskDirectTouch API_AVAILABLE(macos(10.12.2)) = 1ULL << NSEventTypeDirectTouch,++ NSEventMaskChangeMode API_AVAILABLE(macos(10.15)) = 1ULL << NSEventTypeChangeMode,++ NSEventMaskAny = ULONG_MAX,++ };++ typedef enum NSEventModifierFlags {+ NSEventModifierFlagCapsLock = 1 << 16,+ NSEventModifierFlagShift = 1 << 17,+ NSEventModifierFlagControl = 1 << 18,+ NSEventModifierFlagOption = 1 << 19,+ 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 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) + eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:");++ 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, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);++ 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;+ }++ 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 = 0;+ + switch (objc_msgSend_uint(e, sel_registerName("type"))) {+ 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;+ 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_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 1);+ break;+ }++ case NSEventTypeKeyUp: {+ 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_keyReleased;+ 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].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"));+ 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 & 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;+ }+ }++ RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, win->event.type == RGFW_keyPressed);++ break;+ }+ case NSEventTypeLeftMouseDragged:+ case NSEventTypeOtherMouseDragged:+ case NSEventTypeRightMouseDragged:+ 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));++ 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) {+ win->event.button = RGFW_mouseScrollUp;+ }+ 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_mouseButtonPressed;+ RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);+ 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_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:"), (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) {+ assert(win != 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:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true);+ }++ void RGFW_window_minimize(RGFW_window* win) {+ assert(win != NULL);++ objc_msgSend_void_SEL(win->src.window, sel_registerName("performMiniaturize:"), NULL);+ }++ void RGFW_window_restore(RGFW_window* win) {+ assert(win != NULL);++ objc_msgSend_void_SEL(win->src.window, sel_registerName("deminiaturize:"), NULL);+ }++ void RGFW_window_setName(RGFW_window* win, char* name) {+ assert(win != NULL);++ NSString* str = NSString_stringWithUTF8String(name);+ 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:"), (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:"), (NSSize){a.w, a.h});+ }++ void RGFW_window_setIcon(RGFW_window* win, u8* data, RGFW_area area, i32 channels) {+ assert(win != NULL);++ /* code by EimaMei */+ // Make a bitmap representation, then copy the loaded image into it.+ void* representation = NSBitmapImageRep_initWithBitmapData(NULL, area.w, area.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, area.w * channels, 8 * channels);+ memcpy(NSBitmapImageRep_bitmapData(representation), data, area.w * area.h * channels);++ // Add ze representation.+ void* dock_image = NSImage_initWithSize((NSSize){area.w, area.h});+ NSImage_addRepresentation(dock_image, (void*) representation);++ // Finally, set the dock image to it.+ objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), dock_image);+ // Free the garbage.+ release(dock_image);+ release(representation);+ }++ NSCursor* NSCursor_arrowStr(char* str) {+ void* nclass = objc_getClass("NSCursor");+ void* func = sel_registerName(str);+ return (NSCursor*) objc_msgSend_id(nclass, func);+ }++ void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) {+ assert(win != NULL);++ if (image == NULL) {+ objc_msgSend_void(NSCursor_arrowStr("arrowCursor"), sel_registerName("set"));+ return;+ }++ /* NOTE(EimaMei): Code by yours truly. */+ // Make a bitmap representation, then copy the loaded image into it.+ void* representation = NSBitmapImageRep_initWithBitmapData(NULL, a.w, a.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, a.w * channels, 8 * channels);+ memcpy(NSBitmapImageRep_bitmapData(representation), image, a.w * a.h * channels);++ // Add ze representation.+ 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, (NSPoint){0.0, 0.0});++ objc_msgSend_void(cursor, sel_registerName("set"));++ // Free the garbage.+ release(cursor_image);+ release(representation);+ }++ void RGFW_window_setMouseDefault(RGFW_window* win) {+ RGFW_window_setMouseStandard(win, RGFW_MOUSE_ARROW);+ }++ void RGFW_window_showMouse(RGFW_window* win, i8 show) {+ RGFW_UNUSED(win);++ if (show) {+ CGDisplayShowCursor(kCGDirectMainDisplay);+ }+ else {+ CGDisplayHideCursor(kCGDirectMainDisplay);+ }+ }++ 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) {+ RGFW_UNUSED(win);+ CGAssociateMouseAndMouseCursorPosition(1); + }++ 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);+ + CGWarpMouseCursorPosition(CGPointMake(v.x, v.y)); + }+++ void RGFW_window_hide(RGFW_window* win) {+ objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), false);+ }++ void RGFW_window_show(RGFW_window* win) {+ ((id(*)(id, SEL, SEL))objc_msgSend)(win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL);+ objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true);+ }++ u8 RGFW_window_isFullscreen(RGFW_window* win) {+ assert(win != NULL);++ NSWindowStyleMask mask = (NSWindowStyleMask) objc_msgSend_uint(win->src.window, sel_registerName("styleMask"));+ return (mask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen;+ }++ u8 RGFW_window_isHidden(RGFW_window* win) {+ assert(win != NULL);++ bool visible = objc_msgSend_bool(win->src.window, sel_registerName("isVisible"));+ return visible == NO && !RGFW_window_isMinimized(win);+ }++ u8 RGFW_window_isMinimized(RGFW_window* win) {+ assert(win != NULL);++ return objc_msgSend_bool(win->src.window, sel_registerName("isMiniaturized")) == YES;+ }++ u8 RGFW_window_isMaximized(RGFW_window* win) {+ assert(win != NULL);++ return objc_msgSend_bool(win->src.window, sel_registerName("isZoomed"));+ }++ static RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display) {+ RGFW_monitor monitor;++ CGRect bounds = CGDisplayBounds(display);+ monitor.rect = RGFW_RECT((int) bounds.origin.x, (int) bounds.origin.y, (int) bounds.size.width, (int) bounds.size.height);++ CGSize screenSizeMM = CGDisplayScreenSize(display);+ monitor.physW = screenSizeMM.width;+ monitor.physH = screenSizeMM.height;++ monitor.scaleX = ((monitor.rect.w / (screenSizeMM.width / 25.4)) / 96) + 0.25;+ monitor.scaleY = ((monitor.rect.h / (screenSizeMM.height / 25.4)) / 96) + 0.25;++ return monitor;+ }+++ static RGFW_monitor RGFW_monitors[7];++ RGFW_monitor* RGFW_getMonitors(void) {+ static CGDirectDisplayID displays[7];+ u32 count;++ if (CGGetActiveDisplayList(6, displays, &count) != kCGErrorSuccess)+ return NULL;++ for (u32 i = 0; i < count; i++)+ RGFW_monitors[i] = RGFW_NSCreateMonitor(displays[i]);++ return RGFW_monitors;+ }++ RGFW_monitor RGFW_getPrimaryMonitor(void) {+ CGDirectDisplayID primary = CGMainDisplayID();+ return RGFW_NSCreateMonitor(primary);+ }++ RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {+ return RGFW_NSCreateMonitor(win->src.display);+ }++ char* RGFW_readClipboard(size_t* size) {+ 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 = clip_len;+ return str;+ }++ void RGFW_writeClipboard(const char* text, u32 textLen) {+ RGFW_UNUSED(textLen);++ NSPasteboardType array[] = { NSPasteboardTypeString, NULL };+ NSPasteBoard_declareTypes(NSPasteboard_generalPasteboard(), array, 1, NULL);++ NSPasteBoard_setString(NSPasteboard_generalPasteboard(), text, NSPasteboardTypeString);+ }++ u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber) {+ RGFW_UNUSED(jsNumber);++ assert(win != NULL);++ return RGFW_registerJoystickF(win, (char*) "");+ }++ u16 RGFW_registerJoystickF(RGFW_window* win, char* file) {+ RGFW_UNUSED(file);++ assert(win != NULL);++ 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);+ #else+ RGFW_UNUSED(swapInterval);+ #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);+ release(win->src.view);++#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+ +#ifdef RGFW_BUFFER+ release(win->src.bitmap);+ release(win->src.image);+#endif++ CVDisplayLinkStop(win->src.displayLink);+ CVDisplayLinkRelease(win->src.displayLink);++ 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 <sys/stat.h>+#include <sys/types.h>+#include <errno.h>++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++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) {+ RGFW_UNUSED(win);+ emscripten_exit_pointerlock();+}++void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { + RGFW_UNUSED(win); RGFW_UNUSED(r);++ 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 <pthread.h>++ RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) {+ RGFW_UNUSED(args);+ + RGFW_thread t;+ pthread_create((pthread_t*) &t, NULL, *ptr, NULL);+ return t;+ }+ 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((pthread_t)thread, priority); }+#endif+#endif++#ifndef RGFW_WEBASM+/* unix sleep */+ void RGFW_sleep(u64 ms) {+ struct timespec time;+ time.tv_sec = 0;+ time.tv_nsec = ms * 1e+6;++ nanosleep(&time, NULL);+ }+#endif++#endif /* end of unix / mac stuff*/+#endif /*RGFW_IMPLEMENTATION*/++#if defined(__cplusplus) && !defined(__EMSCRIPTEN__) } #endif
raylib/src/external/glfw/src/mappings.h view
@@ -996,6 +996,7 @@ "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 };
raylib/src/external/jar_xm.h view
@@ -1204,7 +1204,7 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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;
raylib/src/external/miniaudio.h view
file too large to diff
− raylib/src/external/nanosvg.h
@@ -1,3053 +0,0 @@-/*- * Copyright (c) 2013-14 Mikko Mononen memon@inside.org- *- * This software is provided 'as-is', without any express or implied- * warranty. In no event will the authors be held liable for any damages- * arising from the use of this software.- *- * Permission is granted to anyone to use this software for any purpose,- * including commercial applications, and to alter it and redistribute it- * freely, subject to the following restrictions:- *- * 1. The origin of this software must not be misrepresented; you must not- * claim that you wrote the original software. If you use this software- * in a product, an acknowledgment in the product documentation would be- * appreciated but is not required.- * 2. Altered source versions must be plainly marked as such, and must not be- * misrepresented as being the original software.- * 3. This notice may not be removed or altered from any source distribution.- *- * The SVG parser is based on Anti-Grain Geometry 2.4 SVG example- * Copyright (C) 2002-2004 Maxim Shemanarev (McSeem) (http://www.antigrain.com/)- *- * Arc calculation code based on canvg (https://code.google.com/p/canvg/)- *- * Bounding box calculation based on http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html- *- */--#ifndef NANOSVG_H-#define NANOSVG_H--#ifndef NANOSVG_CPLUSPLUS-#ifdef __cplusplus-extern "C" {-#endif-#endif--// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes.-//-// The library suits well for anything from rendering scalable icons in your editor application to prototyping a game.-//-// NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create a pull request!-//-// The shapes in the SVG images are transformed by the viewBox and converted to specified units.-// That is, you should get the same looking data as your designed in your favorite app.-//-// NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose-// to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters.-//-// The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.-// DPI (dots-per-inch) controls how the unit conversion is done.-//-// If you don't know or care about the units stuff, "px" and 96 should get you going.---/* Example Usage:- // Load SVG- NSVGimage* image;- image = nsvgParseFromFile("test.svg", "px", 96);- printf("size: %f x %f\n", image->width, image->height);- // Use...- for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) {- for (NSVGpath *path = shape->paths; path != NULL; path = path->next) {- for (int i = 0; i < path->npts-1; i += 3) {- float* p = &path->pts[i*2];- drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]);- }- }- }- // Delete- nsvgDelete(image);-*/--enum NSVGpaintType {- NSVG_PAINT_NONE = 0,- NSVG_PAINT_COLOR = 1,- NSVG_PAINT_LINEAR_GRADIENT = 2,- NSVG_PAINT_RADIAL_GRADIENT = 3-};--enum NSVGspreadType {- NSVG_SPREAD_PAD = 0,- NSVG_SPREAD_REFLECT = 1,- NSVG_SPREAD_REPEAT = 2-};--enum NSVGlineJoin {- NSVG_JOIN_MITER = 0,- NSVG_JOIN_ROUND = 1,- NSVG_JOIN_BEVEL = 2-};--enum NSVGlineCap {- NSVG_CAP_BUTT = 0,- NSVG_CAP_ROUND = 1,- NSVG_CAP_SQUARE = 2-};--enum NSVGfillRule {- NSVG_FILLRULE_NONZERO = 0,- NSVG_FILLRULE_EVENODD = 1-};--enum NSVGflags {- NSVG_FLAGS_VISIBLE = 0x01-};--typedef struct NSVGgradientStop {- unsigned int color;- float offset;-} NSVGgradientStop;--typedef struct NSVGgradient {- float xform[6];- char spread;- float fx, fy;- int nstops;- NSVGgradientStop stops[1];-} NSVGgradient;--typedef struct NSVGpaint {- char type;- union {- unsigned int color;- NSVGgradient* gradient;- };-} NSVGpaint;--typedef struct NSVGpath-{- float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ...- int npts; // Total number of bezier points.- char closed; // Flag indicating if shapes should be treated as closed.- float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy].- struct NSVGpath* next; // Pointer to next path, or NULL if last element.-} NSVGpath;--typedef struct NSVGshape-{- char id[64]; // Optional 'id' attr of the shape or its group- NSVGpaint fill; // Fill paint- NSVGpaint stroke; // Stroke paint- float opacity; // Opacity of the shape.- float strokeWidth; // Stroke width (scaled).- float strokeDashOffset; // Stroke dash offset (scaled).- float strokeDashArray[8]; // Stroke dash array (scaled).- char strokeDashCount; // Number of dash values in dash array.- char strokeLineJoin; // Stroke join type.- char strokeLineCap; // Stroke cap type.- float miterLimit; // Miter limit- char fillRule; // Fill rule, see NSVGfillRule.- unsigned char flags; // Logical or of NSVG_FLAGS_* flags- float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy].- NSVGpath* paths; // Linked list of paths in the image.- struct NSVGshape* next; // Pointer to next shape, or NULL if last element.-} NSVGshape;--typedef struct NSVGimage-{- float width; // Width of the image.- float height; // Height of the image.- NSVGshape* shapes; // Linked list of shapes in the image.-} NSVGimage;--// Parses SVG file from a file, returns SVG image as paths.-NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi);--// Parses SVG file from a null terminated string, returns SVG image as paths.-// Important note: changes the string.-NSVGimage* nsvgParse(char* input, const char* units, float dpi);--// Duplicates a path.-NSVGpath* nsvgDuplicatePath(NSVGpath* p);--// Deletes an image.-void nsvgDelete(NSVGimage* image);--#ifndef NANOSVG_CPLUSPLUS-#ifdef __cplusplus-}-#endif-#endif--#ifdef NANOSVG_IMPLEMENTATION--#include <string.h>-#include <stdlib.h>-#include <stdio.h>-#include <math.h>--#define NSVG_PI (3.14159265358979323846264338327f)-#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs.--#define NSVG_ALIGN_MIN 0-#define NSVG_ALIGN_MID 1-#define NSVG_ALIGN_MAX 2-#define NSVG_ALIGN_NONE 0-#define NSVG_ALIGN_MEET 1-#define NSVG_ALIGN_SLICE 2--#define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0)-#define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16))--#ifdef _MSC_VER- #pragma warning (disable: 4996) // Switch off security warnings- #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings- #ifdef __cplusplus- #define NSVG_INLINE inline- #else- #define NSVG_INLINE- #endif-#else- #define NSVG_INLINE inline-#endif---static int nsvg__isspace(char c)-{- return strchr(" \t\n\v\f\r", c) != 0;-}--static int nsvg__isdigit(char c)-{- return c >= '0' && c <= '9';-}--static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; }-static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; }---// Simple XML parser--#define NSVG_XML_TAG 1-#define NSVG_XML_CONTENT 2-#define NSVG_XML_MAX_ATTRIBS 256--static void nsvg__parseContent(char* s,- void (*contentCb)(void* ud, const char* s),- void* ud)-{- // Trim start white spaces- while (*s && nsvg__isspace(*s)) s++;- if (!*s) return;-- if (contentCb)- (*contentCb)(ud, s);-}--static void nsvg__parseElement(char* s,- void (*startelCb)(void* ud, const char* el, const char** attr),- void (*endelCb)(void* ud, const char* el),- void* ud)-{- const char* attr[NSVG_XML_MAX_ATTRIBS];- int nattr = 0;- char* name;- int start = 0;- int end = 0;- char quote;-- // Skip white space after the '<'- while (*s && nsvg__isspace(*s)) s++;-- // Check if the tag is end tag- if (*s == '/') {- s++;- end = 1;- } else {- start = 1;- }-- // Skip comments, data and preprocessor stuff.- if (!*s || *s == '?' || *s == '!')- return;-- // Get tag name- name = s;- while (*s && !nsvg__isspace(*s)) s++;- if (*s) { *s++ = '\0'; }-- // Get attribs- while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) {- char* name = NULL;- char* value = NULL;-- // Skip white space before the attrib name- while (*s && nsvg__isspace(*s)) s++;- if (!*s) break;- if (*s == '/') {- end = 1;- break;- }- name = s;- // Find end of the attrib name.- while (*s && !nsvg__isspace(*s) && *s != '=') s++;- if (*s) { *s++ = '\0'; }- // Skip until the beginning of the value.- while (*s && *s != '\"' && *s != '\'') s++;- if (!*s) break;- quote = *s;- s++;- // Store value and find the end of it.- value = s;- while (*s && *s != quote) s++;- if (*s) { *s++ = '\0'; }-- // Store only well formed attributes- if (name && value) {- attr[nattr++] = name;- attr[nattr++] = value;- }- }-- // List terminator- attr[nattr++] = 0;- attr[nattr++] = 0;-- // Call callbacks.- if (start && startelCb)- (*startelCb)(ud, name, attr);- if (end && endelCb)- (*endelCb)(ud, name);-}--int nsvg__parseXML(char* input,- void (*startelCb)(void* ud, const char* el, const char** attr),- void (*endelCb)(void* ud, const char* el),- void (*contentCb)(void* ud, const char* s),- void* ud)-{- char* s = input;- char* mark = s;- int state = NSVG_XML_CONTENT;- while (*s) {- if (*s == '<' && state == NSVG_XML_CONTENT) {- // Start of a tag- *s++ = '\0';- nsvg__parseContent(mark, contentCb, ud);- mark = s;- state = NSVG_XML_TAG;- } else if (*s == '>' && state == NSVG_XML_TAG) {- // Start of a content or new tag.- *s++ = '\0';- nsvg__parseElement(mark, startelCb, endelCb, ud);- mark = s;- state = NSVG_XML_CONTENT;- } else {- s++;- }- }-- return 1;-}---/* Simple SVG parser. */--#define NSVG_MAX_ATTR 128--enum NSVGgradientUnits {- NSVG_USER_SPACE = 0,- NSVG_OBJECT_SPACE = 1-};--#define NSVG_MAX_DASHES 8--enum NSVGunits {- NSVG_UNITS_USER,- NSVG_UNITS_PX,- NSVG_UNITS_PT,- NSVG_UNITS_PC,- NSVG_UNITS_MM,- NSVG_UNITS_CM,- NSVG_UNITS_IN,- NSVG_UNITS_PERCENT,- NSVG_UNITS_EM,- NSVG_UNITS_EX-};--typedef struct NSVGcoordinate {- float value;- int units;-} NSVGcoordinate;--typedef struct NSVGlinearData {- NSVGcoordinate x1, y1, x2, y2;-} NSVGlinearData;--typedef struct NSVGradialData {- NSVGcoordinate cx, cy, r, fx, fy;-} NSVGradialData;--typedef struct NSVGgradientData-{- char id[64];- char ref[64];- char type;- union {- NSVGlinearData linear;- NSVGradialData radial;- };- char spread;- char units;- float xform[6];- int nstops;- NSVGgradientStop* stops;- struct NSVGgradientData* next;-} NSVGgradientData;--typedef struct NSVGattrib-{- char id[64];- float xform[6];- unsigned int fillColor;- unsigned int strokeColor;- float opacity;- float fillOpacity;- float strokeOpacity;- char fillGradient[64];- char strokeGradient[64];- float strokeWidth;- float strokeDashOffset;- float strokeDashArray[NSVG_MAX_DASHES];- int strokeDashCount;- char strokeLineJoin;- char strokeLineCap;- float miterLimit;- char fillRule;- float fontSize;- unsigned int stopColor;- float stopOpacity;- float stopOffset;- char hasFill;- char hasStroke;- char visible;-} NSVGattrib;--typedef struct NSVGparser-{- NSVGattrib attr[NSVG_MAX_ATTR];- int attrHead;- float* pts;- int npts;- int cpts;- NSVGpath* plist;- NSVGimage* image;- NSVGgradientData* gradients;- NSVGshape* shapesTail;- float viewMinx, viewMiny, viewWidth, viewHeight;- int alignX, alignY, alignType;- float dpi;- char pathFlag;- char defsFlag;-} NSVGparser;--static void nsvg__xformIdentity(float* t)-{- t[0] = 1.0f; t[1] = 0.0f;- t[2] = 0.0f; t[3] = 1.0f;- t[4] = 0.0f; t[5] = 0.0f;-}--static void nsvg__xformSetTranslation(float* t, float tx, float ty)-{- t[0] = 1.0f; t[1] = 0.0f;- t[2] = 0.0f; t[3] = 1.0f;- t[4] = tx; t[5] = ty;-}--static void nsvg__xformSetScale(float* t, float sx, float sy)-{- t[0] = sx; t[1] = 0.0f;- t[2] = 0.0f; t[3] = sy;- t[4] = 0.0f; t[5] = 0.0f;-}--static void nsvg__xformSetSkewX(float* t, float a)-{- t[0] = 1.0f; t[1] = 0.0f;- t[2] = tanf(a); t[3] = 1.0f;- t[4] = 0.0f; t[5] = 0.0f;-}--static void nsvg__xformSetSkewY(float* t, float a)-{- t[0] = 1.0f; t[1] = tanf(a);- t[2] = 0.0f; t[3] = 1.0f;- t[4] = 0.0f; t[5] = 0.0f;-}--static void nsvg__xformSetRotation(float* t, float a)-{- float cs = cosf(a), sn = sinf(a);- t[0] = cs; t[1] = sn;- t[2] = -sn; t[3] = cs;- t[4] = 0.0f; t[5] = 0.0f;-}--static void nsvg__xformMultiply(float* t, float* s)-{- float t0 = t[0] * s[0] + t[1] * s[2];- float t2 = t[2] * s[0] + t[3] * s[2];- float t4 = t[4] * s[0] + t[5] * s[2] + s[4];- t[1] = t[0] * s[1] + t[1] * s[3];- t[3] = t[2] * s[1] + t[3] * s[3];- t[5] = t[4] * s[1] + t[5] * s[3] + s[5];- t[0] = t0;- t[2] = t2;- t[4] = t4;-}--static void nsvg__xformInverse(float* inv, float* t)-{- double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1];- if (det > -1e-6 && det < 1e-6) {- nsvg__xformIdentity(t);- return;- }- invdet = 1.0 / det;- inv[0] = (float)(t[3] * invdet);- inv[2] = (float)(-t[2] * invdet);- inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet);- inv[1] = (float)(-t[1] * invdet);- inv[3] = (float)(t[0] * invdet);- inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet);-}--static void nsvg__xformPremultiply(float* t, float* s)-{- float s2[6];- memcpy(s2, s, sizeof(float)*6);- nsvg__xformMultiply(s2, t);- memcpy(t, s2, sizeof(float)*6);-}--static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t)-{- *dx = x*t[0] + y*t[2] + t[4];- *dy = x*t[1] + y*t[3] + t[5];-}--static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t)-{- *dx = x*t[0] + y*t[2];- *dy = x*t[1] + y*t[3];-}--#define NSVG_EPSILON (1e-12)--static int nsvg__ptInBounds(float* pt, float* bounds)-{- return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3];-}---static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3)-{- double it = 1.0-t;- return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3;-}--static void nsvg__curveBounds(float* bounds, float* curve)-{- int i, j, count;- double roots[2], a, b, c, b2ac, t, v;- float* v0 = &curve[0];- float* v1 = &curve[2];- float* v2 = &curve[4];- float* v3 = &curve[6];-- // Start the bounding box by end points- bounds[0] = nsvg__minf(v0[0], v3[0]);- bounds[1] = nsvg__minf(v0[1], v3[1]);- bounds[2] = nsvg__maxf(v0[0], v3[0]);- bounds[3] = nsvg__maxf(v0[1], v3[1]);-- // Bezier curve fits inside the convex hull of it's control points.- // If control points are inside the bounds, we're done.- if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds))- return;-- // Add bezier curve inflection points in X and Y.- for (i = 0; i < 2; i++) {- a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i];- b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i];- c = 3.0 * v1[i] - 3.0 * v0[i];- count = 0;- if (fabs(a) < NSVG_EPSILON) {- if (fabs(b) > NSVG_EPSILON) {- t = -c / b;- if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)- roots[count++] = t;- }- } else {- b2ac = b*b - 4.0*c*a;- if (b2ac > NSVG_EPSILON) {- t = (-b + sqrt(b2ac)) / (2.0 * a);- if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)- roots[count++] = t;- t = (-b - sqrt(b2ac)) / (2.0 * a);- if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)- roots[count++] = t;- }- }- for (j = 0; j < count; j++) {- v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]);- bounds[0+i] = nsvg__minf(bounds[0+i], (float)v);- bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v);- }- }-}--static NSVGparser* nsvg__createParser(void)-{- NSVGparser* p;- p = (NSVGparser*)malloc(sizeof(NSVGparser));- if (p == NULL) goto error;- memset(p, 0, sizeof(NSVGparser));-- p->image = (NSVGimage*)malloc(sizeof(NSVGimage));- if (p->image == NULL) goto error;- memset(p->image, 0, sizeof(NSVGimage));-- // Init style- nsvg__xformIdentity(p->attr[0].xform);- memset(p->attr[0].id, 0, sizeof p->attr[0].id);- p->attr[0].fillColor = NSVG_RGB(0,0,0);- p->attr[0].strokeColor = NSVG_RGB(0,0,0);- p->attr[0].opacity = 1;- p->attr[0].fillOpacity = 1;- p->attr[0].strokeOpacity = 1;- p->attr[0].stopOpacity = 1;- p->attr[0].strokeWidth = 1;- p->attr[0].strokeLineJoin = NSVG_JOIN_MITER;- p->attr[0].strokeLineCap = NSVG_CAP_BUTT;- p->attr[0].miterLimit = 4;- p->attr[0].fillRule = NSVG_FILLRULE_NONZERO;- p->attr[0].hasFill = 1;- p->attr[0].visible = 1;-- return p;--error:- if (p) {- if (p->image) free(p->image);- free(p);- }- return NULL;-}--static void nsvg__deletePaths(NSVGpath* path)-{- while (path) {- NSVGpath *next = path->next;- if (path->pts != NULL)- free(path->pts);- free(path);- path = next;- }-}--static void nsvg__deletePaint(NSVGpaint* paint)-{- if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT)- free(paint->gradient);-}--static void nsvg__deleteGradientData(NSVGgradientData* grad)-{- NSVGgradientData* next;- while (grad != NULL) {- next = grad->next;- free(grad->stops);- free(grad);- grad = next;- }-}--static void nsvg__deleteParser(NSVGparser* p)-{- if (p != NULL) {- nsvg__deletePaths(p->plist);- nsvg__deleteGradientData(p->gradients);- nsvgDelete(p->image);- free(p->pts);- free(p);- }-}--static void nsvg__resetPath(NSVGparser* p)-{- p->npts = 0;-}--static void nsvg__addPoint(NSVGparser* p, float x, float y)-{- if (p->npts+1 > p->cpts) {- p->cpts = p->cpts ? p->cpts*2 : 8;- p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float));- if (!p->pts) return;- }- p->pts[p->npts*2+0] = x;- p->pts[p->npts*2+1] = y;- p->npts++;-}--static void nsvg__moveTo(NSVGparser* p, float x, float y)-{- if (p->npts > 0) {- p->pts[(p->npts-1)*2+0] = x;- p->pts[(p->npts-1)*2+1] = y;- } else {- nsvg__addPoint(p, x, y);- }-}--static void nsvg__lineTo(NSVGparser* p, float x, float y)-{- float px,py, dx,dy;- if (p->npts > 0) {- px = p->pts[(p->npts-1)*2+0];- py = p->pts[(p->npts-1)*2+1];- dx = x - px;- dy = y - py;- nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f);- nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f);- nsvg__addPoint(p, x, y);- }-}--static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y)-{- if (p->npts > 0) {- nsvg__addPoint(p, cpx1, cpy1);- nsvg__addPoint(p, cpx2, cpy2);- nsvg__addPoint(p, x, y);- }-}--static NSVGattrib* nsvg__getAttr(NSVGparser* p)-{- return &p->attr[p->attrHead];-}--static void nsvg__pushAttr(NSVGparser* p)-{- if (p->attrHead < NSVG_MAX_ATTR-1) {- p->attrHead++;- memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib));- }-}--static void nsvg__popAttr(NSVGparser* p)-{- if (p->attrHead > 0)- p->attrHead--;-}--static float nsvg__actualOrigX(NSVGparser* p)-{- return p->viewMinx;-}--static float nsvg__actualOrigY(NSVGparser* p)-{- return p->viewMiny;-}--static float nsvg__actualWidth(NSVGparser* p)-{- return p->viewWidth;-}--static float nsvg__actualHeight(NSVGparser* p)-{- return p->viewHeight;-}--static float nsvg__actualLength(NSVGparser* p)-{- float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p);- return sqrtf(w*w + h*h) / sqrtf(2.0f);-}--static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length)-{- NSVGattrib* attr = nsvg__getAttr(p);- switch (c.units) {- case NSVG_UNITS_USER: return c.value;- case NSVG_UNITS_PX: return c.value;- case NSVG_UNITS_PT: return c.value / 72.0f * p->dpi;- case NSVG_UNITS_PC: return c.value / 6.0f * p->dpi;- case NSVG_UNITS_MM: return c.value / 25.4f * p->dpi;- case NSVG_UNITS_CM: return c.value / 2.54f * p->dpi;- case NSVG_UNITS_IN: return c.value * p->dpi;- case NSVG_UNITS_EM: return c.value * attr->fontSize;- case NSVG_UNITS_EX: return c.value * attr->fontSize * 0.52f; // x-height of Helvetica.- case NSVG_UNITS_PERCENT: return orig + c.value / 100.0f * length;- default: return c.value;- }- return c.value;-}--static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id)-{- NSVGgradientData* grad = p->gradients;- if (id == NULL || *id == '\0')- return NULL;- while (grad != NULL) {- if (strcmp(grad->id, id) == 0)- return grad;- grad = grad->next;- }- return NULL;-}--static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, char* paintType)-{- NSVGattrib* attr = nsvg__getAttr(p);- NSVGgradientData* data = NULL;- NSVGgradientData* ref = NULL;- NSVGgradientStop* stops = NULL;- NSVGgradient* grad;- float ox, oy, sw, sh, sl;- int nstops = 0;- int refIter;-- data = nsvg__findGradientData(p, id);- if (data == NULL) return NULL;-- // TODO: use ref to fill in all unset values too.- ref = data;- refIter = 0;- while (ref != NULL) {- NSVGgradientData* nextRef = NULL;- if (stops == NULL && ref->stops != NULL) {- stops = ref->stops;- nstops = ref->nstops;- break;- }- nextRef = nsvg__findGradientData(p, ref->ref);- if (nextRef == ref) break; // prevent infite loops on malformed data- ref = nextRef;- refIter++;- if (refIter > 32) break; // prevent infite loops on malformed data- }- if (stops == NULL) return NULL;-- grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1));- if (grad == NULL) return NULL;-- // The shape width and height.- if (data->units == NSVG_OBJECT_SPACE) {- ox = localBounds[0];- oy = localBounds[1];- sw = localBounds[2] - localBounds[0];- sh = localBounds[3] - localBounds[1];- } else {- ox = nsvg__actualOrigX(p);- oy = nsvg__actualOrigY(p);- sw = nsvg__actualWidth(p);- sh = nsvg__actualHeight(p);- }- sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f);-- if (data->type == NSVG_PAINT_LINEAR_GRADIENT) {- float x1, y1, x2, y2, dx, dy;- x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw);- y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh);- x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw);- y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh);- // Calculate transform aligned to the line- dx = x2 - x1;- dy = y2 - y1;- grad->xform[0] = dy; grad->xform[1] = -dx;- grad->xform[2] = dx; grad->xform[3] = dy;- grad->xform[4] = x1; grad->xform[5] = y1;- } else {- float cx, cy, fx, fy, r;- cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw);- cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh);- fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw);- fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh);- r = nsvg__convertToPixels(p, data->radial.r, 0, sl);- // Calculate transform aligned to the circle- grad->xform[0] = r; grad->xform[1] = 0;- grad->xform[2] = 0; grad->xform[3] = r;- grad->xform[4] = cx; grad->xform[5] = cy;- grad->fx = fx / r;- grad->fy = fy / r;- }-- nsvg__xformMultiply(grad->xform, data->xform);- nsvg__xformMultiply(grad->xform, attr->xform);-- grad->spread = data->spread;- memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop));- grad->nstops = nstops;-- *paintType = data->type;-- return grad;-}--static float nsvg__getAverageScale(float* t)-{- float sx = sqrtf(t[0]*t[0] + t[2]*t[2]);- float sy = sqrtf(t[1]*t[1] + t[3]*t[3]);- return (sx + sy) * 0.5f;-}--static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform)-{- NSVGpath* path;- float curve[4*2], curveBounds[4];- int i, first = 1;- for (path = shape->paths; path != NULL; path = path->next) {- nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform);- for (i = 0; i < path->npts-1; i += 3) {- nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform);- nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform);- nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform);- nsvg__curveBounds(curveBounds, curve);- if (first) {- bounds[0] = curveBounds[0];- bounds[1] = curveBounds[1];- bounds[2] = curveBounds[2];- bounds[3] = curveBounds[3];- first = 0;- } else {- bounds[0] = nsvg__minf(bounds[0], curveBounds[0]);- bounds[1] = nsvg__minf(bounds[1], curveBounds[1]);- bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]);- bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]);- }- curve[0] = curve[6];- curve[1] = curve[7];- }- }-}--static void nsvg__addShape(NSVGparser* p)-{- NSVGattrib* attr = nsvg__getAttr(p);- float scale = 1.0f;- NSVGshape* shape;- NSVGpath* path;- int i;-- if (p->plist == NULL)- return;-- shape = (NSVGshape*)malloc(sizeof(NSVGshape));- if (shape == NULL) goto error;- memset(shape, 0, sizeof(NSVGshape));-- memcpy(shape->id, attr->id, sizeof shape->id);- scale = nsvg__getAverageScale(attr->xform);- shape->strokeWidth = attr->strokeWidth * scale;- shape->strokeDashOffset = attr->strokeDashOffset * scale;- shape->strokeDashCount = (char)attr->strokeDashCount;- for (i = 0; i < attr->strokeDashCount; i++)- shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale;- shape->strokeLineJoin = attr->strokeLineJoin;- shape->strokeLineCap = attr->strokeLineCap;- shape->miterLimit = attr->miterLimit;- shape->fillRule = attr->fillRule;- shape->opacity = attr->opacity;-- shape->paths = p->plist;- p->plist = NULL;-- // Calculate shape bounds- shape->bounds[0] = shape->paths->bounds[0];- shape->bounds[1] = shape->paths->bounds[1];- shape->bounds[2] = shape->paths->bounds[2];- shape->bounds[3] = shape->paths->bounds[3];- for (path = shape->paths->next; path != NULL; path = path->next) {- shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]);- shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]);- shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]);- shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]);- }-- // Set fill- if (attr->hasFill == 0) {- shape->fill.type = NSVG_PAINT_NONE;- } else if (attr->hasFill == 1) {- shape->fill.type = NSVG_PAINT_COLOR;- shape->fill.color = attr->fillColor;- shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24;- } else if (attr->hasFill == 2) {- float inv[6], localBounds[4];- nsvg__xformInverse(inv, attr->xform);- nsvg__getLocalBounds(localBounds, shape, inv);- shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type);- if (shape->fill.gradient == NULL) {- shape->fill.type = NSVG_PAINT_NONE;- }- }-- // Set stroke- if (attr->hasStroke == 0) {- shape->stroke.type = NSVG_PAINT_NONE;- } else if (attr->hasStroke == 1) {- shape->stroke.type = NSVG_PAINT_COLOR;- shape->stroke.color = attr->strokeColor;- shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24;- } else if (attr->hasStroke == 2) {- float inv[6], localBounds[4];- nsvg__xformInverse(inv, attr->xform);- nsvg__getLocalBounds(localBounds, shape, inv);- shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type);- if (shape->stroke.gradient == NULL)- shape->stroke.type = NSVG_PAINT_NONE;- }-- // Set flags- shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00);-- // Add to tail- if (p->image->shapes == NULL)- p->image->shapes = shape;- else- p->shapesTail->next = shape;- p->shapesTail = shape;-- return;--error:- if (shape) free(shape);-}--static void nsvg__addPath(NSVGparser* p, char closed)-{- NSVGattrib* attr = nsvg__getAttr(p);- NSVGpath* path = NULL;- float bounds[4];- float* curve;- int i;-- if (p->npts < 4)- return;-- if (closed)- nsvg__lineTo(p, p->pts[0], p->pts[1]);-- // Expect 1 + N*3 points (N = number of cubic bezier segments).- if ((p->npts % 3) != 1)- return;-- path = (NSVGpath*)malloc(sizeof(NSVGpath));- if (path == NULL) goto error;- memset(path, 0, sizeof(NSVGpath));-- path->pts = (float*)malloc(p->npts*2*sizeof(float));- if (path->pts == NULL) goto error;- path->closed = closed;- path->npts = p->npts;-- // Transform path.- for (i = 0; i < p->npts; ++i)- nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform);-- // Find bounds- for (i = 0; i < path->npts-1; i += 3) {- curve = &path->pts[i*2];- nsvg__curveBounds(bounds, curve);- if (i == 0) {- path->bounds[0] = bounds[0];- path->bounds[1] = bounds[1];- path->bounds[2] = bounds[2];- path->bounds[3] = bounds[3];- } else {- path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]);- path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]);- path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]);- path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]);- }- }-- path->next = p->plist;- p->plist = path;-- return;--error:- if (path != NULL) {- if (path->pts != NULL) free(path->pts);- free(path);- }-}--// We roll our own string to float because the std library one uses locale and messes things up.-static double nsvg__atof(const char* s)-{- char* cur = (char*)s;- char* end = NULL;- double res = 0.0, sign = 1.0;- long long intPart = 0, fracPart = 0;- char hasIntPart = 0, hasFracPart = 0;-- // Parse optional sign- if (*cur == '+') {- cur++;- } else if (*cur == '-') {- sign = -1;- cur++;- }-- // Parse integer part- if (nsvg__isdigit(*cur)) {- // Parse digit sequence- intPart = strtoll(cur, &end, 10);- if (cur != end) {- res = (double)intPart;- hasIntPart = 1;- cur = end;- }- }-- // Parse fractional part.- if (*cur == '.') {- cur++; // Skip '.'- if (nsvg__isdigit(*cur)) {- // Parse digit sequence- fracPart = strtoll(cur, &end, 10);- if (cur != end) {- res += (double)fracPart / pow(10.0, (double)(end - cur));- hasFracPart = 1;- cur = end;- }- }- }-- // A valid number should have integer or fractional part.- if (!hasIntPart && !hasFracPart)- return 0.0;-- // Parse optional exponent- if (*cur == 'e' || *cur == 'E') {- long expPart = 0;- cur++; // skip 'E'- expPart = strtol(cur, &end, 10); // Parse digit sequence with sign- if (cur != end) {- res *= pow(10.0, (double)expPart);- }- }-- return res * sign;-}---static const char* nsvg__parseNumber(const char* s, char* it, const int size)-{- const int last = size-1;- int i = 0;-- // sign- if (*s == '-' || *s == '+') {- if (i < last) it[i++] = *s;- s++;- }- // integer part- while (*s && nsvg__isdigit(*s)) {- if (i < last) it[i++] = *s;- s++;- }- if (*s == '.') {- // decimal point- if (i < last) it[i++] = *s;- s++;- // fraction part- while (*s && nsvg__isdigit(*s)) {- if (i < last) it[i++] = *s;- s++;- }- }- // exponent- if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) {- if (i < last) it[i++] = *s;- s++;- if (*s == '-' || *s == '+') {- if (i < last) it[i++] = *s;- s++;- }- while (*s && nsvg__isdigit(*s)) {- if (i < last) it[i++] = *s;- s++;- }- }- it[i] = '\0';-- return s;-}--static const char* nsvg__getNextPathItem(const char* s, char* it)-{- it[0] = '\0';- // Skip white spaces and commas- while (*s && (nsvg__isspace(*s) || *s == ',')) s++;- if (!*s) return s;- if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) {- s = nsvg__parseNumber(s, it, 64);- } else {- // Parse command- it[0] = *s++;- it[1] = '\0';- return s;- }-- return s;-}--static unsigned int nsvg__parseColorHex(const char* str)-{- unsigned int r=0, g=0, b=0;- if (sscanf(str, "#%2x%2x%2x", &r, &g, &b) == 3 ) // 2 digit hex- return NSVG_RGB(r, g, b);- if (sscanf(str, "#%1x%1x%1x", &r, &g, &b) == 3 ) // 1 digit hex, e.g. #abc -> 0xccbbaa- return NSVG_RGB(r*17, g*17, b*17); // same effect as (r<<4|r), (g<<4|g), ..- return NSVG_RGB(128, 128, 128);-}--// Parse rgb color. The pointer 'str' must point at "rgb(" (4+ characters).-// This function returns gray (rgb(128, 128, 128) == '#808080') on parse errors-// for backwards compatibility. Note: other image viewers return black instead.--static unsigned int nsvg__parseColorRGB(const char* str)-{- int i;- unsigned int rgbi[3];- float rgbf[3];- // try decimal integers first- if (sscanf(str, "rgb(%u, %u, %u)", &rgbi[0], &rgbi[1], &rgbi[2]) != 3) {- // integers failed, try percent values (float, locale independent)- const char delimiter[3] = {',', ',', ')'};- str += 4; // skip "rgb("- for (i = 0; i < 3; i++) {- while (*str && (nsvg__isspace(*str))) str++; // skip leading spaces- if (*str == '+') str++; // skip '+' (don't allow '-')- if (!*str) break;- rgbf[i] = nsvg__atof(str);-- // Note 1: it would be great if nsvg__atof() returned how many- // bytes it consumed but it doesn't. We need to skip the number,- // the '%' character, spaces, and the delimiter ',' or ')'.-- // Note 2: The following code does not allow values like "33.%",- // i.e. a decimal point w/o fractional part, but this is consistent- // with other image viewers, e.g. firefox, chrome, eog, gimp.-- while (*str && nsvg__isdigit(*str)) str++; // skip integer part- if (*str == '.') {- str++;- if (!nsvg__isdigit(*str)) break; // error: no digit after '.'- while (*str && nsvg__isdigit(*str)) str++; // skip fractional part- }- if (*str == '%') str++; else break;- while (nsvg__isspace(*str)) str++;- if (*str == delimiter[i]) str++;- else break;- }- if (i == 3) {- rgbi[0] = roundf(rgbf[0] * 2.55f);- rgbi[1] = roundf(rgbf[1] * 2.55f);- rgbi[2] = roundf(rgbf[2] * 2.55f);- } else {- rgbi[0] = rgbi[1] = rgbi[2] = 128;- }- }- // clip values as the CSS spec requires- for (i = 0; i < 3; i++) {- if (rgbi[i] > 255) rgbi[i] = 255;- }- return NSVG_RGB(rgbi[0], rgbi[1], rgbi[2]);-}--typedef struct NSVGNamedColor {- const char* name;- unsigned int color;-} NSVGNamedColor;--NSVGNamedColor nsvg__colors[] = {-- { "red", NSVG_RGB(255, 0, 0) },- { "green", NSVG_RGB( 0, 128, 0) },- { "blue", NSVG_RGB( 0, 0, 255) },- { "yellow", NSVG_RGB(255, 255, 0) },- { "cyan", NSVG_RGB( 0, 255, 255) },- { "magenta", NSVG_RGB(255, 0, 255) },- { "black", NSVG_RGB( 0, 0, 0) },- { "grey", NSVG_RGB(128, 128, 128) },- { "gray", NSVG_RGB(128, 128, 128) },- { "white", NSVG_RGB(255, 255, 255) },--#ifdef NANOSVG_ALL_COLOR_KEYWORDS- { "aliceblue", NSVG_RGB(240, 248, 255) },- { "antiquewhite", NSVG_RGB(250, 235, 215) },- { "aqua", NSVG_RGB( 0, 255, 255) },- { "aquamarine", NSVG_RGB(127, 255, 212) },- { "azure", NSVG_RGB(240, 255, 255) },- { "beige", NSVG_RGB(245, 245, 220) },- { "bisque", NSVG_RGB(255, 228, 196) },- { "blanchedalmond", NSVG_RGB(255, 235, 205) },- { "blueviolet", NSVG_RGB(138, 43, 226) },- { "brown", NSVG_RGB(165, 42, 42) },- { "burlywood", NSVG_RGB(222, 184, 135) },- { "cadetblue", NSVG_RGB( 95, 158, 160) },- { "chartreuse", NSVG_RGB(127, 255, 0) },- { "chocolate", NSVG_RGB(210, 105, 30) },- { "coral", NSVG_RGB(255, 127, 80) },- { "cornflowerblue", NSVG_RGB(100, 149, 237) },- { "cornsilk", NSVG_RGB(255, 248, 220) },- { "crimson", NSVG_RGB(220, 20, 60) },- { "darkblue", NSVG_RGB( 0, 0, 139) },- { "darkcyan", NSVG_RGB( 0, 139, 139) },- { "darkgoldenrod", NSVG_RGB(184, 134, 11) },- { "darkgray", NSVG_RGB(169, 169, 169) },- { "darkgreen", NSVG_RGB( 0, 100, 0) },- { "darkgrey", NSVG_RGB(169, 169, 169) },- { "darkkhaki", NSVG_RGB(189, 183, 107) },- { "darkmagenta", NSVG_RGB(139, 0, 139) },- { "darkolivegreen", NSVG_RGB( 85, 107, 47) },- { "darkorange", NSVG_RGB(255, 140, 0) },- { "darkorchid", NSVG_RGB(153, 50, 204) },- { "darkred", NSVG_RGB(139, 0, 0) },- { "darksalmon", NSVG_RGB(233, 150, 122) },- { "darkseagreen", NSVG_RGB(143, 188, 143) },- { "darkslateblue", NSVG_RGB( 72, 61, 139) },- { "darkslategray", NSVG_RGB( 47, 79, 79) },- { "darkslategrey", NSVG_RGB( 47, 79, 79) },- { "darkturquoise", NSVG_RGB( 0, 206, 209) },- { "darkviolet", NSVG_RGB(148, 0, 211) },- { "deeppink", NSVG_RGB(255, 20, 147) },- { "deepskyblue", NSVG_RGB( 0, 191, 255) },- { "dimgray", NSVG_RGB(105, 105, 105) },- { "dimgrey", NSVG_RGB(105, 105, 105) },- { "dodgerblue", NSVG_RGB( 30, 144, 255) },- { "firebrick", NSVG_RGB(178, 34, 34) },- { "floralwhite", NSVG_RGB(255, 250, 240) },- { "forestgreen", NSVG_RGB( 34, 139, 34) },- { "fuchsia", NSVG_RGB(255, 0, 255) },- { "gainsboro", NSVG_RGB(220, 220, 220) },- { "ghostwhite", NSVG_RGB(248, 248, 255) },- { "gold", NSVG_RGB(255, 215, 0) },- { "goldenrod", NSVG_RGB(218, 165, 32) },- { "greenyellow", NSVG_RGB(173, 255, 47) },- { "honeydew", NSVG_RGB(240, 255, 240) },- { "hotpink", NSVG_RGB(255, 105, 180) },- { "indianred", NSVG_RGB(205, 92, 92) },- { "indigo", NSVG_RGB( 75, 0, 130) },- { "ivory", NSVG_RGB(255, 255, 240) },- { "khaki", NSVG_RGB(240, 230, 140) },- { "lavender", NSVG_RGB(230, 230, 250) },- { "lavenderblush", NSVG_RGB(255, 240, 245) },- { "lawngreen", NSVG_RGB(124, 252, 0) },- { "lemonchiffon", NSVG_RGB(255, 250, 205) },- { "lightblue", NSVG_RGB(173, 216, 230) },- { "lightcoral", NSVG_RGB(240, 128, 128) },- { "lightcyan", NSVG_RGB(224, 255, 255) },- { "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) },- { "lightgray", NSVG_RGB(211, 211, 211) },- { "lightgreen", NSVG_RGB(144, 238, 144) },- { "lightgrey", NSVG_RGB(211, 211, 211) },- { "lightpink", NSVG_RGB(255, 182, 193) },- { "lightsalmon", NSVG_RGB(255, 160, 122) },- { "lightseagreen", NSVG_RGB( 32, 178, 170) },- { "lightskyblue", NSVG_RGB(135, 206, 250) },- { "lightslategray", NSVG_RGB(119, 136, 153) },- { "lightslategrey", NSVG_RGB(119, 136, 153) },- { "lightsteelblue", NSVG_RGB(176, 196, 222) },- { "lightyellow", NSVG_RGB(255, 255, 224) },- { "lime", NSVG_RGB( 0, 255, 0) },- { "limegreen", NSVG_RGB( 50, 205, 50) },- { "linen", NSVG_RGB(250, 240, 230) },- { "maroon", NSVG_RGB(128, 0, 0) },- { "mediumaquamarine", NSVG_RGB(102, 205, 170) },- { "mediumblue", NSVG_RGB( 0, 0, 205) },- { "mediumorchid", NSVG_RGB(186, 85, 211) },- { "mediumpurple", NSVG_RGB(147, 112, 219) },- { "mediumseagreen", NSVG_RGB( 60, 179, 113) },- { "mediumslateblue", NSVG_RGB(123, 104, 238) },- { "mediumspringgreen", NSVG_RGB( 0, 250, 154) },- { "mediumturquoise", NSVG_RGB( 72, 209, 204) },- { "mediumvioletred", NSVG_RGB(199, 21, 133) },- { "midnightblue", NSVG_RGB( 25, 25, 112) },- { "mintcream", NSVG_RGB(245, 255, 250) },- { "mistyrose", NSVG_RGB(255, 228, 225) },- { "moccasin", NSVG_RGB(255, 228, 181) },- { "navajowhite", NSVG_RGB(255, 222, 173) },- { "navy", NSVG_RGB( 0, 0, 128) },- { "oldlace", NSVG_RGB(253, 245, 230) },- { "olive", NSVG_RGB(128, 128, 0) },- { "olivedrab", NSVG_RGB(107, 142, 35) },- { "orange", NSVG_RGB(255, 165, 0) },- { "orangered", NSVG_RGB(255, 69, 0) },- { "orchid", NSVG_RGB(218, 112, 214) },- { "palegoldenrod", NSVG_RGB(238, 232, 170) },- { "palegreen", NSVG_RGB(152, 251, 152) },- { "paleturquoise", NSVG_RGB(175, 238, 238) },- { "palevioletred", NSVG_RGB(219, 112, 147) },- { "papayawhip", NSVG_RGB(255, 239, 213) },- { "peachpuff", NSVG_RGB(255, 218, 185) },- { "peru", NSVG_RGB(205, 133, 63) },- { "pink", NSVG_RGB(255, 192, 203) },- { "plum", NSVG_RGB(221, 160, 221) },- { "powderblue", NSVG_RGB(176, 224, 230) },- { "purple", NSVG_RGB(128, 0, 128) },- { "rosybrown", NSVG_RGB(188, 143, 143) },- { "royalblue", NSVG_RGB( 65, 105, 225) },- { "saddlebrown", NSVG_RGB(139, 69, 19) },- { "salmon", NSVG_RGB(250, 128, 114) },- { "sandybrown", NSVG_RGB(244, 164, 96) },- { "seagreen", NSVG_RGB( 46, 139, 87) },- { "seashell", NSVG_RGB(255, 245, 238) },- { "sienna", NSVG_RGB(160, 82, 45) },- { "silver", NSVG_RGB(192, 192, 192) },- { "skyblue", NSVG_RGB(135, 206, 235) },- { "slateblue", NSVG_RGB(106, 90, 205) },- { "slategray", NSVG_RGB(112, 128, 144) },- { "slategrey", NSVG_RGB(112, 128, 144) },- { "snow", NSVG_RGB(255, 250, 250) },- { "springgreen", NSVG_RGB( 0, 255, 127) },- { "steelblue", NSVG_RGB( 70, 130, 180) },- { "tan", NSVG_RGB(210, 180, 140) },- { "teal", NSVG_RGB( 0, 128, 128) },- { "thistle", NSVG_RGB(216, 191, 216) },- { "tomato", NSVG_RGB(255, 99, 71) },- { "turquoise", NSVG_RGB( 64, 224, 208) },- { "violet", NSVG_RGB(238, 130, 238) },- { "wheat", NSVG_RGB(245, 222, 179) },- { "whitesmoke", NSVG_RGB(245, 245, 245) },- { "yellowgreen", NSVG_RGB(154, 205, 50) },-#endif-};--static unsigned int nsvg__parseColorName(const char* str)-{- int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor);-- for (i = 0; i < ncolors; i++) {- if (strcmp(nsvg__colors[i].name, str) == 0) {- return nsvg__colors[i].color;- }- }-- return NSVG_RGB(128, 128, 128);-}--static unsigned int nsvg__parseColor(const char* str)-{- size_t len = 0;- while(*str == ' ') ++str;- len = strlen(str);- if (len >= 1 && *str == '#')- return nsvg__parseColorHex(str);- else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(')- return nsvg__parseColorRGB(str);- return nsvg__parseColorName(str);-}--static float nsvg__parseOpacity(const char* str)-{- float val = nsvg__atof(str);- if (val < 0.0f) val = 0.0f;- if (val > 1.0f) val = 1.0f;- return val;-}--static float nsvg__parseMiterLimit(const char* str)-{- float val = nsvg__atof(str);- if (val < 0.0f) val = 0.0f;- return val;-}--static int nsvg__parseUnits(const char* units)-{- if (units[0] == 'p' && units[1] == 'x')- return NSVG_UNITS_PX;- else if (units[0] == 'p' && units[1] == 't')- return NSVG_UNITS_PT;- else if (units[0] == 'p' && units[1] == 'c')- return NSVG_UNITS_PC;- else if (units[0] == 'm' && units[1] == 'm')- return NSVG_UNITS_MM;- else if (units[0] == 'c' && units[1] == 'm')- return NSVG_UNITS_CM;- else if (units[0] == 'i' && units[1] == 'n')- return NSVG_UNITS_IN;- else if (units[0] == '%')- return NSVG_UNITS_PERCENT;- else if (units[0] == 'e' && units[1] == 'm')- return NSVG_UNITS_EM;- else if (units[0] == 'e' && units[1] == 'x')- return NSVG_UNITS_EX;- return NSVG_UNITS_USER;-}--static int nsvg__isCoordinate(const char* s)-{- // optional sign- if (*s == '-' || *s == '+')- s++;- // must have at least one digit, or start by a dot- return (nsvg__isdigit(*s) || *s == '.');-}--static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str)-{- NSVGcoordinate coord = {0, NSVG_UNITS_USER};- char buf[64];- coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64));- coord.value = nsvg__atof(buf);- return coord;-}--static NSVGcoordinate nsvg__coord(float v, int units)-{- NSVGcoordinate coord = {v, units};- return coord;-}--static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length)-{- NSVGcoordinate coord = nsvg__parseCoordinateRaw(str);- return nsvg__convertToPixels(p, coord, orig, length);-}--static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na)-{- const char* end;- const char* ptr;- char it[64];-- *na = 0;- ptr = str;- while (*ptr && *ptr != '(') ++ptr;- if (*ptr == 0)- return 1;- end = ptr;- while (*end && *end != ')') ++end;- if (*end == 0)- return 1;-- while (ptr < end) {- if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) {- if (*na >= maxNa) return 0;- ptr = nsvg__parseNumber(ptr, it, 64);- args[(*na)++] = (float)nsvg__atof(it);- } else {- ++ptr;- }- }- return (int)(end - str);-}---static int nsvg__parseMatrix(float* xform, const char* str)-{- float t[6];- int na = 0;- int len = nsvg__parseTransformArgs(str, t, 6, &na);- if (na != 6) return len;- memcpy(xform, t, sizeof(float)*6);- return len;-}--static int nsvg__parseTranslate(float* xform, const char* str)-{- float args[2];- float t[6];- int na = 0;- int len = nsvg__parseTransformArgs(str, args, 2, &na);- if (na == 1) args[1] = 0.0;-- nsvg__xformSetTranslation(t, args[0], args[1]);- memcpy(xform, t, sizeof(float)*6);- return len;-}--static int nsvg__parseScale(float* xform, const char* str)-{- float args[2];- int na = 0;- float t[6];- int len = nsvg__parseTransformArgs(str, args, 2, &na);- if (na == 1) args[1] = args[0];- nsvg__xformSetScale(t, args[0], args[1]);- memcpy(xform, t, sizeof(float)*6);- return len;-}--static int nsvg__parseSkewX(float* xform, const char* str)-{- float args[1];- int na = 0;- float t[6];- int len = nsvg__parseTransformArgs(str, args, 1, &na);- nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI);- memcpy(xform, t, sizeof(float)*6);- return len;-}--static int nsvg__parseSkewY(float* xform, const char* str)-{- float args[1];- int na = 0;- float t[6];- int len = nsvg__parseTransformArgs(str, args, 1, &na);- nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI);- memcpy(xform, t, sizeof(float)*6);- return len;-}--static int nsvg__parseRotate(float* xform, const char* str)-{- float args[3];- int na = 0;- float m[6];- float t[6];- int len = nsvg__parseTransformArgs(str, args, 3, &na);- if (na == 1)- args[1] = args[2] = 0.0f;- nsvg__xformIdentity(m);-- if (na > 1) {- nsvg__xformSetTranslation(t, -args[1], -args[2]);- nsvg__xformMultiply(m, t);- }-- nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI);- nsvg__xformMultiply(m, t);-- if (na > 1) {- nsvg__xformSetTranslation(t, args[1], args[2]);- nsvg__xformMultiply(m, t);- }-- memcpy(xform, m, sizeof(float)*6);-- return len;-}--static void nsvg__parseTransform(float* xform, const char* str)-{- float t[6];- int len;- nsvg__xformIdentity(xform);- while (*str)- {- if (strncmp(str, "matrix", 6) == 0)- len = nsvg__parseMatrix(t, str);- else if (strncmp(str, "translate", 9) == 0)- len = nsvg__parseTranslate(t, str);- else if (strncmp(str, "scale", 5) == 0)- len = nsvg__parseScale(t, str);- else if (strncmp(str, "rotate", 6) == 0)- len = nsvg__parseRotate(t, str);- else if (strncmp(str, "skewX", 5) == 0)- len = nsvg__parseSkewX(t, str);- else if (strncmp(str, "skewY", 5) == 0)- len = nsvg__parseSkewY(t, str);- else{- ++str;- continue;- }- if (len != 0) {- str += len;- } else {- ++str;- continue;- }-- nsvg__xformPremultiply(xform, t);- }-}--static void nsvg__parseUrl(char* id, const char* str)-{- int i = 0;- str += 4; // "url(";- if (*str && *str == '#')- str++;- while (i < 63 && *str && *str != ')') {- id[i] = *str++;- i++;- }- id[i] = '\0';-}--static char nsvg__parseLineCap(const char* str)-{- if (strcmp(str, "butt") == 0)- return NSVG_CAP_BUTT;- else if (strcmp(str, "round") == 0)- return NSVG_CAP_ROUND;- else if (strcmp(str, "square") == 0)- return NSVG_CAP_SQUARE;- // TODO: handle inherit.- return NSVG_CAP_BUTT;-}--static char nsvg__parseLineJoin(const char* str)-{- if (strcmp(str, "miter") == 0)- return NSVG_JOIN_MITER;- else if (strcmp(str, "round") == 0)- return NSVG_JOIN_ROUND;- else if (strcmp(str, "bevel") == 0)- return NSVG_JOIN_BEVEL;- // TODO: handle inherit.- return NSVG_JOIN_MITER;-}--static char nsvg__parseFillRule(const char* str)-{- if (strcmp(str, "nonzero") == 0)- return NSVG_FILLRULE_NONZERO;- else if (strcmp(str, "evenodd") == 0)- return NSVG_FILLRULE_EVENODD;- // TODO: handle inherit.- return NSVG_FILLRULE_NONZERO;-}--static const char* nsvg__getNextDashItem(const char* s, char* it)-{- int n = 0;- it[0] = '\0';- // Skip white spaces and commas- while (*s && (nsvg__isspace(*s) || *s == ',')) s++;- // Advance until whitespace, comma or end.- while (*s && (!nsvg__isspace(*s) && *s != ',')) {- if (n < 63)- it[n++] = *s;- s++;- }- it[n++] = '\0';- return s;-}--static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray)-{- char item[64];- int count = 0, i;- float sum = 0.0f;-- // Handle "none"- if (str[0] == 'n')- return 0;-- // Parse dashes- while (*str) {- str = nsvg__getNextDashItem(str, item);- if (!*item) break;- if (count < NSVG_MAX_DASHES)- strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p)));- }-- for (i = 0; i < count; i++)- sum += strokeDashArray[i];- if (sum <= 1e-6f)- count = 0;-- return count;-}--static void nsvg__parseStyle(NSVGparser* p, const char* str);--static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value)-{- float xform[6];- NSVGattrib* attr = nsvg__getAttr(p);- if (!attr) return 0;-- if (strcmp(name, "style") == 0) {- nsvg__parseStyle(p, value);- } else if (strcmp(name, "display") == 0) {- if (strcmp(value, "none") == 0)- attr->visible = 0;- // Don't reset ->visible on display:inline, one display:none hides the whole subtree-- } else if (strcmp(name, "fill") == 0) {- if (strcmp(value, "none") == 0) {- attr->hasFill = 0;- } else if (strncmp(value, "url(", 4) == 0) {- attr->hasFill = 2;- nsvg__parseUrl(attr->fillGradient, value);- } else {- attr->hasFill = 1;- attr->fillColor = nsvg__parseColor(value);- }- } else if (strcmp(name, "opacity") == 0) {- attr->opacity = nsvg__parseOpacity(value);- } else if (strcmp(name, "fill-opacity") == 0) {- attr->fillOpacity = nsvg__parseOpacity(value);- } else if (strcmp(name, "stroke") == 0) {- if (strcmp(value, "none") == 0) {- attr->hasStroke = 0;- } else if (strncmp(value, "url(", 4) == 0) {- attr->hasStroke = 2;- nsvg__parseUrl(attr->strokeGradient, value);- } else {- attr->hasStroke = 1;- attr->strokeColor = nsvg__parseColor(value);- }- } else if (strcmp(name, "stroke-width") == 0) {- attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));- } else if (strcmp(name, "stroke-dasharray") == 0) {- attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray);- } else if (strcmp(name, "stroke-dashoffset") == 0) {- attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));- } else if (strcmp(name, "stroke-opacity") == 0) {- attr->strokeOpacity = nsvg__parseOpacity(value);- } else if (strcmp(name, "stroke-linecap") == 0) {- attr->strokeLineCap = nsvg__parseLineCap(value);- } else if (strcmp(name, "stroke-linejoin") == 0) {- attr->strokeLineJoin = nsvg__parseLineJoin(value);- } else if (strcmp(name, "stroke-miterlimit") == 0) {- attr->miterLimit = nsvg__parseMiterLimit(value);- } else if (strcmp(name, "fill-rule") == 0) {- attr->fillRule = nsvg__parseFillRule(value);- } else if (strcmp(name, "font-size") == 0) {- attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));- } else if (strcmp(name, "transform") == 0) {- nsvg__parseTransform(xform, value);- nsvg__xformPremultiply(attr->xform, xform);- } else if (strcmp(name, "stop-color") == 0) {- attr->stopColor = nsvg__parseColor(value);- } else if (strcmp(name, "stop-opacity") == 0) {- attr->stopOpacity = nsvg__parseOpacity(value);- } else if (strcmp(name, "offset") == 0) {- attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f);- } else if (strcmp(name, "id") == 0) {- strncpy(attr->id, value, 63);- attr->id[63] = '\0';- } else {- return 0;- }- return 1;-}--static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end)-{- const char* str;- const char* val;- char name[512];- char value[512];- int n;-- str = start;- while (str < end && *str != ':') ++str;-- val = str;-- // Right Trim- while (str > start && (*str == ':' || nsvg__isspace(*str))) --str;- ++str;-- n = (int)(str - start);- if (n > 511) n = 511;- if (n) memcpy(name, start, n);- name[n] = 0;-- while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val;-- n = (int)(end - val);- if (n > 511) n = 511;- if (n) memcpy(value, val, n);- value[n] = 0;-- return nsvg__parseAttr(p, name, value);-}--static void nsvg__parseStyle(NSVGparser* p, const char* str)-{- const char* start;- const char* end;-- while (*str) {- // Left Trim- while(*str && nsvg__isspace(*str)) ++str;- start = str;- while(*str && *str != ';') ++str;- end = str;-- // Right Trim- while (end > start && (*end == ';' || nsvg__isspace(*end))) --end;- ++end;-- nsvg__parseNameValue(p, start, end);- if (*str) ++str;- }-}--static void nsvg__parseAttribs(NSVGparser* p, const char** attr)-{- int i;- for (i = 0; attr[i]; i += 2)- {- if (strcmp(attr[i], "style") == 0)- nsvg__parseStyle(p, attr[i + 1]);- else- nsvg__parseAttr(p, attr[i], attr[i + 1]);- }-}--static int nsvg__getArgsPerElement(char cmd)-{- switch (cmd) {- case 'v':- case 'V':- case 'h':- case 'H':- return 1;- case 'm':- case 'M':- case 'l':- case 'L':- case 't':- case 'T':- return 2;- case 'q':- case 'Q':- case 's':- case 'S':- return 4;- case 'c':- case 'C':- return 6;- case 'a':- case 'A':- return 7;- case 'z':- case 'Z':- return 0;- }- return -1;-}--static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)-{- if (rel) {- *cpx += args[0];- *cpy += args[1];- } else {- *cpx = args[0];- *cpy = args[1];- }- nsvg__moveTo(p, *cpx, *cpy);-}--static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)-{- if (rel) {- *cpx += args[0];- *cpy += args[1];- } else {- *cpx = args[0];- *cpy = args[1];- }- nsvg__lineTo(p, *cpx, *cpy);-}--static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)-{- if (rel)- *cpx += args[0];- else- *cpx = args[0];- nsvg__lineTo(p, *cpx, *cpy);-}--static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)-{- if (rel)- *cpy += args[0];- else- *cpy = args[0];- nsvg__lineTo(p, *cpx, *cpy);-}--static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy,- float* cpx2, float* cpy2, float* args, int rel)-{- float x2, y2, cx1, cy1, cx2, cy2;-- if (rel) {- cx1 = *cpx + args[0];- cy1 = *cpy + args[1];- cx2 = *cpx + args[2];- cy2 = *cpy + args[3];- x2 = *cpx + args[4];- y2 = *cpy + args[5];- } else {- cx1 = args[0];- cy1 = args[1];- cx2 = args[2];- cy2 = args[3];- x2 = args[4];- y2 = args[5];- }-- nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);-- *cpx2 = cx2;- *cpy2 = cy2;- *cpx = x2;- *cpy = y2;-}--static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy,- float* cpx2, float* cpy2, float* args, int rel)-{- float x1, y1, x2, y2, cx1, cy1, cx2, cy2;-- x1 = *cpx;- y1 = *cpy;- if (rel) {- cx2 = *cpx + args[0];- cy2 = *cpy + args[1];- x2 = *cpx + args[2];- y2 = *cpy + args[3];- } else {- cx2 = args[0];- cy2 = args[1];- x2 = args[2];- y2 = args[3];- }-- cx1 = 2*x1 - *cpx2;- cy1 = 2*y1 - *cpy2;-- nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);-- *cpx2 = cx2;- *cpy2 = cy2;- *cpx = x2;- *cpy = y2;-}--static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy,- float* cpx2, float* cpy2, float* args, int rel)-{- float x1, y1, x2, y2, cx, cy;- float cx1, cy1, cx2, cy2;-- x1 = *cpx;- y1 = *cpy;- if (rel) {- cx = *cpx + args[0];- cy = *cpy + args[1];- x2 = *cpx + args[2];- y2 = *cpy + args[3];- } else {- cx = args[0];- cy = args[1];- x2 = args[2];- y2 = args[3];- }-- // Convert to cubic bezier- cx1 = x1 + 2.0f/3.0f*(cx - x1);- cy1 = y1 + 2.0f/3.0f*(cy - y1);- cx2 = x2 + 2.0f/3.0f*(cx - x2);- cy2 = y2 + 2.0f/3.0f*(cy - y2);-- nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);-- *cpx2 = cx;- *cpy2 = cy;- *cpx = x2;- *cpy = y2;-}--static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy,- float* cpx2, float* cpy2, float* args, int rel)-{- float x1, y1, x2, y2, cx, cy;- float cx1, cy1, cx2, cy2;-- x1 = *cpx;- y1 = *cpy;- if (rel) {- x2 = *cpx + args[0];- y2 = *cpy + args[1];- } else {- x2 = args[0];- y2 = args[1];- }-- cx = 2*x1 - *cpx2;- cy = 2*y1 - *cpy2;-- // Convert to cubix bezier- cx1 = x1 + 2.0f/3.0f*(cx - x1);- cy1 = y1 + 2.0f/3.0f*(cy - y1);- cx2 = x2 + 2.0f/3.0f*(cx - x2);- cy2 = y2 + 2.0f/3.0f*(cy - y2);-- nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);-- *cpx2 = cx;- *cpy2 = cy;- *cpx = x2;- *cpy = y2;-}--static float nsvg__sqr(float x) { return x*x; }-static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); }--static float nsvg__vecrat(float ux, float uy, float vx, float vy)-{- return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy));-}--static float nsvg__vecang(float ux, float uy, float vx, float vy)-{- float r = nsvg__vecrat(ux,uy, vx,vy);- if (r < -1.0f) r = -1.0f;- if (r > 1.0f) r = 1.0f;- return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r);-}--static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)-{- // Ported from canvg (https://code.google.com/p/canvg/)- float rx, ry, rotx;- float x1, y1, x2, y2, cx, cy, dx, dy, d;- float x1p, y1p, cxp, cyp, s, sa, sb;- float ux, uy, vx, vy, a1, da;- float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6];- float sinrx, cosrx;- int fa, fs;- int i, ndivs;- float hda, kappa;-- rx = fabsf(args[0]); // y radius- ry = fabsf(args[1]); // x radius- rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle- fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc- fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction- x1 = *cpx; // start point- y1 = *cpy;- if (rel) { // end point- x2 = *cpx + args[5];- y2 = *cpy + args[6];- } else {- x2 = args[5];- y2 = args[6];- }-- dx = x1 - x2;- dy = y1 - y2;- d = sqrtf(dx*dx + dy*dy);- if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) {- // The arc degenerates to a line- nsvg__lineTo(p, x2, y2);- *cpx = x2;- *cpy = y2;- return;- }-- sinrx = sinf(rotx);- cosrx = cosf(rotx);-- // Convert to center point parameterization.- // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes- // 1) Compute x1', y1'- x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f;- y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f;- d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry);- if (d > 1) {- d = sqrtf(d);- rx *= d;- ry *= d;- }- // 2) Compute cx', cy'- s = 0.0f;- sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p);- sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p);- if (sa < 0.0f) sa = 0.0f;- if (sb > 0.0f)- s = sqrtf(sa / sb);- if (fa == fs)- s = -s;- cxp = s * rx * y1p / ry;- cyp = s * -ry * x1p / rx;-- // 3) Compute cx,cy from cx',cy'- cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp;- cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp;-- // 4) Calculate theta1, and delta theta.- ux = (x1p - cxp) / rx;- uy = (y1p - cyp) / ry;- vx = (-x1p - cxp) / rx;- vy = (-y1p - cyp) / ry;- a1 = nsvg__vecang(1.0f,0.0f, ux,uy); // Initial angle- da = nsvg__vecang(ux,uy, vx,vy); // Delta angle--// if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI;-// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0;-- if (fs == 0 && da > 0)- da -= 2 * NSVG_PI;- else if (fs == 1 && da < 0)- da += 2 * NSVG_PI;-- // Approximate the arc using cubic spline segments.- t[0] = cosrx; t[1] = sinrx;- t[2] = -sinrx; t[3] = cosrx;- t[4] = cx; t[5] = cy;-- // Split arc into max 90 degree segments.- // The loop assumes an iteration per end point (including start and end), this +1.- ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f);- hda = (da / (float)ndivs) / 2.0f;- // Fix for ticket #179: division by 0: avoid cotangens around 0 (infinite)- if ((hda < 1e-3f) && (hda > -1e-3f))- hda *= 0.5f;- else- hda = (1.0f - cosf(hda)) / sinf(hda);- kappa = fabsf(4.0f / 3.0f * hda);- if (da < 0.0f)- kappa = -kappa;-- for (i = 0; i <= ndivs; i++) {- a = a1 + da * ((float)i/(float)ndivs);- dx = cosf(a);- dy = sinf(a);- nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position- nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent- if (i > 0)- nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y);- px = x;- py = y;- ptanx = tanx;- ptany = tany;- }-- *cpx = x2;- *cpy = y2;-}--static void nsvg__parsePath(NSVGparser* p, const char** attr)-{- const char* s = NULL;- char cmd = '\0';- float args[10];- int nargs;- int rargs = 0;- char initPoint;- float cpx, cpy, cpx2, cpy2;- const char* tmp[4];- char closedFlag;- int i;- char item[64];-- for (i = 0; attr[i]; i += 2) {- if (strcmp(attr[i], "d") == 0) {- s = attr[i + 1];- } else {- tmp[0] = attr[i];- tmp[1] = attr[i + 1];- tmp[2] = 0;- tmp[3] = 0;- nsvg__parseAttribs(p, tmp);- }- }-- if (s) {- nsvg__resetPath(p);- cpx = 0; cpy = 0;- cpx2 = 0; cpy2 = 0;- initPoint = 0;- closedFlag = 0;- nargs = 0;-- while (*s) {- s = nsvg__getNextPathItem(s, item);- if (!*item) break;- if (cmd != '\0' && nsvg__isCoordinate(item)) {- if (nargs < 10)- args[nargs++] = (float)nsvg__atof(item);- if (nargs >= rargs) {- switch (cmd) {- case 'm':- case 'M':- nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0);- // Moveto can be followed by multiple coordinate pairs,- // which should be treated as linetos.- cmd = (cmd == 'm') ? 'l' : 'L';- rargs = nsvg__getArgsPerElement(cmd);- cpx2 = cpx; cpy2 = cpy;- initPoint = 1;- break;- case 'l':- case 'L':- nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0);- cpx2 = cpx; cpy2 = cpy;- break;- case 'H':- case 'h':- nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0);- cpx2 = cpx; cpy2 = cpy;- break;- case 'V':- case 'v':- nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0);- cpx2 = cpx; cpy2 = cpy;- break;- case 'C':- case 'c':- nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0);- break;- case 'S':- case 's':- nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0);- break;- case 'Q':- case 'q':- nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0);- break;- case 'T':- case 't':- nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0);- break;- case 'A':- case 'a':- nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0);- cpx2 = cpx; cpy2 = cpy;- break;- default:- if (nargs >= 2) {- cpx = args[nargs-2];- cpy = args[nargs-1];- cpx2 = cpx; cpy2 = cpy;- }- break;- }- nargs = 0;- }- } else {- cmd = item[0];- if (cmd == 'M' || cmd == 'm') {- // Commit path.- if (p->npts > 0)- nsvg__addPath(p, closedFlag);- // Start new subpath.- nsvg__resetPath(p);- closedFlag = 0;- nargs = 0;- } else if (initPoint == 0) {- // Do not allow other commands until initial point has been set (moveTo called once).- cmd = '\0';- }- if (cmd == 'Z' || cmd == 'z') {- closedFlag = 1;- // Commit path.- if (p->npts > 0) {- // Move current point to first point- cpx = p->pts[0];- cpy = p->pts[1];- cpx2 = cpx; cpy2 = cpy;- nsvg__addPath(p, closedFlag);- }- // Start new subpath.- nsvg__resetPath(p);- nsvg__moveTo(p, cpx, cpy);- closedFlag = 0;- nargs = 0;- }- rargs = nsvg__getArgsPerElement(cmd);- if (rargs == -1) {- // Command not recognized- cmd = '\0';- rargs = 0;- }- }- }- // Commit path.- if (p->npts)- nsvg__addPath(p, closedFlag);- }-- nsvg__addShape(p);-}--static void nsvg__parseRect(NSVGparser* p, const char** attr)-{- float x = 0.0f;- float y = 0.0f;- float w = 0.0f;- float h = 0.0f;- float rx = -1.0f; // marks not set- float ry = -1.0f;- int i;-- for (i = 0; attr[i]; i += 2) {- if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {- if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));- if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));- if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p));- if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p));- if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)));- if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)));- }- }-- if (rx < 0.0f && ry > 0.0f) rx = ry;- if (ry < 0.0f && rx > 0.0f) ry = rx;- if (rx < 0.0f) rx = 0.0f;- if (ry < 0.0f) ry = 0.0f;- if (rx > w/2.0f) rx = w/2.0f;- if (ry > h/2.0f) ry = h/2.0f;-- if (w != 0.0f && h != 0.0f) {- nsvg__resetPath(p);-- if (rx < 0.00001f || ry < 0.0001f) {- nsvg__moveTo(p, x, y);- nsvg__lineTo(p, x+w, y);- nsvg__lineTo(p, x+w, y+h);- nsvg__lineTo(p, x, y+h);- } else {- // Rounded rectangle- nsvg__moveTo(p, x+rx, y);- nsvg__lineTo(p, x+w-rx, y);- nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry);- nsvg__lineTo(p, x+w, y+h-ry);- nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h);- nsvg__lineTo(p, x+rx, y+h);- nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry);- nsvg__lineTo(p, x, y+ry);- nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y);- }-- nsvg__addPath(p, 1);-- nsvg__addShape(p);- }-}--static void nsvg__parseCircle(NSVGparser* p, const char** attr)-{- float cx = 0.0f;- float cy = 0.0f;- float r = 0.0f;- int i;-- for (i = 0; attr[i]; i += 2) {- if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {- if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));- if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));- if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p)));- }- }-- if (r > 0.0f) {- nsvg__resetPath(p);-- nsvg__moveTo(p, cx+r, cy);- nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r);- nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy);- nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r);- nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy);-- nsvg__addPath(p, 1);-- nsvg__addShape(p);- }-}--static void nsvg__parseEllipse(NSVGparser* p, const char** attr)-{- float cx = 0.0f;- float cy = 0.0f;- float rx = 0.0f;- float ry = 0.0f;- int i;-- for (i = 0; attr[i]; i += 2) {- if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {- if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));- if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));- if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)));- if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)));- }- }-- if (rx > 0.0f && ry > 0.0f) {-- nsvg__resetPath(p);-- nsvg__moveTo(p, cx+rx, cy);- nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry);- nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy);- nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry);- nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy);-- nsvg__addPath(p, 1);-- nsvg__addShape(p);- }-}--static void nsvg__parseLine(NSVGparser* p, const char** attr)-{- float x1 = 0.0;- float y1 = 0.0;- float x2 = 0.0;- float y2 = 0.0;- int i;-- for (i = 0; attr[i]; i += 2) {- if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {- if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p));- if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p));- if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p));- if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p));- }- }-- nsvg__resetPath(p);-- nsvg__moveTo(p, x1, y1);- nsvg__lineTo(p, x2, y2);-- nsvg__addPath(p, 0);-- nsvg__addShape(p);-}--static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag)-{- int i;- const char* s;- float args[2];- int nargs, npts = 0;- char item[64];-- nsvg__resetPath(p);-- for (i = 0; attr[i]; i += 2) {- if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {- if (strcmp(attr[i], "points") == 0) {- s = attr[i + 1];- nargs = 0;- while (*s) {- s = nsvg__getNextPathItem(s, item);- args[nargs++] = (float)nsvg__atof(item);- if (nargs >= 2) {- if (npts == 0)- nsvg__moveTo(p, args[0], args[1]);- else- nsvg__lineTo(p, args[0], args[1]);- nargs = 0;- npts++;- }- }- }- }- }-- nsvg__addPath(p, (char)closeFlag);-- nsvg__addShape(p);-}--static void nsvg__parseSVG(NSVGparser* p, const char** attr)-{- int i;- for (i = 0; attr[i]; i += 2) {- if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {- if (strcmp(attr[i], "width") == 0) {- p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);- } else if (strcmp(attr[i], "height") == 0) {- p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);- } else if (strcmp(attr[i], "viewBox") == 0) {- const char *s = attr[i + 1];- char buf[64];- s = nsvg__parseNumber(s, buf, 64);- p->viewMinx = nsvg__atof(buf);- while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;- if (!*s) return;- s = nsvg__parseNumber(s, buf, 64);- p->viewMiny = nsvg__atof(buf);- while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;- if (!*s) return;- s = nsvg__parseNumber(s, buf, 64);- p->viewWidth = nsvg__atof(buf);- while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;- if (!*s) return;- s = nsvg__parseNumber(s, buf, 64);- p->viewHeight = nsvg__atof(buf);- } else if (strcmp(attr[i], "preserveAspectRatio") == 0) {- if (strstr(attr[i + 1], "none") != 0) {- // No uniform scaling- p->alignType = NSVG_ALIGN_NONE;- } else {- // Parse X align- if (strstr(attr[i + 1], "xMin") != 0)- p->alignX = NSVG_ALIGN_MIN;- else if (strstr(attr[i + 1], "xMid") != 0)- p->alignX = NSVG_ALIGN_MID;- else if (strstr(attr[i + 1], "xMax") != 0)- p->alignX = NSVG_ALIGN_MAX;- // Parse X align- if (strstr(attr[i + 1], "yMin") != 0)- p->alignY = NSVG_ALIGN_MIN;- else if (strstr(attr[i + 1], "yMid") != 0)- p->alignY = NSVG_ALIGN_MID;- else if (strstr(attr[i + 1], "yMax") != 0)- p->alignY = NSVG_ALIGN_MAX;- // Parse meet/slice- p->alignType = NSVG_ALIGN_MEET;- if (strstr(attr[i + 1], "slice") != 0)- p->alignType = NSVG_ALIGN_SLICE;- }- }- }- }-}--static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type)-{- int i;- NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData));- if (grad == NULL) return;- memset(grad, 0, sizeof(NSVGgradientData));- grad->units = NSVG_OBJECT_SPACE;- grad->type = type;- if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) {- grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);- grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);- grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT);- grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);- } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) {- grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);- grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);- grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);- }-- nsvg__xformIdentity(grad->xform);-- for (i = 0; attr[i]; i += 2) {- if (strcmp(attr[i], "id") == 0) {- strncpy(grad->id, attr[i+1], 63);- grad->id[63] = '\0';- } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {- if (strcmp(attr[i], "gradientUnits") == 0) {- if (strcmp(attr[i+1], "objectBoundingBox") == 0)- grad->units = NSVG_OBJECT_SPACE;- else- grad->units = NSVG_USER_SPACE;- } else if (strcmp(attr[i], "gradientTransform") == 0) {- nsvg__parseTransform(grad->xform, attr[i + 1]);- } else if (strcmp(attr[i], "cx") == 0) {- grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]);- } else if (strcmp(attr[i], "cy") == 0) {- grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]);- } else if (strcmp(attr[i], "r") == 0) {- grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]);- } else if (strcmp(attr[i], "fx") == 0) {- grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]);- } else if (strcmp(attr[i], "fy") == 0) {- grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]);- } else if (strcmp(attr[i], "x1") == 0) {- grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]);- } else if (strcmp(attr[i], "y1") == 0) {- grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]);- } else if (strcmp(attr[i], "x2") == 0) {- grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]);- } else if (strcmp(attr[i], "y2") == 0) {- grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]);- } else if (strcmp(attr[i], "spreadMethod") == 0) {- if (strcmp(attr[i+1], "pad") == 0)- grad->spread = NSVG_SPREAD_PAD;- else if (strcmp(attr[i+1], "reflect") == 0)- grad->spread = NSVG_SPREAD_REFLECT;- else if (strcmp(attr[i+1], "repeat") == 0)- grad->spread = NSVG_SPREAD_REPEAT;- } else if (strcmp(attr[i], "xlink:href") == 0) {- const char *href = attr[i+1];- strncpy(grad->ref, href+1, 62);- grad->ref[62] = '\0';- }- }- }-- grad->next = p->gradients;- p->gradients = grad;-}--static void nsvg__parseGradientStop(NSVGparser* p, const char** attr)-{- NSVGattrib* curAttr = nsvg__getAttr(p);- NSVGgradientData* grad;- NSVGgradientStop* stop;- int i, idx;-- curAttr->stopOffset = 0;- curAttr->stopColor = 0;- curAttr->stopOpacity = 1.0f;-- for (i = 0; attr[i]; i += 2) {- nsvg__parseAttr(p, attr[i], attr[i + 1]);- }-- // Add stop to the last gradient.- grad = p->gradients;- if (grad == NULL) return;-- grad->nstops++;- grad->stops = (NSVGgradientStop*)realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops);- if (grad->stops == NULL) return;-- // Insert- idx = grad->nstops-1;- for (i = 0; i < grad->nstops-1; i++) {- if (curAttr->stopOffset < grad->stops[i].offset) {- idx = i;- break;- }- }- if (idx != grad->nstops-1) {- for (i = grad->nstops-1; i > idx; i--)- grad->stops[i] = grad->stops[i-1];- }-- stop = &grad->stops[idx];- stop->color = curAttr->stopColor;- stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24;- stop->offset = curAttr->stopOffset;-}--static void nsvg__startElement(void* ud, const char* el, const char** attr)-{- NSVGparser* p = (NSVGparser*)ud;-- if (p->defsFlag) {- // Skip everything but gradients in defs- if (strcmp(el, "linearGradient") == 0) {- nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT);- } else if (strcmp(el, "radialGradient") == 0) {- nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);- } else if (strcmp(el, "stop") == 0) {- nsvg__parseGradientStop(p, attr);- }- return;- }-- if (strcmp(el, "g") == 0) {- nsvg__pushAttr(p);- nsvg__parseAttribs(p, attr);- } else if (strcmp(el, "path") == 0) {- if (p->pathFlag) // Do not allow nested paths.- return;- nsvg__pushAttr(p);- nsvg__parsePath(p, attr);- nsvg__popAttr(p);- } else if (strcmp(el, "rect") == 0) {- nsvg__pushAttr(p);- nsvg__parseRect(p, attr);- nsvg__popAttr(p);- } else if (strcmp(el, "circle") == 0) {- nsvg__pushAttr(p);- nsvg__parseCircle(p, attr);- nsvg__popAttr(p);- } else if (strcmp(el, "ellipse") == 0) {- nsvg__pushAttr(p);- nsvg__parseEllipse(p, attr);- nsvg__popAttr(p);- } else if (strcmp(el, "line") == 0) {- nsvg__pushAttr(p);- nsvg__parseLine(p, attr);- nsvg__popAttr(p);- } else if (strcmp(el, "polyline") == 0) {- nsvg__pushAttr(p);- nsvg__parsePoly(p, attr, 0);- nsvg__popAttr(p);- } else if (strcmp(el, "polygon") == 0) {- nsvg__pushAttr(p);- nsvg__parsePoly(p, attr, 1);- nsvg__popAttr(p);- } else if (strcmp(el, "linearGradient") == 0) {- nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT);- } else if (strcmp(el, "radialGradient") == 0) {- nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);- } else if (strcmp(el, "stop") == 0) {- nsvg__parseGradientStop(p, attr);- } else if (strcmp(el, "defs") == 0) {- p->defsFlag = 1;- } else if (strcmp(el, "svg") == 0) {- nsvg__parseSVG(p, attr);- }-}--static void nsvg__endElement(void* ud, const char* el)-{- NSVGparser* p = (NSVGparser*)ud;-- if (strcmp(el, "g") == 0) {- nsvg__popAttr(p);- } else if (strcmp(el, "path") == 0) {- p->pathFlag = 0;- } else if (strcmp(el, "defs") == 0) {- p->defsFlag = 0;- }-}--static void nsvg__content(void* ud, const char* s)-{- NSVG_NOTUSED(ud);- NSVG_NOTUSED(s);- // empty-}--static void nsvg__imageBounds(NSVGparser* p, float* bounds)-{- NSVGshape* shape;- shape = p->image->shapes;- if (shape == NULL) {- bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0;- return;- }- bounds[0] = shape->bounds[0];- bounds[1] = shape->bounds[1];- bounds[2] = shape->bounds[2];- bounds[3] = shape->bounds[3];- for (shape = shape->next; shape != NULL; shape = shape->next) {- bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]);- bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]);- bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]);- bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]);- }-}--static float nsvg__viewAlign(float content, float container, int type)-{- if (type == NSVG_ALIGN_MIN)- return 0;- else if (type == NSVG_ALIGN_MAX)- return container - content;- // mid- return (container - content) * 0.5f;-}--static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy)-{- float t[6];- nsvg__xformSetTranslation(t, tx, ty);- nsvg__xformMultiply (grad->xform, t);-- nsvg__xformSetScale(t, sx, sy);- nsvg__xformMultiply (grad->xform, t);-}--static void nsvg__scaleToViewbox(NSVGparser* p, const char* units)-{- NSVGshape* shape;- NSVGpath* path;- float tx, ty, sx, sy, us, bounds[4], t[6], avgs;- int i;- float* pt;-- // Guess image size if not set completely.- nsvg__imageBounds(p, bounds);-- if (p->viewWidth == 0) {- if (p->image->width > 0) {- p->viewWidth = p->image->width;- } else {- p->viewMinx = bounds[0];- p->viewWidth = bounds[2] - bounds[0];- }- }- if (p->viewHeight == 0) {- if (p->image->height > 0) {- p->viewHeight = p->image->height;- } else {- p->viewMiny = bounds[1];- p->viewHeight = bounds[3] - bounds[1];- }- }- if (p->image->width == 0)- p->image->width = p->viewWidth;- if (p->image->height == 0)- p->image->height = p->viewHeight;-- tx = -p->viewMinx;- ty = -p->viewMiny;- sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0;- sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0;- // Unit scaling- us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f);-- // Fix aspect ratio- if (p->alignType == NSVG_ALIGN_MEET) {- // fit whole image into viewbox- sx = sy = nsvg__minf(sx, sy);- tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx;- ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy;- } else if (p->alignType == NSVG_ALIGN_SLICE) {- // fill whole viewbox with image- sx = sy = nsvg__maxf(sx, sy);- tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx;- ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy;- }-- // Transform- sx *= us;- sy *= us;- avgs = (sx+sy) / 2.0f;- for (shape = p->image->shapes; shape != NULL; shape = shape->next) {- shape->bounds[0] = (shape->bounds[0] + tx) * sx;- shape->bounds[1] = (shape->bounds[1] + ty) * sy;- shape->bounds[2] = (shape->bounds[2] + tx) * sx;- shape->bounds[3] = (shape->bounds[3] + ty) * sy;- for (path = shape->paths; path != NULL; path = path->next) {- path->bounds[0] = (path->bounds[0] + tx) * sx;- path->bounds[1] = (path->bounds[1] + ty) * sy;- path->bounds[2] = (path->bounds[2] + tx) * sx;- path->bounds[3] = (path->bounds[3] + ty) * sy;- for (i =0; i < path->npts; i++) {- pt = &path->pts[i*2];- pt[0] = (pt[0] + tx) * sx;- pt[1] = (pt[1] + ty) * sy;- }- }-- if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) {- nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy);- memcpy(t, shape->fill.gradient->xform, sizeof(float)*6);- nsvg__xformInverse(shape->fill.gradient->xform, t);- }- if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) {- nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy);- memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6);- nsvg__xformInverse(shape->stroke.gradient->xform, t);- }-- shape->strokeWidth *= avgs;- shape->strokeDashOffset *= avgs;- for (i = 0; i < shape->strokeDashCount; i++)- shape->strokeDashArray[i] *= avgs;- }-}--NSVGimage* nsvgParse(char* input, const char* units, float dpi)-{- NSVGparser* p;- NSVGimage* ret = 0;-- p = nsvg__createParser();- if (p == NULL) {- return NULL;- }- p->dpi = dpi;-- nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p);-- // Scale to viewBox- nsvg__scaleToViewbox(p, units);-- ret = p->image;- p->image = NULL;-- nsvg__deleteParser(p);-- return ret;-}--NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi)-{- FILE* fp = NULL;- size_t size;- char* data = NULL;- NSVGimage* image = NULL;-- fp = fopen(filename, "rb");- if (!fp) goto error;- fseek(fp, 0, SEEK_END);- size = ftell(fp);- fseek(fp, 0, SEEK_SET);- data = (char*)malloc(size+1);- if (data == NULL) goto error;- if (fread(data, 1, size, fp) != size) goto error;- data[size] = '\0'; // Must be null terminated.- fclose(fp);- image = nsvgParse(data, units, dpi);- free(data);-- return image;--error:- if (fp) fclose(fp);- if (data) free(data);- if (image) nsvgDelete(image);- return NULL;-}--NSVGpath* nsvgDuplicatePath(NSVGpath* p)-{- NSVGpath* res = NULL;-- if (p == NULL)- return NULL;-- res = (NSVGpath*)malloc(sizeof(NSVGpath));- if (res == NULL) goto error;- memset(res, 0, sizeof(NSVGpath));-- res->pts = (float*)malloc(p->npts*2*sizeof(float));- if (res->pts == NULL) goto error;- memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2);- res->npts = p->npts;-- memcpy(res->bounds, p->bounds, sizeof(p->bounds));-- res->closed = p->closed;-- return res;--error:- if (res != NULL) {- free(res->pts);- free(res);- }- return NULL;-}--void nsvgDelete(NSVGimage* image)-{- NSVGshape *snext, *shape;- if (image == NULL) return;- shape = image->shapes;- while (shape != NULL) {- snext = shape->next;- nsvg__deletePaths(shape->paths);- nsvg__deletePaint(&shape->fill);- nsvg__deletePaint(&shape->stroke);- free(shape);- shape = snext;- }- free(image);-}--#endif // NANOSVG_IMPLEMENTATION--#endif // NANOSVG_H
− raylib/src/external/nanosvgrast.h
@@ -1,1458 +0,0 @@-/*- * Copyright (c) 2013-14 Mikko Mononen memon@inside.org- *- * This software is provided 'as-is', without any express or implied- * warranty. In no event will the authors be held liable for any damages- * arising from the use of this software.- *- * Permission is granted to anyone to use this software for any purpose,- * including commercial applications, and to alter it and redistribute it- * freely, subject to the following restrictions:- *- * 1. The origin of this software must not be misrepresented; you must not- * claim that you wrote the original software. If you use this software- * in a product, an acknowledgment in the product documentation would be- * appreciated but is not required.- * 2. Altered source versions must be plainly marked as such, and must not be- * misrepresented as being the original software.- * 3. This notice may not be removed or altered from any source distribution.- *- * The polygon rasterization is heavily based on stb_truetype rasterizer- * by Sean Barrett - http://nothings.org/- *- */--#ifndef NANOSVGRAST_H-#define NANOSVGRAST_H--#include "nanosvg.h"--#ifndef NANOSVGRAST_CPLUSPLUS-#ifdef __cplusplus-extern "C" {-#endif-#endif--typedef struct NSVGrasterizer NSVGrasterizer;--/* Example Usage:- // Load SVG- NSVGimage* image;- image = nsvgParseFromFile("test.svg", "px", 96);-- // Create rasterizer (can be used to render multiple images).- struct NSVGrasterizer* rast = nsvgCreateRasterizer();- // Allocate memory for image- unsigned char* img = malloc(w*h*4);- // Rasterize- nsvgRasterize(rast, image, 0,0,1, img, w, h, w*4);-*/--// Allocated rasterizer context.-NSVGrasterizer* nsvgCreateRasterizer(void);--// Rasterizes SVG image, returns RGBA image (non-premultiplied alpha)-// r - pointer to rasterizer context-// image - pointer to image to rasterize-// tx,ty - image offset (applied after scaling)-// scale - image scale-// dst - pointer to destination image data, 4 bytes per pixel (RGBA)-// w - width of the image to render-// h - height of the image to render-// stride - number of bytes per scaleline in the destination buffer-void nsvgRasterize(NSVGrasterizer* r,- NSVGimage* image, float tx, float ty, float scale,- unsigned char* dst, int w, int h, int stride);--// Deletes rasterizer context.-void nsvgDeleteRasterizer(NSVGrasterizer*);---#ifndef NANOSVGRAST_CPLUSPLUS-#ifdef __cplusplus-}-#endif-#endif--#ifdef NANOSVGRAST_IMPLEMENTATION--#include <math.h>-#include <stdlib.h>-#include <string.h>--#define NSVG__SUBSAMPLES 5-#define NSVG__FIXSHIFT 10-#define NSVG__FIX (1 << NSVG__FIXSHIFT)-#define NSVG__FIXMASK (NSVG__FIX-1)-#define NSVG__MEMPAGE_SIZE 1024--typedef struct NSVGedge {- float x0,y0, x1,y1;- int dir;- struct NSVGedge* next;-} NSVGedge;--typedef struct NSVGpoint {- float x, y;- float dx, dy;- float len;- float dmx, dmy;- unsigned char flags;-} NSVGpoint;--typedef struct NSVGactiveEdge {- int x,dx;- float ey;- int dir;- struct NSVGactiveEdge *next;-} NSVGactiveEdge;--typedef struct NSVGmemPage {- unsigned char mem[NSVG__MEMPAGE_SIZE];- int size;- struct NSVGmemPage* next;-} NSVGmemPage;--typedef struct NSVGcachedPaint {- char type;- char spread;- float xform[6];- unsigned int colors[256];-} NSVGcachedPaint;--struct NSVGrasterizer-{- float px, py;-- float tessTol;- float distTol;-- NSVGedge* edges;- int nedges;- int cedges;-- NSVGpoint* points;- int npoints;- int cpoints;-- NSVGpoint* points2;- int npoints2;- int cpoints2;-- NSVGactiveEdge* freelist;- NSVGmemPage* pages;- NSVGmemPage* curpage;-- unsigned char* scanline;- int cscanline;-- unsigned char* bitmap;- int width, height, stride;-};--NSVGrasterizer* nsvgCreateRasterizer(void)-{- NSVGrasterizer* r = (NSVGrasterizer*)malloc(sizeof(NSVGrasterizer));- if (r == NULL) goto error;- memset(r, 0, sizeof(NSVGrasterizer));-- r->tessTol = 0.25f;- r->distTol = 0.01f;-- return r;--error:- nsvgDeleteRasterizer(r);- return NULL;-}--void nsvgDeleteRasterizer(NSVGrasterizer* r)-{- NSVGmemPage* p;-- if (r == NULL) return;-- p = r->pages;- while (p != NULL) {- NSVGmemPage* next = p->next;- free(p);- p = next;- }-- if (r->edges) free(r->edges);- if (r->points) free(r->points);- if (r->points2) free(r->points2);- if (r->scanline) free(r->scanline);-- free(r);-}--static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur)-{- NSVGmemPage *newp;-- // If using existing chain, return the next page in chain- if (cur != NULL && cur->next != NULL) {- return cur->next;- }-- // Alloc new page- newp = (NSVGmemPage*)malloc(sizeof(NSVGmemPage));- if (newp == NULL) return NULL;- memset(newp, 0, sizeof(NSVGmemPage));-- // Add to linked list- if (cur != NULL)- cur->next = newp;- else- r->pages = newp;-- return newp;-}--static void nsvg__resetPool(NSVGrasterizer* r)-{- NSVGmemPage* p = r->pages;- while (p != NULL) {- p->size = 0;- p = p->next;- }- r->curpage = r->pages;-}--static unsigned char* nsvg__alloc(NSVGrasterizer* r, int size)-{- unsigned char* buf;- if (size > NSVG__MEMPAGE_SIZE) return NULL;- if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) {- r->curpage = nsvg__nextPage(r, r->curpage);- }- buf = &r->curpage->mem[r->curpage->size];- r->curpage->size += size;- return buf;-}--static int nsvg__ptEquals(float x1, float y1, float x2, float y2, float tol)-{- float dx = x2 - x1;- float dy = y2 - y1;- return dx*dx + dy*dy < tol*tol;-}--static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags)-{- NSVGpoint* pt;-- if (r->npoints > 0) {- pt = &r->points[r->npoints-1];- if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) {- pt->flags = (unsigned char)(pt->flags | flags);- return;- }- }-- if (r->npoints+1 > r->cpoints) {- r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;- r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints);- if (r->points == NULL) return;- }-- pt = &r->points[r->npoints];- pt->x = x;- pt->y = y;- pt->flags = (unsigned char)flags;- r->npoints++;-}--static void nsvg__appendPathPoint(NSVGrasterizer* r, NSVGpoint pt)-{- if (r->npoints+1 > r->cpoints) {- r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;- r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints);- if (r->points == NULL) return;- }- r->points[r->npoints] = pt;- r->npoints++;-}--static void nsvg__duplicatePoints(NSVGrasterizer* r)-{- if (r->npoints > r->cpoints2) {- r->cpoints2 = r->npoints;- r->points2 = (NSVGpoint*)realloc(r->points2, sizeof(NSVGpoint) * r->cpoints2);- if (r->points2 == NULL) return;- }-- memcpy(r->points2, r->points, sizeof(NSVGpoint) * r->npoints);- r->npoints2 = r->npoints;-}--static void nsvg__addEdge(NSVGrasterizer* r, float x0, float y0, float x1, float y1)-{- NSVGedge* e;-- // Skip horizontal edges- if (y0 == y1)- return;-- if (r->nedges+1 > r->cedges) {- r->cedges = r->cedges > 0 ? r->cedges * 2 : 64;- r->edges = (NSVGedge*)realloc(r->edges, sizeof(NSVGedge) * r->cedges);- if (r->edges == NULL) return;- }-- e = &r->edges[r->nedges];- r->nedges++;-- if (y0 < y1) {- e->x0 = x0;- e->y0 = y0;- e->x1 = x1;- e->y1 = y1;- e->dir = 1;- } else {- e->x0 = x1;- e->y0 = y1;- e->x1 = x0;- e->y1 = y0;- e->dir = -1;- }-}--static float nsvg__normalize(float *x, float* y)-{- float d = sqrtf((*x)*(*x) + (*y)*(*y));- if (d > 1e-6f) {- float id = 1.0f / d;- *x *= id;- *y *= id;- }- return d;-}--static float nsvg__absf(float x) { return x < 0 ? -x : x; }--static void nsvg__flattenCubicBez(NSVGrasterizer* r,- float x1, float y1, float x2, float y2,- float x3, float y3, float x4, float y4,- int level, int type)-{- float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;- float dx,dy,d2,d3;-- if (level > 10) return;-- x12 = (x1+x2)*0.5f;- y12 = (y1+y2)*0.5f;- x23 = (x2+x3)*0.5f;- y23 = (y2+y3)*0.5f;- x34 = (x3+x4)*0.5f;- y34 = (y3+y4)*0.5f;- x123 = (x12+x23)*0.5f;- y123 = (y12+y23)*0.5f;-- dx = x4 - x1;- dy = y4 - y1;- d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx));- d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx));-- if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) {- nsvg__addPathPoint(r, x4, y4, type);- return;- }-- x234 = (x23+x34)*0.5f;- y234 = (y23+y34)*0.5f;- x1234 = (x123+x234)*0.5f;- y1234 = (y123+y234)*0.5f;-- nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0);- nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type);-}--static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float scale)-{- int i, j;- NSVGpath* path;-- for (path = shape->paths; path != NULL; path = path->next) {- r->npoints = 0;- // Flatten path- nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);- for (i = 0; i < path->npts-1; i += 3) {- float* p = &path->pts[i*2];- nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, 0);- }- // Close path- nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);- // Build edges- for (i = 0, j = r->npoints-1; i < r->npoints; j = i++)- nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y);- }-}--enum NSVGpointFlags-{- NSVG_PT_CORNER = 0x01,- NSVG_PT_BEVEL = 0x02,- NSVG_PT_LEFT = 0x04-};--static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)-{- float w = lineWidth * 0.5f;- float dx = p1->x - p0->x;- float dy = p1->y - p0->y;- float len = nsvg__normalize(&dx, &dy);- float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f;- float dlx = dy, dly = -dx;- float lx = px - dlx*w, ly = py - dly*w;- float rx = px + dlx*w, ry = py + dly*w;- left->x = lx; left->y = ly;- right->x = rx; right->y = ry;-}--static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect)-{- float w = lineWidth * 0.5f;- float px = p->x, py = p->y;- float dlx = dy, dly = -dx;- float lx = px - dlx*w, ly = py - dly*w;- float rx = px + dlx*w, ry = py + dly*w;-- nsvg__addEdge(r, lx, ly, rx, ry);-- if (connect) {- nsvg__addEdge(r, left->x, left->y, lx, ly);- nsvg__addEdge(r, rx, ry, right->x, right->y);- }- left->x = lx; left->y = ly;- right->x = rx; right->y = ry;-}--static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect)-{- float w = lineWidth * 0.5f;- float px = p->x - dx*w, py = p->y - dy*w;- float dlx = dy, dly = -dx;- float lx = px - dlx*w, ly = py - dly*w;- float rx = px + dlx*w, ry = py + dly*w;-- nsvg__addEdge(r, lx, ly, rx, ry);-- if (connect) {- nsvg__addEdge(r, left->x, left->y, lx, ly);- nsvg__addEdge(r, rx, ry, right->x, right->y);- }- left->x = lx; left->y = ly;- right->x = rx; right->y = ry;-}--#ifndef NSVG_PI-#define NSVG_PI (3.14159265358979323846264338327f)-#endif--static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int ncap, int connect)-{- int i;- float w = lineWidth * 0.5f;- float px = p->x, py = p->y;- float dlx = dy, dly = -dx;- float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0;-- for (i = 0; i < ncap; i++) {- float a = (float)i/(float)(ncap-1)*NSVG_PI;- float ax = cosf(a) * w, ay = sinf(a) * w;- float x = px - dlx*ax - dx*ay;- float y = py - dly*ax - dy*ay;-- if (i > 0)- nsvg__addEdge(r, prevx, prevy, x, y);-- prevx = x;- prevy = y;-- if (i == 0) {- lx = x; ly = y;- } else if (i == ncap-1) {- rx = x; ry = y;- }- }-- if (connect) {- nsvg__addEdge(r, left->x, left->y, lx, ly);- nsvg__addEdge(r, rx, ry, right->x, right->y);- }-- left->x = lx; left->y = ly;- right->x = rx; right->y = ry;-}--static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)-{- float w = lineWidth * 0.5f;- float dlx0 = p0->dy, dly0 = -p0->dx;- float dlx1 = p1->dy, dly1 = -p1->dx;- float lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w);- float rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w);- float lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w);- float rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w);-- nsvg__addEdge(r, lx0, ly0, left->x, left->y);- nsvg__addEdge(r, lx1, ly1, lx0, ly0);-- nsvg__addEdge(r, right->x, right->y, rx0, ry0);- nsvg__addEdge(r, rx0, ry0, rx1, ry1);-- left->x = lx1; left->y = ly1;- right->x = rx1; right->y = ry1;-}--static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)-{- float w = lineWidth * 0.5f;- float dlx0 = p0->dy, dly0 = -p0->dx;- float dlx1 = p1->dy, dly1 = -p1->dx;- float lx0, rx0, lx1, rx1;- float ly0, ry0, ly1, ry1;-- if (p1->flags & NSVG_PT_LEFT) {- lx0 = lx1 = p1->x - p1->dmx * w;- ly0 = ly1 = p1->y - p1->dmy * w;- nsvg__addEdge(r, lx1, ly1, left->x, left->y);-- rx0 = p1->x + (dlx0 * w);- ry0 = p1->y + (dly0 * w);- rx1 = p1->x + (dlx1 * w);- ry1 = p1->y + (dly1 * w);- nsvg__addEdge(r, right->x, right->y, rx0, ry0);- nsvg__addEdge(r, rx0, ry0, rx1, ry1);- } else {- lx0 = p1->x - (dlx0 * w);- ly0 = p1->y - (dly0 * w);- lx1 = p1->x - (dlx1 * w);- ly1 = p1->y - (dly1 * w);- nsvg__addEdge(r, lx0, ly0, left->x, left->y);- nsvg__addEdge(r, lx1, ly1, lx0, ly0);-- rx0 = rx1 = p1->x + p1->dmx * w;- ry0 = ry1 = p1->y + p1->dmy * w;- nsvg__addEdge(r, right->x, right->y, rx1, ry1);- }-- left->x = lx1; left->y = ly1;- right->x = rx1; right->y = ry1;-}--static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth, int ncap)-{- int i, n;- float w = lineWidth * 0.5f;- float dlx0 = p0->dy, dly0 = -p0->dx;- float dlx1 = p1->dy, dly1 = -p1->dx;- float a0 = atan2f(dly0, dlx0);- float a1 = atan2f(dly1, dlx1);- float da = a1 - a0;- float lx, ly, rx, ry;-- if (da < NSVG_PI) da += NSVG_PI*2;- if (da > NSVG_PI) da -= NSVG_PI*2;-- n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * (float)ncap);- if (n < 2) n = 2;- if (n > ncap) n = ncap;-- lx = left->x;- ly = left->y;- rx = right->x;- ry = right->y;-- for (i = 0; i < n; i++) {- float u = (float)i/(float)(n-1);- float a = a0 + u*da;- float ax = cosf(a) * w, ay = sinf(a) * w;- float lx1 = p1->x - ax, ly1 = p1->y - ay;- float rx1 = p1->x + ax, ry1 = p1->y + ay;-- nsvg__addEdge(r, lx1, ly1, lx, ly);- nsvg__addEdge(r, rx, ry, rx1, ry1);-- lx = lx1; ly = ly1;- rx = rx1; ry = ry1;- }-- left->x = lx; left->y = ly;- right->x = rx; right->y = ry;-}--static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1, float lineWidth)-{- float w = lineWidth * 0.5f;- float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w);- float rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w);-- nsvg__addEdge(r, lx, ly, left->x, left->y);- nsvg__addEdge(r, right->x, right->y, rx, ry);-- left->x = lx; left->y = ly;- right->x = rx; right->y = ry;-}--static int nsvg__curveDivs(float r, float arc, float tol)-{- float da = acosf(r / (r + tol)) * 2.0f;- int divs = (int)ceilf(arc / da);- if (divs < 2) divs = 2;- return divs;-}--static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points, int npoints, int closed, int lineJoin, int lineCap, float lineWidth)-{- int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol); // Calculate divisions per half circle.- NSVGpoint left = {0,0,0,0,0,0,0,0}, right = {0,0,0,0,0,0,0,0}, firstLeft = {0,0,0,0,0,0,0,0}, firstRight = {0,0,0,0,0,0,0,0};- NSVGpoint* p0, *p1;- int j, s, e;-- // Build stroke edges- if (closed) {- // Looping- p0 = &points[npoints-1];- p1 = &points[0];- s = 0;- e = npoints;- } else {- // Add cap- p0 = &points[0];- p1 = &points[1];- s = 1;- e = npoints-1;- }-- if (closed) {- nsvg__initClosed(&left, &right, p0, p1, lineWidth);- firstLeft = left;- firstRight = right;- } else {- // Add cap- float dx = p1->x - p0->x;- float dy = p1->y - p0->y;- nsvg__normalize(&dx, &dy);- if (lineCap == NSVG_CAP_BUTT)- nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0);- else if (lineCap == NSVG_CAP_SQUARE)- nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0);- else if (lineCap == NSVG_CAP_ROUND)- nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0);- }-- for (j = s; j < e; ++j) {- if (p1->flags & NSVG_PT_CORNER) {- if (lineJoin == NSVG_JOIN_ROUND)- nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap);- else if (lineJoin == NSVG_JOIN_BEVEL || (p1->flags & NSVG_PT_BEVEL))- nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth);- else- nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth);- } else {- nsvg__straightJoin(r, &left, &right, p1, lineWidth);- }- p0 = p1++;- }-- if (closed) {- // Loop it- nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y);- nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y);- } else {- // Add cap- float dx = p1->x - p0->x;- float dy = p1->y - p0->y;- nsvg__normalize(&dx, &dy);- if (lineCap == NSVG_CAP_BUTT)- nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);- else if (lineCap == NSVG_CAP_SQUARE)- nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);- else if (lineCap == NSVG_CAP_ROUND)- nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1);- }-}--static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoin)-{- int i, j;- NSVGpoint* p0, *p1;-- p0 = &r->points[r->npoints-1];- p1 = &r->points[0];- for (i = 0; i < r->npoints; i++) {- // Calculate segment direction and length- p0->dx = p1->x - p0->x;- p0->dy = p1->y - p0->y;- p0->len = nsvg__normalize(&p0->dx, &p0->dy);- // Advance- p0 = p1++;- }-- // calculate joins- p0 = &r->points[r->npoints-1];- p1 = &r->points[0];- for (j = 0; j < r->npoints; j++) {- float dlx0, dly0, dlx1, dly1, dmr2, cross;- dlx0 = p0->dy;- dly0 = -p0->dx;- dlx1 = p1->dy;- dly1 = -p1->dx;- // Calculate extrusions- p1->dmx = (dlx0 + dlx1) * 0.5f;- p1->dmy = (dly0 + dly1) * 0.5f;- dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy;- if (dmr2 > 0.000001f) {- float s2 = 1.0f / dmr2;- if (s2 > 600.0f) {- s2 = 600.0f;- }- p1->dmx *= s2;- p1->dmy *= s2;- }-- // Clear flags, but keep the corner.- p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0;-- // Keep track of left turns.- cross = p1->dx * p0->dy - p0->dx * p1->dy;- if (cross > 0.0f)- p1->flags |= NSVG_PT_LEFT;-- // Check to see if the corner needs to be beveled.- if (p1->flags & NSVG_PT_CORNER) {- if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) {- p1->flags |= NSVG_PT_BEVEL;- }- }-- p0 = p1++;- }-}--static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float scale)-{- int i, j, closed;- NSVGpath* path;- NSVGpoint* p0, *p1;- float miterLimit = shape->miterLimit;- int lineJoin = shape->strokeLineJoin;- int lineCap = shape->strokeLineCap;- float lineWidth = shape->strokeWidth * scale;-- for (path = shape->paths; path != NULL; path = path->next) {- // Flatten path- r->npoints = 0;- nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, NSVG_PT_CORNER);- for (i = 0; i < path->npts-1; i += 3) {- float* p = &path->pts[i*2];- nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, NSVG_PT_CORNER);- }- if (r->npoints < 2)- continue;-- closed = path->closed;-- // If the first and last points are the same, remove the last, mark as closed path.- p0 = &r->points[r->npoints-1];- p1 = &r->points[0];- if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) {- r->npoints--;- p0 = &r->points[r->npoints-1];- closed = 1;- }-- if (shape->strokeDashCount > 0) {- int idash = 0, dashState = 1;- float totalDist = 0, dashLen, allDashLen, dashOffset;- NSVGpoint cur;-- if (closed)- nsvg__appendPathPoint(r, r->points[0]);-- // Duplicate points -> points2.- nsvg__duplicatePoints(r);-- r->npoints = 0;- cur = r->points2[0];- nsvg__appendPathPoint(r, cur);-- // Figure out dash offset.- allDashLen = 0;- for (j = 0; j < shape->strokeDashCount; j++)- allDashLen += shape->strokeDashArray[j];- if (shape->strokeDashCount & 1)- allDashLen *= 2.0f;- // Find location inside pattern- dashOffset = fmodf(shape->strokeDashOffset, allDashLen);- if (dashOffset < 0.0f)- dashOffset += allDashLen;-- while (dashOffset > shape->strokeDashArray[idash]) {- dashOffset -= shape->strokeDashArray[idash];- idash = (idash + 1) % shape->strokeDashCount;- }- dashLen = (shape->strokeDashArray[idash] - dashOffset) * scale;-- for (j = 1; j < r->npoints2; ) {- float dx = r->points2[j].x - cur.x;- float dy = r->points2[j].y - cur.y;- float dist = sqrtf(dx*dx + dy*dy);-- if ((totalDist + dist) > dashLen) {- // Calculate intermediate point- float d = (dashLen - totalDist) / dist;- float x = cur.x + dx * d;- float y = cur.y + dy * d;- nsvg__addPathPoint(r, x, y, NSVG_PT_CORNER);-- // Stroke- if (r->npoints > 1 && dashState) {- nsvg__prepareStroke(r, miterLimit, lineJoin);- nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);- }- // Advance dash pattern- dashState = !dashState;- idash = (idash+1) % shape->strokeDashCount;- dashLen = shape->strokeDashArray[idash] * scale;- // Restart- cur.x = x;- cur.y = y;- cur.flags = NSVG_PT_CORNER;- totalDist = 0.0f;- r->npoints = 0;- nsvg__appendPathPoint(r, cur);- } else {- totalDist += dist;- cur = r->points2[j];- nsvg__appendPathPoint(r, cur);- j++;- }- }- // Stroke any leftover path- if (r->npoints > 1 && dashState)- nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);- } else {- nsvg__prepareStroke(r, miterLimit, lineJoin);- nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, lineWidth);- }- }-}--static int nsvg__cmpEdge(const void *p, const void *q)-{- const NSVGedge* a = (const NSVGedge*)p;- const NSVGedge* b = (const NSVGedge*)q;-- if (a->y0 < b->y0) return -1;- if (a->y0 > b->y0) return 1;- return 0;-}---static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float startPoint)-{- NSVGactiveEdge* z;-- if (r->freelist != NULL) {- // Restore from freelist.- z = r->freelist;- r->freelist = z->next;- } else {- // Alloc new edge.- z = (NSVGactiveEdge*)nsvg__alloc(r, sizeof(NSVGactiveEdge));- if (z == NULL) return NULL;- }-- float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);-// STBTT_assert(e->y0 <= start_point);- // round dx down to avoid going too far- if (dxdy < 0)- z->dx = (int)(-floorf(NSVG__FIX * -dxdy));- else- z->dx = (int)floorf(NSVG__FIX * dxdy);- z->x = (int)floorf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0)));-// z->x -= off_x * FIX;- z->ey = e->y1;- z->next = 0;- z->dir = e->dir;-- return z;-}--static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z)-{- z->next = r->freelist;- r->freelist = z;-}--static void nsvg__fillScanline(unsigned char* scanline, int len, int x0, int x1, int maxWeight, int* xmin, int* xmax)-{- int i = x0 >> NSVG__FIXSHIFT;- int j = x1 >> NSVG__FIXSHIFT;- if (i < *xmin) *xmin = i;- if (j > *xmax) *xmax = j;- if (i < len && j >= 0) {- if (i == j) {- // x0,x1 are the same pixel, so compute combined coverage- scanline[i] = (unsigned char)(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT));- } else {- if (i >= 0) // add antialiasing for x0- scanline[i] = (unsigned char)(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT));- else- i = -1; // clip-- if (j < len) // add antialiasing for x1- scanline[j] = (unsigned char)(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT));- else- j = len; // clip-- for (++i; i < j; ++i) // fill pixels between x0 and x1- scanline[i] = (unsigned char)(scanline[i] + maxWeight);- }- }-}--// note: this routine clips fills that extend off the edges... ideally this-// wouldn't happen, but it could happen if the truetype glyph bounding boxes-// are wrong, or if the user supplies a too-small bitmap-static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEdge* e, int maxWeight, int* xmin, int* xmax, char fillRule)-{- // non-zero winding fill- int x0 = 0, w = 0;-- if (fillRule == NSVG_FILLRULE_NONZERO) {- // Non-zero- while (e != NULL) {- if (w == 0) {- // if we're currently at zero, we need to record the edge start point- x0 = e->x; w += e->dir;- } else {- int x1 = e->x; w += e->dir;- // if we went to zero, we need to draw- if (w == 0)- nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);- }- e = e->next;- }- } else if (fillRule == NSVG_FILLRULE_EVENODD) {- // Even-odd- while (e != NULL) {- if (w == 0) {- // if we're currently at zero, we need to record the edge start point- x0 = e->x; w = 1;- } else {- int x1 = e->x; w = 0;- nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);- }- e = e->next;- }- }-}--static float nsvg__clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); }--static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)-{- return ((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16) | ((unsigned int)a << 24);-}--static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, float u)-{- int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);- int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8;- int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8;- int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8;- int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8;- return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a);-}--static unsigned int nsvg__applyOpacity(unsigned int c, float u)-{- int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);- int r = (c) & 0xff;- int g = (c>>8) & 0xff;- int b = (c>>16) & 0xff;- int a = (((c>>24) & 0xff)*iu) >> 8;- return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a);-}--static inline int nsvg__div255(int x)-{- return ((x+1) * 257) >> 16;-}--static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* cover, int x, int y,- float tx, float ty, float scale, NSVGcachedPaint* cache)-{-- if (cache->type == NSVG_PAINT_COLOR) {- int i, cr, cg, cb, ca;- cr = cache->colors[0] & 0xff;- cg = (cache->colors[0] >> 8) & 0xff;- cb = (cache->colors[0] >> 16) & 0xff;- ca = (cache->colors[0] >> 24) & 0xff;-- for (i = 0; i < count; i++) {- int r,g,b;- int a = nsvg__div255((int)cover[0] * ca);- int ia = 255 - a;- // Premultiply- r = nsvg__div255(cr * a);- g = nsvg__div255(cg * a);- b = nsvg__div255(cb * a);-- // Blend over- r += nsvg__div255(ia * (int)dst[0]);- g += nsvg__div255(ia * (int)dst[1]);- b += nsvg__div255(ia * (int)dst[2]);- a += nsvg__div255(ia * (int)dst[3]);-- dst[0] = (unsigned char)r;- dst[1] = (unsigned char)g;- dst[2] = (unsigned char)b;- dst[3] = (unsigned char)a;-- cover++;- dst += 4;- }- } else if (cache->type == NSVG_PAINT_LINEAR_GRADIENT) {- // TODO: spread modes.- // TODO: plenty of opportunities to optimize.- float fx, fy, dx, gy;- float* t = cache->xform;- int i, cr, cg, cb, ca;- unsigned int c;-- fx = ((float)x - tx) / scale;- fy = ((float)y - ty) / scale;- dx = 1.0f / scale;-- for (i = 0; i < count; i++) {- int r,g,b,a,ia;- gy = fx*t[1] + fy*t[3] + t[5];- c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)];- cr = (c) & 0xff;- cg = (c >> 8) & 0xff;- cb = (c >> 16) & 0xff;- ca = (c >> 24) & 0xff;-- a = nsvg__div255((int)cover[0] * ca);- ia = 255 - a;-- // Premultiply- r = nsvg__div255(cr * a);- g = nsvg__div255(cg * a);- b = nsvg__div255(cb * a);-- // Blend over- r += nsvg__div255(ia * (int)dst[0]);- g += nsvg__div255(ia * (int)dst[1]);- b += nsvg__div255(ia * (int)dst[2]);- a += nsvg__div255(ia * (int)dst[3]);-- dst[0] = (unsigned char)r;- dst[1] = (unsigned char)g;- dst[2] = (unsigned char)b;- dst[3] = (unsigned char)a;-- cover++;- dst += 4;- fx += dx;- }- } else if (cache->type == NSVG_PAINT_RADIAL_GRADIENT) {- // TODO: spread modes.- // TODO: plenty of opportunities to optimize.- // TODO: focus (fx,fy)- float fx, fy, dx, gx, gy, gd;- float* t = cache->xform;- int i, cr, cg, cb, ca;- unsigned int c;-- fx = ((float)x - tx) / scale;- fy = ((float)y - ty) / scale;- dx = 1.0f / scale;-- for (i = 0; i < count; i++) {- int r,g,b,a,ia;- gx = fx*t[0] + fy*t[2] + t[4];- gy = fx*t[1] + fy*t[3] + t[5];- gd = sqrtf(gx*gx + gy*gy);- c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)];- cr = (c) & 0xff;- cg = (c >> 8) & 0xff;- cb = (c >> 16) & 0xff;- ca = (c >> 24) & 0xff;-- a = nsvg__div255((int)cover[0] * ca);- ia = 255 - a;-- // Premultiply- r = nsvg__div255(cr * a);- g = nsvg__div255(cg * a);- b = nsvg__div255(cb * a);-- // Blend over- r += nsvg__div255(ia * (int)dst[0]);- g += nsvg__div255(ia * (int)dst[1]);- b += nsvg__div255(ia * (int)dst[2]);- a += nsvg__div255(ia * (int)dst[3]);-- dst[0] = (unsigned char)r;- dst[1] = (unsigned char)g;- dst[2] = (unsigned char)b;- dst[3] = (unsigned char)a;-- cover++;- dst += 4;- fx += dx;- }- }-}--static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float scale, NSVGcachedPaint* cache, char fillRule)-{- NSVGactiveEdge *active = NULL;- int y, s;- int e = 0;- int maxWeight = (255 / NSVG__SUBSAMPLES); // weight per vertical scanline- int xmin, xmax;-- for (y = 0; y < r->height; y++) {- memset(r->scanline, 0, r->width);- xmin = r->width;- xmax = 0;- for (s = 0; s < NSVG__SUBSAMPLES; ++s) {- // find center of pixel for this scanline- float scany = (float)(y*NSVG__SUBSAMPLES + s) + 0.5f;- NSVGactiveEdge **step = &active;-- // update all active edges;- // remove all active edges that terminate before the center of this scanline- while (*step) {- NSVGactiveEdge *z = *step;- if (z->ey <= scany) {- *step = z->next; // delete from list-// NSVG__assert(z->valid);- nsvg__freeActive(r, z);- } else {- z->x += z->dx; // advance to position for current scanline- step = &((*step)->next); // advance through list- }- }-- // resort the list if needed- for (;;) {- int changed = 0;- step = &active;- while (*step && (*step)->next) {- if ((*step)->x > (*step)->next->x) {- NSVGactiveEdge* t = *step;- NSVGactiveEdge* q = t->next;- t->next = q->next;- q->next = t;- *step = q;- changed = 1;- }- step = &(*step)->next;- }- if (!changed) break;- }-- // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline- while (e < r->nedges && r->edges[e].y0 <= scany) {- if (r->edges[e].y1 > scany) {- NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany);- if (z == NULL) break;- // find insertion point- if (active == NULL) {- active = z;- } else if (z->x < active->x) {- // insert at front- z->next = active;- active = z;- } else {- // find thing to insert AFTER- NSVGactiveEdge* p = active;- while (p->next && p->next->x < z->x)- p = p->next;- // at this point, p->next->x is NOT < z->x- z->next = p->next;- p->next = z;- }- }- e++;- }-- // now process all active edges in non-zero fashion- if (active != NULL)- nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax, fillRule);- }- // Blit- if (xmin < 0) xmin = 0;- if (xmax > r->width-1) xmax = r->width-1;- if (xmin <= xmax) {- nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, scale, cache);- }- }--}--static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int stride)-{- int x,y;-- // Unpremultiply- for (y = 0; y < h; y++) {- unsigned char *row = &image[y*stride];- for (x = 0; x < w; x++) {- int r = row[0], g = row[1], b = row[2], a = row[3];- if (a != 0) {- row[0] = (unsigned char)(r*255/a);- row[1] = (unsigned char)(g*255/a);- row[2] = (unsigned char)(b*255/a);- }- row += 4;- }- }-- // Defringe- for (y = 0; y < h; y++) {- unsigned char *row = &image[y*stride];- for (x = 0; x < w; x++) {- int r = 0, g = 0, b = 0, a = row[3], n = 0;- if (a == 0) {- if (x-1 > 0 && row[-1] != 0) {- r += row[-4];- g += row[-3];- b += row[-2];- n++;- }- if (x+1 < w && row[7] != 0) {- r += row[4];- g += row[5];- b += row[6];- n++;- }- if (y-1 > 0 && row[-stride+3] != 0) {- r += row[-stride];- g += row[-stride+1];- b += row[-stride+2];- n++;- }- if (y+1 < h && row[stride+3] != 0) {- r += row[stride];- g += row[stride+1];- b += row[stride+2];- n++;- }- if (n > 0) {- row[0] = (unsigned char)(r/n);- row[1] = (unsigned char)(g/n);- row[2] = (unsigned char)(b/n);- }- }- row += 4;- }- }-}---static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opacity)-{- int i, j;- NSVGgradient* grad;-- cache->type = paint->type;-- if (paint->type == NSVG_PAINT_COLOR) {- cache->colors[0] = nsvg__applyOpacity(paint->color, opacity);- return;- }-- grad = paint->gradient;-- cache->spread = grad->spread;- memcpy(cache->xform, grad->xform, sizeof(float)*6);-- if (grad->nstops == 0) {- for (i = 0; i < 256; i++)- cache->colors[i] = 0;- } if (grad->nstops == 1) {- for (i = 0; i < 256; i++)- cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity);- } else {- unsigned int ca, cb = 0;- float ua, ub, du, u;- int ia, ib, count;-- ca = nsvg__applyOpacity(grad->stops[0].color, opacity);- ua = nsvg__clampf(grad->stops[0].offset, 0, 1);- ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1);- ia = (int)(ua * 255.0f);- ib = (int)(ub * 255.0f);- for (i = 0; i < ia; i++) {- cache->colors[i] = ca;- }-- for (i = 0; i < grad->nstops-1; i++) {- ca = nsvg__applyOpacity(grad->stops[i].color, opacity);- cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity);- ua = nsvg__clampf(grad->stops[i].offset, 0, 1);- ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1);- ia = (int)(ua * 255.0f);- ib = (int)(ub * 255.0f);- count = ib - ia;- if (count <= 0) continue;- u = 0;- du = 1.0f / (float)count;- for (j = 0; j < count; j++) {- cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u);- u += du;- }- }-- for (i = ib; i < 256; i++)- cache->colors[i] = cb;- }--}--/*-static void dumpEdges(NSVGrasterizer* r, const char* name)-{- float xmin = 0, xmax = 0, ymin = 0, ymax = 0;- NSVGedge *e = NULL;- int i;- if (r->nedges == 0) return;- FILE* fp = fopen(name, "w");- if (fp == NULL) return;-- xmin = xmax = r->edges[0].x0;- ymin = ymax = r->edges[0].y0;- for (i = 0; i < r->nedges; i++) {- e = &r->edges[i];- xmin = nsvg__minf(xmin, e->x0);- xmin = nsvg__minf(xmin, e->x1);- xmax = nsvg__maxf(xmax, e->x0);- xmax = nsvg__maxf(xmax, e->x1);- ymin = nsvg__minf(ymin, e->y0);- ymin = nsvg__minf(ymin, e->y1);- ymax = nsvg__maxf(ymax, e->y0);- ymax = nsvg__maxf(ymax, e->y1);- }-- fprintf(fp, "<svg viewBox=\"%f %f %f %f\" xmlns=\"http://www.w3.org/2000/svg\">", xmin, ymin, (xmax - xmin), (ymax - ymin));-- for (i = 0; i < r->nedges; i++) {- e = &r->edges[i];- fprintf(fp ,"<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" style=\"stroke:#000;\" />", e->x0,e->y0, e->x1,e->y1);- }-- for (i = 0; i < r->npoints; i++) {- if (i+1 < r->npoints)- fprintf(fp ,"<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" style=\"stroke:#f00;\" />", r->points[i].x, r->points[i].y, r->points[i+1].x, r->points[i+1].y);- fprintf(fp ,"<circle cx=\"%f\" cy=\"%f\" r=\"1\" style=\"fill:%s;\" />", r->points[i].x, r->points[i].y, r->points[i].flags == 0 ? "#f00" : "#0f0");- }-- fprintf(fp, "</svg>");- fclose(fp);-}-*/--void nsvgRasterize(NSVGrasterizer* r,- NSVGimage* image, float tx, float ty, float scale,- unsigned char* dst, int w, int h, int stride)-{- NSVGshape *shape = NULL;- NSVGedge *e = NULL;- NSVGcachedPaint cache;- int i;-- r->bitmap = dst;- r->width = w;- r->height = h;- r->stride = stride;-- if (w > r->cscanline) {- r->cscanline = w;- r->scanline = (unsigned char*)realloc(r->scanline, w);- if (r->scanline == NULL) return;- }-- for (i = 0; i < h; i++)- memset(&dst[i*stride], 0, w*4);-- for (shape = image->shapes; shape != NULL; shape = shape->next) {- if (!(shape->flags & NSVG_FLAGS_VISIBLE))- continue;-- if (shape->fill.type != NSVG_PAINT_NONE) {- nsvg__resetPool(r);- r->freelist = NULL;- r->nedges = 0;-- nsvg__flattenShape(r, shape, scale);-- // Scale and translate edges- for (i = 0; i < r->nedges; i++) {- e = &r->edges[i];- e->x0 = tx + e->x0;- e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;- e->x1 = tx + e->x1;- e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;- }-- // Rasterize edges- if (r->nedges != 0)- qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);-- // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule- nsvg__initPaint(&cache, &shape->fill, shape->opacity);-- nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule);- }- if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) {- nsvg__resetPool(r);- r->freelist = NULL;- r->nedges = 0;-- nsvg__flattenShapeStroke(r, shape, scale);--// dumpEdges(r, "edge.svg");-- // Scale and translate edges- for (i = 0; i < r->nedges; i++) {- e = &r->edges[i];- e->x0 = tx + e->x0;- e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;- e->x1 = tx + e->x1;- e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;- }-- // Rasterize edges- if (r->nedges != 0)- qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);-- // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule- nsvg__initPaint(&cache, &shape->stroke, shape->opacity);-- nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO);- }- }-- nsvg__unpremultiplyAlpha(dst, w, h, stride);-- r->bitmap = NULL;- r->width = 0;- r->height = 0;- r->stride = 0;-}--#endif // NANOSVGRAST_IMPLEMENTATION--#endif // NANOSVGRAST_H
raylib/src/external/par_shapes.h view
@@ -1130,7 +1130,7 @@ 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;
raylib/src/external/stb_image_resize2.h view
@@ -1,10303 +1,10572 @@-/* stb_image_resize2 - v2.01 - 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 - scaling and translation is supported, no rotations or shears.-- COMPILING & LINKING- In one C/C++ file that #includes this file, do this:- #define STB_IMAGE_RESIZE_IMPLEMENTATION- before the #include. That will create the implementation in that file.-- PORTING FROM VERSION 1-- The API has changed. You can continue to use the old version of stb_image_resize.h,- which is available in the "deprecated/" directory.-- If you're using the old simple-to-use API, porting is straightforward.- (For more advanced APIs, read the documentation.)-- stbir_resize_uint8():- - call `stbir_resize_uint8_linear`, cast channel count to `stbir_pixel_layout`-- stbir_resize_float():- - call `stbir_resize_float_linear`, cast channel count to `stbir_pixel_layout`-- stbir_resize_uint8_srgb():- - function name is unchanged- - cast channel count to `stbir_pixel_layout`- - above is sufficient unless your image has alpha and it's not RGBA/BGRA- - in that case, follow the below instructions for stbir_resize_uint8_srgb_edgemode-- stbir_resize_uint8_srgb_edgemode()- - switch to the "medium complexity" API- - stbir_resize(), very similar API but a few more parameters:- - pixel_layout: cast channel count to `stbir_pixel_layout`- - data_type: STBIR_TYPE_UINT8_SRGB- - edge: unchanged (STBIR_EDGE_WRAP, etc.)- - filter: STBIR_FILTER_DEFAULT- - which channel is alpha is specified in stbir_pixel_layout, see enum for details-- EASY API CALLS:- Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation, clamps to edge.-- stbir_resize_uint8_srgb( input_pixels, input_w, input_h, input_stride_in_bytes,- output_pixels, output_w, output_h, output_stride_in_bytes,- pixel_layout_enum )-- stbir_resize_uint8_linear( input_pixels, input_w, input_h, input_stride_in_bytes,- output_pixels, output_w, output_h, output_stride_in_bytes,- pixel_layout_enum )-- stbir_resize_float_linear( input_pixels, input_w, input_h, input_stride_in_bytes,- output_pixels, output_w, output_h, output_stride_in_bytes,- pixel_layout_enum )-- If you pass NULL or zero for the output_pixels, we will allocate the output buffer- for you and return it from the function (free with free() or STBIR_FREE).- As a special case, XX_stride_in_bytes of 0 means packed continuously in memory.-- API LEVELS- There are three levels of API - easy-to-use, medium-complexity and extended-complexity.-- See the "header file" section of the source for API documentation.-- ADDITIONAL DOCUMENTATION-- MEMORY ALLOCATION- 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 - 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 - 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 - 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 - 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. -- 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 - 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 - 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. -- 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 - 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 - channel of an image is processed.-- When alpha represents transparency, it is important that when combining- colors with filtering, the pixels should not be treated equally; they- should use a weighted average based on their alpha values. For example,- if a pixel is 1% opaque bright green and another pixel is 99% opaque- black and you average them, the average will be 50% opaque, but the- unweighted average and will be a middling green color, while the weighted- average will be nearly black. This means the unweighted version introduced- green energy that didn't exist in the source image.-- (If you want to know why this makes sense, you can work out the math for- the following: consider what happens if you alpha composite a source image- over a fixed color and then average the output, vs. if you average the- source image pixels and then composite that over the same fixed color.- Only the weighted average produces the same result as the ground truth- composite-then-average result.)-- Therefore, it is in general best to "alpha weight" the pixels when applying- filters to them. This essentially means multiplying the colors by the alpha- values before combining them, and then dividing by the alpha value at the- end.-- The computer graphics industry introduced a technique called "premultiplied- alpha" or "associated alpha" in which image colors are stored in image files- already multiplied by their alpha. This saves some math when compositing,- and also avoids the need to divide by the alpha at the end (which is quite- inefficient). However, while premultiplied alpha is common in the movie CGI- industry, it is not commonplace in other industries like videogames, and most- consumer file formats are generally expected to contain not-premultiplied- colors. For example, Photoshop saves PNG files "unpremultiplied", and web- browsers like Chrome and Firefox expect PNG images to be unpremultiplied.-- Note that there are three possibilities that might describe your image- and resize expectation:-- 1. images are not premultiplied, alpha weighting is desired- 2. images are not premultiplied, alpha weighting is not desired- 3. images are premultiplied-- Both case #2 and case #3 require the exact same math: no alpha weighting- should be applied or removed. Only case 1 requires extra math operations;- the other two cases can be handled identically.-- 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. -- 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 - 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. -- 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- output image is effectively premultiplied, this is actually more performant- 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() - 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- options.-- PIXEL LAYOUT CONVERSION- The resizer can convert from some pixel layouts to others. When using the- stbir_set_pixel_layouts(), you can, for example, specify STBIR_RGBA- on input, and STBIR_ARGB on output, and it will re-organize the channels- during the resize. Currently, you can only convert between two pixel- 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). - 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 - -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. - 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 - -fpmath=sse.-- Note that we will not be deterministic with float data containing NaNs -- 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. -- 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. -- 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- resolution in size_t sized integers. However, the scale ratio from input- resolution to output resolution is calculated in float form. This means- the effective possible scale ratio is limited to 24 bits (or 16 million- to 1). As you get close to the size of the float resolution (again, 16- million pixels wide or high), you might start seeing float inaccuracy- issues in general in the pipeline. If you have to do extreme resizes,- you can usually do this is multiple stages (using float intermediate- 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 - 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 - use, you can change the compile-time defaults with:-- #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something- #define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something-- 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 - 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 - 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 - STBIR_FLOORF(v) macros and we'll use them instead. In SIMD, we just use- our own versions.-- ASSERT- Define STBIR_ASSERT(boolval) to override assert() and not use assert.h-- FUTURE TODOS- * For polyphase integral filters, we just memcpy the coeffs to dupe- them, but we should indirect and use the same coeff memory.- * Add pixel layout conversions for sensible different channel counts- (maybe, 1->3/4, 3->4, 4->1, 3->1).- * 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 - 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?- * Rewrite the coefficient generator to do many at once.- * AVX-512 vertical kernels - worried about downclocking here.- * Convert the reincludes to macros when we know they aren't changing.- * Experiment with pivoting the horizontal and always using the- vertical filters (which are faster, but perhaps not enough to overcome- 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? -- CONTRIBUTORS- Jeff Roberts: 2.0 implementation, optimizations, SIMD- 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- 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)- 0.96 (2019-03-04) fixed warnings- 0.95 (2017-07-23) fixed warnings- 0.94 (2017-03-18) fixed warnings- 0.93 (2017-03-03) fixed bug with certain combinations of heights- 0.92 (2017-01-02) fix integer overflow on large (>2GB) images- 0.91 (2016-04-02) fix warnings; fix handling of subpixel regions- 0.90 (2014-09-17) first released version-- LICENSE- See end of file for license information.-*/--#if !defined(STB_IMAGE_RESIZE_DO_HORIZONTALS) && !defined(STB_IMAGE_RESIZE_DO_VERTICALS) && !defined(STB_IMAGE_RESIZE_DO_CODERS) // for internal re-includes--#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE2_H-#define STBIR_INCLUDE_STB_IMAGE_RESIZE2_H--#include <stddef.h>-#ifdef _MSC_VER-typedef unsigned char stbir_uint8;-typedef unsigned short stbir_uint16;-typedef unsigned int stbir_uint32;-typedef unsigned __int64 stbir_uint64;-#else-#include <stdint.h>-typedef uint8_t stbir_uint8;-typedef uint16_t stbir_uint16;-typedef uint32_t stbir_uint32;-typedef uint64_t stbir_uint64;-#endif--#ifdef _M_IX86_FP-#if ( _M_IX86_FP >= 1 )-#ifndef STBIR_SSE-#define STBIR_SSE-#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- #define STBIR_SSE2- #endif- #if defined(__AVX__) || defined(STBIR_AVX2)- #ifndef STBIR_AVX- #ifndef STBIR_NO_AVX- #define STBIR_AVX- #endif- #endif- #endif- #if defined(__AVX2__) || defined(STBIR_AVX2)- #ifndef STBIR_NO_AVX2- #ifndef STBIR_AVX2 - #define STBIR_AVX2- #endif- #if defined( _MSC_VER ) && !defined(__clang__)- #ifndef STBIR_FP16C // FP16C instructions are on all AVX2 cpus, so we can autoselect it here on microsoft - clang needs -m16c- #define STBIR_FP16C- #endif- #endif- #endif- #endif- #ifdef __F16C__- #ifndef STBIR_FP16C // turn on FP16C instructions if the define is set (for clang and gcc)- #define STBIR_FP16C- #endif- #endif-#endif--#if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(_M_ARM) || (__ARM_NEON_FP & 4) != 0 && __ARM_FP16_FORMAT_IEEE != 0-#ifndef STBIR_NEON-#define STBIR_NEON-#endif-#endif--#if defined(_M_ARM)-#ifdef STBIR_USE_FMA-#undef STBIR_USE_FMA // no FMA for 32-bit arm on MSVC -#endif-#endif--#if defined(__wasm__) && defined(__wasm_simd128__)-#ifndef STBIR_WASM-#define STBIR_WASM-#endif-#endif--#ifndef STBIRDEF-#ifdef STB_IMAGE_RESIZE_STATIC-#define STBIRDEF static-#else-#ifdef __cplusplus-#define STBIRDEF extern "C"-#else-#define STBIRDEF extern-#endif-#endif-#endif--//////////////////////////////////////////////////////////////////////////////-//// start "header file" ///////////////////////////////////////////////////-//-// Easy-to-use API:-//-// * 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-// * Uses edge mode clamped-// * returned result is 1 for success or 0 in case of an error.---// stbir_pixel_layout specifies:-// number of channels-// 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 -{- STBIR_BGR = 0, // 3-chan, with order specified (for channel flipping)- 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_4CHANNEL = 5,- 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_BGRA_PM = 12,- STBIR_ARGB_PM = 13,- STBIR_ABGR_PM = 14,- STBIR_RA_PM = 15,- STBIR_AR_PM = 16,-} stbir_pixel_layout;--//===============================================================-// Simple-complexity API-//-// If output_pixels is NULL (0), then we will allocate the buffer and return it to you.-//----------------------------------STBIRDEF unsigned char * stbir_resize_uint8_srgb( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes,- unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,- stbir_pixel_layout pixel_type );--STBIRDEF unsigned char * stbir_resize_uint8_linear( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes,- unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,- stbir_pixel_layout pixel_type );--STBIRDEF float * stbir_resize_float_linear( const float *input_pixels , int input_w , int input_h, int input_stride_in_bytes,- float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,- stbir_pixel_layout pixel_type );-//===============================================================--//===============================================================-// Medium-complexity API-//-// This extends the easy-to-use API as follows:-//-// * Can specify the datatype - U8, U8_SRGB, U16, FLOAT, HALF_FLOAT-// * Edge wrap can selected explicitly-// * Filter can be selected explicitly-//----------------------------------typedef enum-{- STBIR_EDGE_CLAMP = 0,- STBIR_EDGE_REFLECT = 1,- STBIR_EDGE_WRAP = 2, // this edge mode is slower and uses more memory- STBIR_EDGE_ZERO = 3,-} stbir_edge;--typedef enum-{- STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses- STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios- STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering- STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque- STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline- STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3- STBIR_FILTER_POINT_SAMPLE = 6, // Simple point sampling- STBIR_FILTER_OTHER = 7, // User callback specified-} stbir_filter;--typedef enum-{- STBIR_TYPE_UINT8 = 0,- STBIR_TYPE_UINT8_SRGB = 1,- STBIR_TYPE_UINT8_SRGB_ALPHA = 2, // alpha channel, when present, should also be SRGB (this is very unusual)- STBIR_TYPE_UINT16 = 3,- STBIR_TYPE_FLOAT = 4,- STBIR_TYPE_HALF_FLOAT = 5-} stbir_datatype;--// medium api-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_edge edge, stbir_filter filter );-//===============================================================----//===============================================================-// Extended-complexity API-//-// This API exposes all resize functionality.-//-// * Separate filter types for each axis-// * Separate edge modes for each axis-// * 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 be threaded for a single resize-// * Can be used to resize many frames without recalculating the sampler info-//-// Use this API as follows:-// 1) Call the stbir_resize_init function on a local STBIR_RESIZE structure-// 2) Call any of the stbir_set functions-// 3) Optionally call stbir_build_samplers() if you are going to resample multiple times-// with the same input and output dimensions (like resizing video frames)-// 4) Resample by calling stbir_resize_extended().-// 5) Call stbir_free_samplers() if you called stbir_build_samplers()-//-----------------------------------// Types:--// INPUT CALLBACK: this callback is used for input scanlines-typedef void const * stbir_input_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context );--// OUTPUT CALLBACK: this callback is used for output scanlines-typedef void stbir_output_callback( void const * output_ptr, int num_pixels, int y, void * context );--// callbacks for user installed filters-typedef float stbir__kernel_callback( float x, float scale, void * user_data ); // centered at zero-typedef float stbir__support_callback( float scale, void * user_data );--// internal structure with precomputed scaling-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-{- void * user_data;- void const * input_pixels;- int input_w, input_h;- double input_s0, input_t0, input_s1, input_t1;- stbir_input_callback * input_cb;- void * output_pixels;- int output_w, output_h;- int output_subx, output_suby, output_subw, output_subh;- stbir_output_callback * output_cb;- int input_stride_in_bytes;- int output_stride_in_bytes;- int splits;- int fast_alpha;- int needs_rebuild;- int called_alloc;- stbir_pixel_layout input_pixel_layout_public;- stbir_pixel_layout output_pixel_layout_public;- stbir_datatype input_data_type;- stbir_datatype output_data_type;- stbir_filter horizontal_filter, vertical_filter;- 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_RESIZE;--// extended complexity api---// First off, you must ALWAYS call stbir_resize_init on your resize structure before any of the other calls!-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 );--//===============================================================-// 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_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 );--//===============================================================---//===============================================================-// If you call any of these functions, you will trigger a sampler rebuild!-//----------------------------------STBIRDEF int stbir_set_pixel_layouts( STBIR_RESIZE * resize, stbir_pixel_layout input_pixel_layout, stbir_pixel_layout output_pixel_layout ); // sets new buffer layouts-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_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)-STBIRDEF int stbir_set_output_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, int subw, int subh ); // sets output sub-region (full region by default)--// when inputting AND outputting non-premultiplied alpha pixels, we use a slower but higher quality technique-// that fills the zero alpha pixel's RGB values with something plausible. If you don't care about areas of-// zero alpha, you can call this function to get about a 25% speed improvement for STBIR_RGBA to STBIR_RGBA-// types of resizes.-STBIRDEF int stbir_set_non_pm_alpha_speed_over_quality( STBIR_RESIZE * resize, int non_pma_alpha_speed_over_quality );-//===============================================================---//===============================================================-// You can call build_samplers to prebuild all the internal data we need to resample.-// Then, if you call resize_extended many times with the same resize, you only pay the-// cost once.-// If you do call build_samplers, you MUST call free_samplers eventually.-//----------------------------------// This builds the samplers and does one allocation-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 );-//===============================================================---// And this is the main function to perform the resize synchronously on one thread.-STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize );---//===============================================================-// Use these functions for multithreading.-// 1) You call stbir_build_samplers_with_splits first on the main thread-// 2) Then stbir_resize_with_split on each thread-// 3) stbir_free_samplers when done on the main thread-//----------------------------------// This will build samplers for threading.-// You can pass in the number of threads you'd like to use (try_splits).-// 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 ); --// 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.--// Note that you MUST call stbir_build_samplers_with_splits before stbir_resize_extended_split!--// 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 -// 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 ); -//===============================================================---//===============================================================-// Pixel Callbacks info:-//----------------------------------// 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. -//-// 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.)-//-// You can also install just an input or just an output callback by setting the-// callback that you don't want to zero.-//-// First example, progress: (getting a callback that you can monitor the progress):-// void const * my_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context )-// {-// percentage_done = y / input_height;-// return input_ptr; // use buffer from call-// }-//-// 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): -// 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 );-// return pixels; // return pointer to your data without copying-// }-//-//-// The output callback is considerably simpler - it just calls you so that you can dump-// out each scanline. You could even directly copy out to disk if you have a simple format-// like TGA or BMP. You can also convert to other output types here if you want.-//-// Simple example:-// void const * my_output( void * output_ptr, int num_pixels, int y, void * context )-// {-// percentage_done = y / output_height;-// fwrite( output_ptr, pixel_width_in_bytes, num_pixels, output_file );-// }-//===============================================================-----//===============================================================-// optional built-in profiling API-//----------------------------------#ifdef STBIR_PROFILE--typedef struct STBIR_PROFILE_INFO -{- stbir_uint64 total_clocks;-- // how many clocks spent (of total_clocks) in the various resize routines, along with a string description- // 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;--// use after calling stbir_resize_extended (or stbir_build_samplers or stbir_build_samplers_with_splits)-STBIRDEF void stbir_resize_build_profile_info( STBIR_PROFILE_INFO * out_info, STBIR_RESIZE const * resize );--// use after calling stbir_resize_extended-STBIRDEF void stbir_resize_extended_profile_info( STBIR_PROFILE_INFO * out_info, STBIR_RESIZE const * resize );--// use after calling stbir_resize_extended_split-STBIRDEF void stbir_resize_split_profile_info( STBIR_PROFILE_INFO * out_info, STBIR_RESIZE const * resize, int split_start, int split_num );--//===============================================================--#endif---//// end header file /////////////////////////////////////////////////////-#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE2_H--#if defined(STB_IMAGE_RESIZE_IMPLEMENTATION) || defined(STB_IMAGE_RESIZE2_IMPLEMENTATION)--#ifndef STBIR_ASSERT-#include <assert.h>-#define STBIR_ASSERT(x) assert(x)-#endif--#ifndef STBIR_MALLOC-#include <stdlib.h>-#define STBIR_MALLOC(size,user_data) ((void)(user_data), malloc(size))-#define STBIR_FREE(ptr,user_data) ((void)(user_data), free(ptr))-// (we used the comma operator to evaluate user_data, to avoid "unused parameter" warnings)-#endif--#ifdef _MSC_VER--#define stbir__inline __forceinline--#else--#define stbir__inline __inline__--// Clang address sanitizer-#if defined(__has_feature)- #if __has_feature(address_sanitizer) || __has_feature(memory_sanitizer)- #ifndef STBIR__SEPARATE_ALLOCATIONS- #define STBIR__SEPARATE_ALLOCATIONS- #endif- #endif-#endif--#endif--// GCC and MSVC-#if defined(__SANITIZE_ADDRESS__)- #ifndef STBIR__SEPARATE_ALLOCATIONS- #define STBIR__SEPARATE_ALLOCATIONS- #endif-#endif--// Always turn off automatic FMA use - use STBIR_USE_FMA if you want.-// Otherwise, this is a determinism disaster.-#ifndef STBIR_DONT_CHANGE_FP_CONTRACT // override in case you don't want this behavior-#if defined(_MSC_VER) && !defined(__clang__)-#if _MSC_VER > 1200-#pragma fp_contract(off)-#endif-#elif defined(__GNUC__) && !defined(__clang__)-#pragma GCC optimize("fp-contract=off")-#else-#pragma STDC FP_CONTRACT OFF-#endif-#endif--#ifdef _MSC_VER-#define STBIR__UNUSED(v) (void)(v)-#else-#define STBIR__UNUSED(v) (void)sizeof(v)-#endif--#define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0]))---#ifndef STBIR_DEFAULT_FILTER_UPSAMPLE-#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM-#endif--#ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE-#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL-#endif---#ifndef STBIR__HEADER_FILENAME-#define STBIR__HEADER_FILENAME "stb_image_resize2.h"-#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 -{- STBIRI_1CHANNEL = 0,- STBIRI_2CHANNEL = 1,- STBIRI_RGB = 2,- STBIRI_BGR = 3,- STBIRI_4CHANNEL = 4,- - STBIRI_RGBA = 5,- STBIRI_BGRA = 6,- STBIRI_ARGB = 7,- STBIRI_ABGR = 8,- STBIRI_RA = 9,- STBIRI_AR = 10,-- STBIRI_RGBA_PM = 11,- STBIRI_BGRA_PM = 12,- STBIRI_ARGB_PM = 13,- STBIRI_ABGR_PM = 14,- STBIRI_RA_PM = 15,- STBIRI_AR_PM = 16,-} stbir_internal_pixel_layout;--// define the public pixel layouts to not compile inside the implementation (to avoid accidental use)-#define STBIR_BGR bad_dont_use_in_implementation-#define STBIR_1CHANNEL STBIR_BGR-#define STBIR_2CHANNEL STBIR_BGR-#define STBIR_RGB STBIR_BGR-#define STBIR_RGBA STBIR_BGR-#define STBIR_4CHANNEL STBIR_BGR-#define STBIR_BGRA STBIR_BGR-#define STBIR_ARGB STBIR_BGR-#define STBIR_ABGR STBIR_BGR-#define STBIR_RA STBIR_BGR-#define STBIR_AR STBIR_BGR-#define STBIR_RGBA_PM STBIR_BGR-#define STBIR_BGRA_PM STBIR_BGR-#define STBIR_ARGB_PM STBIR_BGR-#define STBIR_ABGR_PM STBIR_BGR-#define STBIR_RA_PM STBIR_BGR-#define STBIR_AR_PM STBIR_BGR--// must match stbir_datatype-static unsigned char stbir__type_size[] = {- 1,1,1,2,4,2 // STBIR_TYPE_UINT8,STBIR_TYPE_UINT8_SRGB,STBIR_TYPE_UINT8_SRGB_ALPHA,STBIR_TYPE_UINT16,STBIR_TYPE_FLOAT,STBIR_TYPE_HALF_FLOAT-};--// When gathering, the contributors are which source pixels contribute.-// When scattering, the contributors are which destination pixels are contributed to.-typedef struct-{- int n0; // First contributing pixel- int n1; // Last contributing pixel-} stbir__contributors;--typedef struct-{- int lowest; // First sample index for whole filter- int highest; // Last sample index for whole filter- int widest; // widest single set of samples for an output-} stbir__filter_extent_info;--typedef struct-{- int n0; // First pixel of decode buffer to write to- int n1; // Last pixel of decode that will be written to- int pixel_offset_for_input; // Pixel offset into input_scanline-} stbir__span;--typedef struct stbir__scale_info-{- int input_full_size;- int output_sub_size;- float scale;- float inv_scale;- float pixel_shift; // starting shift in output pixel space (in pixels)- int scale_is_rational;- stbir_uint32 scale_numerator, scale_denominator;-} stbir__scale_info;--typedef struct-{- stbir__contributors * contributors;- float* coefficients;- stbir__contributors * gather_prescatter_contributors;- float * gather_prescatter_coefficients;- stbir__scale_info scale_info;- float support;- stbir_filter filter_enum;- stbir__kernel_callback * filter_kernel;- stbir__support_callback * filter_support;- stbir_edge edge;- int coefficient_width;- int filter_pixel_width;- int filter_pixel_margin;- int num_contributors;- int contributors_size;- int coefficients_size;- stbir__filter_extent_info extent_info;- int is_gather; // 0 = scatter, 1 = gather with scale >= 1, 2 = gather with scale < 1- int gather_prescatter_num_contributors;- int gather_prescatter_coefficient_width;- int gather_prescatter_contributors_size;- int gather_prescatter_coefficients_size;-} stbir__sampler;--typedef struct-{- stbir__contributors conservative;- int edge_sizes[2]; // this can be less than filter_pixel_margin, if the filter and scaling falls off- stbir__span spans[2]; // can be two spans, if doing input subrect with clamp mode WRAP-} stbir__extents;--typedef struct -{-#ifdef STBIR_PROFILE- union- {- struct { stbir_uint64 total, looping, vertical, horizontal, decode, encode, alpha, unalpha; } named;- stbir_uint64 array[8];- } profile;- stbir_uint64 * current_zone_excluded_ptr;-#endif- float* decode_buffer;-- int ring_buffer_first_scanline;- int ring_buffer_last_scanline;- int ring_buffer_begin_index; // first_scanline is at this index in the ring buffer- int start_output_y, end_output_y;- int start_input_y, end_input_y; // used in scatter only-- #ifdef STBIR__SEPARATE_ALLOCATIONS- float** ring_buffers; // one pointer for each ring buffer- #else- float* ring_buffer; // one big buffer that we index into- #endif-- float* vertical_buffer;-- char no_cache_straddle[64];-} stbir__per_split_info;--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, - 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 );--struct stbir__info-{-#ifdef STBIR_PROFILE- union- {- struct { stbir_uint64 total, build, alloc, horizontal, vertical, cleanup, pivot; } named;- stbir_uint64 array[7];- } profile;- stbir_uint64 * current_zone_excluded_ptr;-#endif- stbir__sampler horizontal;- stbir__sampler vertical;-- void const * input_data;- void * output_data;-- int input_stride_bytes;- int output_stride_bytes;- int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)- int ring_buffer_num_entries; // Total number of entries in the ring buffer.-- stbir_datatype input_type;- stbir_datatype output_type;-- stbir_input_callback * in_pixels_cb;- void * user_data;- stbir_output_callback * out_pixels_cb;-- stbir__extents scanline_extents;-- void * alloced_mem;- stbir__per_split_info * split_info; // by default 1, but there will be N of these allocated based on the thread init you did-- stbir__decode_pixels_func * decode_pixels;- stbir__alpha_weight_func * alpha_weight;- stbir__horizontal_gather_channels_func * horizontal_gather_channels;- stbir__alpha_unweight_func * alpha_unweight;- stbir__encode_pixels_func * encode_pixels;- - int alloced_total;- int splits; // count of splits- - stbir_internal_pixel_layout input_pixel_layout_internal;- stbir_internal_pixel_layout output_pixel_layout_internal;-- int input_color_and_type;- int offset_x, offset_y; // offset within output_data- 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-};---#define stbir__max_uint8_as_float 255.0f-#define stbir__max_uint16_as_float 65535.0f-#define stbir__max_uint8_as_float_inverted (1.0f/255.0f)-#define stbir__max_uint16_as_float_inverted (1.0f/65535.0f)-#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 { \- if ( (x) < (xmin) ) (x) = (xmin); \- if ( (x) > (xmax) ) (x) = (xmax); \-} while (0)--static stbir__inline int stbir__min(int a, int b)-{- return a < b ? a : b;-}--static stbir__inline int stbir__max(int a, int b)-{- return a > b ? a : b;-}--static float stbir__srgb_uchar_to_linear_float[256] = {- 0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f,- 0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f,- 0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f,- 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f,- 0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f,- 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f,- 0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f,- 0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f,- 0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f,- 0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f,- 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f,- 0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f,- 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f,- 0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f,- 0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f,- 0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f,- 0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f,- 0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f,- 0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f,- 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f,- 0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f,- 0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f,- 0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f,- 0.982251f, 0.991102f, 1.0f-};--typedef union-{- unsigned int u;- float f;-} stbir__FP32;--// From https://gist.github.com/rygorous/2203834--static const stbir_uint32 fp32_to_srgb8_tab4[104] = {- 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,- 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,- 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,- 0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,- 0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,- 0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,- 0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,- 0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,- 0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,- 0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,- 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,- 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- static const stbir__FP32 minval = { (127-13) << 23 };- stbir_uint32 tab,bias,scale,t;- stbir__FP32 f;-- // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively.- // The tests are carefully written so that NaNs map to 0, same as in the reference- // implementation.- if (!(in > minval.f)) // written this way to catch NaNs- return 0;- if (in > almostone.f)- return 255;-- // Do the table lookup and unpack bias, scale- f.f = in;- tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20];- bias = (tab >> 16) << 9;- scale = tab & 0xffff;-- // Grab next-highest mantissa bits and perform linear interpolation- t = (f.u >> 12) & 0xff;- return (unsigned char) ((bias + scale*t) >> 16);-}--#ifndef STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT-#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-#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__ )- #define STBIR_STREAMOUT_PTR( star ) star __restrict__- #define STBIR_NO_UNROLL( ptr ) __asm__ (""::"r"(ptr))-#else- #define STBIR_STREAMOUT_PTR( star ) star- #define STBIR_NO_UNROLL( ptr )-#endif--#ifdef STBIR_NO_SIMD // force simd off for whatever reason--// force simd off overrides everything else, so clear it all--#ifdef STBIR_SSE2-#undef STBIR_SSE2-#endif--#ifdef STBIR_AVX-#undef STBIR_AVX-#endif--#ifdef STBIR_NEON-#undef STBIR_NEON-#endif--#ifdef STBIR_AVX2-#undef STBIR_AVX2-#endif--#ifdef STBIR_FP16C-#undef STBIR_FP16C-#endif--#ifdef STBIR_WASM-#undef STBIR_WASM-#endif--#ifdef STBIR_SIMD-#undef STBIR_SIMD-#endif--#else // STBIR_SIMD--#ifdef STBIR_SSE2- #include <emmintrin.h>- - #define stbir__simdf __m128- #define stbir__simdi __m128i-- #define stbir_simdi_castf( reg ) _mm_castps_si128(reg)- #define stbir_simdf_casti( reg ) _mm_castsi128_ps(reg)-- #define stbir__simdf_load( reg, ptr ) (reg) = _mm_loadu_ps( (float const*)(ptr) )- #define stbir__simdi_load( reg, ptr ) (reg) = _mm_loadu_si128 ( (stbir__simdi const*)(ptr) )- #define stbir__simdf_load1( out, ptr ) (out) = _mm_load_ss( (float const*)(ptr) ) // top values can be random (not denormal or nan for perf)- #define stbir__simdi_load1( out, ptr ) (out) = _mm_castps_si128( _mm_load_ss( (float const*)(ptr) ))- #define stbir__simdf_load1z( out, ptr ) (out) = _mm_load_ss( (float const*)(ptr) ) // top values must be zero- #define stbir__simdf_frep4( fvar ) _mm_set_ps1( fvar )- #define stbir__simdf_load1frep4( out, fvar ) (out) = _mm_set_ps1( fvar )- #define stbir__simdf_load2( out, ptr ) (out) = _mm_castsi128_ps( _mm_loadl_epi64( (__m128i*)(ptr)) ) // top values can be random (not denormal or nan for perf)- #define stbir__simdf_load2z( out, ptr ) (out) = _mm_castsi128_ps( _mm_loadl_epi64( (__m128i*)(ptr)) ) // top values must be zero- #define stbir__simdf_load2hmerge( out, reg, ptr ) (out) = _mm_castpd_ps(_mm_loadh_pd( _mm_castps_pd(reg), (double*)(ptr) ))-- #define stbir__simdf_zeroP() _mm_setzero_ps()- #define stbir__simdf_zero( reg ) (reg) = _mm_setzero_ps()-- #define stbir__simdf_store( ptr, reg ) _mm_storeu_ps( (float*)(ptr), reg )- #define stbir__simdf_store1( ptr, reg ) _mm_store_ss( (float*)(ptr), reg )- #define stbir__simdf_store2( ptr, reg ) _mm_storel_epi64( (__m128i*)(ptr), _mm_castps_si128(reg) )- #define stbir__simdf_store2h( ptr, reg ) _mm_storeh_pd( (double*)(ptr), _mm_castps_pd(reg) )-- #define stbir__simdi_store( ptr, reg ) _mm_storeu_si128( (__m128i*)(ptr), reg )- #define stbir__simdi_store1( ptr, reg ) _mm_store_ss( (float*)(ptr), _mm_castsi128_ps(reg) )- #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(); \- out2 = _mm_unpacklo_epi8( ireg, zero ); \- out3 = _mm_unpackhi_epi8( ireg, zero ); \- out0 = _mm_unpacklo_epi16( out2, zero ); \- out1 = _mm_unpackhi_epi16( out2, zero ); \- out2 = _mm_unpacklo_epi16( out3, zero ); \- out3 = _mm_unpackhi_epi16( out3, zero ); \- }--#define stbir__simdi_expand_u8_to_1u32(out,ireg) \- { \- stbir__simdi zero = _mm_setzero_si128(); \- out = _mm_unpacklo_epi8( ireg, zero ); \- out = _mm_unpacklo_epi16( out, zero ); \- }-- #define stbir__simdi_expand_u16_to_u32(out0,out1,ireg) \- { \- stbir__simdi zero = _mm_setzero_si128(); \- out0 = _mm_unpacklo_epi16( ireg, zero ); \- out1 = _mm_unpackhi_epi16( ireg, zero ); \- }-- #define stbir__simdf_convert_float_to_i32( i, f ) (i) = _mm_cvttps_epi32(f)- #define stbir__simdf_convert_float_to_int( f ) _mm_cvtt_ss2si(f)- #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_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 )- #define stbir__simdf_mult_mem( out, reg, ptr ) (out) = _mm_mul_ps( reg, _mm_loadu_ps( (float const*)(ptr) ) )- #define stbir__simdf_mult1_mem( out, reg, ptr ) (out) = _mm_mul_ss( reg, _mm_load_ss( (float const*)(ptr) ) )- #define stbir__simdf_add_mem( out, reg, ptr ) (out) = _mm_add_ps( reg, _mm_loadu_ps( (float const*)(ptr) ) )- #define stbir__simdf_add1_mem( out, reg, ptr ) (out) = _mm_add_ss( reg, _mm_load_ss( (float const*)(ptr) ) )-- #ifdef STBIR_USE_FMA // not on by default to maintain bit identical simd to non-simd- #include <immintrin.h>- #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = _mm_fmadd_ps( mul1, mul2, add )- #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = _mm_fmadd_ss( mul1, mul2, add )- #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = _mm_fmadd_ps( mul, _mm_loadu_ps( (float const*)(ptr) ), add )- #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = _mm_fmadd_ss( mul, _mm_load_ss( (float const*)(ptr) ), add )- #else- #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = _mm_add_ps( add, _mm_mul_ps( mul1, mul2 ) )- #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = _mm_add_ss( add, _mm_mul_ss( mul1, mul2 ) )- #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = _mm_add_ps( add, _mm_mul_ps( mul, _mm_loadu_ps( (float const*)(ptr) ) ) )- #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = _mm_add_ss( add, _mm_mul_ss( mul, _mm_load_ss( (float const*)(ptr) ) ) )- #endif-- #define stbir__simdf_add1( out, reg0, reg1 ) (out) = _mm_add_ss( reg0, reg1 )- #define stbir__simdf_mult1( out, reg0, reg1 ) (out) = _mm_mul_ss( reg0, reg1 )-- #define stbir__simdf_and( out, reg0, reg1 ) (out) = _mm_and_ps( reg0, reg1 )- #define stbir__simdf_or( out, reg0, reg1 ) (out) = _mm_or_ps( reg0, reg1 )-- #define stbir__simdf_min( out, reg0, reg1 ) (out) = _mm_min_ps( reg0, reg1 )- #define stbir__simdf_max( out, reg0, reg1 ) (out) = _mm_max_ps( reg0, reg1 )- #define stbir__simdf_min1( out, reg0, reg1 ) (out) = _mm_min_ss( reg0, reg1 )- #define stbir__simdf_max1( out, reg0, reg1 ) (out) = _mm_max_ss( reg0, reg1 )-- #define stbir__simdf_0123ABCDto3ABx( out, reg0, reg1 ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_shuffle_ps( reg1,reg0, (0<<0) + (1<<2) + (2<<4) + (3<<6) )), (3<<0) + (0<<2) + (1<<4) + (2<<6) ) )- #define stbir__simdf_0123ABCDto23Ax( out, reg0, reg1 ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_shuffle_ps( reg1,reg0, (0<<0) + (1<<2) + (2<<4) + (3<<6) )), (2<<0) + (3<<2) + (0<<4) + (1<<6) ) )-- static const stbir__simdf STBIR_zeroones = { 0.0f,1.0f,0.0f,1.0f };- static const stbir__simdf STBIR_onezeros = { 1.0f,0.0f,1.0f,0.0f };- #define stbir__simdf_aaa1( out, alp, ones ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_movehl_ps( ones, alp ) ), (1<<0) + (1<<2) + (1<<4) + (2<<6) ) )- #define stbir__simdf_1aaa( out, alp, ones ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_movelh_ps( ones, alp ) ), (0<<0) + (2<<2) + (2<<4) + (2<<6) ) )- #define stbir__simdf_a1a1( out, alp, ones) (out) = _mm_or_ps( _mm_castsi128_ps( _mm_srli_epi64( _mm_castps_si128(alp), 32 ) ), STBIR_zeroones )- #define stbir__simdf_1a1a( out, alp, ones) (out) = _mm_or_ps( _mm_castsi128_ps( _mm_slli_epi64( _mm_castps_si128(alp), 32 ) ), STBIR_onezeros )-- #define stbir__simdf_swiz( reg, one, two, three, four ) _mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( reg ), (one<<0) + (two<<2) + (three<<4) + (four<<6) ) )-- #define stbir__simdi_and( out, reg0, reg1 ) (out) = _mm_and_si128( reg0, reg1 )- #define stbir__simdi_or( out, reg0, reg1 ) (out) = _mm_or_si128( reg0, reg1 )- #define stbir__simdi_16madd( out, reg0, reg1 ) (out) = _mm_madd_epi16( reg0, reg1 )-- #define stbir__simdf_pack_to_8bytes(out,aa,bb) \- { \- stbir__simdf af,bf; \- stbir__simdi a,b; \- af = _mm_min_ps( aa, STBIR_max_uint8_as_float ); \- bf = _mm_min_ps( bb, STBIR_max_uint8_as_float ); \- af = _mm_max_ps( af, _mm_setzero_ps() ); \- bf = _mm_max_ps( bf, _mm_setzero_ps() ); \- a = _mm_cvttps_epi32( af ); \- b = _mm_cvttps_epi32( bf ); \- a = _mm_packs_epi32( a, b ); \- out = _mm_packus_epi16( a, a ); \- }-- #define stbir__simdf_load4_transposed( o0, o1, o2, o3, ptr ) \- stbir__simdf_load( o0, (ptr) ); \- stbir__simdf_load( o1, (ptr)+4 ); \- stbir__simdf_load( o2, (ptr)+8 ); \- stbir__simdf_load( o3, (ptr)+12 ); \- { \- __m128 tmp0, tmp1, tmp2, tmp3; \- tmp0 = _mm_unpacklo_ps(o0, o1); \- tmp2 = _mm_unpacklo_ps(o2, o3); \- tmp1 = _mm_unpackhi_ps(o0, o1); \- tmp3 = _mm_unpackhi_ps(o2, o3); \- o0 = _mm_movelh_ps(tmp0, tmp2); \- o1 = _mm_movehl_ps(tmp2, tmp0); \- o2 = _mm_movelh_ps(tmp1, tmp3); \- o3 = _mm_movehl_ps(tmp3, tmp1); \- }-- #define stbir__interleave_pack_and_store_16_u8( ptr, r0, r1, r2, r3 ) \- r0 = _mm_packs_epi32( r0, r1 ); \- r2 = _mm_packs_epi32( r2, r3 ); \- r1 = _mm_unpacklo_epi16( r0, r2 ); \- r3 = _mm_unpackhi_epi16( r0, r2 ); \- r0 = _mm_unpacklo_epi16( r1, r3 ); \- r2 = _mm_unpackhi_epi16( r1, r3 ); \- r0 = _mm_packus_epi16( r0, r2 ); \- stbir__simdi_store( ptr, r0 ); \-- #define stbir__simdi_32shr( out, reg, imm ) out = _mm_srli_epi32( reg, imm )-- #if defined(_MSC_VER) && !defined(__clang__)- // msvc inits with 8 bytes- #define STBIR__CONST_32_TO_8( v ) (char)(unsigned char)((v)&255),(char)(unsigned char)(((v)>>8)&255),(char)(unsigned char)(((v)>>16)&255),(char)(unsigned char)(((v)>>24)&255)- #define STBIR__CONST_4_32i( v ) STBIR__CONST_32_TO_8( v ), STBIR__CONST_32_TO_8( v ), STBIR__CONST_32_TO_8( v ), STBIR__CONST_32_TO_8( v )- #define STBIR__CONST_4d_32i( v0, v1, v2, v3 ) STBIR__CONST_32_TO_8( v0 ), STBIR__CONST_32_TO_8( v1 ), STBIR__CONST_32_TO_8( v2 ), STBIR__CONST_32_TO_8( v3 )- #else- // everything else inits with long long's- #define STBIR__CONST_4_32i( v ) (long long)((((stbir_uint64)(stbir_uint32)(v))<<32)|((stbir_uint64)(stbir_uint32)(v))),(long long)((((stbir_uint64)(stbir_uint32)(v))<<32)|((stbir_uint64)(stbir_uint32)(v)))- #define STBIR__CONST_4d_32i( v0, v1, v2, v3 ) (long long)((((stbir_uint64)(stbir_uint32)(v1))<<32)|((stbir_uint64)(stbir_uint32)(v0))),(long long)((((stbir_uint64)(stbir_uint32)(v3))<<32)|((stbir_uint64)(stbir_uint32)(v2)))- #endif-- #define STBIR__SIMDF_CONST(var, x) stbir__simdf var = { x, x, x, x }- #define STBIR__SIMDI_CONST(var, x) stbir__simdi var = { STBIR__CONST_4_32i(x) }- #define STBIR__CONSTF(var) (var)- #define STBIR__CONSTI(var) (var)-- #if defined(STBIR_AVX) || defined(__SSE4_1__)- #include <smmintrin.h>- #define stbir__simdf_pack_to_8words(out,reg0,reg1) out = _mm_packus_epi32(_mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg0,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())), _mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg1,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())))- #else- STBIR__SIMDI_CONST(stbir__s32_32768, 32768);- STBIR__SIMDI_CONST(stbir__s16_32768, ((32768<<16)|32768));-- #define stbir__simdf_pack_to_8words(out,reg0,reg1) \- { \- stbir__simdi tmp0,tmp1; \- tmp0 = _mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg0,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())); \- tmp1 = _mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg1,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())); \- tmp0 = _mm_sub_epi32( tmp0, stbir__s32_32768 ); \- tmp1 = _mm_sub_epi32( tmp1, stbir__s32_32768 ); \- out = _mm_packs_epi32( tmp0, tmp1 ); \- out = _mm_sub_epi16( out, stbir__s16_32768 ); \- }-- #endif-- #define STBIR_SIMD-- // if we detect AVX, set the simd8 defines- #ifdef STBIR_AVX- #include <immintrin.h>- #define STBIR_SIMD8- #define stbir__simdf8 __m256- #define stbir__simdi8 __m256i- #define stbir__simdf8_load( out, ptr ) (out) = _mm256_loadu_ps( (float const *)(ptr) )- #define stbir__simdi8_load( out, ptr ) (out) = _mm256_loadu_si256( (__m256i const *)(ptr) )- #define stbir__simdf8_mult( out, a, b ) (out) = _mm256_mul_ps( (a), (b) )- #define stbir__simdf8_store( ptr, out ) _mm256_storeu_ps( (float*)(ptr), out )- #define stbir__simdi8_store( ptr, reg ) _mm256_storeu_si256( (__m256i*)(ptr), reg )- #define stbir__simdf8_frep8( fval ) _mm256_set1_ps( fval )-- #define stbir__simdf8_min( out, reg0, reg1 ) (out) = _mm256_min_ps( reg0, reg1 )- #define stbir__simdf8_max( out, reg0, reg1 ) (out) = _mm256_max_ps( reg0, reg1 )-- #define stbir__simdf8_add4halves( out, bot4, top8 ) (out) = _mm_add_ps( bot4, _mm256_extractf128_ps( top8, 1 ) )- #define stbir__simdf8_mult_mem( out, reg, ptr ) (out) = _mm256_mul_ps( reg, _mm256_loadu_ps( (float const*)(ptr) ) )- #define stbir__simdf8_add_mem( out, reg, ptr ) (out) = _mm256_add_ps( reg, _mm256_loadu_ps( (float const*)(ptr) ) )- #define stbir__simdf8_add( out, a, b ) (out) = _mm256_add_ps( a, b )- #define stbir__simdf8_load1b( out, ptr ) (out) = _mm256_broadcast_ss( ptr )- #define stbir__simdf_load1rep4( out, ptr ) (out) = _mm_broadcast_ss( ptr ) // avx load instruction-- #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-- #define stbir__simdi8_expand_u8_to_u32(out0,out1,ireg) \- { \- stbir__simdi8 a, zero =_mm256_setzero_si256();\- a = _mm256_permute4x64_epi64( _mm256_unpacklo_epi8( _mm256_permute4x64_epi64(_mm256_castsi128_si256(ireg),(0<<0)+(2<<2)+(1<<4)+(3<<6)), zero ),(0<<0)+(2<<2)+(1<<4)+(3<<6)); \- out0 = _mm256_unpacklo_epi16( a, zero ); \- out1 = _mm256_unpackhi_epi16( a, zero ); \- }-- #define stbir__simdf8_pack_to_16bytes(out,aa,bb) \- { \- stbir__simdi8 t; \- stbir__simdf8 af,bf; \- stbir__simdi8 a,b; \- af = _mm256_min_ps( aa, STBIR_max_uint8_as_floatX ); \- bf = _mm256_min_ps( bb, STBIR_max_uint8_as_floatX ); \- af = _mm256_max_ps( af, _mm256_setzero_ps() ); \- bf = _mm256_max_ps( bf, _mm256_setzero_ps() ); \- a = _mm256_cvttps_epi32( af ); \- b = _mm256_cvttps_epi32( bf ); \- t = _mm256_permute4x64_epi64( _mm256_packs_epi32( a, b ), (0<<0)+(2<<2)+(1<<4)+(3<<6) ); \- 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__simdf8_pack_to_16words(out,aa,bb) \- { \- stbir__simdf8 af,bf; \- stbir__simdi8 a,b; \- af = _mm256_min_ps( aa, STBIR_max_uint16_as_floatX ); \- bf = _mm256_min_ps( bb, STBIR_max_uint16_as_floatX ); \- af = _mm256_max_ps( af, _mm256_setzero_ps() ); \- bf = _mm256_max_ps( bf, _mm256_setzero_ps() ); \- a = _mm256_cvttps_epi32( af ); \- b = _mm256_cvttps_epi32( bf ); \- (out) = _mm256_permute4x64_epi64( _mm256_packus_epi32(a, b), (0<<0)+(2<<2)+(1<<4)+(3<<6) ); \- }-- #else-- #define stbir__simdi8_expand_u8_to_u32(out0,out1,ireg) \- { \- stbir__simdi a,zero = _mm_setzero_si128(); \- a = _mm_unpacklo_epi8( ireg, zero ); \- out0 = _mm256_setr_m128i( _mm_unpacklo_epi16( a, zero ), _mm_unpackhi_epi16( a, zero ) ); \- 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; \- stbir__simdf8 af,bf; \- stbir__simdi8 a,b; \- af = _mm256_min_ps( aa, STBIR_max_uint8_as_floatX ); \- bf = _mm256_min_ps( bb, STBIR_max_uint8_as_floatX ); \- af = _mm256_max_ps( af, _mm256_setzero_ps() ); \- bf = _mm256_max_ps( bf, _mm256_setzero_ps() ); \- a = _mm256_cvttps_epi32( af ); \- b = _mm256_cvttps_epi32( bf ); \- out = _mm_packs_epi32( _mm256_castsi256_si128(a), _mm256_extractf128_si256( a, 1 ) ); \- out = _mm_packus_epi16( out, out ); \- t = _mm_packs_epi32( _mm256_castsi256_si128(b), _mm256_extractf128_si256( b, 1 ) ); \- 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(); \- a = _mm_unpacklo_epi16( ireg, zero ); \- b = _mm_unpackhi_epi16( ireg, zero ); \- out = _mm256_insertf128_si256( _mm256_castsi128_si256( a ), b, 1 ); \- }-- #define stbir__simdf8_pack_to_16words(out,aa,bb) \- { \- stbir__simdi t0,t1; \- stbir__simdf8 af,bf; \- stbir__simdi8 a,b; \- af = _mm256_min_ps( aa, STBIR_max_uint16_as_floatX ); \- bf = _mm256_min_ps( bb, STBIR_max_uint16_as_floatX ); \- af = _mm256_max_ps( af, _mm256_setzero_ps() ); \- bf = _mm256_max_ps( bf, _mm256_setzero_ps() ); \- a = _mm256_cvttps_epi32( af ); \- b = _mm256_cvttps_epi32( bf ); \- t0 = _mm_packus_epi32( _mm256_castsi256_si128(a), _mm256_extractf128_si256( a, 1 ) ); \- t1 = _mm_packus_epi32( _mm256_castsi256_si128(b), _mm256_extractf128_si256( b, 1 ) ); \- out = _mm256_setr_m128i( t0, t1 ); \- }-- #endif-- static __m256i stbir_00001111 = { STBIR__CONST_4d_32i( 0, 0, 0, 0 ), STBIR__CONST_4d_32i( 1, 1, 1, 1 ) };- #define stbir__simdf8_0123to00001111( out, in ) (out) = _mm256_permutevar_ps ( in, stbir_00001111 )-- static __m256i stbir_22223333 = { STBIR__CONST_4d_32i( 2, 2, 2, 2 ), STBIR__CONST_4d_32i( 3, 3, 3, 3 ) };- #define stbir__simdf8_0123to22223333( out, in ) (out) = _mm256_permutevar_ps ( in, stbir_22223333 )-- #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 ) };- #define stbir__simdf8_0123to00112233( out, in ) (out) = _mm256_permutevar_ps ( in, stbir_00112233 )- #define stbir__simdf8_add4( out, a8, b ) (out) = _mm256_add_ps( a8, _mm256_castps128_ps256( b ) )-- static __m256i stbir_load6 = { STBIR__CONST_4_32i( 0x80000000 ), STBIR__CONST_4d_32i( 0x80000000, 0x80000000, 0, 0 ) };- #define stbir__simdf8_load6z( out, ptr ) (out) = _mm256_maskload_ps( ptr, stbir_load6 )-- #define stbir__simdf8_0123to00000000( out, in ) (out) = _mm256_shuffle_ps ( in, in, (0<<0)+(0<<2)+(0<<4)+(0<<6) )- #define stbir__simdf8_0123to11111111( out, in ) (out) = _mm256_shuffle_ps ( in, in, (1<<0)+(1<<2)+(1<<4)+(1<<6) )- #define stbir__simdf8_0123to22222222( out, in ) (out) = _mm256_shuffle_ps ( in, in, (2<<0)+(2<<2)+(2<<4)+(2<<6) )- #define stbir__simdf8_0123to33333333( out, in ) (out) = _mm256_shuffle_ps ( in, in, (3<<0)+(3<<2)+(3<<4)+(3<<6) )- #define stbir__simdf8_0123to21032103( out, in ) (out) = _mm256_shuffle_ps ( in, in, (2<<0)+(1<<2)+(0<<4)+(3<<6) )- #define stbir__simdf8_0123to32103210( out, in ) (out) = _mm256_shuffle_ps ( in, in, (3<<0)+(2<<2)+(1<<4)+(0<<6) )- #define stbir__simdf8_0123to12301230( out, in ) (out) = _mm256_shuffle_ps ( in, in, (1<<0)+(2<<2)+(3<<4)+(0<<6) )- #define stbir__simdf8_0123to10321032( out, in ) (out) = _mm256_shuffle_ps ( in, in, (1<<0)+(0<<2)+(3<<4)+(2<<6) )- #define stbir__simdf8_0123to30123012( out, in ) (out) = _mm256_shuffle_ps ( in, in, (3<<0)+(0<<2)+(1<<4)+(2<<6) )-- #define stbir__simdf8_0123to11331133( out, in ) (out) = _mm256_shuffle_ps ( in, in, (1<<0)+(1<<2)+(3<<4)+(3<<6) )- #define stbir__simdf8_0123to00220022( out, in ) (out) = _mm256_shuffle_ps ( in, in, (0<<0)+(0<<2)+(2<<4)+(2<<6) )-- #define stbir__simdf8_aaa1( out, alp, ones ) (out) = _mm256_blend_ps( alp, ones, (1<<0)+(1<<1)+(1<<2)+(0<<3)+(1<<4)+(1<<5)+(1<<6)+(0<<7)); (out)=_mm256_shuffle_ps( out,out, (3<<0) + (3<<2) + (3<<4) + (0<<6) )- #define stbir__simdf8_1aaa( out, alp, ones ) (out) = _mm256_blend_ps( alp, ones, (0<<0)+(1<<1)+(1<<2)+(1<<3)+(0<<4)+(1<<5)+(1<<6)+(1<<7)); (out)=_mm256_shuffle_ps( out,out, (1<<0) + (0<<2) + (0<<4) + (0<<6) )- #define stbir__simdf8_a1a1( out, alp, ones) (out) = _mm256_blend_ps( alp, ones, (1<<0)+(0<<1)+(1<<2)+(0<<3)+(1<<4)+(0<<5)+(1<<6)+(0<<7)); (out)=_mm256_shuffle_ps( out,out, (1<<0) + (0<<2) + (3<<4) + (2<<6) )- #define stbir__simdf8_1a1a( out, alp, ones) (out) = _mm256_blend_ps( alp, ones, (0<<0)+(1<<1)+(0<<2)+(1<<3)+(0<<4)+(1<<5)+(0<<6)+(1<<7)); (out)=_mm256_shuffle_ps( out,out, (1<<0) + (0<<2) + (3<<4) + (2<<6) )-- #define stbir__simdf8_zero( reg ) (reg) = _mm256_setzero_ps()-- #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 )- #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) ) ) ) )- #endif- #define stbir__if_simdf8_cast_to_simdf4( val ) _mm256_castps256_ps128( val )-- #endif-- #ifdef STBIR_FLOORF- #undef STBIR_FLOORF- #endif- #define STBIR_FLOORF stbir_simd_floorf- static stbir__inline float stbir_simd_floorf(float x) // martins floorf- {- #if defined(STBIR_AVX) || defined(__SSE4_1__) || defined(STBIR_SSE41)- __m128 t = _mm_set_ss(x);- return _mm_cvtss_f32( _mm_floor_ss(t, t) );- #else- __m128 f = _mm_set_ss(x);- __m128 t = _mm_cvtepi32_ps(_mm_cvttps_epi32(f));- __m128 r = _mm_add_ss(t, _mm_and_ps(_mm_cmplt_ss(f, t), _mm_set_ss(-1.0f)));- return _mm_cvtss_f32(r);- #endif- }-- #ifdef STBIR_CEILF- #undef STBIR_CEILF- #endif- #define STBIR_CEILF stbir_simd_ceilf- static stbir__inline float stbir_simd_ceilf(float x) // martins ceilf- {- #if defined(STBIR_AVX) || defined(__SSE4_1__) || defined(STBIR_SSE41)- __m128 t = _mm_set_ss(x);- return _mm_cvtss_f32( _mm_ceil_ss(t, t) );- #else- __m128 f = _mm_set_ss(x);- __m128 t = _mm_cvtepi32_ps(_mm_cvttps_epi32(f));- __m128 r = _mm_add_ss(t, _mm_and_ps(_mm_cmplt_ss(t, f), _mm_set_ss(1.0f)));- return _mm_cvtss_f32(r);- #endif- }--#elif defined(STBIR_NEON)- - #include <arm_neon.h>-- #define stbir__simdf float32x4_t- #define stbir__simdi uint32x4_t-- #define stbir_simdi_castf( reg ) vreinterpretq_u32_f32(reg)- #define stbir_simdf_casti( reg ) vreinterpretq_f32_u32(reg)-- #define stbir__simdf_load( reg, ptr ) (reg) = vld1q_f32( (float const*)(ptr) )- #define stbir__simdi_load( reg, ptr ) (reg) = vld1q_u32( (uint32_t const*)(ptr) )- #define stbir__simdf_load1( out, ptr ) (out) = vld1q_dup_f32( (float const*)(ptr) ) // top values can be random (not denormal or nan for perf)- #define stbir__simdi_load1( out, ptr ) (out) = vld1q_dup_u32( (uint32_t const*)(ptr) )- #define stbir__simdf_load1z( out, ptr ) (out) = vld1q_lane_f32( (float const*)(ptr), vdupq_n_f32(0), 0 ) // top values must be zero- #define stbir__simdf_frep4( fvar ) vdupq_n_f32( fvar )- #define stbir__simdf_load1frep4( out, fvar ) (out) = vdupq_n_f32( fvar )- #define stbir__simdf_load2( out, ptr ) (out) = vcombine_f32( vld1_f32( (float const*)(ptr) ), vcreate_f32(0) ) // top values can be random (not denormal or nan for perf)- #define stbir__simdf_load2z( out, ptr ) (out) = vcombine_f32( vld1_f32( (float const*)(ptr) ), vcreate_f32(0) ) // top values must be zero- #define stbir__simdf_load2hmerge( out, reg, ptr ) (out) = vcombine_f32( vget_low_f32(reg), vld1_f32( (float const*)(ptr) ) )-- #define stbir__simdf_zeroP() vdupq_n_f32(0)- #define stbir__simdf_zero( reg ) (reg) = vdupq_n_f32(0)-- #define stbir__simdf_store( ptr, reg ) vst1q_f32( (float*)(ptr), reg )- #define stbir__simdf_store1( ptr, reg ) vst1q_lane_f32( (float*)(ptr), reg, 0)- #define stbir__simdf_store2( ptr, reg ) vst1_f32( (float*)(ptr), vget_low_f32(reg) )- #define stbir__simdf_store2h( ptr, reg ) vst1_f32( (float*)(ptr), vget_high_f32(reg) )-- #define stbir__simdi_store( ptr, reg ) vst1q_u32( (uint32_t*)(ptr), reg )- #define stbir__simdi_store1( ptr, reg ) vst1q_lane_u32( (uint32_t*)(ptr), reg, 0 )- #define stbir__simdi_store2( ptr, reg ) vst1_u32( (uint32_t*)(ptr), vget_low_u32(reg) )-- #define stbir__prefetch( ptr )-- #define stbir__simdi_expand_u8_to_u32(out0,out1,out2,out3,ireg) \- { \- uint16x8_t l = vmovl_u8( vget_low_u8 ( vreinterpretq_u8_u32(ireg) ) ); \- uint16x8_t h = vmovl_u8( vget_high_u8( vreinterpretq_u8_u32(ireg) ) ); \- out0 = vmovl_u16( vget_low_u16 ( l ) ); \- out1 = vmovl_u16( vget_high_u16( l ) ); \- out2 = vmovl_u16( vget_low_u16 ( h ) ); \- out3 = vmovl_u16( vget_high_u16( h ) ); \- }-- #define stbir__simdi_expand_u8_to_1u32(out,ireg) \- { \- uint16x8_t tmp = vmovl_u8( vget_low_u8( vreinterpretq_u8_u32(ireg) ) ); \- out = vmovl_u16( vget_low_u16( tmp ) ); \- }-- #define stbir__simdi_expand_u16_to_u32(out0,out1,ireg) \- { \- uint16x8_t tmp = vreinterpretq_u16_u32(ireg); \- out0 = vmovl_u16( vget_low_u16 ( tmp ) ); \- out1 = vmovl_u16( vget_high_u16( tmp ) ); \- }-- #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__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) )- #define stbir__simdf_add( out, reg0, reg1 ) (out) = vaddq_f32( reg0, reg1 )- #define stbir__simdf_mult( out, reg0, reg1 ) (out) = vmulq_f32( reg0, reg1 )- #define stbir__simdf_mult_mem( out, reg, ptr ) (out) = vmulq_f32( reg, vld1q_f32( (float const*)(ptr) ) )- #define stbir__simdf_mult1_mem( out, reg, ptr ) (out) = vmulq_f32( reg, vld1q_dup_f32( (float const*)(ptr) ) )- #define stbir__simdf_add_mem( out, reg, ptr ) (out) = vaddq_f32( reg, vld1q_f32( (float const*)(ptr) ) )- #define stbir__simdf_add1_mem( out, reg, ptr ) (out) = vaddq_f32( reg, vld1q_dup_f32( (float const*)(ptr) ) )-- #ifdef STBIR_USE_FMA // not on by default to maintain bit identical simd to non-simd (and also x64 no madd to arm madd)- #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = vfmaq_f32( add, mul1, mul2 )- #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = vfmaq_f32( add, mul1, mul2 )- #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = vfmaq_f32( add, mul, vld1q_f32( (float const*)(ptr) ) )- #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = vfmaq_f32( add, mul, vld1q_dup_f32( (float const*)(ptr) ) )- #else- #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = vaddq_f32( add, vmulq_f32( mul1, mul2 ) )- #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = vaddq_f32( add, vmulq_f32( mul1, mul2 ) )- #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = vaddq_f32( add, vmulq_f32( mul, vld1q_f32( (float const*)(ptr) ) ) )- #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = vaddq_f32( add, vmulq_f32( mul, vld1q_dup_f32( (float const*)(ptr) ) ) )- #endif-- #define stbir__simdf_add1( out, reg0, reg1 ) (out) = vaddq_f32( reg0, reg1 )- #define stbir__simdf_mult1( out, reg0, reg1 ) (out) = vmulq_f32( reg0, reg1 )-- #define stbir__simdf_and( out, reg0, reg1 ) (out) = vreinterpretq_f32_u32( vandq_u32( vreinterpretq_u32_f32(reg0), vreinterpretq_u32_f32(reg1) ) )- #define stbir__simdf_or( out, reg0, reg1 ) (out) = vreinterpretq_f32_u32( vorrq_u32( vreinterpretq_u32_f32(reg0), vreinterpretq_u32_f32(reg1) ) )-- #define stbir__simdf_min( out, reg0, reg1 ) (out) = vminq_f32( reg0, reg1 )- #define stbir__simdf_max( out, reg0, reg1 ) (out) = vmaxq_f32( reg0, reg1 )- #define stbir__simdf_min1( out, reg0, reg1 ) (out) = vminq_f32( reg0, reg1 )- #define stbir__simdf_max1( out, reg0, reg1 ) (out) = vmaxq_f32( reg0, reg1 )-- #define stbir__simdf_0123ABCDto3ABx( out, reg0, reg1 ) (out) = vextq_f32( reg0, reg1, 3 )- #define stbir__simdf_0123ABCDto23Ax( out, reg0, reg1 ) (out) = vextq_f32( reg0, reg1, 2 )-- #define stbir__simdf_a1a1( out, alp, ones ) (out) = vzipq_f32(vuzpq_f32(alp, alp).val[1], ones).val[0]- #define stbir__simdf_1a1a( out, alp, ones ) (out) = vzipq_f32(ones, vuzpq_f32(alp, alp).val[0]).val[0]-- #if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ )-- #define stbir__simdf_aaa1( out, alp, ones ) (out) = vcopyq_laneq_f32(vdupq_n_f32(vgetq_lane_f32(alp, 3)), 3, ones, 3)- #define stbir__simdf_1aaa( out, alp, ones ) (out) = vcopyq_laneq_f32(vdupq_n_f32(vgetq_lane_f32(alp, 0)), 0, ones, 0)-- #if defined( _MSC_VER ) && !defined(__clang__)- #define stbir_make16(a,b,c,d) vcombine_u8( \- vcreate_u8( (4*a+0) | ((4*a+1)<<8) | ((4*a+2)<<16) | ((4*a+3)<<24) | \- ((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) ) )- #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}- #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__simdi_16madd( out, reg0, reg1 ) \- { \- int16x8_t r0 = vreinterpretq_s16_u32(reg0); \- int16x8_t r1 = vreinterpretq_s16_u32(reg1); \- int32x4_t tmp0 = vmull_s16( vget_low_s16(r0), vget_low_s16(r1) ); \- int32x4_t tmp1 = vmull_s16( vget_high_s16(r0), vget_high_s16(r1) ); \- (out) = vreinterpretq_u32_s32( vpaddq_s32(tmp0, tmp1) ); \- }-- #else-- #define stbir__simdf_aaa1( out, alp, ones ) (out) = vsetq_lane_f32(1.0f, vdupq_n_f32(vgetq_lane_f32(alp, 3)), 3)- #define stbir__simdf_1aaa( out, alp, ones ) (out) = vsetq_lane_f32(1.0f, vdupq_n_f32(vgetq_lane_f32(alp, 0)), 0)-- #if defined( _MSC_VER ) && !defined(__clang__)- static stbir__inline uint8x8x2_t stbir_make8x2(float32x4_t reg)- {- uint8x8x2_t r = { { vget_low_u8(vreinterpretq_u8_f32(reg)), vget_high_u8(vreinterpretq_u8_f32(reg)) } };- return r;- }- #define stbir_make8(a,b) vcreate_u8( \- (4*a+0) | ((4*a+1)<<8) | ((4*a+2)<<16) | ((4*a+3)<<24) | \- ((stbir_uint64)(4*b+0)<<32) | ((stbir_uint64)(4*b+1)<<40) | ((stbir_uint64)(4*b+2)<<48) | ((stbir_uint64)(4*b+3)<<56) )- #else- #define stbir_make8x2(reg) (uint8x8x2_t){ { vget_low_u8(vreinterpretq_u8_f32(reg)), vget_high_u8(vreinterpretq_u8_f32(reg)) } }- #define stbir_make8(a,b) (uint8x8_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}- #endif-- #define stbir__simdf_swiz( reg, one, two, three, four ) vreinterpretq_f32_u8( vcombine_u8( \- vtbl2_u8( stbir_make8x2( reg ), stbir_make8( one, two ) ), \- vtbl2_u8( stbir_make8x2( reg ), stbir_make8( three, four ) ) ) )-- #define stbir__simdi_16madd( out, reg0, reg1 ) \- { \- int16x8_t r0 = vreinterpretq_s16_u32(reg0); \- int16x8_t r1 = vreinterpretq_s16_u32(reg1); \- int32x4_t tmp0 = vmull_s16( vget_low_s16(r0), vget_low_s16(r1) ); \- int32x4_t tmp1 = vmull_s16( vget_high_s16(r0), vget_high_s16(r1) ); \- int32x2_t out0 = vpadd_s32( vget_low_s32(tmp0), vget_high_s32(tmp0) ); \- int32x2_t out1 = vpadd_s32( vget_low_s32(tmp1), vget_high_s32(tmp1) ); \- (out) = vreinterpretq_u32_s32( vcombine_s32(out0, out1) ); \- }-- #endif-- #define stbir__simdi_and( out, reg0, reg1 ) (out) = vandq_u32( reg0, reg1 )- #define stbir__simdi_or( out, reg0, reg1 ) (out) = vorrq_u32( reg0, reg1 )-- #define stbir__simdf_pack_to_8bytes(out,aa,bb) \- { \- float32x4_t af = vmaxq_f32( vminq_f32(aa,STBIR__CONSTF(STBIR_max_uint8_as_float) ), vdupq_n_f32(0) ); \- float32x4_t bf = vmaxq_f32( vminq_f32(bb,STBIR__CONSTF(STBIR_max_uint8_as_float) ), vdupq_n_f32(0) ); \- int16x4_t ai = vqmovn_s32( vcvtq_s32_f32( af ) ); \- int16x4_t bi = vqmovn_s32( vcvtq_s32_f32( bf ) ); \- uint8x8_t out8 = vqmovun_s16( vcombine_s16(ai, bi) ); \- out = vreinterpretq_u32_u8( vcombine_u8(out8, out8) ); \- }-- #define stbir__simdf_pack_to_8words(out,aa,bb) \- { \- float32x4_t af = vmaxq_f32( vminq_f32(aa,STBIR__CONSTF(STBIR_max_uint16_as_float) ), vdupq_n_f32(0) ); \- float32x4_t bf = vmaxq_f32( vminq_f32(bb,STBIR__CONSTF(STBIR_max_uint16_as_float) ), vdupq_n_f32(0) ); \- int32x4_t ai = vcvtq_s32_f32( af ); \- int32x4_t bi = vcvtq_s32_f32( bf ); \- out = vreinterpretq_u32_u16( vcombine_u16(vqmovun_s32(ai), vqmovun_s32(bi)) ); \- }-- #define stbir__interleave_pack_and_store_16_u8( ptr, r0, r1, r2, r3 ) \- { \- int16x4x2_t tmp0 = vzip_s16( vqmovn_s32(vreinterpretq_s32_u32(r0)), vqmovn_s32(vreinterpretq_s32_u32(r2)) ); \- int16x4x2_t tmp1 = vzip_s16( vqmovn_s32(vreinterpretq_s32_u32(r1)), vqmovn_s32(vreinterpretq_s32_u32(r3)) ); \- uint8x8x2_t out = \- { { \- vqmovun_s16( vcombine_s16(tmp0.val[0], tmp0.val[1]) ), \- vqmovun_s16( vcombine_s16(tmp1.val[0], tmp1.val[1]) ), \- } }; \- vst2_u8(ptr, out); \- }-- #define stbir__simdf_load4_transposed( o0, o1, o2, o3, ptr ) \- { \- float32x4x4_t tmp = vld4q_f32(ptr); \- o0 = tmp.val[0]; \- o1 = tmp.val[1]; \- o2 = tmp.val[2]; \- o3 = tmp.val[3]; \- }-- #define stbir__simdi_32shr( out, reg, imm ) out = vshrq_n_u32( reg, imm )-- #if defined( _MSC_VER ) && !defined(__clang__)- #define STBIR__SIMDF_CONST(var, x) __declspec(align(8)) float var[] = { x, x, x, x }- #define STBIR__SIMDI_CONST(var, x) __declspec(align(8)) uint32_t var[] = { x, x, x, x }- #define STBIR__CONSTF(var) (*(const float32x4_t*)var)- #define STBIR__CONSTI(var) (*(const uint32x4_t*)var)- #else- #define STBIR__SIMDF_CONST(var, x) stbir__simdf var = { x, x, x, x }- #define STBIR__SIMDI_CONST(var, x) stbir__simdi var = { x, x, x, x }- #define STBIR__CONSTF(var) (var)- #define STBIR__CONSTI(var) (var)- #endif-- #ifdef STBIR_FLOORF- #undef STBIR_FLOORF- #endif- #define STBIR_FLOORF stbir_simd_floorf- static stbir__inline float stbir_simd_floorf(float x)- {- #if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ )- return vget_lane_f32( vrndm_f32( vdup_n_f32(x) ), 0);- #else- float32x2_t f = vdup_n_f32(x);- float32x2_t t = vcvt_f32_s32(vcvt_s32_f32(f));- uint32x2_t a = vclt_f32(f, t);- uint32x2_t b = vreinterpret_u32_f32(vdup_n_f32(-1.0f));- float32x2_t r = vadd_f32(t, vreinterpret_f32_u32(vand_u32(a, b)));- return vget_lane_f32(r, 0);- #endif- }-- #ifdef STBIR_CEILF- #undef STBIR_CEILF- #endif- #define STBIR_CEILF stbir_simd_ceilf- static stbir__inline float stbir_simd_ceilf(float x)- {- #if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ )- return vget_lane_f32( vrndp_f32( vdup_n_f32(x) ), 0);- #else- float32x2_t f = vdup_n_f32(x);- float32x2_t t = vcvt_f32_s32(vcvt_s32_f32(f));- uint32x2_t a = vclt_f32(t, f);- uint32x2_t b = vreinterpret_u32_f32(vdup_n_f32(1.0f));- float32x2_t r = vadd_f32(t, vreinterpret_f32_u32(vand_u32(a, b)));- return vget_lane_f32(r, 0);- #endif- }-- #define STBIR_SIMD--#elif defined(STBIR_WASM)-- #include <wasm_simd128.h>-- #define stbir__simdf v128_t- #define stbir__simdi v128_t-- #define stbir_simdi_castf( reg ) (reg)- #define stbir_simdf_casti( reg ) (reg)-- #define stbir__simdf_load( reg, ptr ) (reg) = wasm_v128_load( (void const*)(ptr) )- #define stbir__simdi_load( reg, ptr ) (reg) = wasm_v128_load( (void const*)(ptr) )- #define stbir__simdf_load1( out, ptr ) (out) = wasm_v128_load32_splat( (void const*)(ptr) ) // top values can be random (not denormal or nan for perf)- #define stbir__simdi_load1( out, ptr ) (out) = wasm_v128_load32_splat( (void const*)(ptr) )- #define stbir__simdf_load1z( out, ptr ) (out) = wasm_v128_load32_zero( (void const*)(ptr) ) // top values must be zero- #define stbir__simdf_frep4( fvar ) wasm_f32x4_splat( fvar )- #define stbir__simdf_load1frep4( out, fvar ) (out) = wasm_f32x4_splat( fvar )- #define stbir__simdf_load2( out, ptr ) (out) = wasm_v128_load64_splat( (void const*)(ptr) ) // top values can be random (not denormal or nan for perf)- #define stbir__simdf_load2z( out, ptr ) (out) = wasm_v128_load64_zero( (void const*)(ptr) ) // top values must be zero- #define stbir__simdf_load2hmerge( out, reg, ptr ) (out) = wasm_v128_load64_lane( (void const*)(ptr), reg, 1 )-- #define stbir__simdf_zeroP() wasm_f32x4_const_splat(0)- #define stbir__simdf_zero( reg ) (reg) = wasm_f32x4_const_splat(0)-- #define stbir__simdf_store( ptr, reg ) wasm_v128_store( (void*)(ptr), reg )- #define stbir__simdf_store1( ptr, reg ) wasm_v128_store32_lane( (void*)(ptr), reg, 0 )- #define stbir__simdf_store2( ptr, reg ) wasm_v128_store64_lane( (void*)(ptr), reg, 0 )- #define stbir__simdf_store2h( ptr, reg ) wasm_v128_store64_lane( (void*)(ptr), reg, 1 )-- #define stbir__simdi_store( ptr, reg ) wasm_v128_store( (void*)(ptr), reg )- #define stbir__simdi_store1( ptr, reg ) wasm_v128_store32_lane( (void*)(ptr), reg, 0 )- #define stbir__simdi_store2( ptr, reg ) wasm_v128_store64_lane( (void*)(ptr), reg, 0 )-- #define stbir__prefetch( ptr )-- #define stbir__simdi_expand_u8_to_u32(out0,out1,out2,out3,ireg) \- { \- v128_t l = wasm_u16x8_extend_low_u8x16 ( ireg ); \- v128_t h = wasm_u16x8_extend_high_u8x16( ireg ); \- out0 = wasm_u32x4_extend_low_u16x8 ( l ); \- out1 = wasm_u32x4_extend_high_u16x8( l ); \- out2 = wasm_u32x4_extend_low_u16x8 ( h ); \- out3 = wasm_u32x4_extend_high_u16x8( h ); \- }-- #define stbir__simdi_expand_u8_to_1u32(out,ireg) \- { \- v128_t tmp = wasm_u16x8_extend_low_u8x16(ireg); \- out = wasm_u32x4_extend_low_u16x8(tmp); \- }-- #define stbir__simdi_expand_u16_to_u32(out0,out1,ireg) \- { \- out0 = wasm_u32x4_extend_low_u16x8 ( ireg ); \- out1 = wasm_u32x4_extend_high_u16x8( ireg ); \- }-- #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__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)- #define stbir__simdf_add( out, reg0, reg1 ) (out) = wasm_f32x4_add( reg0, reg1 )- #define stbir__simdf_mult( out, reg0, reg1 ) (out) = wasm_f32x4_mul( reg0, reg1 )- #define stbir__simdf_mult_mem( out, reg, ptr ) (out) = wasm_f32x4_mul( reg, wasm_v128_load( (void const*)(ptr) ) )- #define stbir__simdf_mult1_mem( out, reg, ptr ) (out) = wasm_f32x4_mul( reg, wasm_v128_load32_splat( (void const*)(ptr) ) )- #define stbir__simdf_add_mem( out, reg, ptr ) (out) = wasm_f32x4_add( reg, wasm_v128_load( (void const*)(ptr) ) )- #define stbir__simdf_add1_mem( out, reg, ptr ) (out) = wasm_f32x4_add( reg, wasm_v128_load32_splat( (void const*)(ptr) ) )-- #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul1, mul2 ) )- #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul1, mul2 ) )- #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul, wasm_v128_load( (void const*)(ptr) ) ) )- #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul, wasm_v128_load32_splat( (void const*)(ptr) ) ) )-- #define stbir__simdf_add1( out, reg0, reg1 ) (out) = wasm_f32x4_add( reg0, reg1 )- #define stbir__simdf_mult1( out, reg0, reg1 ) (out) = wasm_f32x4_mul( reg0, reg1 )-- #define stbir__simdf_and( out, reg0, reg1 ) (out) = wasm_v128_and( reg0, reg1 )- #define stbir__simdf_or( out, reg0, reg1 ) (out) = wasm_v128_or( reg0, reg1 )-- #define stbir__simdf_min( out, reg0, reg1 ) (out) = wasm_f32x4_min( reg0, reg1 )- #define stbir__simdf_max( out, reg0, reg1 ) (out) = wasm_f32x4_max( reg0, reg1 )- #define stbir__simdf_min1( out, reg0, reg1 ) (out) = wasm_f32x4_min( reg0, reg1 )- #define stbir__simdf_max1( out, reg0, reg1 ) (out) = wasm_f32x4_max( reg0, reg1 )-- #define stbir__simdf_0123ABCDto3ABx( out, reg0, reg1 ) (out) = wasm_i32x4_shuffle( reg0, reg1, 3, 4, 5, -1 )- #define stbir__simdf_0123ABCDto23Ax( out, reg0, reg1 ) (out) = wasm_i32x4_shuffle( reg0, reg1, 2, 3, 4, -1 )-- #define stbir__simdf_aaa1(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 3, 3, 3, 4)- #define stbir__simdf_1aaa(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 4, 0, 0, 0)- #define stbir__simdf_a1a1(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 1, 4, 3, 4)- #define stbir__simdf_1a1a(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 4, 0, 4, 2)-- #define stbir__simdf_swiz( reg, one, two, three, four ) wasm_i32x4_shuffle(reg, reg, one, two, three, four)-- #define stbir__simdi_and( out, reg0, reg1 ) (out) = wasm_v128_and( reg0, reg1 )- #define stbir__simdi_or( out, reg0, reg1 ) (out) = wasm_v128_or( reg0, reg1 )- #define stbir__simdi_16madd( out, reg0, reg1 ) (out) = wasm_i32x4_dot_i16x8( reg0, reg1 )-- #define stbir__simdf_pack_to_8bytes(out,aa,bb) \- { \- v128_t af = wasm_f32x4_max( wasm_f32x4_min(aa, STBIR_max_uint8_as_float), wasm_f32x4_const_splat(0) ); \- v128_t bf = wasm_f32x4_max( wasm_f32x4_min(bb, STBIR_max_uint8_as_float), wasm_f32x4_const_splat(0) ); \- v128_t ai = wasm_i32x4_trunc_sat_f32x4( af ); \- v128_t bi = wasm_i32x4_trunc_sat_f32x4( bf ); \- v128_t out16 = wasm_i16x8_narrow_i32x4( ai, bi ); \- out = wasm_u8x16_narrow_i16x8( out16, out16 ); \- }-- #define stbir__simdf_pack_to_8words(out,aa,bb) \- { \- v128_t af = wasm_f32x4_max( wasm_f32x4_min(aa, STBIR_max_uint16_as_float), wasm_f32x4_const_splat(0)); \- v128_t bf = wasm_f32x4_max( wasm_f32x4_min(bb, STBIR_max_uint16_as_float), wasm_f32x4_const_splat(0)); \- v128_t ai = wasm_i32x4_trunc_sat_f32x4( af ); \- v128_t bi = wasm_i32x4_trunc_sat_f32x4( bf ); \- out = wasm_u16x8_narrow_i32x4( ai, bi ); \- }-- #define stbir__interleave_pack_and_store_16_u8( ptr, r0, r1, r2, r3 ) \- { \- v128_t tmp0 = wasm_i16x8_narrow_i32x4(r0, r1); \- v128_t tmp1 = wasm_i16x8_narrow_i32x4(r2, r3); \- v128_t tmp = wasm_u8x16_narrow_i16x8(tmp0, tmp1); \- tmp = wasm_i8x16_shuffle(tmp, tmp, 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); \- wasm_v128_store( (void*)(ptr), tmp); \- }-- #define stbir__simdf_load4_transposed( o0, o1, o2, o3, ptr ) \- { \- v128_t t0 = wasm_v128_load( ptr ); \- v128_t t1 = wasm_v128_load( ptr+4 ); \- v128_t t2 = wasm_v128_load( ptr+8 ); \- v128_t t3 = wasm_v128_load( ptr+12 ); \- v128_t s0 = wasm_i32x4_shuffle(t0, t1, 0, 4, 2, 6); \- v128_t s1 = wasm_i32x4_shuffle(t0, t1, 1, 5, 3, 7); \- v128_t s2 = wasm_i32x4_shuffle(t2, t3, 0, 4, 2, 6); \- v128_t s3 = wasm_i32x4_shuffle(t2, t3, 1, 5, 3, 7); \- o0 = wasm_i32x4_shuffle(s0, s2, 0, 1, 4, 5); \- o1 = wasm_i32x4_shuffle(s1, s3, 0, 1, 4, 5); \- o2 = wasm_i32x4_shuffle(s0, s2, 2, 3, 6, 7); \- o3 = wasm_i32x4_shuffle(s1, s3, 2, 3, 6, 7); \- }-- #define stbir__simdi_32shr( out, reg, imm ) out = wasm_u32x4_shr( reg, imm )-- typedef float stbir__f32x4 __attribute__((__vector_size__(16), __aligned__(16)));- #define STBIR__SIMDF_CONST(var, x) stbir__simdf var = (v128_t)(stbir__f32x4){ x, x, x, x }- #define STBIR__SIMDI_CONST(var, x) stbir__simdi var = { x, x, x, x }- #define STBIR__CONSTF(var) (var)- #define STBIR__CONSTI(var) (var)-- #ifdef STBIR_FLOORF- #undef STBIR_FLOORF- #endif- #define STBIR_FLOORF stbir_simd_floorf- static stbir__inline float stbir_simd_floorf(float x)- {- return wasm_f32x4_extract_lane( wasm_f32x4_floor( wasm_f32x4_splat(x) ), 0);- }-- #ifdef STBIR_CEILF- #undef STBIR_CEILF- #endif- #define STBIR_CEILF stbir_simd_ceilf- static stbir__inline float stbir_simd_ceilf(float x)- {- return wasm_f32x4_extract_lane( wasm_f32x4_ceil( wasm_f32x4_splat(x) ), 0);- }-- #define STBIR_SIMD--#endif // SSE2/NEON/WASM--#endif // NO SIMD--#ifdef STBIR_SIMD8- #define stbir__simdfX stbir__simdf8- #define stbir__simdiX stbir__simdi8- #define stbir__simdfX_load stbir__simdf8_load- #define stbir__simdiX_load stbir__simdi8_load- #define stbir__simdfX_mult stbir__simdf8_mult- #define stbir__simdfX_add_mem stbir__simdf8_add_mem- #define stbir__simdfX_madd_mem stbir__simdf8_madd_mem- #define stbir__simdfX_store stbir__simdf8_store- #define stbir__simdiX_store stbir__simdi8_store- #define stbir__simdf_frepX stbir__simdf8_frep8- #define stbir__simdfX_madd stbir__simdf8_madd- #define stbir__simdfX_min stbir__simdf8_min- #define stbir__simdfX_max stbir__simdf8_max- #define stbir__simdfX_aaa1 stbir__simdf8_aaa1- #define stbir__simdfX_1aaa stbir__simdf8_1aaa- #define stbir__simdfX_a1a1 stbir__simdf8_a1a1- #define stbir__simdfX_1a1a stbir__simdf8_1a1a- #define stbir__simdfX_convert_float_to_i32 stbir__simdf8_convert_float_to_i32- #define stbir__simdfX_pack_to_words stbir__simdf8_pack_to_16words- #define stbir__simdfX_zero stbir__simdf8_zero- #define STBIR_onesX STBIR_ones8- #define STBIR_max_uint8_as_floatX STBIR_max_uint8_as_float8- #define STBIR_max_uint16_as_floatX STBIR_max_uint16_as_float8- #define STBIR_simd_point5X STBIR_simd_point58- #define stbir__simdfX_float_count 8- #define stbir__simdfX_0123to1230 stbir__simdf8_0123to12301230- #define stbir__simdfX_0123to2103 stbir__simdf8_0123to21032103- static const stbir__simdf8 STBIR_max_uint16_as_float_inverted8 = { stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted };- static const stbir__simdf8 STBIR_max_uint8_as_float_inverted8 = { stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted };- static const stbir__simdf8 STBIR_ones8 = { 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 };- static const stbir__simdf8 STBIR_simd_point58 = { 0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5 };- static const stbir__simdf8 STBIR_max_uint8_as_float8 = { stbir__max_uint8_as_float,stbir__max_uint8_as_float,stbir__max_uint8_as_float,stbir__max_uint8_as_float, stbir__max_uint8_as_float,stbir__max_uint8_as_float,stbir__max_uint8_as_float,stbir__max_uint8_as_float };- static const stbir__simdf8 STBIR_max_uint16_as_float8 = { stbir__max_uint16_as_float,stbir__max_uint16_as_float,stbir__max_uint16_as_float,stbir__max_uint16_as_float, stbir__max_uint16_as_float,stbir__max_uint16_as_float,stbir__max_uint16_as_float,stbir__max_uint16_as_float };-#else- #define stbir__simdfX stbir__simdf- #define stbir__simdiX stbir__simdi- #define stbir__simdfX_load stbir__simdf_load- #define stbir__simdiX_load stbir__simdi_load- #define stbir__simdfX_mult stbir__simdf_mult- #define stbir__simdfX_add_mem stbir__simdf_add_mem- #define stbir__simdfX_madd_mem stbir__simdf_madd_mem- #define stbir__simdfX_store stbir__simdf_store- #define stbir__simdiX_store stbir__simdi_store- #define stbir__simdf_frepX stbir__simdf_frep4- #define stbir__simdfX_madd stbir__simdf_madd- #define stbir__simdfX_min stbir__simdf_min- #define stbir__simdfX_max stbir__simdf_max- #define stbir__simdfX_aaa1 stbir__simdf_aaa1- #define stbir__simdfX_1aaa stbir__simdf_1aaa- #define stbir__simdfX_a1a1 stbir__simdf_a1a1- #define stbir__simdfX_1a1a stbir__simdf_1a1a- #define stbir__simdfX_convert_float_to_i32 stbir__simdf_convert_float_to_i32- #define stbir__simdfX_pack_to_words stbir__simdf_pack_to_8words- #define stbir__simdfX_zero stbir__simdf_zero- #define STBIR_onesX STBIR__CONSTF(STBIR_ones)- #define STBIR_simd_point5X STBIR__CONSTF(STBIR_simd_point5)- #define STBIR_max_uint8_as_floatX STBIR__CONSTF(STBIR_max_uint8_as_float)- #define STBIR_max_uint16_as_floatX STBIR__CONSTF(STBIR_max_uint16_as_float)- #define stbir__simdfX_float_count 4- #define stbir__if_simdf8_cast_to_simdf4( val ) ( val )- #define stbir__simdfX_0123to1230 stbir__simdf_0123to1230- #define stbir__simdfX_0123to2103 stbir__simdf_0123to2103-#endif---#if defined(STBIR_NEON) && !defined(_M_ARM)-- #if defined( _MSC_VER ) && !defined(__clang__)- typedef __int16 stbir__FP16;- #else- typedef float16_t stbir__FP16;- #endif--#else // no NEON, or 32-bit ARM for MSVC-- typedef union stbir__FP16- {- unsigned short u;- } stbir__FP16;--#endif--#if !defined(STBIR_NEON) && !defined(STBIR_FP16C) || defined(STBIR_NEON) && defined(_M_ARM)-- // Fabian's half float routines, see: https://gist.github.com/rygorous/2156668-- static stbir__inline float stbir__half_to_float( stbir__FP16 h )- {- static const stbir__FP32 magic = { (254 - 15) << 23 };- static const stbir__FP32 was_infnan = { (127 + 16) << 23 };- stbir__FP32 o;-- o.u = (h.u & 0x7fff) << 13; // exponent/mantissa bits- o.f *= magic.f; // exponent adjust- if (o.f >= was_infnan.f) // make sure Inf/NaN survive- o.u |= 255 << 23;- o.u |= (h.u & 0x8000) << 16; // sign bit- return o.f;- }-- static stbir__inline stbir__FP16 stbir__float_to_half(float val)- {- stbir__FP32 f32infty = { 255 << 23 };- stbir__FP32 f16max = { (127 + 16) << 23 };- stbir__FP32 denorm_magic = { ((127 - 15) + (23 - 10) + 1) << 23 };- unsigned int sign_mask = 0x80000000u;- stbir__FP16 o = { 0 };- stbir__FP32 f;- unsigned int sign; -- f.f = val;- sign = f.u & sign_mask;- f.u ^= sign;-- if (f.u >= f16max.u) // result is Inf or NaN (all exponent bits set)- o.u = (f.u > f32infty.u) ? 0x7e00 : 0x7c00; // NaN->qNaN and Inf->Inf- else // (De)normalized number or zero- {- if (f.u < (113 << 23)) // resulting FP16 is subnormal or zero- {- // use a magic value to align our 10 mantissa bits at the bottom of- // the float. as long as FP addition is round-to-nearest-even this- // just works.- f.f += denorm_magic.f;- // and one integer subtract of the bias later, we have our final float!- o.u = (unsigned short) ( f.u - denorm_magic.u );- }- else- {- unsigned int mant_odd = (f.u >> 13) & 1; // resulting mantissa is odd- // update exponent, rounding bias part 1- f.u = f.u + ((15u - 127) << 23) + 0xfff;- // rounding bias part 2- f.u += mant_odd;- // take the bits!- o.u = (unsigned short) ( f.u >> 13 );- }- }-- o.u |= sign >> 16;- return o;- }--#endif---#if defined(STBIR_FP16C)-- #include <immintrin.h>-- static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input)- {- _mm256_storeu_ps( (float*)output, _mm256_cvtph_ps( _mm_loadu_si128( (__m128i const* )input ) ) );- }-- static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input)- {- _mm_storeu_si128( (__m128i*)output, _mm256_cvtps_ph( _mm256_loadu_ps( input ), 0 ) );- }-- static stbir__inline float stbir__half_to_float( stbir__FP16 h )- {- return _mm_cvtss_f32( _mm_cvtph_ps( _mm_cvtsi32_si128( (int)h.u ) ) );- }-- static stbir__inline stbir__FP16 stbir__float_to_half( float f )- {- stbir__FP16 h;- h.u = (unsigned short) _mm_cvtsi128_si32( _mm_cvtps_ph( _mm_set_ss( f ), 0 ) );- return h;- }--#elif defined(STBIR_SSE2)-- // Fabian's half float routines, see: https://gist.github.com/rygorous/2156668- stbir__inline static void stbir__half_to_float_SIMD(float * output, void const * input)- {- static const STBIR__SIMDI_CONST(mask_nosign, 0x7fff);- static const STBIR__SIMDI_CONST(smallest_normal, 0x0400);- static const STBIR__SIMDI_CONST(infinity, 0x7c00);- static const STBIR__SIMDI_CONST(expadjust_normal, (127 - 15) << 23);- static const STBIR__SIMDI_CONST(magic_denorm, 113 << 23);-- __m128i i = _mm_loadu_si128 ( (__m128i const*)(input) );- __m128i h = _mm_unpacklo_epi16 ( i, _mm_setzero_si128() );- __m128i mnosign = STBIR__CONSTI(mask_nosign);- __m128i eadjust = STBIR__CONSTI(expadjust_normal);- __m128i smallest = STBIR__CONSTI(smallest_normal);- __m128i infty = STBIR__CONSTI(infinity);- __m128i expmant = _mm_and_si128(mnosign, h);- __m128i justsign = _mm_xor_si128(h, expmant);- __m128i b_notinfnan = _mm_cmpgt_epi32(infty, expmant);- __m128i b_isdenorm = _mm_cmpgt_epi32(smallest, expmant);- __m128i shifted = _mm_slli_epi32(expmant, 13);- __m128i adj_infnan = _mm_andnot_si128(b_notinfnan, eadjust);- __m128i adjusted = _mm_add_epi32(eadjust, shifted);- __m128i den1 = _mm_add_epi32(shifted, STBIR__CONSTI(magic_denorm));- __m128i adjusted2 = _mm_add_epi32(adjusted, adj_infnan);- __m128 den2 = _mm_sub_ps(_mm_castsi128_ps(den1), *(const __m128 *)&magic_denorm);- __m128 adjusted3 = _mm_and_ps(den2, _mm_castsi128_ps(b_isdenorm));- __m128 adjusted4 = _mm_andnot_ps(_mm_castsi128_ps(b_isdenorm), _mm_castsi128_ps(adjusted2));- __m128 adjusted5 = _mm_or_ps(adjusted3, adjusted4);- __m128i sign = _mm_slli_epi32(justsign, 16);- __m128 final = _mm_or_ps(adjusted5, _mm_castsi128_ps(sign));- stbir__simdf_store( output + 0, final );-- h = _mm_unpackhi_epi16 ( i, _mm_setzero_si128() );- expmant = _mm_and_si128(mnosign, h);- justsign = _mm_xor_si128(h, expmant);- b_notinfnan = _mm_cmpgt_epi32(infty, expmant);- b_isdenorm = _mm_cmpgt_epi32(smallest, expmant);- shifted = _mm_slli_epi32(expmant, 13);- adj_infnan = _mm_andnot_si128(b_notinfnan, eadjust);- adjusted = _mm_add_epi32(eadjust, shifted);- den1 = _mm_add_epi32(shifted, STBIR__CONSTI(magic_denorm));- adjusted2 = _mm_add_epi32(adjusted, adj_infnan);- den2 = _mm_sub_ps(_mm_castsi128_ps(den1), *(const __m128 *)&magic_denorm);- adjusted3 = _mm_and_ps(den2, _mm_castsi128_ps(b_isdenorm));- adjusted4 = _mm_andnot_ps(_mm_castsi128_ps(b_isdenorm), _mm_castsi128_ps(adjusted2));- adjusted5 = _mm_or_ps(adjusted3, adjusted4);- sign = _mm_slli_epi32(justsign, 16);- final = _mm_or_ps(adjusted5, _mm_castsi128_ps(sign));- stbir__simdf_store( output + 4, final );-- // ~38 SSE2 ops for 8 values- }-- // Fabian's round-to-nearest-even float to half- // ~48 SSE2 ops for 8 output- stbir__inline static void stbir__float_to_half_SIMD(void * output, float const * input)- {- static const STBIR__SIMDI_CONST(mask_sign, 0x80000000u);- static const STBIR__SIMDI_CONST(c_f16max, (127 + 16) << 23); // all FP32 values >=this round to +inf- static const STBIR__SIMDI_CONST(c_nanbit, 0x200);- static const STBIR__SIMDI_CONST(c_infty_as_fp16, 0x7c00);- static const STBIR__SIMDI_CONST(c_min_normal, (127 - 14) << 23); // smallest FP32 that yields a normalized FP16- static const STBIR__SIMDI_CONST(c_subnorm_magic, ((127 - 15) + (23 - 10) + 1) << 23);- static const STBIR__SIMDI_CONST(c_normal_bias, 0xfff - ((127 - 15) << 23)); // adjust exponent and add mantissa rounding-- __m128 f = _mm_loadu_ps(input);- __m128 msign = _mm_castsi128_ps(STBIR__CONSTI(mask_sign));- __m128 justsign = _mm_and_ps(msign, f);- __m128 absf = _mm_xor_ps(f, justsign);- __m128i absf_int = _mm_castps_si128(absf); // the cast is "free" (extra bypass latency, but no thruput hit)- __m128i f16max = STBIR__CONSTI(c_f16max);- __m128 b_isnan = _mm_cmpunord_ps(absf, absf); // is this a NaN?- __m128i b_isregular = _mm_cmpgt_epi32(f16max, absf_int); // (sub)normalized or special?- __m128i nanbit = _mm_and_si128(_mm_castps_si128(b_isnan), STBIR__CONSTI(c_nanbit));- __m128i inf_or_nan = _mm_or_si128(nanbit, STBIR__CONSTI(c_infty_as_fp16)); // output for specials-- __m128i min_normal = STBIR__CONSTI(c_min_normal);- __m128i b_issub = _mm_cmpgt_epi32(min_normal, absf_int);-- // "result is subnormal" path- __m128 subnorm1 = _mm_add_ps(absf, _mm_castsi128_ps(STBIR__CONSTI(c_subnorm_magic))); // magic value to round output mantissa- __m128i subnorm2 = _mm_sub_epi32(_mm_castps_si128(subnorm1), STBIR__CONSTI(c_subnorm_magic)); // subtract out bias-- // "result is normal" path- __m128i mantoddbit = _mm_slli_epi32(absf_int, 31 - 13); // shift bit 13 (mantissa LSB) to sign- __m128i mantodd = _mm_srai_epi32(mantoddbit, 31); // -1 if FP16 mantissa odd, else 0-- __m128i round1 = _mm_add_epi32(absf_int, STBIR__CONSTI(c_normal_bias));- __m128i round2 = _mm_sub_epi32(round1, mantodd); // if mantissa LSB odd, bias towards rounding up (RTNE)- __m128i normal = _mm_srli_epi32(round2, 13); // rounded result-- // combine the two non-specials- __m128i nonspecial = _mm_or_si128(_mm_and_si128(subnorm2, b_issub), _mm_andnot_si128(b_issub, normal));-- // merge in specials as well- __m128i joined = _mm_or_si128(_mm_and_si128(nonspecial, b_isregular), _mm_andnot_si128(b_isregular, inf_or_nan));-- __m128i sign_shift = _mm_srai_epi32(_mm_castps_si128(justsign), 16);- __m128i final2, final= _mm_or_si128(joined, sign_shift);-- f = _mm_loadu_ps(input+4);- justsign = _mm_and_ps(msign, f);- absf = _mm_xor_ps(f, justsign);- absf_int = _mm_castps_si128(absf); // the cast is "free" (extra bypass latency, but no thruput hit)- b_isnan = _mm_cmpunord_ps(absf, absf); // is this a NaN?- b_isregular = _mm_cmpgt_epi32(f16max, absf_int); // (sub)normalized or special?- nanbit = _mm_and_si128(_mm_castps_si128(b_isnan), c_nanbit);- inf_or_nan = _mm_or_si128(nanbit, STBIR__CONSTI(c_infty_as_fp16)); // output for specials-- b_issub = _mm_cmpgt_epi32(min_normal, absf_int);-- // "result is subnormal" path- subnorm1 = _mm_add_ps(absf, _mm_castsi128_ps(STBIR__CONSTI(c_subnorm_magic))); // magic value to round output mantissa- subnorm2 = _mm_sub_epi32(_mm_castps_si128(subnorm1), STBIR__CONSTI(c_subnorm_magic)); // subtract out bias-- // "result is normal" path- mantoddbit = _mm_slli_epi32(absf_int, 31 - 13); // shift bit 13 (mantissa LSB) to sign- mantodd = _mm_srai_epi32(mantoddbit, 31); // -1 if FP16 mantissa odd, else 0-- round1 = _mm_add_epi32(absf_int, STBIR__CONSTI(c_normal_bias));- round2 = _mm_sub_epi32(round1, mantodd); // if mantissa LSB odd, bias towards rounding up (RTNE)- normal = _mm_srli_epi32(round2, 13); // rounded result-- // combine the two non-specials- nonspecial = _mm_or_si128(_mm_and_si128(subnorm2, b_issub), _mm_andnot_si128(b_issub, normal));-- // merge in specials as well- joined = _mm_or_si128(_mm_and_si128(nonspecial, b_isregular), _mm_andnot_si128(b_isregular, inf_or_nan));-- sign_shift = _mm_srai_epi32(_mm_castps_si128(justsign), 16);- final2 = _mm_or_si128(joined, sign_shift);- final = _mm_packs_epi32(final, final2);- 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)- {- float16x4_t in0 = vld1_f16(input + 0);- float16x4_t in1 = vld1_f16(input + 4);- vst1q_f32(output + 0, vcvt_f32_f16(in0));- vst1q_f32(output + 4, vcvt_f32_f16(in1));- }-- static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input)- {- float16x4_t out0 = vcvt_f16_f32(vld1q_f32(input + 0));- float16x4_t out1 = vcvt_f16_f32(vld1q_f32(input + 4));- vst1_f16(output+0, out0);- vst1_f16(output+4, out1);- }-- static stbir__inline float stbir__half_to_float( stbir__FP16 h )- {- return vgetq_lane_f32(vcvt_f32_f16(vld1_dup_f16(&h)), 0);- }-- static stbir__inline stbir__FP16 stbir__float_to_half( float f )- {- return vget_lane_f16(vcvt_f16_f32(vdupq_n_f32(f)), 0).n16_u16[0];- }--#elif defined(STBIR_NEON) // 64-bit ARM-- static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input)- {- float16x8_t in = vld1q_f16(input);- vst1q_f32(output + 0, vcvt_f32_f16(vget_low_f16(in)));- vst1q_f32(output + 4, vcvt_f32_f16(vget_high_f16(in)));- }-- static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input)- {- float16x4_t out0 = vcvt_f16_f32(vld1q_f32(input + 0));- float16x4_t out1 = vcvt_f16_f32(vld1q_f32(input + 4));- vst1q_f16(output, vcombine_f16(out0, out1));- }-- static stbir__inline float stbir__half_to_float( stbir__FP16 h )- {- return vgetq_lane_f32(vcvt_f32_f16(vdup_n_f16(h)), 0);- }-- static stbir__inline stbir__FP16 stbir__float_to_half( float f )- {- return vget_lane_f16(vcvt_f16_f32(vdupq_n_f32(f)), 0);- }--#endif---#ifdef STBIR_SIMD--#define stbir__simdf_0123to3333( out, reg ) (out) = stbir__simdf_swiz( reg, 3,3,3,3 )-#define stbir__simdf_0123to2222( out, reg ) (out) = stbir__simdf_swiz( reg, 2,2,2,2 )-#define stbir__simdf_0123to1111( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,1,1 )-#define stbir__simdf_0123to0000( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,0,0 )-#define stbir__simdf_0123to0003( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,0,3 )-#define stbir__simdf_0123to0001( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,0,1 )-#define stbir__simdf_0123to1122( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,2,2 )-#define stbir__simdf_0123to2333( out, reg ) (out) = stbir__simdf_swiz( reg, 2,3,3,3 )-#define stbir__simdf_0123to0023( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,2,3 )-#define stbir__simdf_0123to1230( out, reg ) (out) = stbir__simdf_swiz( reg, 1,2,3,0 )-#define stbir__simdf_0123to2103( out, reg ) (out) = stbir__simdf_swiz( reg, 2,1,0,3 )-#define stbir__simdf_0123to3210( out, reg ) (out) = stbir__simdf_swiz( reg, 3,2,1,0 )-#define stbir__simdf_0123to2301( out, reg ) (out) = stbir__simdf_swiz( reg, 2,3,0,1 )-#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 ) --typedef union stbir__simdi_u32-{- stbir_uint32 m128i_u32[4];- int m128i_i32[4];- stbir__simdi m128i_i128;-} stbir__simdi_u32;--static const int STBIR_mask[9] = { 0,0,0,-1,-1,-1,0,0,0 };--static const STBIR__SIMDF_CONST(STBIR_max_uint8_as_float, stbir__max_uint8_as_float);-static const STBIR__SIMDF_CONST(STBIR_max_uint16_as_float, stbir__max_uint16_as_float);-static const STBIR__SIMDF_CONST(STBIR_max_uint8_as_float_inverted, stbir__max_uint8_as_float_inverted);-static const STBIR__SIMDF_CONST(STBIR_max_uint16_as_float_inverted, stbir__max_uint16_as_float_inverted);--static const STBIR__SIMDF_CONST(STBIR_simd_point5, 0.5f);-static const STBIR__SIMDF_CONST(STBIR_ones, 1.0f);-static const STBIR__SIMDI_CONST(STBIR_almost_zero, (127 - 13) << 23);-static const STBIR__SIMDI_CONST(STBIR_almost_one, 0x3f7fffff);-static const STBIR__SIMDI_CONST(STBIR_mastissa_mask, 0xff);-static const STBIR__SIMDI_CONST(STBIR_topscale, 0x02000000);--// Basically, in simd mode, we unroll the proper amount, and we don't want-// the non-simd remnant loops to be unroll because they only run a few times-// 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)--#ifdef STBIR_MEMCPY-#undef STBIR_MEMCPY-#define STBIR_MEMCPY stbir_simd_memcpy-#endif--// 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 ) -{- char STBIR_SIMD_STREAMOUT_PTR (*) d = (char*) dest;- char STBIR_SIMD_STREAMOUT_PTR( * ) d_end = ((char*) dest) + bytes;- ptrdiff_t ofs_to_src = (char*)src - (char*)dest;-- // check overlaps- STBIR_ASSERT( ( ( d >= ( (char*)src) + bytes ) ) || ( ( d + bytes ) <= (char*)src ) );-- if ( bytes < (16*stbir__simdfX_float_count) )- {- if ( bytes < 16 )- {- if ( bytes ) - {- do- {- STBIR_SIMD_NO_UNROLL(d);- d[ 0 ] = d[ ofs_to_src ];- ++d;- } while ( d < d_end );- }- }- else- {- stbir__simdf x;- // 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 );-- for(;;)- {- STBIR_SIMD_NO_UNROLL(d);-- if ( d > ( d_end - 16 ) )- {- if ( d == d_end )- return;- d = d_end - 16;- }-- stbir__simdf_load( x, ( d + ofs_to_src ) );- stbir__simdf_store( d, x );- d += 16;- }- }- }- else- {- stbir__simdfX x0,x1,x2,x3;-- // do one unaligned to get us aligned for the stream out below- stbir__simdfX_load( x0, ( d + ofs_to_src ) + 0*stbir__simdfX_float_count );- stbir__simdfX_load( x1, ( d + ofs_to_src ) + 4*stbir__simdfX_float_count );- stbir__simdfX_load( x2, ( d + ofs_to_src ) + 8*stbir__simdfX_float_count );- stbir__simdfX_load( x3, ( d + ofs_to_src ) + 12*stbir__simdfX_float_count );- stbir__simdfX_store( d + 0*stbir__simdfX_float_count, x0 );- 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) );-- for(;;)- {- STBIR_SIMD_NO_UNROLL(d);- - if ( d > ( d_end - (16*stbir__simdfX_float_count) ) )- {- if ( d == d_end )- return;- d = d_end - (16*stbir__simdfX_float_count);- }-- stbir__simdfX_load( x0, ( d + ofs_to_src ) + 0*stbir__simdfX_float_count );- stbir__simdfX_load( x1, ( d + ofs_to_src ) + 4*stbir__simdfX_float_count );- stbir__simdfX_load( x2, ( d + ofs_to_src ) + 8*stbir__simdfX_float_count );- stbir__simdfX_load( x3, ( d + ofs_to_src ) + 12*stbir__simdfX_float_count );- stbir__simdfX_store( d + 0*stbir__simdfX_float_count, x0 );- 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 += (16*stbir__simdfX_float_count);- }- }-}--// 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 ) -{- char STBIR_SIMD_STREAMOUT_PTR (*) sd = (char*) src;- char STBIR_SIMD_STREAMOUT_PTR( * ) s_end = ((char*) src) + bytes;- ptrdiff_t ofs_to_dest = (char*)dest - (char*)src;-- if ( ofs_to_dest >= 16 ) // is the overlap more than 16 away?- {- char STBIR_SIMD_STREAMOUT_PTR( * ) s_end16 = ((char*) src) + (bytes&~15);- do- {- stbir__simdf x;- STBIR_SIMD_NO_UNROLL(sd);- stbir__simdf_load( x, sd );- stbir__simdf_store( ( sd + ofs_to_dest ), x );- sd += 16;- } while ( sd < s_end16 );-- if ( sd == s_end )- return;- }-- do- {- STBIR_SIMD_NO_UNROLL(sd);- *(int*)( sd + ofs_to_dest ) = *(int*) sd; - sd += 4;- } while ( sd < s_end );-}--#else // no SSE2--// 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) --#endif // SSE2---#ifdef STBIR_PROFILE--#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-- STBIRDEF stbir_uint64 __rdtsc();- #define STBIR_PROFILE_FUNC() __rdtsc()--#else // non msvc-- static stbir__inline stbir_uint64 STBIR_PROFILE_FUNC() - {- stbir_uint32 lo, hi;- asm volatile ("rdtsc" : "=a" (lo), "=d" (hi) );- return ( ( (stbir_uint64) hi ) << 32 ) | ( (stbir_uint64) lo );- }--#endif // msvc--#elif defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(__ARM_NEON__) --#if defined( _MSC_VER ) && !defined(__clang__)-- #define STBIR_PROFILE_FUNC() _ReadStatusReg(ARM64_CNTVCT)--#else-- static stbir__inline stbir_uint64 STBIR_PROFILE_FUNC()- {- stbir_uint64 tsc;- asm volatile("mrs %0, cntvct_el0" : "=r" (tsc));- return tsc;- }--#endif--#else // x64, arm--#error Unknown platform for profiling.--#endif //x64 and ---#define STBIR_ONLY_PROFILE_GET_SPLIT_INFO ,stbir__per_split_info * split_info-#define STBIR_ONLY_PROFILE_SET_SPLIT_INFO ,split_info--#define STBIR_ONLY_PROFILE_BUILD_GET_INFO ,stbir__info * profile_info-#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_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;i<STBIR__ARRAY_SIZE(info->profile.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;i<STBIR__ARRAY_SIZE((info)->profile.array);i++) (info)[extra].profile.array[i]=0; } }--// for thread data-#define STBIR_PROFILE_START( wh ) STBIR_PROFILE_START_ll( split_info, wh )-#define STBIR_PROFILE_END( wh ) STBIR_PROFILE_END_ll( split_info, wh )-#define STBIR_PROFILE_FIRST_START( wh ) STBIR_PROFILE_FIRST_START_ll( split_info, wh )-#define STBIR_PROFILE_CLEAR_EXTRAS() STBIR_PROFILE_CLEAR_EXTRAS_ll( split_info, split_count )--// for build data-#define STBIR_PROFILE_BUILD_START( wh ) STBIR_PROFILE_START_ll( profile_info, wh )-#define STBIR_PROFILE_BUILD_END( wh ) STBIR_PROFILE_END_ll( profile_info, wh )-#define STBIR_PROFILE_BUILD_FIRST_START( wh ) STBIR_PROFILE_FIRST_START_ll( profile_info, wh )-#define STBIR_PROFILE_BUILD_CLEAR( info ) { int i; for(i=0;i<STBIR__ARRAY_SIZE(info->profile.array);i++) info->profile.array[i]=0; }--#else // no profile--#define STBIR_ONLY_PROFILE_GET_SPLIT_INFO-#define STBIR_ONLY_PROFILE_SET_SPLIT_INFO--#define STBIR_ONLY_PROFILE_BUILD_GET_INFO-#define STBIR_ONLY_PROFILE_BUILD_SET_INFO--#define STBIR_PROFILE_START( wh )-#define STBIR_PROFILE_END( wh )-#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_FIRST_START( wh )-#define STBIR_PROFILE_BUILD_CLEAR( info )--#endif // stbir_profile--#ifndef STBIR_CEILF-#include <math.h>-#if _MSC_VER <= 1200 // support VC6 for Sean-#define STBIR_CEILF(x) ((float)ceil((float)(x)))-#define STBIR_FLOORF(x) ((float)floor((float)(x)))-#else-#define STBIR_CEILF(x) ceilf(x)-#define STBIR_FLOORF(x) floorf(x)-#endif-#endif--#ifndef STBIR_MEMCPY-// For memcpy-#include <string.h>-#define STBIR_MEMCPY( dest, src, len ) memcpy( dest, src, len )-#endif--#ifndef STBIR_SIMD--// 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 ) -{- char STBIR_SIMD_STREAMOUT_PTR (*) sd = (char*) src;- char STBIR_SIMD_STREAMOUT_PTR( * ) s_end = ((char*) src) + bytes;- ptrdiff_t ofs_to_dest = (char*)dest - (char*)src;-- if ( ofs_to_dest >= 8 ) // is the overlap more than 8 away?- {- char STBIR_SIMD_STREAMOUT_PTR( * ) s_end8 = ((char*) src) + (bytes&~7);- do- {- STBIR_NO_UNROLL(sd);- *(stbir_uint64*)( sd + ofs_to_dest ) = *(stbir_uint64*) sd; - sd += 8;- } while ( sd < s_end8 );-- if ( sd == s_end )- return;- }-- do- {- STBIR_NO_UNROLL(sd);- *(int*)( sd + ofs_to_dest ) = *(int*) sd; - sd += 4;- } while ( sd < s_end );-}--#endif--static float stbir__filter_trapezoid(float x, float scale, void * user_data)-{- float halfscale = scale / 2;- float t = 0.5f + halfscale;- STBIR_ASSERT(scale <= 1);- STBIR__UNUSED(user_data);-- if ( x < 0.0f ) x = -x;-- if (x >= t)- return 0.0f;- else- {- float r = 0.5f - halfscale;- if (x <= r)- return 1.0f;- else- return (t - x) / scale;- }-}--static float stbir__support_trapezoid(float scale, void * user_data)-{- STBIR__UNUSED(user_data);- return 0.5f + scale / 2.0f;-}--static float stbir__filter_triangle(float x, float s, void * user_data)-{- STBIR__UNUSED(s);- STBIR__UNUSED(user_data);-- if ( x < 0.0f ) x = -x;-- if (x <= 1.0f)- return 1.0f - x;- else- return 0.0f;-}--static float stbir__filter_point(float x, float s, void * user_data)-{- STBIR__UNUSED(x);- STBIR__UNUSED(s);- STBIR__UNUSED(user_data);-- return 1.0f;-}--static float stbir__filter_cubic(float x, float s, void * user_data)-{- STBIR__UNUSED(s);- STBIR__UNUSED(user_data);-- if ( x < 0.0f ) x = -x;-- if (x < 1.0f)- return (4.0f + x*x*(3.0f*x - 6.0f))/6.0f;- else if (x < 2.0f)- return (8.0f + x*(-12.0f + x*(6.0f - x)))/6.0f;-- return (0.0f);-}--static float stbir__filter_catmullrom(float x, float s, void * user_data)-{- STBIR__UNUSED(s);- STBIR__UNUSED(user_data);-- if ( x < 0.0f ) x = -x;-- if (x < 1.0f)- return 1.0f - x*x*(2.5f - 1.5f*x);- else if (x < 2.0f)- return 2.0f - x*(4.0f + x*(0.5f*x - 2.5f));-- return (0.0f);-}--static float stbir__filter_mitchell(float x, float s, void * user_data)-{- STBIR__UNUSED(s);- STBIR__UNUSED(user_data);-- if ( x < 0.0f ) x = -x;-- if (x < 1.0f)- return (16.0f + x*x*(21.0f * x - 36.0f))/18.0f;- else if (x < 2.0f)- return (32.0f + x*(-60.0f + x*(36.0f - 7.0f*x)))/18.0f;-- 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);- STBIR__UNUSED(user_data);- return 0.5f;-}--static float stbir__support_one(float s, void * user_data)-{- STBIR__UNUSED(s);- STBIR__UNUSED(user_data);- return 1;-}--static float stbir__support_two(float s, void * user_data) -{- STBIR__UNUSED(s);- STBIR__UNUSED(user_data);- return 2;-}--// This is the maximum number of input samples that can affect an output sample-// with the given filter from the output pixel's perspective-static int stbir__get_filter_pixel_width(stbir__support_callback * support, float scale, void * user_data)-{- STBIR_ASSERT(support != 0);-- if ( scale >= ( 1.0f-stbir__small_float ) ) // upscale- return (int)STBIR_CEILF(support(1.0f/scale,user_data) * 2.0f);- else- return (int)STBIR_CEILF(support(scale,user_data) * 2.0f / scale);-}--// 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)-{- float scale = samp->scale_info.scale;- stbir__support_callback * support = samp->filter_support;-- switch( is_gather )- {- case 1:- return (int)STBIR_CEILF(support(1.0f / scale, user_data) * 2.0f);- case 2:- return (int)STBIR_CEILF(support(scale, user_data) * 2.0f / scale);- case 0:- return (int)STBIR_CEILF(support(scale, user_data) * 2.0f);- default:- STBIR_ASSERT( (is_gather >= 0 ) && (is_gather <= 2 ) );- return 0;- }-}--static int stbir__get_contributors(stbir__sampler * samp, int is_gather) -{- if (is_gather)- return samp->scale_info.output_sub_size;- else- return (samp->scale_info.input_full_size + samp->filter_pixel_margin * 2);-}--static int stbir__edge_zero_full( int n, int max )-{- STBIR__UNUSED(n);- STBIR__UNUSED(max);- return 0; // NOTREACHED-}--static int stbir__edge_clamp_full( int n, int max )-{- if (n < 0)- return 0;-- if (n >= max)- return max - 1;-- return n; // NOTREACHED-}--static int stbir__edge_reflect_full( int n, int max )-{- if (n < 0)- {- if (n > -max) - return -n;- else- return max - 1;- }-- if (n >= max)- {- int max2 = max * 2;- if (n >= max2)- return 0;- else- return max2 - n - 1;- }-- return n; // NOTREACHED-}--static int stbir__edge_wrap_full( int n, int max )-{- if (n >= 0)- return (n % max);- else- {- int m = (-n) % max;-- if (m != 0)- m = max - m;-- return (m);- }-}--typedef int stbir__edge_wrap_func( int n, int max );-static stbir__edge_wrap_func * stbir__edge_wrap_slow[] =-{- stbir__edge_clamp_full, // STBIR_EDGE_CLAMP- stbir__edge_reflect_full, // STBIR_EDGE_REFLECT- stbir__edge_wrap_full, // STBIR_EDGE_WRAP- stbir__edge_zero_full, // STBIR_EDGE_ZERO-};--stbir__inline static int stbir__edge_wrap(stbir_edge edge, int n, int max)-{- // avoid per-pixel switch- if (n >= 0 && n < max)- return n;- return stbir__edge_wrap_slow[edge]( n, max );-}--#define STBIR__MERGE_RUNS_PIXEL_THRESHOLD 16--// get information on the extents of a sampler-static void stbir__get_extents( stbir__sampler * samp, stbir__extents * scanline_extents )-{- int j, stop;- int left_margin, right_margin;- int min_n = 0x7fffffff, max_n = -0x7fffffff;- int min_left = 0x7fffffff, max_left = -0x7fffffff;- int min_right = 0x7fffffff, max_right = -0x7fffffff;- stbir_edge edge = samp->edge;- stbir__contributors* contributors = samp->contributors;- int output_sub_size = samp->scale_info.output_sub_size;- int input_full_size = samp->scale_info.input_full_size;- int filter_pixel_margin = samp->filter_pixel_margin;-- STBIR_ASSERT( samp->is_gather );-- stop = output_sub_size;- for (j = 0; j < stop; j++ )- {- STBIR_ASSERT( contributors[j].n1 >= contributors[j].n0 );- if ( contributors[j].n0 < min_n )- {- min_n = contributors[j].n0;- stop = j + filter_pixel_margin; // if we find a new min, only scan another filter width- if ( stop > output_sub_size ) stop = output_sub_size;- }- }-- stop = 0;- for (j = output_sub_size - 1; j >= stop; j-- )- {- STBIR_ASSERT( contributors[j].n1 >= contributors[j].n0 );- if ( contributors[j].n1 > max_n )- {- max_n = contributors[j].n1;- stop = j - filter_pixel_margin; // if we find a new max, only scan another filter width- if (stop<0) stop = 0;- }- }-- STBIR_ASSERT( scanline_extents->conservative.n0 <= min_n );- STBIR_ASSERT( scanline_extents->conservative.n1 >= max_n );-- // now calculate how much into the margins we really read- left_margin = 0;- if ( min_n < 0 )- {- left_margin = -min_n;- min_n = 0;- }- - right_margin = 0;- if ( max_n >= input_full_size )- {- right_margin = max_n - input_full_size + 1;- max_n = input_full_size - 1;- }-- // index 1 is margin pixel extents (how many pixels we hang over the edge)- scanline_extents->edge_sizes[0] = left_margin;- scanline_extents->edge_sizes[1] = right_margin;-- // index 2 is pixels read from the input- scanline_extents->spans[0].n0 = min_n;- scanline_extents->spans[0].n1 = max_n;- scanline_extents->spans[0].pixel_offset_for_input = min_n;-- // default to no other input range- scanline_extents->spans[1].n0 = 0;- scanline_extents->spans[1].n1 = -1;- scanline_extents->spans[1].pixel_offset_for_input = 0;-- // 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++ )- {- int p = stbir__edge_wrap( edge, j, input_full_size );- if ( p < min_left )- min_left = p;- if ( p > max_left )- max_left = p;- }-- for( j = input_full_size ; j < (input_full_size + right_margin) ; j++ )- {- int p = stbir__edge_wrap( edge, j, input_full_size );- if ( p < min_right )- min_right = p;- if ( p > max_right )- max_right = p;- }-- // merge the left margin pixel region if it connects within 4 pixels of main pixel region- if ( min_left != 0x7fffffff )- {- if ( ( ( min_left <= min_n ) && ( ( max_left + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= min_n ) ) ||- ( ( min_n <= min_left ) && ( ( max_n + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= max_left ) ) )- {- scanline_extents->spans[0].n0 = min_n = stbir__min( min_n, min_left );- scanline_extents->spans[0].n1 = max_n = stbir__max( max_n, max_left );- scanline_extents->spans[0].pixel_offset_for_input = min_n;- left_margin = 0;- }- }-- // merge the right margin pixel region if it connects within 4 pixels of main pixel region- if ( min_right != 0x7fffffff )- {- if ( ( ( min_right <= min_n ) && ( ( max_right + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= min_n ) ) ||- ( ( min_n <= min_right ) && ( ( max_n + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= max_right ) ) )- {- scanline_extents->spans[0].n0 = min_n = stbir__min( min_n, min_right );- scanline_extents->spans[0].n1 = max_n = stbir__max( max_n, max_right );- scanline_extents->spans[0].pixel_offset_for_input = min_n;- right_margin = 0;- }- }-- STBIR_ASSERT( scanline_extents->conservative.n0 <= min_n );- STBIR_ASSERT( scanline_extents->conservative.n1 >= max_n );-- // you get two ranges when you have the WRAP edge mode and you are doing just the a piece of the resize- // so you need to get a second run of pixels from the opposite side of the scanline (which you- // wouldn't need except for WRAP)--- // if we can't merge the min_left range, add it as a second range- if ( ( left_margin ) && ( min_left != 0x7fffffff ) )- {- stbir__span * newspan = scanline_extents->spans + 1;- STBIR_ASSERT( right_margin == 0 );- if ( min_left < scanline_extents->spans[0].n0 )- {- scanline_extents->spans[1].pixel_offset_for_input = scanline_extents->spans[0].n0;- scanline_extents->spans[1].n0 = scanline_extents->spans[0].n0;- scanline_extents->spans[1].n1 = scanline_extents->spans[0].n1;- --newspan;- }- newspan->pixel_offset_for_input = min_left;- newspan->n0 = -left_margin;- newspan->n1 = ( max_left - min_left ) - left_margin;- scanline_extents->edge_sizes[0] = 0; // don't need to copy the left margin, since we are directly decoding into the margin- return;- }-- // if we can't merge the min_left range, add it as a second range- if ( ( right_margin ) && ( min_right != 0x7fffffff ) )- {- stbir__span * newspan = scanline_extents->spans + 1;- if ( min_right < scanline_extents->spans[0].n0 )- {- scanline_extents->spans[1].pixel_offset_for_input = scanline_extents->spans[0].n0;- scanline_extents->spans[1].n0 = scanline_extents->spans[0].n0;- scanline_extents->spans[1].n1 = scanline_extents->spans[0].n1;- --newspan;- }- newspan->pixel_offset_for_input = min_right;- newspan->n0 = scanline_extents->spans[1].n1 + 1;- newspan->n1 = scanline_extents->spans[1].n1 + 1 + ( max_right - min_right );- scanline_extents->edge_sizes[1] = 0; // don't need to copy the right margin, since we are directly decoding into the margin- return;- }-}--static void stbir__calculate_in_pixel_range( int * first_pixel, int * last_pixel, float out_pixel_center, float out_filter_radius, float inv_scale, float out_shift, int input_size, stbir_edge edge )-{- int first, last;- 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; -- 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 ( last >= (input_size*2))- last = (input_size*2) - 1;- }- - *first_pixel = first;- *last_pixel = last;-}--static void stbir__calculate_coefficients_for_gather_upsample( float out_filter_radius, stbir__kernel_callback * kernel, stbir__scale_info * scale_info, int num_contributors, stbir__contributors* contributors, float* coefficient_group, int coefficient_width, stbir_edge edge, void * user_data )-{- int n, end;- float inv_scale = scale_info->inv_scale;- float out_shift = scale_info->pixel_shift;- int input_size = scale_info->input_full_size;- int numerator = scale_info->scale_numerator;- int polyphase = ( ( scale_info->scale_is_rational ) && ( numerator < num_contributors ) );-- // Looping through out pixels- end = num_contributors; if ( polyphase ) end = numerator;- for (n = 0; n < end; n++)- {- 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; -- 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;- for (i = 0; i <= in_last_pixel - in_first_pixel; i++)- {- float in_pixel_center = (float)(i + in_first_pixel) + 0.5f;- float coeff = kernel(in_center_of_out - in_pixel_center, inv_scale, user_data);-- // kill denormals- 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--;- continue;- }- coeff = 0; // make sure is fully zero (should keep denormals away)- }- 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;-- STBIR_ASSERT(contributors->n1 >= contributors->n0);-- ++contributors;- coefficient_group += coefficient_width;- }-}--static void stbir__insert_coeff( stbir__contributors * contribs, float * coeffs, int new_pixel, float new_coeff )-{- if ( new_pixel <= contribs->n1 ) // before the end- {- if ( new_pixel < contribs->n0 ) // before the front?- {- int j, o = contribs->n0 - new_pixel;- for ( j = contribs->n1 - contribs->n0 ; j <= 0 ; j-- )- coeffs[ j + o ] = coeffs[ j ];- for ( j = 1 ; j < o ; j-- )- coeffs[ j ] = coeffs[ 0 ];- coeffs[ 0 ] = new_coeff;- contribs->n0 = new_pixel;- }- else- {- coeffs[ new_pixel - contribs->n0 ] += new_coeff;- }- }- else- {- int j, e = new_pixel - contribs->n0;- for( j = ( contribs->n1 - contribs->n0 ) + 1 ; j < e ; j++ ) // clear in-betweens coeffs if there are any- coeffs[j] = 0;-- coeffs[ e ] = new_coeff;- contribs->n1 = new_pixel;- }-}--static void stbir__calculate_out_pixel_range( int * first_pixel, int * last_pixel, float in_pixel_center, float in_pixels_radius, float scale, float out_shift, int out_size )-{- float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius;- float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius;- float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale - out_shift;- float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale - out_shift;- int out_first_pixel = (int)(STBIR_FLOORF(out_pixel_influence_lowerbound + 0.5f));- int out_last_pixel = (int)(STBIR_FLOORF(out_pixel_influence_upperbound - 0.5f));-- if ( out_first_pixel < 0 )- out_first_pixel = 0;- if ( out_last_pixel >= out_size )- out_last_pixel = out_size - 1;- *first_pixel = out_first_pixel;- *last_pixel = out_last_pixel;-}--static void stbir__calculate_coefficients_for_gather_downsample( int start, int end, float in_pixels_radius, stbir__kernel_callback * kernel, stbir__scale_info * scale_info, int coefficient_width, int num_contributors, stbir__contributors * contributors, float * coefficient_group, void * user_data )-{- int in_pixel;- int i;- int first_out_inited = -1;- float scale = scale_info->scale;- float out_shift = scale_info->pixel_shift;- int out_size = scale_info->output_sub_size;- int numerator = scale_info->scale_numerator;- int polyphase = ( ( scale_info->scale_is_rational ) && ( numerator < out_size ) );-- STBIR__UNUSED(num_contributors);-- // Loop through the input pixels- for (in_pixel = start; in_pixel < end; in_pixel++)- {- float in_pixel_center = (float)in_pixel + 0.5f;- float out_center_of_in = in_pixel_center * scale - out_shift;- int out_first_pixel, out_last_pixel;-- stbir__calculate_out_pixel_range( &out_first_pixel, &out_last_pixel, in_pixel_center, in_pixels_radius, scale, out_shift, out_size );-- if ( out_first_pixel > out_last_pixel )- continue;-- // clamp or exit if we are using polyphase filtering, and the limit is up- if ( polyphase )- {- // when polyphase, you only have to do coeffs up to the numerator count- if ( out_first_pixel == numerator )- break;-- // don't do any extra work, clamp last pixel at numerator too- if ( out_last_pixel >= numerator )- out_last_pixel = numerator - 1;- }-- for (i = 0; i <= out_last_pixel - out_first_pixel; i++)- {- float out_pixel_center = (float)(i + out_first_pixel) + 0.5f;- float x = out_pixel_center - out_center_of_in;- float coeff = kernel(x, scale, user_data) * scale;-- // kill the coeff if it's too small (avoid denormals)- if ( ( ( coeff < stbir__small_float ) && ( coeff > -stbir__small_float ) ) )- coeff = 0.0f;-- {- int out = i + out_first_pixel;- float * coeffs = coefficient_group + out * coefficient_width;- stbir__contributors * contribs = contributors + out;-- // is this the first time this output pixel has been seen? Init it.- if ( out > first_out_inited ) - {- STBIR_ASSERT( out == ( first_out_inited + 1 ) ); // ensure we have only advanced one at time- first_out_inited = out;- contribs->n0 = in_pixel;- contribs->n1 = in_pixel;- coeffs[0] = coeff;- }- else - {- // insert on end (always in order)- if ( coeffs[0] == 0.0f ) // if the first coefficent is zero, then zap it for this coeffs- {- STBIR_ASSERT( ( in_pixel - contribs->n0 ) == 1 ); // ensure that when we zap, we're at the 2nd pos- contribs->n0 = in_pixel;- }- contribs->n1 = in_pixel;- STBIR_ASSERT( ( in_pixel - contribs->n0 ) < coefficient_width );- coeffs[in_pixel - contribs->n0] = coeff;- }- }- }- }-}--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 n, end;- int lowest = 0x7fffffff;- int highest = -0x7fffffff;- int widest = -1;- int numerator = scale_info->scale_numerator;- int denominator = scale_info->scale_denominator;- int polyphase = ( ( scale_info->scale_is_rational ) && ( numerator < num_contributors ) );- float * coeffs;- stbir__contributors * contribs;-- // weight all the coeffs for each sample- coeffs = coefficient_group;- contribs = contributors;- end = num_contributors; if ( polyphase ) end = numerator;- for (n = 0; n < end; n++)- {- int i;- float 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];- STBIR_ASSERT( ( coeffs[i] >= -2.0f ) && ( coeffs[i] <= 2.0f ) ); // check for wonky weights- }-- // rescale- if ( ( total_filter < stbir__small_float ) && ( total_filter > -stbir__small_float ) )- {- // all coeffs are extremely small, just zero it- contribs->n1 = contribs->n0;- coeffs[0] = 0.0f;- }- else- {- // 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;- // scale them all- for (i = 0; i <= e; i++)- coeffs[i] *= filter_scale;- }- }- ++contribs;- coeffs += coefficient_width;- }-- // if we have a rational for the scale, we can exploit the polyphaseness to not calculate- // most of the coefficients, so we copy them here- if ( polyphase )- {- stbir__contributors * prev_contribs = contributors;- stbir__contributors * cur_contribs = contributors + numerator;-- for( n = numerator ; n < num_contributors ; n++ )- {- cur_contribs->n0 = prev_contribs->n0 + denominator;- cur_contribs->n1 = prev_contribs->n1 + denominator;- ++cur_contribs;- ++prev_contribs;- }- stbir_overlapping_memcpy( coefficient_group + numerator * coefficient_width, coefficient_group, ( num_contributors - numerator ) * coefficient_width * sizeof( coeffs[ 0 ] ) );- }-- coeffs = coefficient_group;- contribs = contributors;- for (n = 0; n < num_contributors; n++)- {- int i;-- // in zero edge mode, just remove out of bounds contribs completely (since their weights are accounted for now)- if ( edge == STBIR_EDGE_ZERO )- {- // shrink the right side if necessary- if ( contribs->n1 > input_last_n1 )- contribs->n1 = input_last_n1;-- // shrink the left side- if ( contribs->n0 < 0 )- {- int j, left, skips = 0;-- skips = -contribs->n0;- contribs->n0 = 0;-- // now move down the weights- left = contribs->n1 - contribs->n0 + 1;- if ( left > 0 )- {- for( j = 0 ; j < left ; j++ )- coeffs[ j ] = coeffs[ j + skips ];- }- }- }- 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; - for( i = input_size; i <= endi; i++ )- stbir__insert_coeff( contribs, coeffs, stbir__edge_wrap_slow[edge]( i, input_size ), coeffs[i-start] );- }-- // now check left hand edge- if ( contribs->n0 < 0 )- {- 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-- ) - 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; - 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 );- }- }-- if ( contribs->n0 <= contribs->n1 )- {- int diff = contribs->n1 - contribs->n0 + 1;- while ( diff && ( coeffs[ diff-1 ] == 0.0f ) )- --diff;- contribs->n1 = contribs->n0 + diff - 1;-- if ( contribs->n0 <= contribs->n1 )- {- if ( contribs->n0 < lowest )- lowest = contribs->n0;- if ( contribs->n1 > highest )- highest = contribs->n1;- if ( diff > widest )- widest = diff;- }-- // re-zero out unused coefficients (if any)- for( i = diff ; i < coefficient_width ; i++ )- coeffs[i] = 0.0f;- }-- ++contribs;- coeffs += coefficient_width;- }- filter_info->lowest = lowest;- filter_info->highest = highest;- 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 )-{- #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]; }- #ifdef STBIR_SIMD- #define STBIR_MOVE_4( dest, src ) { stbir__simdf t; STBIR_NO_UNROLL(dest); stbir__simdf_load( t, src ); stbir__simdf_store( dest, t ); }- #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- if ( coefficient_width != widest )- {- float * pc = coefficents;- float * coeffs = coefficents;- float * pc_end = coefficents + num_contributors * widest;- switch( widest )- {- case 1:- do {- STBIR_MOVE_1( pc, coeffs );- ++pc;- coeffs += coefficient_width;- } while ( pc < pc_end );- break;- case 2:- do {- STBIR_MOVE_2( pc, coeffs );- pc += 2;- coeffs += coefficient_width;- } while ( pc < pc_end );- break;- case 3:- do {- STBIR_MOVE_2( pc, coeffs );- STBIR_MOVE_1( pc+2, coeffs+2 );- pc += 3;- coeffs += coefficient_width;- } while ( pc < pc_end );- break;- case 4:- do {- STBIR_MOVE_4( pc, coeffs );- pc += 4;- coeffs += coefficient_width;- } while ( pc < pc_end );- break;- case 5:- do {- STBIR_MOVE_4( pc, coeffs );- STBIR_MOVE_1( pc+4, coeffs+4 );- pc += 5;- coeffs += coefficient_width;- } while ( pc < pc_end );- break;- case 6:- do {- STBIR_MOVE_4( pc, coeffs );- STBIR_MOVE_2( pc+4, coeffs+4 );- pc += 6;- coeffs += coefficient_width;- } while ( pc < pc_end );- break;- case 7:- do {- STBIR_MOVE_4( pc, coeffs );- STBIR_MOVE_2( pc+4, coeffs+4 );- STBIR_MOVE_1( pc+6, coeffs+6 );- pc += 7;- coeffs += coefficient_width;- } while ( pc < pc_end );- break;- case 8:- do {- STBIR_MOVE_4( pc, coeffs );- STBIR_MOVE_4( pc+4, coeffs+4 );- pc += 8;- coeffs += coefficient_width;- } while ( pc < pc_end );- break;- case 9:- do {- STBIR_MOVE_4( pc, coeffs );- STBIR_MOVE_4( pc+4, coeffs+4 );- STBIR_MOVE_1( pc+8, coeffs+8 );- pc += 9;- coeffs += coefficient_width;- } while ( pc < pc_end );- break;- case 10:- do {- STBIR_MOVE_4( pc, coeffs );- STBIR_MOVE_4( pc+4, coeffs+4 );- STBIR_MOVE_2( pc+8, coeffs+8 );- pc += 10;- coeffs += coefficient_width;- } while ( pc < pc_end );- break;- case 11:- do {- STBIR_MOVE_4( pc, coeffs );- STBIR_MOVE_4( pc+4, coeffs+4 );- STBIR_MOVE_2( pc+8, coeffs+8 );- STBIR_MOVE_1( pc+10, coeffs+10 );- pc += 11;- coeffs += coefficient_width;- } while ( pc < pc_end );- break;- case 12:- do {- STBIR_MOVE_4( pc, coeffs );- STBIR_MOVE_4( pc+4, coeffs+4 );- STBIR_MOVE_4( pc+8, coeffs+8 );- pc += 12;- coeffs += coefficient_width;- } while ( pc < pc_end );- break;- default:- do {- float * copy_end = pc + widest - 4;- float * c = coeffs;- do {- STBIR_NO_UNROLL( pc );- STBIR_MOVE_4( pc, c );- pc += 4;- c += 4;- } while ( pc <= copy_end );- copy_end += 4;- while ( pc < copy_end )- {- STBIR_MOVE_1( pc, c );- ++pc; ++c;- }- coeffs += coefficient_width;- } while ( pc < pc_end );- break;- }- }-- // some horizontal routines read one float off the end (which is then masked off), so put in a sentinal so we don't read an snan or denormal- 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 - // 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).- {- stbir__contributors * contribs = contributors + num_contributors - 1;- 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 ) )- {- // might we clip??- if ( ( contribs->n0 + widest ) > row_width )- {- 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 )- {- int mod;-- // 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; -- // 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 )- {- int new_n0 = row_width - 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 ) );-- // move the coeffs over- while( num )- {- *to_co-- = *from_co--;- --num;- }- // zero new positions- while ( to_co >= coeffs )- *to_co-- = 0;- // set new start point- contribs->n0 = new_n0;- if ( widest > 12 )- {- int mod;-- // 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; -- // the n_coeff loops do a minimum amount of coeffs, so factor that in!- if ( stop_range < ( 8 + mod ) ) stop_range = 8 + mod;- }- }- }- --contribs;- coeffs -= widest;- }- }-- return widest;- #undef STBIR_MOVE_1- #undef STBIR_MOVE_2- #undef STBIR_MOVE_4-}--static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * other_axis_for_pivot, void * user_data STBIR_ONLY_PROFILE_BUILD_GET_INFO )-{- int n;- float scale = samp->scale_info.scale;- stbir__kernel_callback * kernel = samp->filter_kernel;- stbir__support_callback * support = samp->filter_support;- float inv_scale = samp->scale_info.inv_scale;- 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; - int gather_coefficient_width = samp->coefficient_width;-- switch ( samp->is_gather )- {- case 1: // gather upsample- {- float out_pixels_radius = support(inv_scale,user_data) * scale;-- stbir__calculate_coefficients_for_gather_upsample( out_pixels_radius, kernel, &samp->scale_info, gather_num_contributors, gather_contributors, gather_coeffs, gather_coefficient_width, samp->edge, user_data );-- STBIR_PROFILE_BUILD_START( cleanup );- stbir__cleanup_gathered_coefficients( samp->edge, &samp->extent_info, &samp->scale_info, gather_num_contributors, gather_contributors, gather_coeffs, gather_coefficient_width );- STBIR_PROFILE_BUILD_END( cleanup );- }- break;-- case 0: // scatter downsample (only on vertical)- 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, - // if so, then we don't have to generate them, we can just pivot from the horizontal.- if ( other_axis_for_pivot )- {- gather_contributors = other_axis_for_pivot->contributors;- gather_coeffs = other_axis_for_pivot->coefficients;- gather_coefficient_width = other_axis_for_pivot->coefficient_width;- gather_num_contributors = other_axis_for_pivot->num_contributors;- samp->extent_info.lowest = other_axis_for_pivot->extent_info.lowest;- samp->extent_info.highest = other_axis_for_pivot->extent_info.highest;- samp->extent_info.widest = other_axis_for_pivot->extent_info.widest;- goto jump_right_to_pivot;- }-- gather_contributors = samp->gather_prescatter_contributors;- gather_coeffs = samp->gather_prescatter_coefficients;- gather_coefficient_width = samp->gather_prescatter_coefficient_width;- gather_num_contributors = samp->gather_prescatter_num_contributors;- }-- stbir__calculate_coefficients_for_gather_downsample( -filter_pixel_margin, input_end, in_pixels_radius, kernel, &samp->scale_info, gather_coefficient_width, gather_num_contributors, gather_contributors, gather_coeffs, user_data );-- STBIR_PROFILE_BUILD_START( cleanup );- stbir__cleanup_gathered_coefficients( samp->edge, &samp->extent_info, &samp->scale_info, gather_num_contributors, gather_contributors, gather_coeffs, gather_coefficient_width );- STBIR_PROFILE_BUILD_END( cleanup );-- if ( !samp->is_gather )- {- // if this is a scatter (vertical only), then we need to pivot the coeffs- stbir__contributors * scatter_contributors;- int highest_set;-- jump_right_to_pivot:-- STBIR_PROFILE_BUILD_START( pivot );-- highest_set = (-filter_pixel_margin) - 1;- for (n = 0; n < gather_num_contributors; n++)- {- int k;- int gn0 = gather_contributors->n0, gn1 = gather_contributors->n1;- int scatter_coefficient_width = samp->coefficient_width;- 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 ) )- {- {- // 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;- }- else- {- stbir__insert_coeff( scatter_contributors, scatter_coeffs, n, gc );- }- ++scatter_contributors;- scatter_coeffs += scatter_coefficient_width;- }-- ++gather_contributors;- gather_coeffs += gather_coefficient_width;- }-- // now clear any unset contribs- {- stbir__contributors * clear_contributors = samp->contributors + ( highest_set + filter_pixel_margin + 1);- stbir__contributors * end_contributors = samp->contributors + samp->num_contributors;- while ( clear_contributors < end_contributors )- {- clear_contributors->n0 = 0;- clear_contributors->n1 = -1;- ++clear_contributors;- }- }-- STBIR_PROFILE_BUILD_END( pivot );- }- }- break;- }-}---//========================================================================================================-// scanline decoders and encoders--#define stbir__coder_min_num 1-#define STB_IMAGE_RESIZE_DO_CODERS-#include STBIR__HEADER_FILENAME--#define stbir__decode_suffix BGRA-#define stbir__decode_swizzle-#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_order1 1-#define stbir__encode_order2 0-#define stbir__encode_order3 3-#define stbir__coder_min_num 4-#define STB_IMAGE_RESIZE_DO_CODERS-#include STBIR__HEADER_FILENAME--#define stbir__decode_suffix ARGB-#define stbir__decode_swizzle-#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_order1 0-#define stbir__encode_order2 1-#define stbir__encode_order3 2-#define stbir__coder_min_num 4-#define STB_IMAGE_RESIZE_DO_CODERS-#include STBIR__HEADER_FILENAME--#define stbir__decode_suffix ABGR-#define stbir__decode_swizzle-#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_order1 2-#define stbir__encode_order2 1-#define stbir__encode_order3 0-#define stbir__coder_min_num 4-#define STB_IMAGE_RESIZE_DO_CODERS-#include STBIR__HEADER_FILENAME--#define stbir__decode_suffix AR-#define stbir__decode_swizzle-#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_order2 3-#define stbir__encode_order3 2-#define stbir__coder_min_num 2-#define STB_IMAGE_RESIZE_DO_CODERS-#include STBIR__HEADER_FILENAME---// fancy alpha means we expand to keep both premultipied and non-premultiplied color channels-static void stbir__fancy_alpha_weight_4ch( float * out_buffer, int width_times_channels )-{- float STBIR_STREAMOUT_PTR(*) out = out_buffer;- float const * end_decode = out_buffer + ( width_times_channels / 4 ) * 7; // decode buffer aligned to end of out_buffer- float STBIR_STREAMOUT_PTR(*) decode = (float*)end_decode - width_times_channels;-- // fancy alpha is stored internally as R G B A Rpm Gpm Bpm-- #ifdef STBIR_SIMD- - #ifdef STBIR_SIMD8- decode += 16;- while ( decode <= end_decode )- {- stbir__simdf8 d0,d1,a0,a1,p0,p1;- STBIR_NO_UNROLL(decode);- stbir__simdf8_load( d0, decode-16 );- stbir__simdf8_load( d1, decode-16+8 );- stbir__simdf8_0123to33333333( a0, d0 );- stbir__simdf8_0123to33333333( a1, d1 );- stbir__simdf8_mult( p0, a0, d0 );- stbir__simdf8_mult( p1, a1, d1 );- stbir__simdf8_bot4s( a0, d0, p0 );- stbir__simdf8_bot4s( a1, d1, p1 );- stbir__simdf8_top4s( d0, d0, p0 );- stbir__simdf8_top4s( d1, d1, p1 );- stbir__simdf8_store ( out, a0 );- stbir__simdf8_store ( out+7, d0 );- stbir__simdf8_store ( out+14, a1 );- stbir__simdf8_store ( out+21, d1 );- decode += 16;- out += 28;- }- decode -= 16;- #else - decode += 8;- while ( decode <= end_decode )- {- stbir__simdf d0,a0,d1,a1,p0,p1;- STBIR_NO_UNROLL(decode);- stbir__simdf_load( d0, decode-8 );- stbir__simdf_load( d1, decode-8+4 );- stbir__simdf_0123to3333( a0, d0 );- stbir__simdf_0123to3333( a1, d1 );- stbir__simdf_mult( p0, a0, d0 );- stbir__simdf_mult( p1, a1, d1 );- stbir__simdf_store ( out, d0 );- stbir__simdf_store ( out+4, p0 );- stbir__simdf_store ( out+7, d1 );- stbir__simdf_store ( out+7+4, p1 );- decode += 8;- out += 14;- }- decode -= 8;- #endif-- // might be one last odd pixel- #ifdef STBIR_SIMD8- while ( decode < end_decode )- #else- if ( decode < end_decode )- #endif- {- stbir__simdf d,a,p;- stbir__simdf_load( d, decode );- stbir__simdf_0123to3333( a, d );- stbir__simdf_mult( p, a, d );- stbir__simdf_store ( out, d );- stbir__simdf_store ( out+4, p );- decode += 4;- out += 7;- }-- #else-- while( decode < end_decode )- {- float r = decode[0], g = decode[1], b = decode[2], alpha = decode[3];- out[0] = r;- out[1] = g;- out[2] = b;- out[3] = alpha;- out[4] = r * alpha;- out[5] = g * alpha;- out[6] = b * alpha;- out += 7;- decode += 4;- }-- #endif-}--static void stbir__fancy_alpha_weight_2ch( float * out_buffer, int width_times_channels )-{- float STBIR_STREAMOUT_PTR(*) out = out_buffer;- float const * end_decode = out_buffer + ( width_times_channels / 2 ) * 3;- float STBIR_STREAMOUT_PTR(*) decode = (float*)end_decode - width_times_channels;-- // for fancy alpha, turns into: [X A Xpm][X A Xpm],etc-- #ifdef STBIR_SIMD-- decode += 8;- if ( decode <= end_decode )- {- do {- #ifdef STBIR_SIMD8- stbir__simdf8 d0,a0,p0;- STBIR_NO_UNROLL(decode);- stbir__simdf8_load( d0, decode-8 );- 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 ) );- #else- stbir__simdf d0,a0,d1,a1,p0,p1;- STBIR_NO_UNROLL(decode);- stbir__simdf_load( d0, decode-8 );- stbir__simdf_load( d1, decode-8+4 );- stbir__simdf_0123to1133( p0, d0 );- stbir__simdf_0123to1133( p1, d1 );- stbir__simdf_0123to0022( a0, d0 );- stbir__simdf_0123to0022( a1, d1 );- stbir__simdf_mult( p0, p0, a0 );- stbir__simdf_mult( p1, p1, a1 );-- stbir__simdf_store2( out, d0 );- stbir__simdf_store( out+2, p0 );- stbir__simdf_store2h( out+3, d0 );-- stbir__simdf_store2( out+6, d1 );- stbir__simdf_store( out+8, p1 );- stbir__simdf_store2h( out+9, d1 );- #endif- decode += 8;- out += 12;- } while ( decode <= end_decode );- }- decode -= 8;- #endif-- while( decode < end_decode )- {- float x = decode[0], y = decode[1];- STBIR_SIMD_NO_UNROLL(decode);- out[0] = x;- out[1] = y;- out[2] = x * y;- out += 3;- decode += 2;- }-}--static void stbir__fancy_alpha_unweight_4ch( float * encode_buffer, int width_times_channels )-{- float STBIR_SIMD_STREAMOUT_PTR(*) encode = encode_buffer;- float STBIR_SIMD_STREAMOUT_PTR(*) input = encode_buffer;- float const * end_output = encode_buffer + width_times_channels;-- // fancy RGBA is stored internally as R G B A Rpm Gpm Bpm-- do {- float alpha = input[3];-#ifdef STBIR_SIMD- stbir__simdf i,ia;- STBIR_SIMD_NO_UNROLL(encode);- if ( alpha < stbir__small_float )- {- stbir__simdf_load( i, input );- stbir__simdf_store( encode, i );- }- else- {- stbir__simdf_load1frep4( ia, 1.0f / alpha );- stbir__simdf_load( i, input+4 );- stbir__simdf_mult( i, i, ia );- stbir__simdf_store( encode, i );- encode[3] = alpha;- }-#else- if ( alpha < stbir__small_float )- {- encode[0] = input[0];- encode[1] = input[1];- encode[2] = input[2];- }- else- {- float ialpha = 1.0f / alpha;- encode[0] = input[4] * ialpha;- encode[1] = input[5] * ialpha;- encode[2] = input[6] * ialpha;- }- encode[3] = alpha;-#endif-- input += 7;- encode += 4;- } while ( encode < end_output );-}--// format: [X A Xpm][X A Xpm] etc-static void stbir__fancy_alpha_unweight_2ch( float * encode_buffer, int width_times_channels )-{- float STBIR_SIMD_STREAMOUT_PTR(*) encode = encode_buffer;- float STBIR_SIMD_STREAMOUT_PTR(*) input = encode_buffer;- float const * end_output = encode_buffer + width_times_channels;-- do {- float alpha = input[1];- encode[0] = input[0];- if ( alpha >= stbir__small_float )- encode[0] = input[2] / alpha;- encode[1] = alpha;-- input += 3;- encode += 2;- } while ( encode < end_output );-}--static void stbir__simple_alpha_weight_4ch( float * decode_buffer, int width_times_channels )-{- float STBIR_STREAMOUT_PTR(*) decode = decode_buffer;- float const * end_decode = decode_buffer + width_times_channels;-- #ifdef STBIR_SIMD- {- decode += 2 * stbir__simdfX_float_count;- while ( decode <= end_decode )- {- stbir__simdfX d0,a0,d1,a1;- STBIR_NO_UNROLL(decode);- stbir__simdfX_load( d0, decode-2*stbir__simdfX_float_count );- stbir__simdfX_load( d1, decode-2*stbir__simdfX_float_count+stbir__simdfX_float_count );- stbir__simdfX_aaa1( a0, d0, STBIR_onesX );- stbir__simdfX_aaa1( a1, d1, STBIR_onesX );- stbir__simdfX_mult( d0, d0, a0 );- stbir__simdfX_mult( d1, d1, a1 );- stbir__simdfX_store ( decode-2*stbir__simdfX_float_count, d0 );- stbir__simdfX_store ( decode-2*stbir__simdfX_float_count+stbir__simdfX_float_count, d1 );- decode += 2 * stbir__simdfX_float_count;- }- decode -= 2 * stbir__simdfX_float_count;-- // few last pixels remnants- #ifdef STBIR_SIMD8- while ( decode < end_decode )- #else- if ( decode < end_decode )- #endif- {- stbir__simdf d,a;- stbir__simdf_load( d, decode );- stbir__simdf_aaa1( a, d, STBIR__CONSTF(STBIR_ones) );- stbir__simdf_mult( d, d, a );- stbir__simdf_store ( decode, d );- decode += 4;- }- }-- #else-- while( decode < end_decode )- {- float alpha = decode[3];- decode[0] *= alpha;- decode[1] *= alpha;- decode[2] *= alpha;- decode += 4;- }-- #endif-}--static void stbir__simple_alpha_weight_2ch( float * decode_buffer, int width_times_channels )-{- float STBIR_STREAMOUT_PTR(*) decode = decode_buffer;- float const * end_decode = decode_buffer + width_times_channels;-- #ifdef STBIR_SIMD- decode += 2 * stbir__simdfX_float_count;- while ( decode <= end_decode )- {- stbir__simdfX d0,a0,d1,a1;- STBIR_NO_UNROLL(decode);- stbir__simdfX_load( d0, decode-2*stbir__simdfX_float_count );- stbir__simdfX_load( d1, decode-2*stbir__simdfX_float_count+stbir__simdfX_float_count );- stbir__simdfX_a1a1( a0, d0, STBIR_onesX );- stbir__simdfX_a1a1( a1, d1, STBIR_onesX );- stbir__simdfX_mult( d0, d0, a0 );- stbir__simdfX_mult( d1, d1, a1 );- stbir__simdfX_store ( decode-2*stbir__simdfX_float_count, d0 );- stbir__simdfX_store ( decode-2*stbir__simdfX_float_count+stbir__simdfX_float_count, d1 );- decode += 2 * stbir__simdfX_float_count;- }- decode -= 2 * stbir__simdfX_float_count;- #endif-- while( decode < end_decode )- {- float alpha = decode[1];- STBIR_SIMD_NO_UNROLL(decode);- decode[0] *= alpha;- decode += 2;- }-}--static void stbir__simple_alpha_unweight_4ch( float * encode_buffer, int width_times_channels )-{- float STBIR_SIMD_STREAMOUT_PTR(*) encode = encode_buffer;- float const * end_output = encode_buffer + width_times_channels;-- do {- float alpha = encode[3];--#ifdef STBIR_SIMD- stbir__simdf i,ia;- STBIR_SIMD_NO_UNROLL(encode);- if ( alpha >= stbir__small_float )- {- stbir__simdf_load1frep4( ia, 1.0f / alpha );- stbir__simdf_load( i, encode );- stbir__simdf_mult( i, i, ia );- stbir__simdf_store( encode, i );- encode[3] = alpha;- }-#else- if ( alpha >= stbir__small_float )- {- float ialpha = 1.0f / alpha;- encode[0] *= ialpha;- encode[1] *= ialpha;- encode[2] *= ialpha;- }-#endif- encode += 4;- } while ( encode < end_output );-}--static void stbir__simple_alpha_unweight_2ch( float * encode_buffer, int width_times_channels )-{- float STBIR_SIMD_STREAMOUT_PTR(*) encode = encode_buffer;- float const * end_output = encode_buffer + width_times_channels;-- do {- float alpha = encode[1];- if ( alpha >= stbir__small_float )- encode[0] /= alpha;- encode += 2;- } while ( encode < end_output );-}---// only used in RGB->BGR or BGR->RGB-static void stbir__simple_flip_3ch( float * decode_buffer, int width_times_channels )-{- float STBIR_STREAMOUT_PTR(*) decode = decode_buffer;- float const * end_decode = decode_buffer + width_times_channels;-- decode += 12;- while( decode <= end_decode )- {- float t0,t1,t2,t3;- STBIR_NO_UNROLL(decode);- t0 = decode[0]; t1 = decode[3]; t2 = decode[6]; t3 = decode[9];- decode[0] = decode[2]; decode[3] = decode[5]; decode[6] = decode[8]; decode[9] = decode[11];- decode[2] = t0; decode[5] = t1; decode[8] = t2; decode[11] = t3;- decode += 12;- }- decode -= 12;-- while( decode < end_decode )- {- float t = decode[0];- STBIR_NO_UNROLL(decode);- decode[0] = decode[2];- decode[2] = t;- decode += 3;- }-}----static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float * output_buffer STBIR_ONLY_PROFILE_GET_SPLIT_INFO )-{- int channels = stbir_info->channels;- int effective_channels = stbir_info->effective_channels;- int input_sample_in_bytes = stbir__type_size[stbir_info->input_type] * channels;- 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;- 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 - {- float * decode_buffer;- void const * input_data;- float * end_decode;- int width_times_channels;- int width;-- if ( spans->n1 < spans->n0 ) - break;-- width = spans->n1 + 1 - spans->n0;- decode_buffer = full_decode_buffer + spans->n0 * effective_channels;- end_decode = full_decode_buffer + ( spans->n1 + 1 ) * effective_channels;- width_times_channels = width * channels;-- // read directly out of input plane by default- input_data = ( (char*)input_plane_data ) + spans->pixel_offset_for_input * input_sample_in_bytes;-- // if we have an input callback, call it to get the input data- if ( stbir_info->in_pixels_cb )- {- // 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 channels<effective_channels, we are right justified in the buffer)- stbir_info->decode_pixels( (float*)end_decode - width_times_channels, width_times_channels, input_data );- STBIR_PROFILE_END( decode );-- if (stbir_info->alpha_weight)- {- STBIR_PROFILE_START( alpha );- stbir_info->alpha_weight( decode_buffer, width_times_channels );- STBIR_PROFILE_END( alpha );- }-- ++spans;- } while ( spans <= ( &stbir_info->scanline_extents.spans[1] ) );-- // handle the edge_wrap filter (all other types are handled back out at the calculate_filter stage)- // basically the idea here is that if we have the whole scanline in memory, we don't redecode the- // wrapped edge pixels, and instead just memcpy them from the scanline into the edge positions- if ( ( edge_horizontal == STBIR_EDGE_WRAP ) && ( stbir_info->scanline_extents.edge_sizes[0] | stbir_info->scanline_extents.edge_sizes[1] ) )- {- // 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-- for( e = 0; e < 2 ; e++ )- {- // do each margin- int margin = stbir_info->scanline_extents.edge_sizes[e];- if ( margin )- {- int x = start_x[e];- float * marg = full_decode_buffer + x * effective_channels;- float const * src = full_decode_buffer + stbir__edge_wrap(edge_horizontal, x, input_full_size) * effective_channels;- STBIR_MEMCPY( marg, src, margin * effective_channels * sizeof(float) );- }- }- }-}---//=================-// Do 1 channel horizontal routines--#ifdef STBIR_SIMD--#define stbir__1_coeff_only() \- stbir__simdf tot,c; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load1( c, hc ); \- stbir__simdf_mult1_mem( tot, c, decode ); --#define stbir__2_coeff_only() \- stbir__simdf tot,c,d; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load2z( c, hc ); \- stbir__simdf_load2( d, decode ); \- stbir__simdf_mult( tot, c, d ); \- stbir__simdf_0123to1230( c, tot ); \- stbir__simdf_add1( tot, tot, c ); --#define stbir__3_coeff_only() \- stbir__simdf tot,c,t; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load( c, hc ); \- stbir__simdf_mult_mem( tot, c, decode ); \- stbir__simdf_0123to1230( c, tot ); \- stbir__simdf_0123to2301( t, tot ); \- stbir__simdf_add1( tot, tot, c ); \- stbir__simdf_add1( tot, tot, t ); --#define stbir__store_output_tiny() \- stbir__simdf_store1( output, tot ); \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 1;--#define stbir__4_coeff_start() \- stbir__simdf tot,c; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load( c, hc ); \- stbir__simdf_mult_mem( tot, c, decode ); \--#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) ); --#define stbir__1_coeff_remnant( ofs ) \- { stbir__simdf d; \- stbir__simdf_load1z( c, hc + (ofs) ); \- stbir__simdf_load1( d, decode + (ofs) ); \- stbir__simdf_madd( tot, tot, d, c ); }--#define stbir__2_coeff_remnant( ofs ) \- { stbir__simdf d; \- stbir__simdf_load2z( c, hc+(ofs) ); \- stbir__simdf_load2( d, decode+(ofs) ); \- stbir__simdf_madd( tot, tot, d, c ); } --#define stbir__3_coeff_setup() \- stbir__simdf mask; \- stbir__simdf_load( mask, STBIR_mask + 3 );--#define stbir__3_coeff_remnant( ofs ) \- stbir__simdf_load( c, hc+(ofs) ); \- stbir__simdf_and( c, c, mask ); \- stbir__simdf_madd_mem( tot, tot, c, decode+(ofs) );--#define stbir__store_output() \- stbir__simdf_0123to2301( c, tot ); \- stbir__simdf_add( tot, tot, c ); \- stbir__simdf_0123to1230( c, tot ); \- stbir__simdf_add1( tot, tot, c ); \- stbir__simdf_store1( output, tot ); \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 1;--#else--#define stbir__1_coeff_only() \- float tot; \- tot = decode[0]*hc[0]; --#define stbir__2_coeff_only() \- float tot; \- tot = decode[0] * hc[0]; \- 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]; --#define stbir__store_output_tiny() \- output[0] = tot; \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 1;--#define stbir__4_coeff_start() \- float tot0,tot1,tot2,tot3; \- tot0 = decode[0] * hc[0]; \- tot1 = decode[1] * hc[1]; \- tot2 = decode[2] * hc[2]; \- 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)]; --#define stbir__1_coeff_remnant( ofs ) \- tot0 += decode[0+(ofs)] * hc[0+(ofs)]; --#define stbir__2_coeff_remnant( ofs ) \- tot0 += decode[0+(ofs)] * hc[0+(ofs)]; \- tot1 += decode[1+(ofs)] * hc[1+(ofs)]; \--#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)]; --#define stbir__store_output() \- output[0] = (tot0+tot2)+(tot1+tot3); \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 1;--#endif --#define STBIR__horizontal_channels 1-#define STB_IMAGE_RESIZE_DO_HORIZONTALS-#include STBIR__HEADER_FILENAME---//=================-// Do 2 channel horizontal routines--#ifdef STBIR_SIMD--#define stbir__1_coeff_only() \- stbir__simdf tot,c,d; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load1z( c, hc ); \- stbir__simdf_0123to0011( c, c ); \- stbir__simdf_load2( d, decode ); \- 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 ); --#define stbir__3_coeff_only() \- stbir__simdf tot,c,cs,d; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load( cs, hc ); \- stbir__simdf_0123to0011( c, cs ); \- 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 ); --#define stbir__store_output_tiny() \- stbir__simdf_0123to2301( c, tot ); \- stbir__simdf_add( tot, tot, c ); \- stbir__simdf_store2( output, tot ); \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 2;--#ifdef STBIR_SIMD8--#define stbir__4_coeff_start() \- stbir__simdf8 tot0,c,cs; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf8_load4b( cs, hc ); \- stbir__simdf8_0123to00112233( c, cs ); \- stbir__simdf8_mult_mem( tot0, c, decode );--#define stbir__4_coeff_continue_from_4( ofs ) \- 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 ); --#define stbir__1_coeff_remnant( ofs ) \- { stbir__simdf t; \- stbir__simdf_load1z( t, hc + (ofs) ); \- stbir__simdf_0123to0011( t, t ); \- stbir__simdf_mult_mem( t, t, decode+(ofs)*2 ); \- stbir__simdf8_add4( tot0, tot0, t ); }--#define stbir__2_coeff_remnant( ofs ) \- { stbir__simdf t; \- stbir__simdf_load2( t, hc + (ofs) ); \- stbir__simdf_0123to0011( t, t ); \- stbir__simdf_mult_mem( t, t, decode+(ofs)*2 ); \- stbir__simdf8_add4( tot0, tot0, t ); }--#define stbir__3_coeff_remnant( ofs ) \- { stbir__simdf8 d; \- 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 ); } --#define stbir__store_output() \- { stbir__simdf t,c; \- 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_store2( output, t ); \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 2; }--#else--#define stbir__4_coeff_start() \- stbir__simdf tot0,tot1,c,cs; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load( cs, hc ); \- 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 ); --#define stbir__4_coeff_continue_from_4( ofs ) \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load( cs, hc + (ofs) ); \- 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 ); --#define stbir__1_coeff_remnant( ofs ) \- { stbir__simdf d; \- stbir__simdf_load1z( cs, hc + (ofs) ); \- stbir__simdf_0123to0011( c, cs ); \- stbir__simdf_load2( d, decode + (ofs) * 2 ); \- stbir__simdf_madd( tot0, tot0, d, c ); }--#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 ); --#define stbir__3_coeff_remnant( ofs ) \- { stbir__simdf d; \- stbir__simdf_load( cs, hc + (ofs) ); \- stbir__simdf_0123to0011( c, cs ); \- 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 ); } --#define stbir__store_output() \- stbir__simdf_add( tot0, tot0, tot1 ); \- stbir__simdf_0123to2301( c, tot0 ); \- stbir__simdf_add( tot0, tot0, c ); \- stbir__simdf_store2( output, tot0 ); \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 2;--#endif--#else--#define stbir__1_coeff_only() \- float tota,totb,c; \- c = hc[0]; \- tota = decode[0]*c; \- totb = decode[1]*c; --#define stbir__2_coeff_only() \- float tota,totb,c; \- c = hc[0]; \- tota = decode[0]*c; \- totb = decode[1]*c; \- c = hc[1]; \- tota += decode[2]*c; \- totb += decode[3]*c; --// this weird order of add matches the simd-#define stbir__3_coeff_only() \- float tota,totb,c; \- c = hc[0]; \- tota = decode[0]*c; \- totb = decode[1]*c; \- c = hc[2]; \- tota += decode[4]*c; \- totb += decode[5]*c; \- c = hc[1]; \- tota += decode[2]*c; \- totb += decode[3]*c; --#define stbir__store_output_tiny() \- output[0] = tota; \- output[1] = totb; \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 2;--#define stbir__4_coeff_start() \- float tota0,tota1,tota2,tota3,totb0,totb1,totb2,totb3,c; \- c = hc[0]; \- tota0 = decode[0]*c; \- totb0 = decode[1]*c; \- c = hc[1]; \- tota1 = decode[2]*c; \- totb1 = decode[3]*c; \- c = hc[2]; \- tota2 = decode[4]*c; \- totb2 = decode[5]*c; \- c = hc[3]; \- tota3 = decode[6]*c; \- totb3 = decode[7]*c; --#define stbir__4_coeff_continue_from_4( ofs ) \- c = hc[0+(ofs)]; \- tota0 += decode[0+(ofs)*2]*c; \- totb0 += decode[1+(ofs)*2]*c; \- c = hc[1+(ofs)]; \- tota1 += decode[2+(ofs)*2]*c; \- totb1 += decode[3+(ofs)*2]*c; \- c = hc[2+(ofs)]; \- tota2 += decode[4+(ofs)*2]*c; \- totb2 += decode[5+(ofs)*2]*c; \- c = hc[3+(ofs)]; \- tota3 += decode[6+(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; --#define stbir__2_coeff_remnant( ofs ) \- c = hc[0+(ofs)]; \- tota0 += decode[0+(ofs)*2] * c; \- totb0 += decode[1+(ofs)*2] * c; \- c = hc[1+(ofs)]; \- tota1 += decode[2+(ofs)*2] * c; \- totb1 += decode[3+(ofs)*2] * c; --#define stbir__3_coeff_remnant( ofs ) \- c = hc[0+(ofs)]; \- tota0 += decode[0+(ofs)*2] * c; \- totb0 += decode[1+(ofs)*2] * c; \- c = hc[1+(ofs)]; \- tota1 += decode[2+(ofs)*2] * c; \- totb1 += decode[3+(ofs)*2] * c; \- c = hc[2+(ofs)]; \- tota2 += decode[4+(ofs)*2] * c; \- totb2 += decode[5+(ofs)*2] * c; --#define stbir__store_output() \- output[0] = (tota0+tota2)+(tota1+tota3); \- output[1] = (totb0+totb2)+(totb1+totb3); \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 2;--#endif --#define STBIR__horizontal_channels 2-#define STB_IMAGE_RESIZE_DO_HORIZONTALS-#include STBIR__HEADER_FILENAME---//=================-// Do 3 channel horizontal routines--#ifdef STBIR_SIMD--#define stbir__1_coeff_only() \- stbir__simdf tot,c,d; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load1z( c, hc ); \- stbir__simdf_0123to0001( c, c ); \- stbir__simdf_load( d, decode ); \- stbir__simdf_mult( tot, d, c ); --#define stbir__2_coeff_only() \- stbir__simdf tot,c,cs,d; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load2( cs, hc ); \- stbir__simdf_0123to0000( c, cs ); \- stbir__simdf_load( d, decode ); \- stbir__simdf_mult( tot, d, c ); \- stbir__simdf_0123to1111( c, cs ); \- stbir__simdf_load( d, decode+3 ); \- stbir__simdf_madd( tot, tot, d, c ); --#define stbir__3_coeff_only() \- stbir__simdf tot,c,d,cs; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load( cs, hc ); \- stbir__simdf_0123to0000( c, cs ); \- stbir__simdf_load( d, decode ); \- 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_0123to2222( c, cs ); \- stbir__simdf_load( d, decode+6 ); \- stbir__simdf_madd( tot, tot, d, c ); --#define stbir__store_output_tiny() \- stbir__simdf_store2( output, tot ); \- stbir__simdf_0123to2301( tot, tot ); \- stbir__simdf_store1( output+2, tot ); \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 3;--#ifdef STBIR_SIMD8--// we're loading from the XXXYYY decode by -1 to get the XXXYYY into different halves of the AVX reg fyi-#define stbir__4_coeff_start() \- stbir__simdf8 tot0,tot1,c,cs; stbir__simdf t; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf8_load4b( cs, hc ); \- 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 ); --#define stbir__4_coeff_continue_from_4( 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_0123to22223333( c, cs ); \- 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 ); --#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 ); - - #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 ); --#define stbir__store_output() \- stbir__simdf8_add( tot0, tot0, tot1 ); \- stbir__simdf_0123to1230( t, stbir__if_simdf8_cast_to_simdf4( tot0 ) ); \- stbir__simdf8_add4halves( t, t, tot0 ); \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 3; \- if ( output < output_end ) \- { \- stbir__simdf_store( output-3, t ); \- continue; \- } \- { stbir__simdf tt; stbir__simdf_0123to2301( tt, t ); \- stbir__simdf_store2( output-3, t ); \- stbir__simdf_store1( output+2-3, tt ); } \- break;---#else--#define stbir__4_coeff_start() \- stbir__simdf tot0,tot1,tot2,c,cs; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load( cs, hc ); \- stbir__simdf_0123to0001( c, cs ); \- stbir__simdf_mult_mem( tot0, c, decode ); \- 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 ); --#define stbir__4_coeff_continue_from_4( ofs ) \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load( cs, hc + (ofs) ); \- stbir__simdf_0123to0001( c, cs ); \- stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 ); \- 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 ); --#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 ); --#define stbir__2_coeff_remnant( ofs ) \- { stbir__simdf d; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load2z( cs, hc + (ofs) ); \- stbir__simdf_0123to0001( c, cs ); \- 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 ); } --#define stbir__3_coeff_remnant( ofs ) \- { stbir__simdf d; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load( cs, hc + (ofs) ); \- stbir__simdf_0123to0001( c, cs ); \- stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 ); \- stbir__simdf_0123to1122( c, cs ); \- 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 ); } --#define stbir__store_output() \- stbir__simdf_0123ABCDto3ABx( c, tot0, tot1 ); \- stbir__simdf_0123ABCDto23Ax( cs, tot1, tot2 ); \- stbir__simdf_0123to1230( tot2, tot2 ); \- stbir__simdf_add( tot0, tot0, cs ); \- stbir__simdf_add( c, c, tot2 ); \- stbir__simdf_add( tot0, tot0, c ); \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 3; \- if ( output < output_end ) \- { \- stbir__simdf_store( output-3, tot0 ); \- continue; \- } \- stbir__simdf_0123to2301( tot1, tot0 ); \- stbir__simdf_store2( output-3, tot0 ); \- stbir__simdf_store1( output+2-3, tot1 ); \- break;--#endif--#else--#define stbir__1_coeff_only() \- float tot0, tot1, tot2, c; \- c = hc[0]; \- tot0 = decode[0]*c; \- tot1 = decode[1]*c; \- tot2 = decode[2]*c; --#define stbir__2_coeff_only() \- float tot0, tot1, tot2, c; \- c = hc[0]; \- tot0 = decode[0]*c; \- tot1 = decode[1]*c; \- tot2 = decode[2]*c; \- c = hc[1]; \- tot0 += decode[3]*c; \- tot1 += decode[4]*c; \- tot2 += decode[5]*c; --#define stbir__3_coeff_only() \- float tot0, tot1, tot2, c; \- c = hc[0]; \- tot0 = decode[0]*c; \- tot1 = decode[1]*c; \- tot2 = decode[2]*c; \- c = hc[1]; \- tot0 += decode[3]*c; \- tot1 += decode[4]*c; \- tot2 += decode[5]*c; \- c = hc[2]; \- tot0 += decode[6]*c; \- tot1 += decode[7]*c; \- tot2 += decode[8]*c; --#define stbir__store_output_tiny() \- output[0] = tot0; \- output[1] = tot1; \- output[2] = tot2; \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 3;--#define stbir__4_coeff_start() \- float tota0,tota1,tota2,totb0,totb1,totb2,totc0,totc1,totc2,totd0,totd1,totd2,c; \- c = hc[0]; \- tota0 = decode[0]*c; \- tota1 = decode[1]*c; \- tota2 = decode[2]*c; \- c = hc[1]; \- totb0 = decode[3]*c; \- totb1 = decode[4]*c; \- totb2 = decode[5]*c; \- c = hc[2]; \- totc0 = decode[6]*c; \- totc1 = decode[7]*c; \- totc2 = decode[8]*c; \- c = hc[3]; \- totd0 = decode[9]*c; \- totd1 = decode[10]*c; \- totd2 = decode[11]*c; --#define stbir__4_coeff_continue_from_4( ofs ) \- c = hc[0+(ofs)]; \- tota0 += decode[0+(ofs)*3]*c; \- tota1 += decode[1+(ofs)*3]*c; \- tota2 += decode[2+(ofs)*3]*c; \- c = hc[1+(ofs)]; \- totb0 += decode[3+(ofs)*3]*c; \- totb1 += decode[4+(ofs)*3]*c; \- totb2 += decode[5+(ofs)*3]*c; \- c = hc[2+(ofs)]; \- totc0 += decode[6+(ofs)*3]*c; \- totc1 += decode[7+(ofs)*3]*c; \- totc2 += decode[8+(ofs)*3]*c; \- c = hc[3+(ofs)]; \- totd0 += decode[9+(ofs)*3]*c; \- totd1 += decode[10+(ofs)*3]*c; \- totd2 += decode[11+(ofs)*3]*c; --#define stbir__1_coeff_remnant( ofs ) \- c = hc[0+(ofs)]; \- tota0 += decode[0+(ofs)*3]*c; \- tota1 += decode[1+(ofs)*3]*c; \- tota2 += decode[2+(ofs)*3]*c;--#define stbir__2_coeff_remnant( ofs ) \- c = hc[0+(ofs)]; \- tota0 += decode[0+(ofs)*3]*c; \- tota1 += decode[1+(ofs)*3]*c; \- tota2 += decode[2+(ofs)*3]*c; \- c = hc[1+(ofs)]; \- totb0 += decode[3+(ofs)*3]*c; \- totb1 += decode[4+(ofs)*3]*c; \- totb2 += decode[5+(ofs)*3]*c; \--#define stbir__3_coeff_remnant( ofs ) \- c = hc[0+(ofs)]; \- tota0 += decode[0+(ofs)*3]*c; \- tota1 += decode[1+(ofs)*3]*c; \- tota2 += decode[2+(ofs)*3]*c; \- c = hc[1+(ofs)]; \- totb0 += decode[3+(ofs)*3]*c; \- totb1 += decode[4+(ofs)*3]*c; \- totb2 += decode[5+(ofs)*3]*c; \- c = hc[2+(ofs)]; \- totc0 += decode[6+(ofs)*3]*c; \- totc1 += decode[7+(ofs)*3]*c; \- totc2 += decode[8+(ofs)*3]*c; --#define stbir__store_output() \- output[0] = (tota0+totc0)+(totb0+totd0); \- output[1] = (tota1+totc1)+(totb1+totd1); \- output[2] = (tota2+totc2)+(totb2+totd2); \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 3;--#endif --#define STBIR__horizontal_channels 3-#define STB_IMAGE_RESIZE_DO_HORIZONTALS-#include STBIR__HEADER_FILENAME--//=================-// Do 4 channel horizontal routines--#ifdef STBIR_SIMD--#define stbir__1_coeff_only() \- stbir__simdf tot,c; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load1( c, hc ); \- stbir__simdf_0123to0000( c, c ); \- stbir__simdf_mult_mem( tot, c, decode ); --#define stbir__2_coeff_only() \- stbir__simdf tot,c,cs; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load2( cs, hc ); \- 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 ); --#define stbir__3_coeff_only() \- stbir__simdf tot,c,cs; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load( cs, hc ); \- 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_0123to2222( c, cs ); \- stbir__simdf_madd_mem( tot, tot, c, decode+8 ); --#define stbir__store_output_tiny() \- stbir__simdf_store( output, tot ); \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 4;--#ifdef STBIR_SIMD8--#define stbir__4_coeff_start() \- stbir__simdf8 tot0,c,cs; stbir__simdf t; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf8_load4b( cs, hc ); \- 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 ); --#define stbir__4_coeff_continue_from_4( 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_0123to22223333( c, cs ); \- 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 ); --#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 ); - - #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 ); --#define stbir__store_output() \- stbir__simdf8_add4halves( t, stbir__if_simdf8_cast_to_simdf4(tot0), tot0 ); \- stbir__simdf_store( output, t ); \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 4;--#else --#define stbir__4_coeff_start() \- stbir__simdf tot0,tot1,c,cs; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load( cs, hc ); \- stbir__simdf_0123to0000( c, cs ); \- stbir__simdf_mult_mem( tot0, c, decode ); \- stbir__simdf_0123to1111( c, cs ); \- stbir__simdf_mult_mem( tot1, c, decode+4 ); \- 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 ); --#define stbir__4_coeff_continue_from_4( ofs ) \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load( cs, hc + (ofs) ); \- 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_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 ); --#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 ); --#define stbir__2_coeff_remnant( ofs ) \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load2( cs, hc + (ofs) ); \- 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 ); - -#define stbir__3_coeff_remnant( ofs ) \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load( cs, hc + (ofs) ); \- 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_0123to2222( c, cs ); \- stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4+8 );--#define stbir__store_output() \- stbir__simdf_add( tot0, tot0, tot1 ); \- stbir__simdf_store( output, tot0 ); \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 4;--#endif--#else--#define stbir__1_coeff_only() \- float p0,p1,p2,p3,c; \- STBIR_SIMD_NO_UNROLL(decode); \- c = hc[0]; \- p0 = decode[0] * c; \- p1 = decode[1] * c; \- p2 = decode[2] * c; \- p3 = decode[3] * c;--#define stbir__2_coeff_only() \- float p0,p1,p2,p3,c; \- STBIR_SIMD_NO_UNROLL(decode); \- c = hc[0]; \- p0 = decode[0] * c; \- p1 = decode[1] * c; \- p2 = decode[2] * c; \- p3 = decode[3] * c; \- c = hc[1]; \- p0 += decode[4] * c; \- p1 += decode[5] * c; \- p2 += decode[6] * c; \- p3 += decode[7] * c;--#define stbir__3_coeff_only() \- float p0,p1,p2,p3,c; \- STBIR_SIMD_NO_UNROLL(decode); \- c = hc[0]; \- p0 = decode[0] * c; \- p1 = decode[1] * c; \- p2 = decode[2] * c; \- p3 = decode[3] * c; \- c = hc[1]; \- p0 += decode[4] * c; \- p1 += decode[5] * c; \- p2 += decode[6] * c; \- p3 += decode[7] * c; \- c = hc[2]; \- p0 += decode[8] * c; \- p1 += decode[9] * c; \- p2 += decode[10] * c; \- p3 += decode[11] * c;--#define stbir__store_output_tiny() \- output[0] = p0; \- output[1] = p1; \- output[2] = p2; \- output[3] = p3; \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 4;--#define stbir__4_coeff_start() \- float x0,x1,x2,x3,y0,y1,y2,y3,c; \- STBIR_SIMD_NO_UNROLL(decode); \- c = hc[0]; \- x0 = decode[0] * c; \- x1 = decode[1] * c; \- x2 = decode[2] * c; \- x3 = decode[3] * c; \- c = hc[1]; \- y0 = decode[4] * c; \- y1 = decode[5] * c; \- y2 = decode[6] * c; \- y3 = decode[7] * c; \- c = hc[2]; \- x0 += decode[8] * c; \- x1 += decode[9] * c; \- x2 += decode[10] * c; \- x3 += decode[11] * c; \- c = hc[3]; \- y0 += decode[12] * c; \- y1 += decode[13] * c; \- y2 += decode[14] * c; \- y3 += decode[15] * c;--#define stbir__4_coeff_continue_from_4( ofs ) \- STBIR_SIMD_NO_UNROLL(decode); \- c = hc[0+(ofs)]; \- x0 += decode[0+(ofs)*4] * c; \- x1 += decode[1+(ofs)*4] * c; \- x2 += decode[2+(ofs)*4] * c; \- x3 += decode[3+(ofs)*4] * c; \- c = hc[1+(ofs)]; \- y0 += decode[4+(ofs)*4] * c; \- y1 += decode[5+(ofs)*4] * c; \- y2 += decode[6+(ofs)*4] * c; \- y3 += decode[7+(ofs)*4] * c; \- c = hc[2+(ofs)]; \- x0 += decode[8+(ofs)*4] * c; \- x1 += decode[9+(ofs)*4] * c; \- x2 += decode[10+(ofs)*4] * c; \- x3 += decode[11+(ofs)*4] * c; \- c = hc[3+(ofs)]; \- y0 += decode[12+(ofs)*4] * c; \- y1 += decode[13+(ofs)*4] * c; \- y2 += decode[14+(ofs)*4] * c; \- y3 += decode[15+(ofs)*4] * c;--#define stbir__1_coeff_remnant( ofs ) \- STBIR_SIMD_NO_UNROLL(decode); \- c = hc[0+(ofs)]; \- x0 += decode[0+(ofs)*4] * c; \- x1 += decode[1+(ofs)*4] * c; \- x2 += decode[2+(ofs)*4] * c; \- x3 += decode[3+(ofs)*4] * c; --#define stbir__2_coeff_remnant( ofs ) \- STBIR_SIMD_NO_UNROLL(decode); \- c = hc[0+(ofs)]; \- x0 += decode[0+(ofs)*4] * c; \- x1 += decode[1+(ofs)*4] * c; \- x2 += decode[2+(ofs)*4] * c; \- x3 += decode[3+(ofs)*4] * c; \- c = hc[1+(ofs)]; \- y0 += decode[4+(ofs)*4] * c; \- y1 += decode[5+(ofs)*4] * c; \- y2 += decode[6+(ofs)*4] * c; \- y3 += decode[7+(ofs)*4] * c; - -#define stbir__3_coeff_remnant( ofs ) \- STBIR_SIMD_NO_UNROLL(decode); \- c = hc[0+(ofs)]; \- x0 += decode[0+(ofs)*4] * c; \- x1 += decode[1+(ofs)*4] * c; \- x2 += decode[2+(ofs)*4] * c; \- x3 += decode[3+(ofs)*4] * c; \- c = hc[1+(ofs)]; \- y0 += decode[4+(ofs)*4] * c; \- y1 += decode[5+(ofs)*4] * c; \- y2 += decode[6+(ofs)*4] * c; \- y3 += decode[7+(ofs)*4] * c; \- c = hc[2+(ofs)]; \- x0 += decode[8+(ofs)*4] * c; \- x1 += decode[9+(ofs)*4] * c; \- x2 += decode[10+(ofs)*4] * c; \- x3 += decode[11+(ofs)*4] * c; --#define stbir__store_output() \- output[0] = x0 + y0; \- output[1] = x1 + y1; \- output[2] = x2 + y2; \- output[3] = x3 + y3; \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 4;--#endif --#define STBIR__horizontal_channels 4-#define STB_IMAGE_RESIZE_DO_HORIZONTALS-#include STBIR__HEADER_FILENAME----//=================-// Do 7 channel horizontal routines--#ifdef STBIR_SIMD--#define stbir__1_coeff_only() \- stbir__simdf tot0,tot1,c; \- STBIR_SIMD_NO_UNROLL(decode); \- 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 ); --#define stbir__2_coeff_only() \- stbir__simdf tot0,tot1,c,cs; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load2( cs, hc ); \- stbir__simdf_0123to0000( c, cs ); \- stbir__simdf_mult_mem( tot0, c, decode ); \- 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 ); --#define stbir__3_coeff_only() \- stbir__simdf tot0,tot1,c,cs; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load( cs, hc ); \- stbir__simdf_0123to0000( c, cs ); \- stbir__simdf_mult_mem( tot0, c, decode ); \- 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_0123to2222( c, cs ); \- stbir__simdf_madd_mem( tot0, tot0, c, decode+14 ); \- stbir__simdf_madd_mem( tot1, tot1, c, decode+17 ); --#define stbir__store_output_tiny() \- stbir__simdf_store( output+3, tot1 ); \- stbir__simdf_store( output, tot0 ); \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 7;--#ifdef STBIR_SIMD8--#define stbir__4_coeff_start() \- stbir__simdf8 tot0,tot1,c,cs; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf8_load4b( cs, hc ); \- stbir__simdf8_0123to00000000( c, cs ); \- stbir__simdf8_mult_mem( tot0, c, decode ); \- stbir__simdf8_0123to11111111( c, cs ); \- stbir__simdf8_mult_mem( tot1, c, decode+7 ); \- 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 ); --#define stbir__4_coeff_continue_from_4( ofs ) \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf8_load4b( cs, hc + (ofs) ); \- stbir__simdf8_0123to00000000( c, cs ); \- stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \- 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_0123to33333333( c, cs ); \- 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 ); --#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 ); --#define stbir__3_coeff_remnant( ofs ) \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf8_load4b( cs, hc + (ofs) ); \- stbir__simdf8_0123to00000000( c, cs ); \- stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \- 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 ); --#define stbir__store_output() \- stbir__simdf8_add( tot0, tot0, tot1 ); \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 7; \- if ( output < output_end ) \- { \- stbir__simdf8_store( output-7, tot0 ); \- continue; \- } \- stbir__simdf_store( output-7+3, stbir__simdf_swiz(stbir__simdf8_gettop4(tot0),0,0,1,2) ); \- stbir__simdf_store( output-7, stbir__if_simdf8_cast_to_simdf4(tot0) ); \- break;--#else--#define stbir__4_coeff_start() \- stbir__simdf tot0,tot1,tot2,tot3,c,cs; \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load( cs, hc ); \- stbir__simdf_0123to0000( c, cs ); \- stbir__simdf_mult_mem( tot0, c, decode ); \- stbir__simdf_mult_mem( tot1, c, decode+3 ); \- stbir__simdf_0123to1111( c, cs ); \- stbir__simdf_mult_mem( tot2, c, decode+7 ); \- stbir__simdf_mult_mem( tot3, 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_0123to3333( c, cs ); \- stbir__simdf_madd_mem( tot2, tot2, c, decode+21 ); \- stbir__simdf_madd_mem( tot3, tot3, c, decode+24 ); --#define stbir__4_coeff_continue_from_4( ofs ) \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load( cs, hc + (ofs) ); \- stbir__simdf_0123to0000( c, cs ); \- stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \- 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_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_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 ); --#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)*7 ); \- stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+3 ); \--#define stbir__2_coeff_remnant( ofs ) \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load2( cs, hc + (ofs) ); \- stbir__simdf_0123to0000( c, cs ); \- stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \- 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 ); - -#define stbir__3_coeff_remnant( ofs ) \- STBIR_SIMD_NO_UNROLL(decode); \- stbir__simdf_load( cs, hc + (ofs) ); \- stbir__simdf_0123to0000( c, cs ); \- stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \- 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_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 ); --#define stbir__store_output() \- stbir__simdf_add( tot0, tot0, tot2 ); \- stbir__simdf_add( tot1, tot1, tot3 ); \- stbir__simdf_store( output+3, tot1 ); \- stbir__simdf_store( output, tot0 ); \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 7;--#endif--#else--#define stbir__1_coeff_only() \- float tot0, tot1, tot2, tot3, tot4, tot5, tot6, c; \- c = hc[0]; \- tot0 = decode[0]*c; \- tot1 = decode[1]*c; \- tot2 = decode[2]*c; \- tot3 = decode[3]*c; \- tot4 = decode[4]*c; \- tot5 = decode[5]*c; \- tot6 = decode[6]*c; --#define stbir__2_coeff_only() \- float tot0, tot1, tot2, tot3, tot4, tot5, tot6, c; \- c = hc[0]; \- tot0 = decode[0]*c; \- tot1 = decode[1]*c; \- tot2 = decode[2]*c; \- tot3 = decode[3]*c; \- tot4 = decode[4]*c; \- tot5 = decode[5]*c; \- tot6 = decode[6]*c; \- c = hc[1]; \- tot0 += decode[7]*c; \- tot1 += decode[8]*c; \- tot2 += decode[9]*c; \- tot3 += decode[10]*c; \- tot4 += decode[11]*c; \- tot5 += decode[12]*c; \- tot6 += decode[13]*c; \--#define stbir__3_coeff_only() \- float tot0, tot1, tot2, tot3, tot4, tot5, tot6, c; \- c = hc[0]; \- tot0 = decode[0]*c; \- tot1 = decode[1]*c; \- tot2 = decode[2]*c; \- tot3 = decode[3]*c; \- tot4 = decode[4]*c; \- tot5 = decode[5]*c; \- tot6 = decode[6]*c; \- c = hc[1]; \- tot0 += decode[7]*c; \- tot1 += decode[8]*c; \- tot2 += decode[9]*c; \- tot3 += decode[10]*c; \- tot4 += decode[11]*c; \- tot5 += decode[12]*c; \- tot6 += decode[13]*c; \- c = hc[2]; \- tot0 += decode[14]*c; \- tot1 += decode[15]*c; \- tot2 += decode[16]*c; \- tot3 += decode[17]*c; \- tot4 += decode[18]*c; \- tot5 += decode[19]*c; \- tot6 += decode[20]*c; \--#define stbir__store_output_tiny() \- output[0] = tot0; \- output[1] = tot1; \- output[2] = tot2; \- output[3] = tot3; \- output[4] = tot4; \- output[5] = tot5; \- output[6] = tot6; \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 7;--#define stbir__4_coeff_start() \- float x0,x1,x2,x3,x4,x5,x6,y0,y1,y2,y3,y4,y5,y6,c; \- STBIR_SIMD_NO_UNROLL(decode); \- c = hc[0]; \- x0 = decode[0] * c; \- x1 = decode[1] * c; \- x2 = decode[2] * c; \- x3 = decode[3] * c; \- x4 = decode[4] * c; \- x5 = decode[5] * c; \- x6 = decode[6] * c; \- c = hc[1]; \- y0 = decode[7] * c; \- y1 = decode[8] * c; \- y2 = decode[9] * c; \- y3 = decode[10] * c; \- y4 = decode[11] * c; \- y5 = decode[12] * c; \- y6 = decode[13] * c; \- c = hc[2]; \- x0 += decode[14] * c; \- x1 += decode[15] * c; \- x2 += decode[16] * c; \- x3 += decode[17] * c; \- x4 += decode[18] * c; \- x5 += decode[19] * c; \- x6 += decode[20] * c; \- c = hc[3]; \- y0 += decode[21] * c; \- y1 += decode[22] * c; \- y2 += decode[23] * c; \- y3 += decode[24] * c; \- y4 += decode[25] * c; \- y5 += decode[26] * c; \- y6 += decode[27] * c; --#define stbir__4_coeff_continue_from_4( ofs ) \- STBIR_SIMD_NO_UNROLL(decode); \- c = hc[0+(ofs)]; \- x0 += decode[0+(ofs)*7] * c; \- x1 += decode[1+(ofs)*7] * c; \- x2 += decode[2+(ofs)*7] * c; \- x3 += decode[3+(ofs)*7] * c; \- x4 += decode[4+(ofs)*7] * c; \- x5 += decode[5+(ofs)*7] * c; \- x6 += decode[6+(ofs)*7] * c; \- c = hc[1+(ofs)]; \- y0 += decode[7+(ofs)*7] * c; \- y1 += decode[8+(ofs)*7] * c; \- y2 += decode[9+(ofs)*7] * c; \- y3 += decode[10+(ofs)*7] * c; \- y4 += decode[11+(ofs)*7] * c; \- y5 += decode[12+(ofs)*7] * c; \- y6 += decode[13+(ofs)*7] * c; \- c = hc[2+(ofs)]; \- x0 += decode[14+(ofs)*7] * c; \- x1 += decode[15+(ofs)*7] * c; \- x2 += decode[16+(ofs)*7] * c; \- x3 += decode[17+(ofs)*7] * c; \- x4 += decode[18+(ofs)*7] * c; \- x5 += decode[19+(ofs)*7] * c; \- x6 += decode[20+(ofs)*7] * c; \- c = hc[3+(ofs)]; \- y0 += decode[21+(ofs)*7] * c; \- y1 += decode[22+(ofs)*7] * c; \- y2 += decode[23+(ofs)*7] * c; \- y3 += decode[24+(ofs)*7] * c; \- y4 += decode[25+(ofs)*7] * c; \- y5 += decode[26+(ofs)*7] * c; \- y6 += decode[27+(ofs)*7] * c; --#define stbir__1_coeff_remnant( ofs ) \- STBIR_SIMD_NO_UNROLL(decode); \- c = hc[0+(ofs)]; \- x0 += decode[0+(ofs)*7] * c; \- x1 += decode[1+(ofs)*7] * c; \- x2 += decode[2+(ofs)*7] * c; \- x3 += decode[3+(ofs)*7] * c; \- x4 += decode[4+(ofs)*7] * c; \- x5 += decode[5+(ofs)*7] * c; \- x6 += decode[6+(ofs)*7] * c; \--#define stbir__2_coeff_remnant( ofs ) \- STBIR_SIMD_NO_UNROLL(decode); \- c = hc[0+(ofs)]; \- x0 += decode[0+(ofs)*7] * c; \- x1 += decode[1+(ofs)*7] * c; \- x2 += decode[2+(ofs)*7] * c; \- x3 += decode[3+(ofs)*7] * c; \- x4 += decode[4+(ofs)*7] * c; \- x5 += decode[5+(ofs)*7] * c; \- x6 += decode[6+(ofs)*7] * c; \- c = hc[1+(ofs)]; \- y0 += decode[7+(ofs)*7] * c; \- y1 += decode[8+(ofs)*7] * c; \- y2 += decode[9+(ofs)*7] * c; \- y3 += decode[10+(ofs)*7] * c; \- 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)]; \- x0 += decode[0+(ofs)*7] * c; \- x1 += decode[1+(ofs)*7] * c; \- x2 += decode[2+(ofs)*7] * c; \- x3 += decode[3+(ofs)*7] * c; \- x4 += decode[4+(ofs)*7] * c; \- x5 += decode[5+(ofs)*7] * c; \- x6 += decode[6+(ofs)*7] * c; \- c = hc[1+(ofs)]; \- y0 += decode[7+(ofs)*7] * c; \- y1 += decode[8+(ofs)*7] * c; \- y2 += decode[9+(ofs)*7] * c; \- y3 += decode[10+(ofs)*7] * c; \- y4 += decode[11+(ofs)*7] * c; \- y5 += decode[12+(ofs)*7] * c; \- y6 += decode[13+(ofs)*7] * c; \- c = hc[2+(ofs)]; \- x0 += decode[14+(ofs)*7] * c; \- x1 += decode[15+(ofs)*7] * c; \- x2 += decode[16+(ofs)*7] * c; \- x3 += decode[17+(ofs)*7] * c; \- x4 += decode[18+(ofs)*7] * c; \- x5 += decode[19+(ofs)*7] * c; \- x6 += decode[20+(ofs)*7] * c; \--#define stbir__store_output() \- output[0] = x0 + y0; \- output[1] = x1 + y1; \- output[2] = x2 + y2; \- output[3] = x3 + y3; \- output[4] = x4 + y4; \- output[5] = x5 + y5; \- output[6] = x6 + y6; \- horizontal_coefficients += coefficient_width; \- ++horizontal_contributors; \- output += 7;--#endif --#define STBIR__horizontal_channels 7-#define STB_IMAGE_RESIZE_DO_HORIZONTALS-#include STBIR__HEADER_FILENAME---// include all of the vertical resamplers (both scatter and gather versions)--#define STBIR__vertical_channels 1-#define STB_IMAGE_RESIZE_DO_VERTICALS-#include STBIR__HEADER_FILENAME--#define STBIR__vertical_channels 1-#define STB_IMAGE_RESIZE_DO_VERTICALS-#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE-#include STBIR__HEADER_FILENAME--#define STBIR__vertical_channels 2-#define STB_IMAGE_RESIZE_DO_VERTICALS-#include STBIR__HEADER_FILENAME--#define STBIR__vertical_channels 2-#define STB_IMAGE_RESIZE_DO_VERTICALS-#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE-#include STBIR__HEADER_FILENAME--#define STBIR__vertical_channels 3-#define STB_IMAGE_RESIZE_DO_VERTICALS-#include STBIR__HEADER_FILENAME--#define STBIR__vertical_channels 3-#define STB_IMAGE_RESIZE_DO_VERTICALS-#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE-#include STBIR__HEADER_FILENAME--#define STBIR__vertical_channels 4-#define STB_IMAGE_RESIZE_DO_VERTICALS-#include STBIR__HEADER_FILENAME--#define STBIR__vertical_channels 4-#define STB_IMAGE_RESIZE_DO_VERTICALS-#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE-#include STBIR__HEADER_FILENAME--#define STBIR__vertical_channels 5-#define STB_IMAGE_RESIZE_DO_VERTICALS-#include STBIR__HEADER_FILENAME--#define STBIR__vertical_channels 5-#define STB_IMAGE_RESIZE_DO_VERTICALS-#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE-#include STBIR__HEADER_FILENAME--#define STBIR__vertical_channels 6-#define STB_IMAGE_RESIZE_DO_VERTICALS-#include STBIR__HEADER_FILENAME--#define STBIR__vertical_channels 6-#define STB_IMAGE_RESIZE_DO_VERTICALS-#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE-#include STBIR__HEADER_FILENAME--#define STBIR__vertical_channels 7-#define STB_IMAGE_RESIZE_DO_VERTICALS-#include STBIR__HEADER_FILENAME--#define STBIR__vertical_channels 7-#define STB_IMAGE_RESIZE_DO_VERTICALS-#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE-#include STBIR__HEADER_FILENAME--#define STBIR__vertical_channels 8-#define STB_IMAGE_RESIZE_DO_VERTICALS-#include STBIR__HEADER_FILENAME--#define STBIR__vertical_channels 8-#define STB_IMAGE_RESIZE_DO_VERTICALS-#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE-#include STBIR__HEADER_FILENAME--typedef void STBIR_VERTICAL_GATHERFUNC( float * output, float const * coeffs, float const ** inputs, float const * input0_end );--static STBIR_VERTICAL_GATHERFUNC * stbir__vertical_gathers[ 8 ] =-{- stbir__vertical_gather_with_1_coeffs,stbir__vertical_gather_with_2_coeffs,stbir__vertical_gather_with_3_coeffs,stbir__vertical_gather_with_4_coeffs,stbir__vertical_gather_with_5_coeffs,stbir__vertical_gather_with_6_coeffs,stbir__vertical_gather_with_7_coeffs,stbir__vertical_gather_with_8_coeffs-};--static STBIR_VERTICAL_GATHERFUNC * stbir__vertical_gathers_continues[ 8 ] =-{- stbir__vertical_gather_with_1_coeffs_cont,stbir__vertical_gather_with_2_coeffs_cont,stbir__vertical_gather_with_3_coeffs_cont,stbir__vertical_gather_with_4_coeffs_cont,stbir__vertical_gather_with_5_coeffs_cont,stbir__vertical_gather_with_6_coeffs_cont,stbir__vertical_gather_with_7_coeffs_cont,stbir__vertical_gather_with_8_coeffs_cont-};--typedef void STBIR_VERTICAL_SCATTERFUNC( float ** outputs, float const * coeffs, float const * input, float const * input_end );--static STBIR_VERTICAL_SCATTERFUNC * stbir__vertical_scatter_sets[ 8 ] =-{- stbir__vertical_scatter_with_1_coeffs,stbir__vertical_scatter_with_2_coeffs,stbir__vertical_scatter_with_3_coeffs,stbir__vertical_scatter_with_4_coeffs,stbir__vertical_scatter_with_5_coeffs,stbir__vertical_scatter_with_6_coeffs,stbir__vertical_scatter_with_7_coeffs,stbir__vertical_scatter_with_8_coeffs-};--static STBIR_VERTICAL_SCATTERFUNC * stbir__vertical_scatter_blends[ 8 ] =-{- stbir__vertical_scatter_with_1_coeffs_cont,stbir__vertical_scatter_with_2_coeffs_cont,stbir__vertical_scatter_with_3_coeffs_cont,stbir__vertical_scatter_with_4_coeffs_cont,stbir__vertical_scatter_with_5_coeffs_cont,stbir__vertical_scatter_with_6_coeffs_cont,stbir__vertical_scatter_with_7_coeffs_cont,stbir__vertical_scatter_with_8_coeffs_cont-};---static void stbir__encode_scanline( stbir__info const * stbir_info, void *output_buffer_data, float * encode_buffer, int row STBIR_ONLY_PROFILE_GET_SPLIT_INFO )-{- int num_pixels = stbir_info->horizontal.scale_info.output_sub_size;- int channels = stbir_info->channels;- int width_times_channels = num_pixels * channels;- void * output_buffer;-- // un-alpha weight if we need to- if ( stbir_info->alpha_unweight )- {- STBIR_PROFILE_START( unalpha );- stbir_info->alpha_unweight( encode_buffer, width_times_channels );- STBIR_PROFILE_END( unalpha );- }-- // write directly into output by default- output_buffer = output_buffer_data;-- // 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 );- STBIR_PROFILE_END( encode );-- // 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 );-}---// Get the ring buffer pointer for an index-static float* stbir__get_ring_buffer_entry(stbir__info const * stbir_info, stbir__per_split_info const * split_info, int index )-{- STBIR_ASSERT( index < stbir_info->ring_buffer_num_entries );-- #ifdef STBIR__SEPARATE_ALLOCATIONS- return split_info->ring_buffers[ index ];- #else- return (float*) ( ( (char*) split_info->ring_buffer ) + ( index * stbir_info->ring_buffer_length_bytes ) );- #endif-}--// Get the specified scan line from the ring buffer-static float* stbir__get_ring_buffer_scanline(stbir__info const * stbir_info, stbir__per_split_info const * split_info, int get_scanline)-{- int ring_buffer_index = (split_info->ring_buffer_begin_index + (get_scanline - split_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries;- return stbir__get_ring_buffer_entry( stbir_info, split_info, ring_buffer_index );-}--static void stbir__resample_horizontal_gather(stbir__info const * stbir_info, float* output_buffer, float const * input_buffer STBIR_ONLY_PROFILE_GET_SPLIT_INFO )-{- float const * decode_buffer = input_buffer - ( stbir_info->scanline_extents.conservative.n0 * stbir_info->effective_channels );-- STBIR_PROFILE_START( horizontal );- if ( ( stbir_info->horizontal.filter_enum == STBIR_FILTER_POINT_SAMPLE ) && ( stbir_info->horizontal.scale_info.scale == 1.0f ) )- STBIR_MEMCPY( output_buffer, input_buffer, stbir_info->horizontal.scale_info.output_sub_size * sizeof( float ) * stbir_info->effective_channels );- else- stbir_info->horizontal_gather_channels( output_buffer, stbir_info->horizontal.scale_info.output_sub_size, decode_buffer, stbir_info->horizontal.contributors, stbir_info->horizontal.coefficients, stbir_info->horizontal.coefficient_width );- STBIR_PROFILE_END( horizontal );-}--static void stbir__resample_vertical_gather(stbir__info const * stbir_info, stbir__per_split_info* split_info, int n, int contrib_n0, int contrib_n1, float const * vertical_coefficients )-{- float* encode_buffer = split_info->vertical_buffer;- float* decode_buffer = split_info->decode_buffer;- int vertical_first = stbir_info->vertical_first;- int width = (vertical_first) ? ( stbir_info->scanline_extents.conservative.n1-stbir_info->scanline_extents.conservative.n0+1 ) : stbir_info->horizontal.scale_info.output_sub_size;- int width_times_channels = stbir_info->effective_channels * width;-- STBIR_ASSERT( stbir_info->vertical.is_gather );-- // loop over the contributing scanlines and scale into the buffer- STBIR_PROFILE_START( vertical );- {- int k = 0, total = contrib_n1 - contrib_n0 + 1;- STBIR_ASSERT( total > 0 );- do {- float const * inputs[8];- int i, cnt = total; if ( cnt > 8 ) cnt = 8;- for( i = 0 ; i < cnt ; i++ )- inputs[ i ] = stbir__get_ring_buffer_scanline(stbir_info, split_info, k+i+contrib_n0 );-- // call the N scanlines at a time function (up to 8 scanlines of blending at once)- ((k==0)?stbir__vertical_gathers:stbir__vertical_gathers_continues)[cnt-1]( (vertical_first) ? decode_buffer : encode_buffer, vertical_coefficients + k, inputs, inputs[0] + width_times_channels );- k += cnt;- total -= cnt;- } while ( total );- }- STBIR_PROFILE_END( vertical );-- if ( vertical_first )- {- // Now resample the gathered vertical data in the horizontal axis into the encode buffer- 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), - encode_buffer, n STBIR_ONLY_PROFILE_SET_SPLIT_INFO );-}--static void stbir__decode_and_resample_for_vertical_gather_loop(stbir__info const * stbir_info, stbir__per_split_info* split_info, int n)-{- int ring_buffer_index;- float* ring_buffer;-- // Decode the nth scanline from the source image into the decode buffer.- stbir__decode_scanline( stbir_info, n, split_info->decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO );-- // update new end scanline- split_info->ring_buffer_last_scanline = n;-- // 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);-- // Now resample it into the ring buffer.- stbir__resample_horizontal_gather( stbir_info, ring_buffer, split_info->decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO );-- // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling.-}--static void stbir__vertical_gather_loop( stbir__info const * stbir_info, stbir__per_split_info* split_info, int split_count )-{- int y, start_output_y, end_output_y;- stbir__contributors* vertical_contributors = stbir_info->vertical.contributors;- float const * vertical_coefficients = stbir_info->vertical.coefficients;-- STBIR_ASSERT( stbir_info->vertical.is_gather );-- start_output_y = split_info->start_output_y;- end_output_y = split_info[split_count-1].end_output_y;-- vertical_contributors += start_output_y;- vertical_coefficients += start_output_y * stbir_info->vertical.coefficient_width;-- // 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_last_scanline = split_info->ring_buffer_first_scanline - 1; // means "empty"-- for (y = start_output_y; y < end_output_y; y++)- {- int in_first_scanline, in_last_scanline;-- in_first_scanline = vertical_contributors->n0;- in_last_scanline = vertical_contributors->n1;-- // make sure the indexing hasn't broken- STBIR_ASSERT( in_first_scanline >= split_info->ring_buffer_first_scanline );-- // Load in new scanlines- while (in_last_scanline > split_info->ring_buffer_last_scanline)- {- STBIR_ASSERT( ( split_info->ring_buffer_last_scanline - split_info->ring_buffer_first_scanline + 1 ) <= stbir_info->ring_buffer_num_entries );-- // make sure there was room in the ring buffer when we add new scanlines- if ( ( split_info->ring_buffer_last_scanline - split_info->ring_buffer_first_scanline + 1 ) == stbir_info->ring_buffer_num_entries )- {- 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 ); - }- else- {- stbir__decode_and_resample_for_vertical_gather_loop(stbir_info, split_info, split_info->ring_buffer_last_scanline + 1);- }- }-- // Now all buffers should be ready to write a row of vertical sampling, so do it.- stbir__resample_vertical_gather(stbir_info, split_info, y, in_first_scanline, in_last_scanline, vertical_coefficients );-- ++vertical_contributors;- vertical_coefficients += stbir_info->vertical.coefficient_width;- }-}--#define STBIR__FLOAT_EMPTY_MARKER 3.0e+38F-#define STBIR__FLOAT_BUFFER_IS_EMPTY(ptr) ((ptr)[0]==STBIR__FLOAT_EMPTY_MARKER)--static void stbir__encode_first_scanline_from_scatter(stbir__info const * stbir_info, stbir__per_split_info* split_info)-{- // 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 );- - // mark it as empty- ring_buffer_entry[ 0 ] = STBIR__FLOAT_EMPTY_MARKER;-- // advance the first scanline- split_info->ring_buffer_first_scanline++;- if ( ++split_info->ring_buffer_begin_index == stbir_info->ring_buffer_num_entries )- split_info->ring_buffer_begin_index = 0;-}--static void stbir__horizontal_resample_and_encode_first_scanline_from_scatter(stbir__info const * stbir_info, stbir__per_split_info* split_info)-{- // 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 );-- // 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 );- - // mark it as empty- ring_buffer_entry[ 0 ] = STBIR__FLOAT_EMPTY_MARKER;-- // advance the first scanline- split_info->ring_buffer_first_scanline++;- if ( ++split_info->ring_buffer_begin_index == stbir_info->ring_buffer_num_entries )- split_info->ring_buffer_begin_index = 0;-}--static void stbir__resample_vertical_scatter(stbir__info const * stbir_info, stbir__per_split_info* split_info, int n0, int n1, float const * vertical_coefficients, float const * vertical_buffer, float const * vertical_buffer_end )-{- STBIR_ASSERT( !stbir_info->vertical.is_gather );-- STBIR_PROFILE_START( vertical );- {- int k = 0, total = n1 - n0 + 1;- STBIR_ASSERT( total > 0 );- do {- float * outputs[8];- int i, n = total; if ( n > 8 ) n = 8;- for( i = 0 ; i < n ; i++ )- {- outputs[ i ] = stbir__get_ring_buffer_scanline(stbir_info, split_info, k+i+n0 );- if ( ( i ) && ( STBIR__FLOAT_BUFFER_IS_EMPTY( outputs[i] ) != STBIR__FLOAT_BUFFER_IS_EMPTY( outputs[0] ) ) ) // make sure runs are of the same type- {- n = i;- break;- }- }- // call the scatter to N scanlines at a time function (up to 8 scanlines of scattering at once)- ((STBIR__FLOAT_BUFFER_IS_EMPTY( outputs[0] ))?stbir__vertical_scatter_sets:stbir__vertical_scatter_blends)[n-1]( outputs, vertical_coefficients + k, vertical_buffer, vertical_buffer_end );- k += n;- total -= n;- } while ( total );- }-- STBIR_PROFILE_END( vertical );-}--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 )-{- int y, start_output_y, end_output_y, start_input_y, end_input_y;- stbir__contributors* vertical_contributors = stbir_info->vertical.contributors;- float const * vertical_coefficients = stbir_info->vertical.coefficients;- stbir__handle_scanline_for_scatter_func * handle_scanline_for_scatter;- void * scanline_scatter_buffer;- void * scanline_scatter_buffer_end;- int on_first_input_y, last_input_y;-- STBIR_ASSERT( !stbir_info->vertical.is_gather );-- start_output_y = split_info->start_output_y;- end_output_y = split_info[split_count-1].end_output_y; // may do multiple split counts-- start_input_y = split_info->start_input_y;- 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; - vertical_contributors += y ;- vertical_coefficients += stbir_info->vertical.coefficient_width * y;-- if ( stbir_info->vertical_first )- {- handle_scanline_for_scatter = stbir__horizontal_resample_and_encode_first_scanline_from_scatter;- scanline_scatter_buffer = split_info->decode_buffer;- scanline_scatter_buffer_end = ( (char*) scanline_scatter_buffer ) + sizeof( float ) * stbir_info->effective_channels * (stbir_info->scanline_extents.conservative.n1-stbir_info->scanline_extents.conservative.n0+1);- }- else- {- handle_scanline_for_scatter = stbir__encode_first_scanline_from_scatter;- scanline_scatter_buffer = split_info->vertical_buffer;- scanline_scatter_buffer_end = ( (char*) scanline_scatter_buffer ) + sizeof( float ) * stbir_info->effective_channels * stbir_info->horizontal.scale_info.output_sub_size;- }-- // initialize the ring buffer for scattering- split_info->ring_buffer_first_scanline = start_output_y;- split_info->ring_buffer_last_scanline = -1;- split_info->ring_buffer_begin_index = -1;-- // mark all the buffers as empty to start- for( y = 0 ; y < stbir_info->ring_buffer_num_entries ; y++ )- stbir__get_ring_buffer_entry( stbir_info, split_info, y )[0] = STBIR__FLOAT_EMPTY_MARKER; // only used on scatter-- // do the loop in input space- on_first_input_y = 1; last_input_y = start_input_y;- for (y = start_input_y ; y < end_input_y; y++)- {- int out_first_scanline, out_last_scanline;-- out_first_scanline = vertical_contributors->n0;- out_last_scanline = vertical_contributors->n1;-- STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);-- if ( ( out_last_scanline >= out_first_scanline ) && ( ( ( out_first_scanline >= start_output_y ) && ( out_first_scanline < end_output_y ) ) || ( ( out_last_scanline >= start_output_y ) && ( out_last_scanline < end_output_y ) ) ) )- {- float const * vc = vertical_coefficients;-- // keep track of the range actually seen for the next resize- last_input_y = y;- if ( ( on_first_input_y ) && ( y > start_input_y ) )- split_info->start_input_y = y;- on_first_input_y = 0;-- // clip the region - if ( out_first_scanline < start_output_y )- {- vc += start_output_y - out_first_scanline;- out_first_scanline = start_output_y;- }-- if ( out_last_scanline >= end_output_y )- out_last_scanline = end_output_y - 1;-- // 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 ); -- // When horizontal first, we resample horizontally into the vertical buffer before we scatter it out- if ( !stbir_info->vertical_first )- stbir__resample_horizontal_gather( stbir_info, split_info->vertical_buffer, split_info->decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO );-- // Now it's sitting in the buffer ready to be distributed into the ring buffers.-- // evict from the ringbuffer, if we need are full- 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 );-- // update the end of the buffer- if ( out_last_scanline > split_info->ring_buffer_last_scanline )- split_info->ring_buffer_last_scanline = out_last_scanline;- }- ++vertical_contributors;- vertical_coefficients += stbir_info->vertical.coefficient_width;- }-- // now evict the scanlines that are left over in the ring buffer- while ( split_info->ring_buffer_first_scanline < end_output_y )- handle_scanline_for_scatter(stbir_info, split_info);-- // update the end_input_y if we do multiple resizes with the same data- ++last_input_y;- for( y = 0 ; y < split_count; y++ )- if ( split_info[y].end_input_y > last_input_y )- split_info[y].end_input_y = last_input_y;-}---static stbir__kernel_callback * stbir__builtin_kernels[] = { 0, stbir__filter_trapezoid, stbir__filter_triangle, stbir__filter_cubic, stbir__filter_catmullrom, stbir__filter_mitchell, stbir__filter_point };-static stbir__support_callback * stbir__builtin_supports[] = { 0, stbir__support_trapezoid, stbir__support_one, stbir__support_two, stbir__support_two, stbir__support_two, stbir__support_zeropoint5 };--static void stbir__set_sampler(stbir__sampler * samp, stbir_filter filter, stbir__kernel_callback * kernel, stbir__support_callback * support, stbir_edge edge, stbir__scale_info * scale_info, int always_gather, void * user_data )-{- // set filter- if (filter == 0)- {- filter = STBIR_DEFAULT_FILTER_DOWNSAMPLE; // default to downsample- 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; - else- filter = STBIR_DEFAULT_FILTER_UPSAMPLE;- }- }- samp->filter_enum = filter;-- STBIR_ASSERT(samp->filter_enum != 0);- STBIR_ASSERT((unsigned)samp->filter_enum < STBIR_FILTER_OTHER); - samp->filter_kernel = stbir__builtin_kernels[ filter ];- samp->filter_support = stbir__builtin_supports[ filter ];-- if ( kernel && support )- {- samp->filter_kernel = kernel;- samp->filter_support = support;- samp->filter_enum = STBIR_FILTER_OTHER;- }-- samp->edge = edge;- samp->filter_pixel_width = stbir__get_filter_pixel_width (samp->filter_support, scale_info->scale, user_data );- // Gather is always better, but in extreme downsamples, you have to most or all of the data in memory- // For horizontal, we always have all the pixels, so we always use gather here (always_gather==1).- // For vertical, we use gather if scaling up (which means we will have samp->filter_pixel_width- // scanlines in memory at once).- samp->is_gather = 0;- if ( scale_info->scale >= ( 1.0f - stbir__small_float ) )- samp->is_gather = 1;- else if ( ( always_gather ) || ( samp->filter_pixel_width <= STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT ) )- samp->is_gather = 2;-- // pre calculate stuff based on the above- samp->coefficient_width = stbir__get_coefficient_width(samp, samp->is_gather, user_data);-- 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;-- // 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;-- 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-- samp->gather_prescatter_contributors = 0;- samp->gather_prescatter_coefficients = 0;- if ( samp->is_gather == 0 )- {- samp->gather_prescatter_coefficient_width = samp->filter_pixel_width;- samp->gather_prescatter_num_contributors = stbir__get_contributors(samp, 2);- samp->gather_prescatter_contributors_size = samp->gather_prescatter_num_contributors * sizeof(stbir__contributors);- samp->gather_prescatter_coefficients_size = samp->gather_prescatter_num_contributors * samp->gather_prescatter_coefficient_width * sizeof(float);- }-}--static void stbir__get_conservative_extents( stbir__sampler * samp, stbir__contributors * range, void * user_data )-{- float scale = samp->scale_info.scale;- float out_shift = samp->scale_info.pixel_shift;- stbir__support_callback * support = samp->filter_support;- int input_full_size = samp->scale_info.input_full_size;- stbir_edge edge = samp->edge;- float inv_scale = samp->scale_info.inv_scale;-- STBIR_ASSERT( samp->is_gather != 0 );-- if ( samp->is_gather == 1 )- {- int in_first_pixel, in_last_pixel;- float out_filter_radius = support(inv_scale, user_data) * scale;-- stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, 0.5, out_filter_radius, inv_scale, out_shift, input_full_size, edge );- range->n0 = in_first_pixel;- stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, ( (float)(samp->scale_info.output_sub_size-1) ) + 0.5f, out_filter_radius, inv_scale, out_shift, input_full_size, edge );- range->n1 = in_last_pixel;- }- else if ( samp->is_gather == 2 ) // downsample gather, refine- {- float in_pixels_radius = support(scale, user_data) * inv_scale;- int filter_pixel_margin = samp->filter_pixel_margin;- int output_sub_size = samp->scale_info.output_sub_size;- int input_end;- int n;- int in_first_pixel, in_last_pixel;-- // get a conservative area of the input range- stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, 0, 0, inv_scale, out_shift, input_full_size, edge );- 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 - n = range->n0 + 1;- input_end = -filter_pixel_margin;- while( n >= input_end )- {- int out_first_pixel, out_last_pixel;- stbir__calculate_out_pixel_range( &out_first_pixel, &out_last_pixel, ((float)n)+0.5f, in_pixels_radius, scale, out_shift, output_sub_size );- if ( out_first_pixel > out_last_pixel )- break;-- if ( ( out_first_pixel < output_sub_size ) || ( out_last_pixel >= 0 ) )- range->n0 = n;- --n;- }-- // 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 )- {- int out_first_pixel, out_last_pixel;- stbir__calculate_out_pixel_range( &out_first_pixel, &out_last_pixel, ((float)n)+0.5f, in_pixels_radius, scale, out_shift, output_sub_size );- if ( out_first_pixel > out_last_pixel )- break;- if ( ( out_first_pixel < output_sub_size ) || ( out_last_pixel >= 0 ) )- range->n1 = n;- ++n;- }- }-- if ( samp->edge == STBIR_EDGE_WRAP )- {- // if we are wrapping, and we are very close to the image size (so the edges might merge), just use the scanline up to the edge- if ( ( range->n0 > 0 ) && ( range->n1 >= input_full_size ) )- {- int marg = range->n1 - input_full_size + 1;- if ( ( marg + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= range->n0 )- range->n0 = 0;- }- if ( ( range->n0 < 0 ) && ( range->n1 < (input_full_size-1) ) )- {- int marg = -range->n0;- if ( ( input_full_size - marg - STBIR__MERGE_RUNS_PIXEL_THRESHOLD - 1 ) <= range->n1 )- range->n1 = input_full_size - 1;- }- }- else- {- // for non-edge-wrap modes, we never read over the edge, so clamp- if ( range->n0 < 0 )- range->n0 = 0;- if ( range->n1 >= input_full_size )- range->n1 = input_full_size - 1;- }-}--static void stbir__get_split_info( stbir__per_split_info* split_info, int splits, int output_height, int vertical_pixel_margin, int input_full_height )-{- int i, cur;- int left = output_height;-- cur = 0;- for( i = 0 ; i < splits ; i++ )- {- int each; - split_info[i].start_output_y = cur;- each = left / ( splits - i );- split_info[i].end_output_y = cur + each;- cur += each;- left -= each;-- // scatter range (updated to minimum as you run it)- split_info[i].start_input_y = -vertical_pixel_margin;- split_info[i].end_input_y = input_full_height + vertical_pixel_margin;- }-}--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- STBIR__FREE_AND_CLEAR( info->alloced_mem );- #else- int i,j;-- if ( ( info->vertical.gather_prescatter_contributors ) && ( (void*)info->vertical.gather_prescatter_contributors != (void*)info->split_info[0].decode_buffer ) )- {- STBIR__FREE_AND_CLEAR( info->vertical.gather_prescatter_coefficients );- STBIR__FREE_AND_CLEAR( info->vertical.gather_prescatter_contributors );- }- for( i = 0 ; i < info->splits ; i++ )- {- for( j = 0 ; j < info->alloc_ring_buffer_num_entries ; j++ )- {- #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 - STBIR__FREE_AND_CLEAR( info->split_info[i].ring_buffers[j] );- }-- #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 - 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 );- }- STBIR__FREE_AND_CLEAR( info->split_info );- if ( info->vertical.coefficients != info->horizontal.coefficients )- {- STBIR__FREE_AND_CLEAR( info->vertical.coefficients );- STBIR__FREE_AND_CLEAR( info->vertical.contributors );- }- STBIR__FREE_AND_CLEAR( info->horizontal.coefficients );- STBIR__FREE_AND_CLEAR( info->horizontal.contributors );- STBIR__FREE_AND_CLEAR( info->alloced_mem );- STBIR__FREE_AND_CLEAR( info );- #endif- }- - #undef STBIR__FREE_AND_CLEAR-}--static int stbir__get_max_split( int splits, int height )-{- int i;- int max = 0;-- for( i = 0 ; i < splits ; i++ )- {- int each = height / ( splits - i );- if ( each > max ) - max = each;- height -= each;- }- return max;-}--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] = -{ - 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-};--// there are six resize classifications: 0 == vertical scatter, 1 == vertical gather < 1x scale, 2 == vertical gather 1x-2x scale, 4 == vertical gather < 3x scale, 4 == vertical gather > 3x scale, 5 == <=4 pixel height, 6 == <=4 pixel wide column-#define STBIR_RESIZE_CLASSIFICATIONS 8--static float stbir__compute_weights[5][STBIR_RESIZE_CLASSIFICATIONS][4]= // 5 = 0=1chan, 1=2chan, 2=3chan, 3=4chan, 4=7chan-{- {- { 1.00000f, 1.00000f, 0.31250f, 1.00000f },- { 0.56250f, 0.59375f, 0.00000f, 0.96875f },- { 1.00000f, 0.06250f, 0.00000f, 1.00000f },- { 0.00000f, 0.09375f, 1.00000f, 1.00000f },- { 1.00000f, 1.00000f, 1.00000f, 1.00000f },- { 0.03125f, 0.12500f, 1.00000f, 1.00000f },- { 0.06250f, 0.12500f, 0.00000f, 1.00000f },- { 0.00000f, 1.00000f, 0.00000f, 0.03125f },- }, {- { 0.00000f, 0.84375f, 0.00000f, 0.03125f },- { 0.09375f, 0.93750f, 0.00000f, 0.78125f },- { 0.87500f, 0.21875f, 0.00000f, 0.96875f },- { 0.09375f, 0.09375f, 1.00000f, 1.00000f },- { 1.00000f, 1.00000f, 1.00000f, 1.00000f },- { 0.03125f, 0.12500f, 1.00000f, 1.00000f },- { 0.06250f, 0.12500f, 0.00000f, 1.00000f },- { 0.00000f, 1.00000f, 0.00000f, 0.53125f },- }, {- { 0.00000f, 0.53125f, 0.00000f, 0.03125f },- { 0.06250f, 0.96875f, 0.00000f, 0.53125f },- { 0.87500f, 0.18750f, 0.00000f, 0.93750f },- { 0.00000f, 0.09375f, 1.00000f, 1.00000f },- { 1.00000f, 1.00000f, 1.00000f, 1.00000f },- { 0.03125f, 0.12500f, 1.00000f, 1.00000f },- { 0.06250f, 0.12500f, 0.00000f, 1.00000f },- { 0.00000f, 1.00000f, 0.00000f, 0.56250f },- }, {- { 0.00000f, 0.50000f, 0.00000f, 0.71875f },- { 0.06250f, 0.84375f, 0.00000f, 0.87500f },- { 1.00000f, 0.50000f, 0.50000f, 0.96875f },- { 1.00000f, 0.09375f, 0.31250f, 0.50000f },- { 1.00000f, 1.00000f, 1.00000f, 1.00000f },- { 1.00000f, 0.03125f, 0.03125f, 0.53125f },- { 0.18750f, 0.12500f, 0.00000f, 1.00000f },- { 0.00000f, 1.00000f, 0.03125f, 0.18750f },- }, {- { 0.00000f, 0.59375f, 0.00000f, 0.96875f },- { 0.06250f, 0.81250f, 0.06250f, 0.59375f },- { 0.75000f, 0.43750f, 0.12500f, 0.96875f },- { 0.87500f, 0.06250f, 0.18750f, 0.43750f },- { 1.00000f, 1.00000f, 1.00000f, 1.00000f },- { 0.15625f, 0.12500f, 1.00000f, 1.00000f },- { 0.06250f, 0.12500f, 0.00000f, 1.00000f },- { 0.00000f, 1.00000f, 0.03125f, 0.34375f },- }-};--// structure that allow us to query and override info for training the costs-typedef struct STBIR__V_FIRST_INFO-{- double v_cost, h_cost;- int control_v_first; // 0 = no control, 1 = force hori, 2 = force vert- int v_first;- int v_resize_classification;- int is_gather;-} STBIR__V_FIRST_INFO;--#ifdef STBIR__V_FIRST_INFO_BUFFER-static STBIR__V_FIRST_INFO STBIR__V_FIRST_INFO_BUFFER = {0};-#define STBIR__V_FIRST_INFO_POINTER &STBIR__V_FIRST_INFO_BUFFER-#else-#define STBIR__V_FIRST_INFO_POINTER 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 -// in that order.-//-// 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 -// fancy caches and SIMD and high IPC abilities, so there's just a lot-// more that goes into it. -//-// 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 -// 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 ) -{- double v_cost, h_cost;- float * weights;- int vertical_first;- int v_classification;-- // categorize the resize into buckets- if ( ( vertical_output_size <= 4 ) || ( horizontal_output_size <= 4 ) )- 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) - v_classification = 2;- else if ( vertical_scale <= 3.0f) - v_classification = 3;- else if ( vertical_scale <= 4.0f) - v_classification = 5;- else - v_classification = 6;- - // use the right weights- weights = weights_table[ v_classification ];-- // this is the costs when you don't take into account modern CPUs with high ipc and simd and caches - wish we had a better estimate- h_cost = (float)horizontal_filter_pixel_width * weights[0] + horizontal_scale * (float)vertical_filter_pixel_width * weights[1];- v_cost = (float)vertical_filter_pixel_width * weights[2] + vertical_scale * (float)horizontal_filter_pixel_width * weights[3];-- // use computation estimate to decide vertical first or not- vertical_first = ( v_cost <= h_cost ) ? 1 : 0;-- // save these, if requested- if ( info )- {- info->h_cost = h_cost;- info->v_cost = v_cost;- info->v_resize_classification = v_classification;- info->v_first = vertical_first;- info->is_gather = is_gather;- }-- // 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;-}--// layout lookups - must match stbir_internal_pixel_layout-static unsigned char stbir__pixel_channels[] = {- 1,2,3,3,4, // 1ch, 2ch, rgb, bgr, 4ch- 4,4,4,4,2,2, // RGBA,BGRA,ARGB,ABGR,RA,AR- 4,4,4,4,2,2, // RGBA_PM,BGRA_PM,ARGB_PM,ABGR_PM,RA_PM,AR_PM-};--// 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 -static stbir_internal_pixel_layout stbir__pixel_layout_convert_public_to_internal[] = {- 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,-};--static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sampler * horizontal, stbir__sampler * vertical, stbir__contributors * conservative, stbir_pixel_layout input_pixel_layout_public, stbir_pixel_layout output_pixel_layout_public, int splits, int new_x, int new_y, int fast_alpha, void * user_data STBIR_ONLY_PROFILE_BUILD_GET_INFO )-{- static char stbir_channel_count_index[8]={ 9,0,1,2, 3,9,9,4 };-- stbir__info * info = 0;- void * alloced = 0;- int 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 ]; - 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 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- {- if ( ( input_pixel_layout >= STBIRI_RGBA ) && ( input_pixel_layout <= STBIRI_AR ) && ( output_pixel_layout >= STBIRI_RGBA ) && ( output_pixel_layout <= STBIRI_AR ) )- {- if ( fast_alpha )- {- alpha_weighting_type = 4;- }- else- {- static int fancy_alpha_effective_cnts[6] = { 7, 7, 7, 7, 3, 3 };- alpha_weighting_type = 2;- effective_channels = fancy_alpha_effective_cnts[ input_pixel_layout - STBIRI_RGBA ];- }- }- else if ( ( input_pixel_layout >= STBIRI_RGBA_PM ) && ( input_pixel_layout <= STBIRI_AR_PM ) && ( output_pixel_layout >= STBIRI_RGBA ) && ( output_pixel_layout <= STBIRI_AR ) )- {- // input premult, output non-premult- alpha_weighting_type = 3;- }- else if ( ( input_pixel_layout >= STBIRI_RGBA ) && ( input_pixel_layout <= STBIRI_AR ) && ( output_pixel_layout >= STBIRI_RGBA_PM ) && ( output_pixel_layout <= STBIRI_AR_PM ) )- {- // input non-premult, output premult- alpha_weighting_type = 1;- }- }-- // channel in and out count must match currently- if ( channels != stbir__pixel_channels[ output_pixel_layout ] )- return 0;-- // get vertical first- vertical_first = stbir__should_do_vertical_first( stbir__compute_weights[ (int)stbir_channel_count_index[ effective_channels ] ], horizontal->filter_pixel_width, horizontal->scale_info.scale, horizontal->scale_info.output_sub_size, vertical->filter_pixel_width, vertical->scale_info.scale, vertical->scale_info.output_sub_size, vertical->is_gather, STBIR__V_FIRST_INFO_POINTER );-- // 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 -- ring_buffer_length_bytes = horizontal->scale_info.output_sub_size * effective_channels * sizeof(float) + sizeof(float); // extra float for padding-- // if we do vertical first, the ring buffer holds a whole decoded line- if ( vertical_first )- ring_buffer_length_bytes = ( decode_buffer_size + 15 ) & ~15;-- if ( ( ring_buffer_length_bytes & 4095 ) == 0 ) ring_buffer_length_bytes += 64*3; // avoid 4k alias-- // One extra entry because floating point precision problems sometimes cause an extra to be necessary.- alloc_ring_buffer_num_entries = vertical->filter_pixel_width + 1;-- // we never need more ring buffer entries than the scanlines we're outputting when in scatter mode- if ( ( !vertical->is_gather ) && ( alloc_ring_buffer_num_entries > conservative_split_output_size ) )- alloc_ring_buffer_num_entries = conservative_split_output_size;-- ring_buffer_size = alloc_ring_buffer_num_entries * ring_buffer_length_bytes;-- // The vertical buffer is used differently, depending on whether we are scattering- // the vertical scanlines, or gathering them.- // If scattering, it's used at the temp buffer to accumulate each output.- // If gathering, it's just the output buffer.- vertical_buffer_size = horizontal->scale_info.output_sub_size * effective_channels * sizeof(float) + sizeof(float); // extra float for padding-- // we make two passes through this loop, 1st to add everything up, 2nd to allocate and init- for(;;)- {- int i;- void * advance_mem = alloced;- int copy_horizontal = 0;- stbir__sampler * possibly_use_horizontal_for_pivot = 0;--#ifdef STBIR__SEPARATE_ALLOCATIONS- #define STBIR__NEXT_PTR( ptr, size, ntype ) if ( alloced ) { void * p = STBIR_MALLOC( size, user_data); if ( p == 0 ) { stbir__free_internal_mem( info ); return 0; } (ptr) = (ntype*)p; }-#else- #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->split_info, sizeof( stbir__per_split_info ) * splits, stbir__per_split_info ); -- if ( info )- {- static stbir__alpha_weight_func * fancy_alpha_weights[6] = { stbir__fancy_alpha_weight_4ch, stbir__fancy_alpha_weight_4ch, stbir__fancy_alpha_weight_4ch, stbir__fancy_alpha_weight_4ch, stbir__fancy_alpha_weight_2ch, stbir__fancy_alpha_weight_2ch };- static stbir__alpha_unweight_func * fancy_alpha_unweights[6] = { stbir__fancy_alpha_unweight_4ch, stbir__fancy_alpha_unweight_4ch, stbir__fancy_alpha_unweight_4ch, stbir__fancy_alpha_unweight_4ch, stbir__fancy_alpha_unweight_2ch, stbir__fancy_alpha_unweight_2ch };- static stbir__alpha_weight_func * simple_alpha_weights[6] = { stbir__simple_alpha_weight_4ch, stbir__simple_alpha_weight_4ch, stbir__simple_alpha_weight_4ch, stbir__simple_alpha_weight_4ch, stbir__simple_alpha_weight_2ch, stbir__simple_alpha_weight_2ch };- static stbir__alpha_unweight_func * simple_alpha_unweights[6] = { stbir__simple_alpha_unweight_4ch, stbir__simple_alpha_unweight_4ch, stbir__simple_alpha_unweight_4ch, stbir__simple_alpha_unweight_4ch, stbir__simple_alpha_unweight_2ch, stbir__simple_alpha_unweight_2ch };-- // initialize info fields- info->alloced_mem = alloced;- info->alloced_total = alloced_total;-- 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_length_bytes = ring_buffer_length_bytes;- info->splits = splits;- info->vertical_first = vertical_first;-- 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_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_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 ]; - }- else if ( alpha_weighting_type == 3 )- {- // incoming is premultiplied, fast alpha dividing on the way out - non-premultiplied output- info->alpha_unweight = simple_alpha_unweights[ output_pixel_layout - STBIRI_RGBA ];- }-- // handle 3-chan color flipping, using the alpha weight path- if ( ( ( input_pixel_layout == STBIRI_RGB ) && ( output_pixel_layout == STBIRI_BGR ) ) ||- ( ( input_pixel_layout == STBIRI_BGR ) && ( output_pixel_layout == STBIRI_RGB ) ) )- {- // do the flipping on the smaller of the two ends- if ( horizontal->scale_info.scale < 1.0f )- info->alpha_unweight = stbir__simple_flip_3ch;- else- info->alpha_weight = stbir__simple_flip_3ch;- }-- } -- // get all the per-split buffers- for( i = 0 ; i < splits ; i++ )- {- STBIR__NEXT_PTR( info->split_info[i].decode_buffer, decode_buffer_size, float );--#ifdef STBIR__SEPARATE_ALLOCATIONS-- #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 -- STBIR__NEXT_PTR( info->split_info[i].ring_buffers, alloc_ring_buffer_num_entries * sizeof(float*), float* );- {- int j;- for( j = 0 ; j < alloc_ring_buffer_num_entries ; j++ )- {- STBIR__NEXT_PTR( info->split_info[i].ring_buffers[j], ring_buffer_length_bytes, float );- #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 - }- }-#else- STBIR__NEXT_PTR( info->split_info[i].ring_buffer, ring_buffer_size, float );-#endif- STBIR__NEXT_PTR( info->split_info[i].vertical_buffer, vertical_buffer_size, float );- }-- // alloc memory for to-be-pivoted coeffs (if necessary)- if ( vertical->is_gather == 0 )- {- int both;- int temp_mem_amt;-- // when in vertical scatter mode, we first build the coefficients in gather mode, and then pivot after,- // that means we need two buffers, so we try to use the decode buffer and ring buffer for this. if that- // is too small, we just allocate extra memory to use as this temp.-- both = vertical->gather_prescatter_contributors_size + vertical->gather_prescatter_coefficients_size;--#ifdef STBIR__SEPARATE_ALLOCATIONS- temp_mem_amt = decode_buffer_size;-#else- temp_mem_amt = ( decode_buffer_size + ring_buffer_size + vertical_buffer_size ) * splits;-#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 ); - }- }- else- {- // ring+decode memory is too small, so allocate temp memory- STBIR__NEXT_PTR( vertical->gather_prescatter_contributors, vertical->gather_prescatter_contributors_size, stbir__contributors );- STBIR__NEXT_PTR( vertical->gather_prescatter_coefficients, vertical->gather_prescatter_coefficients_size, float );- }- }-- STBIR__NEXT_PTR( horizontal->contributors, horizontal->contributors_size, stbir__contributors );- STBIR__NEXT_PTR( horizontal->coefficients, horizontal->coefficients_size, float );-- // are the two filters identical?? (happens a lot with mipmap generation)- if ( ( horizontal->filter_kernel == vertical->filter_kernel ) && ( horizontal->filter_support == vertical->filter_support ) && ( horizontal->edge == vertical->edge ) && ( horizontal->scale_info.output_sub_size == vertical->scale_info.output_sub_size ) )- {- float diff_scale = horizontal->scale_info.scale - vertical->scale_info.scale;- float diff_shift = horizontal->scale_info.pixel_shift - vertical->scale_info.pixel_shift;- if ( diff_scale < 0.0f ) diff_scale = -diff_scale;- 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 ) - {- copy_horizontal = 1;- goto no_vert_alloc;- }- // everything matches, but vertical is scatter, horizontal is gather, use horizontal coeffs for vertical pivot coeffs- possibly_use_horizontal_for_pivot = horizontal;- }- }-- STBIR__NEXT_PTR( vertical->contributors, vertical->contributors_size, stbir__contributors );- STBIR__NEXT_PTR( vertical->coefficients, vertical->coefficients_size, float );-- no_vert_alloc:-- if ( info )- {- STBIR_PROFILE_BUILD_START( horizontal );-- stbir__calculate_filters( horizontal, 0, user_data STBIR_ONLY_PROFILE_BUILD_SET_INFO );-- // setup the horizontal gather functions- // start with defaulting to the n_coeffs functions (specialized on channels and remnant leftover)- info->horizontal_gather_channels = stbir__horizontal_gather_n_coeffs_funcs[ effective_channels ][ horizontal->extent_info.widest & 3 ];- // 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 );- - STBIR_MEMCPY( &info->horizontal, horizontal, sizeof( stbir__sampler ) );-- STBIR_PROFILE_BUILD_END( horizontal );-- if ( copy_horizontal )- {- STBIR_MEMCPY( &info->vertical, horizontal, sizeof( stbir__sampler ) );- }- else- {- STBIR_PROFILE_BUILD_START( vertical );-- stbir__calculate_filters( vertical, possibly_use_horizontal_for_pivot, user_data STBIR_ONLY_PROFILE_BUILD_SET_INFO );- STBIR_MEMCPY( &info->vertical, vertical, sizeof( stbir__sampler ) );-- STBIR_PROFILE_BUILD_END( vertical );- }-- // setup the vertical split ranges- stbir__get_split_info( info->split_info, info->splits, info->vertical.scale_info.output_sub_size, info->vertical.filter_pixel_margin, info->vertical.scale_info.input_full_size );-- // now we know precisely how many entries we need- info->ring_buffer_num_entries = info->vertical.extent_info.widest;-- // we never need more ring buffer entries than the scanlines we're outputting- if ( ( !info->vertical.is_gather ) && ( info->ring_buffer_num_entries > conservative_split_output_size ) )- 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- 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;-- // if vertical filtering first, place a known, but numerically valid value in the all- // of the ring buffer accumulators- if ( vertical_first )- {- 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;- }- }- }- }-- #undef STBIR__NEXT_PTR--- // is this the first time through loop?- if ( info == 0 )- {- alloced_total = (int) ( 15 + (size_t)advance_mem );- alloced = STBIR_MALLOC( alloced_total, user_data );- if ( alloced == 0 )- return 0;- }- else- return info; // success- }-}--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;-- STBIR_PROFILE_CLEAR_EXTRAS();-- STBIR_PROFILE_FIRST_START( looping );- if (info->vertical.is_gather)- stbir__vertical_gather_loop( info, split_info, split_count );- else- stbir__vertical_scatter_loop( info, split_info, split_count );- STBIR_PROFILE_END( looping );-- return 1;-}--static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * resize )-{- 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, - };-- static stbir__decode_pixels_func * decode_alphas[STBIRI_AR-STBIRI_RGBA+1][STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]=- {- { /* RGBA */ stbir__decode_uint8_srgb4_linearalpha, stbir__decode_uint8_srgb, 0, stbir__decode_float_linear, stbir__decode_half_float_linear },- { /* BGRA */ stbir__decode_uint8_srgb4_linearalpha_BGRA, stbir__decode_uint8_srgb_BGRA, 0, stbir__decode_float_linear_BGRA, stbir__decode_half_float_linear_BGRA },- { /* ARGB */ stbir__decode_uint8_srgb4_linearalpha_ARGB, stbir__decode_uint8_srgb_ARGB, 0, stbir__decode_float_linear_ARGB, stbir__decode_half_float_linear_ARGB },- { /* ABGR */ stbir__decode_uint8_srgb4_linearalpha_ABGR, stbir__decode_uint8_srgb_ABGR, 0, stbir__decode_float_linear_ABGR, stbir__decode_half_float_linear_ABGR },- { /* RA */ stbir__decode_uint8_srgb2_linearalpha, stbir__decode_uint8_srgb, 0, stbir__decode_float_linear, stbir__decode_half_float_linear },- { /* AR */ stbir__decode_uint8_srgb2_linearalpha_AR, stbir__decode_uint8_srgb_AR, 0, stbir__decode_float_linear_AR, stbir__decode_half_float_linear_AR },- };-- static stbir__decode_pixels_func * decode_simple_scaled_or_not[2][2]=- {- { stbir__decode_uint8_linear_scaled, stbir__decode_uint8_linear }, { stbir__decode_uint16_linear_scaled, stbir__decode_uint16_linear },- };-- static stbir__decode_pixels_func * decode_alphas_scaled_or_not[STBIRI_AR-STBIRI_RGBA+1][2][2]=- {- { /* RGBA */ { stbir__decode_uint8_linear_scaled, stbir__decode_uint8_linear }, { stbir__decode_uint16_linear_scaled, stbir__decode_uint16_linear } },- { /* BGRA */ { stbir__decode_uint8_linear_scaled_BGRA, stbir__decode_uint8_linear_BGRA }, { stbir__decode_uint16_linear_scaled_BGRA, stbir__decode_uint16_linear_BGRA } },- { /* ARGB */ { stbir__decode_uint8_linear_scaled_ARGB, stbir__decode_uint8_linear_ARGB }, { stbir__decode_uint16_linear_scaled_ARGB, stbir__decode_uint16_linear_ARGB } },- { /* ABGR */ { stbir__decode_uint8_linear_scaled_ABGR, stbir__decode_uint8_linear_ABGR }, { stbir__decode_uint16_linear_scaled_ABGR, stbir__decode_uint16_linear_ABGR } },- { /* RA */ { stbir__decode_uint8_linear_scaled, stbir__decode_uint8_linear }, { stbir__decode_uint16_linear_scaled, stbir__decode_uint16_linear } },- { /* AR */ { stbir__decode_uint8_linear_scaled_AR, stbir__decode_uint8_linear_AR }, { stbir__decode_uint16_linear_scaled_AR, stbir__decode_uint16_linear_AR } }- };-- static stbir__encode_pixels_func * encode_simple[STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]=- {- /* 1ch-4ch */ stbir__encode_uint8_srgb, stbir__encode_uint8_srgb, 0, stbir__encode_float_linear, stbir__encode_half_float_linear,- };-- static stbir__encode_pixels_func * encode_alphas[STBIRI_AR-STBIRI_RGBA+1][STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]=- {- { /* RGBA */ stbir__encode_uint8_srgb4_linearalpha, stbir__encode_uint8_srgb, 0, stbir__encode_float_linear, stbir__encode_half_float_linear },- { /* BGRA */ stbir__encode_uint8_srgb4_linearalpha_BGRA, stbir__encode_uint8_srgb_BGRA, 0, stbir__encode_float_linear_BGRA, stbir__encode_half_float_linear_BGRA },- { /* ARGB */ stbir__encode_uint8_srgb4_linearalpha_ARGB, stbir__encode_uint8_srgb_ARGB, 0, stbir__encode_float_linear_ARGB, stbir__encode_half_float_linear_ARGB },- { /* ABGR */ stbir__encode_uint8_srgb4_linearalpha_ABGR, stbir__encode_uint8_srgb_ABGR, 0, stbir__encode_float_linear_ABGR, stbir__encode_half_float_linear_ABGR },- { /* RA */ stbir__encode_uint8_srgb2_linearalpha, stbir__encode_uint8_srgb, 0, stbir__encode_float_linear, stbir__encode_half_float_linear },- { /* AR */ stbir__encode_uint8_srgb2_linearalpha_AR, stbir__encode_uint8_srgb_AR, 0, stbir__encode_float_linear_AR, stbir__encode_half_float_linear_AR }- };-- static stbir__encode_pixels_func * encode_simple_scaled_or_not[2][2]=- {- { stbir__encode_uint8_linear_scaled, stbir__encode_uint8_linear }, { stbir__encode_uint16_linear_scaled, stbir__encode_uint16_linear },- };-- static stbir__encode_pixels_func * encode_alphas_scaled_or_not[STBIRI_AR-STBIRI_RGBA+1][2][2]=- {- { /* RGBA */ { stbir__encode_uint8_linear_scaled, stbir__encode_uint8_linear }, { stbir__encode_uint16_linear_scaled, stbir__encode_uint16_linear } },- { /* BGRA */ { stbir__encode_uint8_linear_scaled_BGRA, stbir__encode_uint8_linear_BGRA }, { stbir__encode_uint16_linear_scaled_BGRA, stbir__encode_uint16_linear_BGRA } },- { /* ARGB */ { stbir__encode_uint8_linear_scaled_ARGB, stbir__encode_uint8_linear_ARGB }, { stbir__encode_uint16_linear_scaled_ARGB, stbir__encode_uint16_linear_ARGB } },- { /* ABGR */ { stbir__encode_uint8_linear_scaled_ABGR, stbir__encode_uint8_linear_ABGR }, { stbir__encode_uint16_linear_scaled_ABGR, stbir__encode_uint16_linear_ABGR } },- { /* RA */ { stbir__encode_uint8_linear_scaled, stbir__encode_uint8_linear }, { stbir__encode_uint16_linear_scaled, stbir__encode_uint16_linear } },- { /* AR */ { stbir__encode_uint8_linear_scaled_AR, stbir__encode_uint8_linear_AR }, { stbir__encode_uint16_linear_scaled_AR, stbir__encode_uint16_linear_AR } }- };-- stbir__decode_pixels_func * decode_pixels = 0;- stbir__encode_pixels_func * encode_pixels = 0;- stbir_datatype input_type, output_type;-- input_type = resize->input_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;-- // 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 ) ) && - ( ( output_type == STBIR_TYPE_UINT8_SRGB ) || ( output_type == STBIR_TYPE_UINT8_SRGB_ALPHA ) ) )- {- input_type = STBIR_TYPE_UINT8;- output_type = STBIR_TYPE_UINT8;- }- }-- // 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];-- if ( info->output_stride_bytes == 0 )- 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->in_pixels_cb = resize->input_cb;- info->user_data = resize->user_data;- info->out_pixels_cb = resize->output_cb;-- // setup the input format converters- if ( ( input_type == STBIR_TYPE_UINT8 ) || ( input_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 ) ) )- non_scaled = 1;-- if ( info->input_pixel_layout_internal <= STBIRI_4CHANNEL )- decode_pixels = decode_simple_scaled_or_not[ input_type == STBIR_TYPE_UINT16 ][ non_scaled ];- else- decode_pixels = decode_alphas_scaled_or_not[ ( info->input_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR-STBIRI_RGBA+1 ) ][ input_type == STBIR_TYPE_UINT16 ][ non_scaled ];- }- else- {- if ( info->input_pixel_layout_internal <= STBIRI_4CHANNEL )- decode_pixels = decode_simple[ input_type - STBIR_TYPE_UINT8_SRGB ];- else- decode_pixels = decode_alphas[ ( info->input_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR-STBIRI_RGBA+1 ) ][ input_type - STBIR_TYPE_UINT8_SRGB ];- }-- // setup the output format converters- 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 ) ) )- non_scaled = 1;-- if ( info->output_pixel_layout_internal <= STBIRI_4CHANNEL )- encode_pixels = encode_simple_scaled_or_not[ output_type == STBIR_TYPE_UINT16 ][ non_scaled ];- else- encode_pixels = encode_alphas_scaled_or_not[ ( info->output_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR-STBIRI_RGBA+1 ) ][ output_type == STBIR_TYPE_UINT16 ][ non_scaled ];- }- else- {- if ( info->output_pixel_layout_internal <= STBIRI_4CHANNEL )- encode_pixels = encode_simple[ output_type - STBIR_TYPE_UINT8_SRGB ];- else- encode_pixels = encode_alphas[ ( info->output_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR-STBIRI_RGBA+1 ) ][ output_type - STBIR_TYPE_UINT8_SRGB ];- }-- info->input_type = input_type;- info->output_type = output_type; - info->decode_pixels = decode_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 )- {- per = ( (double)*outx ) / ( (double)*outsubw ); // is negative- adj = per * ( *u1 - *u0 );- *u0 -= adj; // increases u0- *outx = 0;- }-- // do right/bot edge- over = outw - ( *outx + *outsubw );- if ( over < 0 )- {- per = ( (double)over ) / ( (double)*outsubw ); // is negative- adj = per * ( *u1 - *u0 );- *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)-{- double err;- stbir_uint64 top, bot;- stbir_uint64 numer_last = 0;- stbir_uint64 denom_last = 1;- stbir_uint64 numer_estimate = 1;- stbir_uint64 denom_estimate = 0;-- // scale to past float error range- top = (stbir_uint64)( f * (double)(1 << 25) );- bot = 1 << 25;-- // keep refining, but usually stops in a few loops - usually 5 for bad cases- for(;;) - {- stbir_uint64 est, temp;-- // hit limit, break out and do best full range estimate- if ( ( ( limit_denom ) ? denom_estimate : numer_estimate ) >= limit )- break;-- // is the current error less than 1 bit of a float? if so, we're done- if ( denom_estimate )- {- err = ( (double)numer_estimate / (double)denom_estimate ) - f;- if ( err < 0.0 ) err = -err;- if ( err < ( 1.0 / (double)(1<<24) ) )- {- // yup, found it- *numer = (stbir_uint32) numer_estimate;- *denom = (stbir_uint32) denom_estimate;- return 1;- }- }-- // no more refinement bits left? break out and do full range estimate- if ( bot == 0 )- break;-- // gcd the estimate bits- est = top / bot;- temp = top % bot;- top = bot;- bot = temp;-- // move remainders- 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; - numer_estimate = temp;- }-- // we didn't fine anything good enough for float, use a full range estimate- if ( limit_denom )- {- numer_estimate= (stbir_uint64)( f * (double)limit + 0.5 );- denom_estimate = limit;- }- else- {- numer_estimate = limit;- denom_estimate = (stbir_uint64)( ( (double)limit / f ) + 0.5 );- }-- *numer = (stbir_uint32) numer_estimate;- *denom = (stbir_uint32) denom_estimate;-- err = ( denom_estimate ) ? ( ( (double)(stbir_uint32)numer_estimate / (double)(stbir_uint32)denom_estimate ) - f ) : 1.0;- if ( err < 0.0 ) err = -err;- return ( err < ( 1.0 / (double)(1<<24) ) ) ? 1 : 0;-}--static int stbir__calculate_region_transform( stbir__scale_info * scale_info, int output_full_range, int * output_offset, int output_sub_range, int input_full_range, double input_s0, double input_s1 )-{- double output_range, input_range, output_s, input_s, ratio, scale;-- input_s = input_s1 - input_s0;-- // null area- if ( ( output_full_range == 0 ) || ( input_full_range == 0 ) ||- ( output_sub_range == 0 ) || ( input_s <= stbir__small_float ) )- return 0;-- // are either of the ranges completely out of bounds?- if ( ( *output_offset >= output_full_range ) || ( ( *output_offset + output_sub_range ) <= 0 ) || ( input_s0 >= (1.0f-stbir__small_float) ) || ( input_s1 <= stbir__small_float ) )- return 0;-- output_range = (double)output_full_range;- input_range = (double)input_full_range;-- output_s = ( (double)output_sub_range) / output_range;-- // figure out the scaling to use - ratio = output_s / input_s; -- // save scale before clipping- scale = ( output_range / input_range ) * ratio; - scale_info->scale = (float)scale;- scale_info->inv_scale = (float)( 1.0 / scale );-- // clip output area to left/right output edges (and adjust input area)- stbir__clip( output_offset, &output_sub_range, output_full_range, &input_s0, &input_s1 );-- // recalc input area- input_s = input_s1 - input_s0;-- // after clipping do we have zero input area?- 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 ); -- 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 ) );-- scale_info->input_full_size = input_full_range;- scale_info->output_sub_size = output_sub_range;-- return 1;-}---static void stbir__init_and_set_layout( STBIR_RESIZE * resize, stbir_pixel_layout pixel_layout, stbir_datatype data_type )-{- resize->input_cb = 0;- 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;- resize->vertical_filter = STBIR_FILTER_DEFAULT;- resize->vertical_filter_kernel = 0; resize->vertical_filter_support = 0;- resize->horizontal_edge = STBIR_EDGE_CLAMP;- resize->vertical_edge = STBIR_EDGE_CLAMP;- resize->input_s0 = 0; resize->input_t0 = 0; resize->input_s1 = 1; resize->input_t1 = 1;- resize->output_subx = 0; resize->output_suby = 0; resize->output_subw = resize->output_w; resize->output_subh = resize->output_h;- resize->input_data_type = data_type;- resize->output_data_type = data_type;- resize->input_pixel_layout_public = pixel_layout;- resize->output_pixel_layout_public = pixel_layout;-}--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 )-{- resize->input_pixels = input_pixels;- resize->input_w = input_w;- resize->input_h = input_h;- resize->input_stride_in_bytes = input_stride_in_bytes;- resize->output_pixels = output_pixels;- resize->output_w = output_w;- resize->output_h = output_h;- resize->output_stride_in_bytes = output_stride_in_bytes;- resize->fast_alpha = 0;-- stbir__init_and_set_layout( resize, pixel_layout, data_type );-}--// You can update parameters any time after resize_init-STBIRDEF void stbir_set_datatypes( STBIR_RESIZE * resize, stbir_datatype input_type, stbir_datatype output_type ) // by default, datatype from resize_init-{- resize->input_data_type = input_type;- resize->output_data_type = 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-{- resize->input_cb = input_cb;- resize->output_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;-}--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 )-{- resize->input_pixels = input_pixels;- resize->input_stride_in_bytes = input_stride_in_bytes;- resize->output_pixels = output_pixels;- resize->output_stride_in_bytes = output_stride_in_bytes;-}---STBIRDEF int stbir_set_edgemodes( STBIR_RESIZE * resize, stbir_edge horizontal_edge, stbir_edge vertical_edge ) // CLAMP by default-{- resize->horizontal_edge = horizontal_edge;- resize->vertical_edge = vertical_edge;- resize->needs_rebuild = 1;- return 1;-}--STBIRDEF int stbir_set_filters( STBIR_RESIZE * resize, stbir_filter horizontal_filter, stbir_filter vertical_filter ) // STBIR_DEFAULT_FILTER_UPSAMPLE/DOWNSAMPLE by default-{- resize->horizontal_filter = horizontal_filter;- resize->vertical_filter = vertical_filter;- resize->needs_rebuild = 1;- return 1;-}--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 )-{- resize->horizontal_filter_kernel = horizontal_filter; resize->horizontal_filter_support = horizontal_support;- resize->vertical_filter_kernel = vertical_filter; resize->vertical_filter_support = vertical_support;- resize->needs_rebuild = 1;- return 1;-}--STBIRDEF int stbir_set_pixel_layouts( STBIR_RESIZE * resize, stbir_pixel_layout input_pixel_layout, stbir_pixel_layout output_pixel_layout ) // sets new pixel layouts-{- resize->input_pixel_layout_public = input_pixel_layout;- resize->output_pixel_layout_public = output_pixel_layout;- resize->needs_rebuild = 1;- return 1;-}---STBIRDEF int stbir_set_non_pm_alpha_speed_over_quality( STBIR_RESIZE * resize, int non_pma_alpha_speed_over_quality ) // sets alpha speed-{- resize->fast_alpha = non_pma_alpha_speed_over_quality;- resize->needs_rebuild = 1;- return 1;-}--STBIRDEF int stbir_set_input_subrect( STBIR_RESIZE * resize, double s0, double t0, double s1, double t1 ) // sets input region (full region by default)-{- resize->input_s0 = s0;- resize->input_t0 = t0;- resize->input_s1 = s1;- resize->input_t1 = t1;- resize->needs_rebuild = 1;-- // are we inbounds?- if ( ( s1 < stbir__small_float ) || ( (s1-s0) < stbir__small_float ) ||- ( t1 < stbir__small_float ) || ( (t1-t0) < stbir__small_float ) ||- ( s0 > (1.0f-stbir__small_float) ) ||- ( t0 > (1.0f-stbir__small_float) ) )- return 0;-- return 1;-}--STBIRDEF int stbir_set_output_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, int subw, int subh ) // sets input region (full region by default)-{- resize->output_subx = subx;- resize->output_suby = suby;- resize->output_subw = subw;- resize->output_subh = subh;- resize->needs_rebuild = 1;-- // are we inbounds?- if ( ( subx >= resize->output_w ) || ( ( subx + subw ) <= 0 ) || ( suby >= resize->output_h ) || ( ( suby + subh ) <= 0 ) || ( subw == 0 ) || ( subh == 0 ) )- return 0;-- return 1;-}--STBIRDEF int stbir_set_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, int subw, int subh ) // sets both regions (full regions by default)-{- double s0, t0, s1, t1;-- s0 = ( (double)subx ) / ( (double)resize->output_w );- t0 = ( (double)suby ) / ( (double)resize->output_h );- s1 = ( (double)(subx+subw) ) / ( (double)resize->output_w );- t1 = ( (double)(suby+subh) ) / ( (double)resize->output_h );-- resize->input_s0 = s0;- resize->input_t0 = t0;- resize->input_s1 = s1;- resize->input_t1 = t1;- resize->output_subx = subx;- resize->output_suby = suby;- resize->output_subw = subw;- resize->output_subh = subh;- resize->needs_rebuild = 1;-- // are we inbounds?- if ( ( subx >= resize->output_w ) || ( ( subx + subw ) <= 0 ) || ( suby >= resize->output_h ) || ( ( suby + subh ) <= 0 ) || ( subw == 0 ) || ( subh == 0 ) )- return 0;-- return 1;-}--static int stbir__perform_build( STBIR_RESIZE * resize, int splits ) -{- stbir__contributors conservative = { 0, 0 };- stbir__sampler horizontal, vertical;- int new_output_subx, new_output_suby;- stbir__info * out_info;- #ifdef STBIR_PROFILE- stbir__info profile_infod; // used to contain building profile info before everything is allocated- stbir__info * profile_info = &profile_infod;- #endif-- // 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 ) - return 0;-- STBIR_PROFILE_BUILD_FIRST_START( build );-- new_output_subx = resize->output_subx;- new_output_suby = resize->output_suby;-- // do horizontal clip and scale calcs- if ( !stbir__calculate_region_transform( &horizontal.scale_info, resize->output_w, &new_output_subx, resize->output_subw, resize->input_w, resize->input_s0, resize->input_s1 ) )- return 0;-- // do vertical clip and scale calcs- if ( !stbir__calculate_region_transform( &vertical.scale_info, resize->output_h, &new_output_suby, resize->output_subh, resize->input_h, resize->input_t0, resize->input_t1 ) )- return 0;-- // if nothing to do, just return- if ( ( horizontal.scale_info.output_sub_size == 0 ) || ( vertical.scale_info.output_sub_size == 0 ) )- return 0;-- stbir__set_sampler(&horizontal, resize->horizontal_filter, resize->horizontal_filter_kernel, resize->horizontal_filter_support, resize->horizontal_edge, &horizontal.scale_info, 1, resize->user_data );- 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)- {- splits = vertical.scale_info.output_sub_size / 4;- if ( splits == 0 ) splits = 1;- }-- STBIR_PROFILE_BUILD_START( alloc );- 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;- resize->samplers = out_info;- resize->needs_rebuild = 0;- #ifdef STBIR_PROFILE- STBIR_MEMCPY( &out_info->profile, &profile_infod.profile, sizeof( out_info->profile ) );- #endif- return splits;- }-- return 0;-}--void stbir_free_samplers( STBIR_RESIZE * resize )-{- if ( resize->samplers )- {- stbir__free_internal_mem( resize->samplers );- resize->samplers = 0;- resize->called_alloc = 0;- }-}--STBIRDEF int stbir_build_samplers_with_splits( STBIR_RESIZE * resize, int splits )-{- if ( ( resize->samplers == 0 ) || ( resize->needs_rebuild ) )- {- if ( resize->samplers )- stbir_free_samplers( resize );-- resize->called_alloc = 1;- return stbir__perform_build( resize, splits );- }-- STBIR_PROFILE_BUILD_CLEAR( resize->samplers );- - return 1;-}--STBIRDEF int stbir_build_samplers( STBIR_RESIZE * resize )-{- return stbir_build_samplers_with_splits( resize, 1 );-}--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-- if ( resize->samplers )- {- stbir__free_internal_mem( resize->samplers );- resize->samplers = 0;- }-- if ( !stbir_build_samplers( resize ) )- return 0;- - resize->called_alloc = alloc_state;-- // 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 )- return 1;- }- else- {- // didn't build anything - clear it- 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 );-- // if we alloced, then free- if ( !resize->called_alloc )- {- stbir_free_samplers( resize );- resize->samplers = 0;- } -- return result;-}--STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start, int split_count )-{- STBIR_ASSERT( resize->samplers );-- // if we're just doing the whole thing, call full- if ( ( split_start == -1 ) || ( ( split_start == 0 ) && ( split_count == resize->splits ) ) )- return stbir_resize_extended( resize );-- // you **must** build samplers first when using split resize- if ( ( resize->samplers == 0 ) || ( resize->needs_rebuild ) )- 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 );-}--static int stbir__check_output_stuff( void ** ret_ptr, int * ret_pitch, void * output_pixels, int type_size, int output_w, int output_h, int output_stride_in_bytes, stbir_internal_pixel_layout pixel_layout )-{- size_t size;- int pitch;- void * ptr;-- pitch = output_w * type_size * stbir__pixel_channels[ pixel_layout ];- if ( pitch == 0 )- return 0;-- if ( output_stride_in_bytes == 0 )- output_stride_in_bytes = pitch;-- if ( output_stride_in_bytes < pitch )- return 0;-- size = output_stride_in_bytes * output_h;- if ( size == 0 )- return 0;-- *ret_ptr = 0;- *ret_pitch = output_stride_in_bytes;-- if ( output_pixels == 0 )- {- ptr = STBIR_MALLOC( size, 0 );- if ( ptr == 0 )- return 0;-- *ret_ptr = ptr;- *ret_pitch = pitch;- }-- return 1; -}---STBIRDEF unsigned char * stbir_resize_uint8_linear( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes,- unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,- stbir_pixel_layout pixel_layout )-{- STBIR_RESIZE resize;- unsigned char * optr;- int opitch;-- 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, - pixel_layout, STBIR_TYPE_UINT8 );-- if ( !stbir_resize_extended( &resize ) )- {- if ( optr )- STBIR_FREE( optr, 0 );- return 0;- }-- return (optr) ? optr : output_pixels;-}--STBIRDEF unsigned char * stbir_resize_uint8_srgb( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes,- unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,- stbir_pixel_layout pixel_layout )-{- STBIR_RESIZE resize;- unsigned char * optr;- int opitch;-- 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, - pixel_layout, STBIR_TYPE_UINT8_SRGB );-- if ( !stbir_resize_extended( &resize ) )- {- if ( optr )- STBIR_FREE( optr, 0 );- return 0;- }-- return (optr) ? optr : output_pixels;-}---STBIRDEF float * stbir_resize_float_linear( const float *input_pixels , int input_w , int input_h, int input_stride_in_bytes,- float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,- stbir_pixel_layout pixel_layout )-{- STBIR_RESIZE resize;- float * optr;- int opitch;-- 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, - pixel_layout, STBIR_TYPE_FLOAT );-- if ( !stbir_resize_extended( &resize ) )- {- if ( optr )- STBIR_FREE( optr, 0 );- return 0;- }-- return (optr) ? optr : output_pixels;-}---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_edge edge, stbir_filter filter )-{- STBIR_RESIZE resize;- float * optr;- int opitch;-- 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, - pixel_layout, data_type );-- resize.horizontal_edge = edge;- resize.vertical_edge = edge;- resize.horizontal_filter = filter;- resize.vertical_filter = filter;-- if ( !stbir_resize_extended( &resize ) )- {- if ( optr )- STBIR_FREE( optr, 0 );- return 0;- }-- return (optr) ? optr : output_pixels;-}--#ifdef STBIR_PROFILE--STBIRDEF void stbir_resize_build_profile_info( STBIR_PROFILE_INFO * info, STBIR_RESIZE const * resize )-{- static char const * bdescriptions[6] = { "Building", "Allocating", "Horizontal sampler", "Vertical sampler", "Coefficient cleanup", "Coefficient piovot" } ;- stbir__info* samp = resize->samplers;- int i;-- typedef int testa[ (STBIR__ARRAY_SIZE( bdescriptions ) == (STBIR__ARRAY_SIZE( samp->profile.array )-1) )?1:-1];- typedef int testb[ (sizeof( samp->profile.array ) == (sizeof(samp->profile.named)) )?1:-1];- typedef int testc[ (sizeof( info->clocks ) >= (sizeof(samp->profile.named)) )?1:-1];-- for( i = 0 ; i < STBIR__ARRAY_SIZE( bdescriptions ) ; i++)- info->clocks[i] = samp->profile.array[i+1];-- info->total_clocks = samp->profile.named.total;- info->descriptions = bdescriptions;- info->count = STBIR__ARRAY_SIZE( bdescriptions );-}--STBIRDEF void stbir_resize_split_profile_info( STBIR_PROFILE_INFO * info, STBIR_RESIZE const * resize, int split_start, int split_count )-{- static char const * descriptions[7] = { "Looping", "Vertical sampling", "Horizontal sampling", "Scanline input", "Scanline output", "Alpha weighting", "Alpha unweighting" };- stbir__per_split_info * split_info;- int s, i;-- typedef int testa[ (STBIR__ARRAY_SIZE( descriptions ) == (STBIR__ARRAY_SIZE( split_info->profile.array )-1) )?1:-1];- typedef int testb[ (sizeof( split_info->profile.array ) == (sizeof(split_info->profile.named)) )?1:-1];- typedef int testc[ (sizeof( info->clocks ) >= (sizeof(split_info->profile.named)) )?1:-1];-- if ( split_start == -1 )- {- split_start = 0;- split_count = resize->samplers->splits;- }-- if ( ( split_start >= resize->splits ) || ( split_start < 0 ) || ( ( split_start + split_count ) > resize->splits ) || ( split_count <= 0 ) )- {- info->total_clocks = 0;- info->descriptions = 0;- info->count = 0;- return;- }-- split_info = resize->samplers->split_info + split_start;-- // sum up the profile from all the splits- for( i = 0 ; i < STBIR__ARRAY_SIZE( descriptions ) ; i++ )- {- stbir_uint64 sum = 0;- for( s = 0 ; s < split_count ; s++ )- sum += split_info[s].profile.array[i+1];- info->clocks[i] = sum;- }-- info->total_clocks = split_info->profile.named.total;- info->descriptions = descriptions;- info->count = STBIR__ARRAY_SIZE( descriptions );-}--STBIRDEF void stbir_resize_extended_profile_info( STBIR_PROFILE_INFO * info, STBIR_RESIZE const * resize )-{- stbir_resize_split_profile_info( info, resize, -1, 0 );-}--#endif // STBIR_PROFILE--#undef STBIR_BGR-#undef STBIR_1CHANNEL-#undef STBIR_2CHANNEL-#undef STBIR_RGB-#undef STBIR_RGBA-#undef STBIR_4CHANNEL-#undef STBIR_BGRA-#undef STBIR_ARGB-#undef STBIR_ABGR-#undef STBIR_RA-#undef STBIR_AR-#undef STBIR_RGBA_PM-#undef STBIR_BGRA_PM-#undef STBIR_ARGB_PM-#undef STBIR_ABGR_PM-#undef STBIR_RA_PM-#undef STBIR_AR_PM--#endif // STB_IMAGE_RESIZE_IMPLEMENTATION--#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* --// by including the header file again this way, we can still debug the functions--#define STBIR_strs_join2( start, mid, end ) start##mid##end-#define STBIR_strs_join1( start, mid, end ) STBIR_strs_join2( start, mid, end )--#define STBIR_strs_join24( start, mid1, mid2, end ) start##mid1##mid2##end-#define STBIR_strs_join14( start, mid1, mid2, end ) STBIR_strs_join24( start, mid1, mid2, end )--#ifdef STB_IMAGE_RESIZE_DO_CODERS--#ifdef stbir__decode_suffix-#define STBIR__CODER_NAME( name ) STBIR_strs_join1( name, _, stbir__decode_suffix )-#else-#define STBIR__CODER_NAME( name ) name-#endif--#ifdef stbir__decode_swizzle-#define stbir__decode_simdf8_flip(reg) STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( stbir__simdf8_0123to,stbir__decode_order0,stbir__decode_order1),stbir__decode_order2,stbir__decode_order3),stbir__decode_order0,stbir__decode_order1),stbir__decode_order2,stbir__decode_order3)(reg, reg)-#define stbir__decode_simdf4_flip(reg) STBIR_strs_join1( STBIR_strs_join1( stbir__simdf_0123to,stbir__decode_order0,stbir__decode_order1),stbir__decode_order2,stbir__decode_order3)(reg, reg)-#define stbir__encode_simdf8_unflip(reg) STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( stbir__simdf8_0123to,stbir__encode_order0,stbir__encode_order1),stbir__encode_order2,stbir__encode_order3),stbir__encode_order0,stbir__encode_order1),stbir__encode_order2,stbir__encode_order3)(reg, reg)-#define stbir__encode_simdf4_unflip(reg) STBIR_strs_join1( STBIR_strs_join1( stbir__simdf_0123to,stbir__encode_order0,stbir__encode_order1),stbir__encode_order2,stbir__encode_order3)(reg, reg)-#else-#define stbir__decode_order0 0-#define stbir__decode_order1 1-#define stbir__decode_order2 2-#define stbir__decode_order3 3-#define stbir__encode_order0 0-#define stbir__encode_order1 1-#define stbir__encode_order2 2-#define stbir__encode_order3 3-#define stbir__decode_simdf8_flip(reg)-#define stbir__decode_simdf4_flip(reg) -#define stbir__encode_simdf8_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 --static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * decodep, int width_times_channels, void const * inputp )-{- float STBIR_STREAMOUT_PTR( * ) decode = decodep;- float * decode_end = (float*) decode + width_times_channels;- unsigned char const * input = (unsigned char const*)inputp;-- #ifdef STBIR_SIMD- unsigned char const * end_input_m16 = input + width_times_channels - 16;- if ( width_times_channels >= 16 )- {- decode_end -= 16;- for(;;)- {- #ifdef STBIR_SIMD8- stbir__simdi i; stbir__simdi8 o0,o1;- stbir__simdf8 of0, of1;- STBIR_NO_UNROLL(decode);- stbir__simdi_load( i, input );- stbir__simdi8_expand_u8_to_u32( o0, o1, i );- stbir__simdi8_convert_i32_to_float( of0, o0 );- stbir__simdi8_convert_i32_to_float( of1, o1 );- stbir__simdf8_mult( of0, of0, STBIR_max_uint8_as_float_inverted8);- stbir__simdf8_mult( of1, of1, STBIR_max_uint8_as_float_inverted8);- stbir__decode_simdf8_flip( of0 );- stbir__decode_simdf8_flip( of1 );- stbir__simdf8_store( decode + 0, of0 );- stbir__simdf8_store( decode + 8, of1 );- #else- stbir__simdi i, o0, o1, o2, o3;- stbir__simdf of0, of1, of2, of3;- STBIR_NO_UNROLL(decode);- stbir__simdi_load( i, input );- stbir__simdi_expand_u8_to_u32( o0,o1,o2,o3,i);- stbir__simdi_convert_i32_to_float( of0, o0 );- stbir__simdi_convert_i32_to_float( of1, o1 );- stbir__simdi_convert_i32_to_float( of2, o2 );- stbir__simdi_convert_i32_to_float( of3, o3 );- stbir__simdf_mult( of0, of0, STBIR__CONSTF(STBIR_max_uint8_as_float_inverted) );- stbir__simdf_mult( of1, of1, STBIR__CONSTF(STBIR_max_uint8_as_float_inverted) );- stbir__simdf_mult( of2, of2, STBIR__CONSTF(STBIR_max_uint8_as_float_inverted) );- stbir__simdf_mult( of3, of3, STBIR__CONSTF(STBIR_max_uint8_as_float_inverted) );- stbir__decode_simdf4_flip( of0 );- stbir__decode_simdf4_flip( of1 );- stbir__decode_simdf4_flip( of2 );- stbir__decode_simdf4_flip( of3 );- stbir__simdf_store( decode + 0, of0 );- stbir__simdf_store( decode + 4, of1 );- stbir__simdf_store( decode + 8, of2 );- stbir__simdf_store( decode + 12, of3 );- #endif- decode += 16;- input += 16;- if ( decode <= decode_end ) - continue;- if ( decode == ( decode_end + 16 ) )- break;- decode = decode_end; // backup and do last couple- input = end_input_m16;- }- return;- }- #endif-- // try to do blocks of 4 when you can- #if stbir__coder_min_num != 3 // doesn't divide cleanly by four- decode += 4;- while( decode <= decode_end )- {- STBIR_SIMD_NO_UNROLL(decode);- decode[0-4] = ((float)(input[stbir__decode_order0])) * stbir__max_uint8_as_float_inverted;- decode[1-4] = ((float)(input[stbir__decode_order1])) * stbir__max_uint8_as_float_inverted;- decode[2-4] = ((float)(input[stbir__decode_order2])) * stbir__max_uint8_as_float_inverted;- decode[3-4] = ((float)(input[stbir__decode_order3])) * stbir__max_uint8_as_float_inverted;- decode += 4;- input += 4;- }- decode -= 4;- #endif-- // do the remnants- #if stbir__coder_min_num < 4- while( decode < decode_end )- {- STBIR_NO_UNROLL(decode);- decode[0] = ((float)(input[stbir__decode_order0])) * stbir__max_uint8_as_float_inverted;- #if stbir__coder_min_num >= 2- decode[1] = ((float)(input[stbir__decode_order1])) * stbir__max_uint8_as_float_inverted;- #endif- #if stbir__coder_min_num >= 3- decode[2] = ((float)(input[stbir__decode_order2])) * stbir__max_uint8_as_float_inverted;- #endif- decode += stbir__coder_min_num;- input += stbir__coder_min_num;- }- #endif-}--static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outputp, int width_times_channels, float const * encode )-{- unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char *) outputp;- unsigned char * end_output = ( (unsigned char *) output ) + width_times_channels;-- #ifdef STBIR_SIMD- if ( width_times_channels >= stbir__simdfX_float_count*2 )- {- float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2;- end_output -= stbir__simdfX_float_count*2;- for(;;)- {- stbir__simdfX e0, e1;- stbir__simdi i;- STBIR_SIMD_NO_UNROLL(encode);- stbir__simdfX_madd_mem( e0, STBIR_simd_point5X, STBIR_max_uint8_as_floatX, encode );- stbir__simdfX_madd_mem( e1, STBIR_simd_point5X, STBIR_max_uint8_as_floatX, encode+stbir__simdfX_float_count );- stbir__encode_simdfX_unflip( e0 );- stbir__encode_simdfX_unflip( e1 );- #ifdef STBIR_SIMD8- stbir__simdf8_pack_to_16bytes( i, e0, e1 ); - stbir__simdi_store( output, i );- #else- 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 ) - continue;- if ( output == ( end_output + stbir__simdfX_float_count*2 ) )- break;- output = end_output; // backup and do last couple- encode = end_encode_m8;- }- return;- }-- // try to do blocks of 4 when you can- #if stbir__coder_min_num != 3 // doesn't divide cleanly by four- output += 4;- while( output <= end_output )- {- stbir__simdf e0;- stbir__simdi i0;- STBIR_NO_UNROLL(encode);- stbir__simdf_load( e0, encode );- stbir__simdf_madd( e0, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint8_as_float), e0 );- stbir__encode_simdf4_unflip( e0 );- stbir__simdf_pack_to_8bytes( i0, e0, e0 ); // only use first 4- *(int*)(output-4) = stbir__simdi_to_int( i0 );- output += 4;- encode += 4;- }- output -= 4;- #endif-- // do the remnants- #if stbir__coder_min_num < 4- while( output < end_output )- {- 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- stbir__simdf_madd1_mem( e0, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint8_as_float), encode+stbir__encode_order1 ); output[1] = stbir__simdf_convert_float_to_uint8( e0 );- #endif- #if stbir__coder_min_num >= 3- stbir__simdf_madd1_mem( e0, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint8_as_float), encode+stbir__encode_order2 ); output[2] = stbir__simdf_convert_float_to_uint8( e0 );- #endif- output += stbir__coder_min_num;- 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;- while( output <= end_output )- {- float f;- f = encode[stbir__encode_order0] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[0-4] = (unsigned char)f;- f = encode[stbir__encode_order1] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[1-4] = (unsigned char)f;- f = encode[stbir__encode_order2] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[2-4] = (unsigned char)f;- f = encode[stbir__encode_order3] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[3-4] = (unsigned char)f;- output += 4;- encode += 4;- }- output -= 4;- #endif-- // do the remnants- #if stbir__coder_min_num < 4- while( output < end_output )- {- float f;- STBIR_NO_UNROLL(encode);- f = encode[stbir__encode_order0] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[0] = (unsigned char)f;- #if stbir__coder_min_num >= 2- f = encode[stbir__encode_order1] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[1] = (unsigned char)f;- #endif- #if stbir__coder_min_num >= 3- f = encode[stbir__encode_order2] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[2] = (unsigned char)f;- #endif- output += stbir__coder_min_num;- encode += stbir__coder_min_num;- }- #endif- #endif-}--static void STBIR__CODER_NAME(stbir__decode_uint8_linear)( float * decodep, int width_times_channels, void const * inputp )-{- float STBIR_STREAMOUT_PTR( * ) decode = decodep;- float * decode_end = (float*) decode + width_times_channels;- unsigned char const * input = (unsigned char const*)inputp;-- #ifdef STBIR_SIMD- unsigned char const * end_input_m16 = input + width_times_channels - 16;- if ( width_times_channels >= 16 )- {- decode_end -= 16;- for(;;)- {- #ifdef STBIR_SIMD8- stbir__simdi i; stbir__simdi8 o0,o1;- stbir__simdf8 of0, of1;- STBIR_NO_UNROLL(decode);- stbir__simdi_load( i, input );- stbir__simdi8_expand_u8_to_u32( o0, o1, i );- stbir__simdi8_convert_i32_to_float( of0, o0 );- stbir__simdi8_convert_i32_to_float( of1, o1 );- stbir__decode_simdf8_flip( of0 );- stbir__decode_simdf8_flip( of1 );- stbir__simdf8_store( decode + 0, of0 );- stbir__simdf8_store( decode + 8, of1 );- #else- stbir__simdi i, o0, o1, o2, o3;- stbir__simdf of0, of1, of2, of3;- STBIR_NO_UNROLL(decode);- stbir__simdi_load( i, input );- stbir__simdi_expand_u8_to_u32( o0,o1,o2,o3,i);- stbir__simdi_convert_i32_to_float( of0, o0 );- stbir__simdi_convert_i32_to_float( of1, o1 );- stbir__simdi_convert_i32_to_float( of2, o2 );- stbir__simdi_convert_i32_to_float( of3, o3 );- stbir__decode_simdf4_flip( of0 );- stbir__decode_simdf4_flip( of1 );- stbir__decode_simdf4_flip( of2 );- stbir__decode_simdf4_flip( of3 );- stbir__simdf_store( decode + 0, of0 );- stbir__simdf_store( decode + 4, of1 );- stbir__simdf_store( decode + 8, of2 );- stbir__simdf_store( decode + 12, of3 );-#endif- decode += 16;- input += 16;- if ( decode <= decode_end ) - continue;- if ( decode == ( decode_end + 16 ) )- break;- decode = decode_end; // backup and do last couple- input = end_input_m16;- }- return;- }- #endif-- // try to do blocks of 4 when you can- #if stbir__coder_min_num != 3 // doesn't divide cleanly by four- decode += 4;- while( decode <= decode_end )- {- STBIR_SIMD_NO_UNROLL(decode);- decode[0-4] = ((float)(input[stbir__decode_order0]));- decode[1-4] = ((float)(input[stbir__decode_order1]));- decode[2-4] = ((float)(input[stbir__decode_order2]));- decode[3-4] = ((float)(input[stbir__decode_order3]));- decode += 4;- input += 4;- }- decode -= 4;- #endif-- // do the remnants- #if stbir__coder_min_num < 4- while( decode < decode_end )- {- STBIR_NO_UNROLL(decode);- decode[0] = ((float)(input[stbir__decode_order0]));- #if stbir__coder_min_num >= 2- decode[1] = ((float)(input[stbir__decode_order1]));- #endif- #if stbir__coder_min_num >= 3- decode[2] = ((float)(input[stbir__decode_order2]));- #endif- decode += stbir__coder_min_num;- input += stbir__coder_min_num;- }- #endif-}--static void STBIR__CODER_NAME( stbir__encode_uint8_linear )( void * outputp, int width_times_channels, float const * encode )-{- unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char *) outputp;- unsigned char * end_output = ( (unsigned char *) output ) + width_times_channels;-- #ifdef STBIR_SIMD- if ( width_times_channels >= stbir__simdfX_float_count*2 )- {- float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2;- end_output -= stbir__simdfX_float_count*2;- for(;;)- {- stbir__simdfX e0, e1;- stbir__simdi i;- STBIR_SIMD_NO_UNROLL(encode);- stbir__simdfX_add_mem( e0, STBIR_simd_point5X, encode );- stbir__simdfX_add_mem( e1, STBIR_simd_point5X, encode+stbir__simdfX_float_count );- stbir__encode_simdfX_unflip( e0 );- stbir__encode_simdfX_unflip( e1 );- #ifdef STBIR_SIMD8- stbir__simdf8_pack_to_16bytes( i, e0, e1 ); - stbir__simdi_store( output, i );- #else- 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 ) - continue;- if ( output == ( end_output + stbir__simdfX_float_count*2 ) )- break;- output = end_output; // backup and do last couple- encode = end_encode_m8;- }- return;- }-- // try to do blocks of 4 when you can- #if stbir__coder_min_num != 3 // doesn't divide cleanly by four- output += 4;- while( output <= end_output )- {- stbir__simdf e0;- stbir__simdi i0;- STBIR_NO_UNROLL(encode);- stbir__simdf_load( e0, encode );- stbir__simdf_add( e0, STBIR__CONSTF(STBIR_simd_point5), e0 );- stbir__encode_simdf4_unflip( e0 );- stbir__simdf_pack_to_8bytes( i0, e0, e0 ); // only use first 4- *(int*)(output-4) = stbir__simdi_to_int( i0 );- output += 4;- encode += 4;- }- output -= 4;- #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;- while( output <= end_output )- {- float f;- f = encode[stbir__encode_order0] + 0.5f; STBIR_CLAMP(f, 0, 255); output[0-4] = (unsigned char)f;- f = encode[stbir__encode_order1] + 0.5f; STBIR_CLAMP(f, 0, 255); output[1-4] = (unsigned char)f;- f = encode[stbir__encode_order2] + 0.5f; STBIR_CLAMP(f, 0, 255); output[2-4] = (unsigned char)f;- f = encode[stbir__encode_order3] + 0.5f; STBIR_CLAMP(f, 0, 255); output[3-4] = (unsigned char)f;- output += 4;- encode += 4;- }- output -= 4;- #endif-- #endif-- // do the remnants- #if stbir__coder_min_num < 4- while( output < end_output )- {- float f;- STBIR_NO_UNROLL(encode);- f = encode[stbir__encode_order0] + 0.5f; STBIR_CLAMP(f, 0, 255); output[0] = (unsigned char)f;- #if stbir__coder_min_num >= 2- f = encode[stbir__encode_order1] + 0.5f; STBIR_CLAMP(f, 0, 255); output[1] = (unsigned char)f;- #endif- #if stbir__coder_min_num >= 3- f = encode[stbir__encode_order2] + 0.5f; STBIR_CLAMP(f, 0, 255); output[2] = (unsigned char)f;- #endif- output += stbir__coder_min_num;- encode += stbir__coder_min_num;- }- #endif-}--static void STBIR__CODER_NAME(stbir__decode_uint8_srgb)( float * decodep, int width_times_channels, void const * inputp )-{- float STBIR_STREAMOUT_PTR( * ) decode = decodep;- float const * decode_end = (float*) decode + width_times_channels;- unsigned char const * input = (unsigned char const *)inputp;-- // try to do blocks of 4 when you can- #if stbir__coder_min_num != 3 // doesn't divide cleanly by four- decode += 4;- while( decode <= decode_end )- {- decode[0-4] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order0 ] ];- decode[1-4] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order1 ] ];- decode[2-4] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order2 ] ];- decode[3-4] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order3 ] ];- decode += 4;- input += 4;- }- decode -= 4;- #endif-- // do the remnants- #if stbir__coder_min_num < 4- while( decode < decode_end )- {- STBIR_NO_UNROLL(decode);- decode[0] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order0 ] ];- #if stbir__coder_min_num >= 2- decode[1] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order1 ] ];- #endif- #if stbir__coder_min_num >= 3- decode[2] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order2 ] ];- #endif- decode += stbir__coder_min_num;- input += stbir__coder_min_num;- }- #endif-}--#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 ); --#define stbir__scale_and_convert( i, f ) \- stbir__simdf_madd( f, STBIR__CONSTF( STBIR_simd_point5 ), STBIR__CONSTF( STBIR_max_uint8_as_float ), f ); \- stbir__simdf_max( f, f, stbir__simdf_zeroP() ); \- stbir__simdf_min( f, f, STBIR__CONSTF( STBIR_max_uint8_as_float ) ); \- stbir__simdf_convert_float_to_i32( i, f );--#define stbir__linear_to_srgb_finish( i, f ) \-{ \- stbir__simdi temp; \- stbir__simdi_32shr( temp, stbir_simdi_castf( f ), 12 ) ; \- stbir__simdi_and( temp, temp, STBIR__CONSTI(STBIR_mastissa_mask) ); \- stbir__simdi_or( temp, temp, STBIR__CONSTI(STBIR_topscale) ); \- stbir__simdi_16madd( i, i, temp ); \- stbir__simdi_32shr( i, i, 16 ); \-}--#define stbir__simdi_table_lookup2( v0,v1, table ) \-{ \- stbir__simdi_u32 temp0,temp1; \- temp0.m128i_i128 = v0; \- temp1.m128i_i128 = v1; \- temp0.m128i_u32[0] = table[temp0.m128i_i32[0]]; temp0.m128i_u32[1] = table[temp0.m128i_i32[1]]; temp0.m128i_u32[2] = table[temp0.m128i_i32[2]]; temp0.m128i_u32[3] = table[temp0.m128i_i32[3]]; \- 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 ) \-{ \- stbir__simdi_u32 temp0,temp1,temp2; \- temp0.m128i_i128 = v0; \- temp1.m128i_i128 = v1; \- temp2.m128i_i128 = v2; \- temp0.m128i_u32[0] = table[temp0.m128i_i32[0]]; temp0.m128i_u32[1] = table[temp0.m128i_i32[1]]; temp0.m128i_u32[2] = table[temp0.m128i_i32[2]]; temp0.m128i_u32[3] = table[temp0.m128i_i32[3]]; \- 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]]; \- temp2.m128i_u32[0] = table[temp2.m128i_i32[0]]; temp2.m128i_u32[1] = table[temp2.m128i_i32[1]]; temp2.m128i_u32[2] = table[temp2.m128i_i32[2]]; temp2.m128i_u32[3] = table[temp2.m128i_i32[3]]; \- v0 = temp0.m128i_i128; \- v1 = temp1.m128i_i128; \- v2 = temp2.m128i_i128; \-}--#define stbir__simdi_table_lookup4( v0,v1,v2,v3, table ) \-{ \- stbir__simdi_u32 temp0,temp1,temp2,temp3; \- temp0.m128i_i128 = v0; \- temp1.m128i_i128 = v1; \- temp2.m128i_i128 = v2; \- temp3.m128i_i128 = v3; \- temp0.m128i_u32[0] = table[temp0.m128i_i32[0]]; temp0.m128i_u32[1] = table[temp0.m128i_i32[1]]; temp0.m128i_u32[2] = table[temp0.m128i_i32[2]]; temp0.m128i_u32[3] = table[temp0.m128i_i32[3]]; \- 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]]; \- temp2.m128i_u32[0] = table[temp2.m128i_i32[0]]; temp2.m128i_u32[1] = table[temp2.m128i_i32[1]]; temp2.m128i_u32[2] = table[temp2.m128i_i32[2]]; temp2.m128i_u32[3] = table[temp2.m128i_i32[3]]; \- temp3.m128i_u32[0] = table[temp3.m128i_i32[0]]; temp3.m128i_u32[1] = table[temp3.m128i_i32[1]]; temp3.m128i_u32[2] = table[temp3.m128i_i32[2]]; temp3.m128i_u32[3] = table[temp3.m128i_i32[3]]; \- v0 = temp0.m128i_i128; \- 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 )-{- unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char*) outputp;- 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;- for(;;)- {- stbir__simdf f0, f1, f2, f3;- stbir__simdi i0, i1, i2, i3; - STBIR_SIMD_NO_UNROLL(encode);-- stbir__simdf_load4_transposed( f0, f1, f2, f3, encode );-- stbir__min_max_shift20( i0, f0 );- 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__linear_to_srgb_finish( i0, f0 );- stbir__linear_to_srgb_finish( i1, f1 );- stbir__linear_to_srgb_finish( i2, f2 );- stbir__linear_to_srgb_finish( i3, f3 );-- stbir__interleave_pack_and_store_16_u8( output, STBIR_strs_join1(i, ,stbir__encode_order0), STBIR_strs_join1(i, ,stbir__encode_order1), STBIR_strs_join1(i, ,stbir__encode_order2), STBIR_strs_join1(i, ,stbir__encode_order3) );-- encode += 16;- output += 16;- if ( output <= end_output ) - continue;- if ( output == ( end_output + 16 ) )- break;- output = end_output; // backup and do last couple- encode = end_encode_m16;- }- return;- }- #endif-- // try to do blocks of 4 when you can- #if stbir__coder_min_num != 3 // doesn't divide cleanly by four- output += 4;- while ( output <= end_output )- {- STBIR_SIMD_NO_UNROLL(encode);-- output[0-4] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order0] );- output[1-4] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order1] );- output[2-4] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order2] );- output[3-4] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order3] );-- output += 4;- encode += 4;- }- output -= 4;- #endif-- // do the remnants- #if stbir__coder_min_num < 4- while( output < end_output ) - {- STBIR_NO_UNROLL(encode);- output[0] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order0] );- #if stbir__coder_min_num >= 2- output[1] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order1] );- #endif- #if stbir__coder_min_num >= 3- output[2] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order2] );- #endif- output += stbir__coder_min_num;- encode += stbir__coder_min_num;- }- #endif-}--#if ( stbir__coder_min_num == 4 ) || ( ( stbir__coder_min_num == 1 ) && ( !defined(stbir__decode_swizzle) ) )--static void STBIR__CODER_NAME(stbir__decode_uint8_srgb4_linearalpha)( float * decodep, int width_times_channels, void const * inputp )-{- float STBIR_STREAMOUT_PTR( * ) decode = decodep;- float const * decode_end = (float*) decode + width_times_channels;- unsigned char const * input = (unsigned char const *)inputp;- do {- decode[0] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order0] ];- decode[1] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order1] ];- decode[2] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order2] ];- decode[3] = ( (float) input[stbir__decode_order3] ) * stbir__max_uint8_as_float_inverted;- input += 4;- decode += 4;- } while( decode < decode_end );-}---static void STBIR__CODER_NAME( stbir__encode_uint8_srgb4_linearalpha )( void * outputp, int width_times_channels, float const * encode )-{- unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char*) outputp;- 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;- for(;;)- {- stbir__simdf f0, f1, f2, f3;- stbir__simdi i0, i1, i2, i3;-- STBIR_SIMD_NO_UNROLL(encode);- stbir__simdf_load4_transposed( f0, f1, f2, f3, encode );-- 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__linear_to_srgb_finish( i0, f0 );- stbir__linear_to_srgb_finish( i1, f1 );- stbir__linear_to_srgb_finish( i2, f2 );-- stbir__interleave_pack_and_store_16_u8( output, STBIR_strs_join1(i, ,stbir__encode_order0), STBIR_strs_join1(i, ,stbir__encode_order1), STBIR_strs_join1(i, ,stbir__encode_order2), STBIR_strs_join1(i, ,stbir__encode_order3) );-- output += 16;- encode += 16;-- if ( output <= end_output ) - continue;- if ( output == ( end_output + 16 ) )- break;- output = end_output; // backup and do last couple- encode = end_encode_m16;- }- return;- }- #endif-- do {- float f;- 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] );- output[stbir__decode_order2] = stbir__linear_to_srgb_uchar( encode[2] );-- f = encode[3] * stbir__max_uint8_as_float + 0.5f;- STBIR_CLAMP(f, 0, 255);- output[stbir__decode_order3] = (unsigned char) f;-- output += 4;- encode += 4;- } while( output < end_output );-}--#endif--#if ( stbir__coder_min_num == 2 ) || ( ( stbir__coder_min_num == 1 ) && ( !defined(stbir__decode_swizzle) ) )--static void STBIR__CODER_NAME(stbir__decode_uint8_srgb2_linearalpha)( float * decodep, int width_times_channels, void const * inputp )-{- float STBIR_STREAMOUT_PTR( * ) decode = decodep;- float const * decode_end = (float*) decode + width_times_channels;- unsigned char const * input = (unsigned char const *)inputp;- decode += 4;- while( decode <= decode_end )- {- decode[0-4] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order0] ];- decode[1-4] = ( (float) input[stbir__decode_order1] ) * stbir__max_uint8_as_float_inverted;- decode[2-4] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order0+2] ];- decode[3-4] = ( (float) input[stbir__decode_order1+2] ) * stbir__max_uint8_as_float_inverted;- input += 4;- decode += 4;- }- decode -= 4;- 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;- }-}--static void STBIR__CODER_NAME( stbir__encode_uint8_srgb2_linearalpha )( void * outputp, int width_times_channels, float const * encode )-{- unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char*) outputp;- 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;- for(;;)- {- stbir__simdf f0, f1, f2, f3;- stbir__simdi i0, i1, i2, i3; -- STBIR_SIMD_NO_UNROLL(encode);- stbir__simdf_load4_transposed( f0, f1, f2, f3, encode );-- stbir__min_max_shift20( i0, f0 );- 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__linear_to_srgb_finish( i0, f0 );- stbir__linear_to_srgb_finish( i2, f2 );-- stbir__interleave_pack_and_store_16_u8( output, STBIR_strs_join1(i, ,stbir__encode_order0), STBIR_strs_join1(i, ,stbir__encode_order1), STBIR_strs_join1(i, ,stbir__encode_order2), STBIR_strs_join1(i, ,stbir__encode_order3) );-- output += 16;- encode += 16;- if ( output <= end_output ) - continue;- if ( output == ( end_output + 16 ) )- break;- output = end_output; // backup and do last couple- encode = end_encode_m16;- }- return;- }- #endif-- do {- float f;- STBIR_SIMD_NO_UNROLL(encode);-- output[stbir__decode_order0] = stbir__linear_to_srgb_uchar( encode[0] );-- f = encode[1] * stbir__max_uint8_as_float + 0.5f;- STBIR_CLAMP(f, 0, 255);- output[stbir__decode_order1] = (unsigned char) f;-- output += 2;- encode += 2;- } while( output < end_output );-}--#endif--static void STBIR__CODER_NAME(stbir__decode_uint16_linear_scaled)( float * decodep, int width_times_channels, void const * inputp )-{- float STBIR_STREAMOUT_PTR( * ) decode = decodep;- float * decode_end = (float*) decode + width_times_channels;- unsigned short const * input = (unsigned short const *)inputp;-- #ifdef STBIR_SIMD- unsigned short const * end_input_m8 = input + width_times_channels - 8;- if ( width_times_channels >= 8 )- {- decode_end -= 8;- for(;;)- {- #ifdef STBIR_SIMD8- stbir__simdi i; stbir__simdi8 o;- stbir__simdf8 of;- STBIR_NO_UNROLL(decode);- stbir__simdi_load( i, input );- stbir__simdi8_expand_u16_to_u32( o, i );- stbir__simdi8_convert_i32_to_float( of, o );- stbir__simdf8_mult( of, of, STBIR_max_uint16_as_float_inverted8);- stbir__decode_simdf8_flip( of );- stbir__simdf8_store( decode + 0, of );- #else- stbir__simdi i, o0, o1;- stbir__simdf of0, of1;- STBIR_NO_UNROLL(decode);- stbir__simdi_load( i, input );- stbir__simdi_expand_u16_to_u32( o0,o1,i );- stbir__simdi_convert_i32_to_float( of0, o0 );- stbir__simdi_convert_i32_to_float( of1, o1 );- stbir__simdf_mult( of0, of0, STBIR__CONSTF(STBIR_max_uint16_as_float_inverted) );- stbir__simdf_mult( of1, of1, STBIR__CONSTF(STBIR_max_uint16_as_float_inverted));- stbir__decode_simdf4_flip( of0 );- stbir__decode_simdf4_flip( of1 );- stbir__simdf_store( decode + 0, of0 );- stbir__simdf_store( decode + 4, of1 );- #endif- decode += 8; - input += 8;- if ( decode <= decode_end ) - continue;- if ( decode == ( decode_end + 8 ) )- break;- decode = decode_end; // backup and do last couple- input = end_input_m8;- }- return;- }- #endif-- // try to do blocks of 4 when you can- #if stbir__coder_min_num != 3 // doesn't divide cleanly by four- decode += 4;- while( decode <= decode_end )- {- STBIR_SIMD_NO_UNROLL(decode);- decode[0-4] = ((float)(input[stbir__decode_order0])) * stbir__max_uint16_as_float_inverted;- decode[1-4] = ((float)(input[stbir__decode_order1])) * stbir__max_uint16_as_float_inverted;- decode[2-4] = ((float)(input[stbir__decode_order2])) * stbir__max_uint16_as_float_inverted;- decode[3-4] = ((float)(input[stbir__decode_order3])) * stbir__max_uint16_as_float_inverted;- decode += 4;- input += 4;- }- decode -= 4;- #endif-- // do the remnants- #if stbir__coder_min_num < 4- while( decode < decode_end )- {- STBIR_NO_UNROLL(decode);- decode[0] = ((float)(input[stbir__decode_order0])) * stbir__max_uint16_as_float_inverted;- #if stbir__coder_min_num >= 2- decode[1] = ((float)(input[stbir__decode_order1])) * stbir__max_uint16_as_float_inverted;- #endif- #if stbir__coder_min_num >= 3- decode[2] = ((float)(input[stbir__decode_order2])) * stbir__max_uint16_as_float_inverted;- #endif- decode += stbir__coder_min_num;- input += stbir__coder_min_num;- }- #endif-}---static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * outputp, int width_times_channels, float const * encode )-{- unsigned short STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned short*) outputp;- unsigned short * end_output = ( (unsigned short*) output ) + width_times_channels;-- #ifdef STBIR_SIMD- {- if ( width_times_channels >= stbir__simdfX_float_count*2 )- {- float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2;- end_output -= stbir__simdfX_float_count*2;- for(;;)- {- stbir__simdfX e0, e1;- stbir__simdiX i;- STBIR_SIMD_NO_UNROLL(encode);- stbir__simdfX_madd_mem( e0, STBIR_simd_point5X, STBIR_max_uint16_as_floatX, encode );- stbir__simdfX_madd_mem( e1, STBIR_simd_point5X, STBIR_max_uint16_as_floatX, encode+stbir__simdfX_float_count );- stbir__encode_simdfX_unflip( e0 );- stbir__encode_simdfX_unflip( e1 );- stbir__simdfX_pack_to_words( i, e0, e1 );- stbir__simdiX_store( output, i );- encode += stbir__simdfX_float_count*2;- output += stbir__simdfX_float_count*2;- if ( output <= end_output ) - continue;- if ( output == ( end_output + stbir__simdfX_float_count*2 ) )- break;- output = end_output; // backup and do last couple- encode = end_encode_m8;- }- return;- }- }-- // try to do blocks of 4 when you can- #if stbir__coder_min_num != 3 // doesn't divide cleanly by four- output += 4;- while( output <= end_output )- {- stbir__simdf e;- stbir__simdi i;- STBIR_NO_UNROLL(encode);- stbir__simdf_load( e, encode );- stbir__simdf_madd( e, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint16_as_float), e );- stbir__encode_simdf4_unflip( e );- stbir__simdf_pack_to_8words( i, e, e ); // only use first 4- stbir__simdi_store2( output-4, i );- output += 4;- encode += 4;- }- output -= 4;- #endif-- // do the remnants- #if stbir__coder_min_num < 4- while( output < end_output )- {- stbir__simdf e;- STBIR_NO_UNROLL(encode);- stbir__simdf_madd1_mem( e, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint16_as_float), encode+stbir__encode_order0 ); output[0] = stbir__simdf_convert_float_to_short( e );- #if stbir__coder_min_num >= 2- stbir__simdf_madd1_mem( e, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint16_as_float), encode+stbir__encode_order1 ); output[1] = stbir__simdf_convert_float_to_short( e );- #endif- #if stbir__coder_min_num >= 3- stbir__simdf_madd1_mem( e, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint16_as_float), encode+stbir__encode_order2 ); output[2] = stbir__simdf_convert_float_to_short( e );- #endif- output += stbir__coder_min_num;- 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;- while( output <= end_output )- {- float f;- STBIR_SIMD_NO_UNROLL(encode);- f = encode[stbir__encode_order0] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[0-4] = (unsigned short)f;- f = encode[stbir__encode_order1] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[1-4] = (unsigned short)f;- f = encode[stbir__encode_order2] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[2-4] = (unsigned short)f;- f = encode[stbir__encode_order3] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[3-4] = (unsigned short)f;- output += 4;- encode += 4;- }- output -= 4;- #endif-- // do the remnants- #if stbir__coder_min_num < 4- while( output < end_output )- {- float f;- STBIR_NO_UNROLL(encode);- f = encode[stbir__encode_order0] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[0] = (unsigned short)f;- #if stbir__coder_min_num >= 2- f = encode[stbir__encode_order1] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[1] = (unsigned short)f;- #endif- #if stbir__coder_min_num >= 3- f = encode[stbir__encode_order2] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[2] = (unsigned short)f;- #endif- output += stbir__coder_min_num;- encode += stbir__coder_min_num;- }- #endif- #endif-}--static void STBIR__CODER_NAME(stbir__decode_uint16_linear)( float * decodep, int width_times_channels, void const * inputp )-{- float STBIR_STREAMOUT_PTR( * ) decode = decodep;- float * decode_end = (float*) decode + width_times_channels;- unsigned short const * input = (unsigned short const *)inputp;-- #ifdef STBIR_SIMD- unsigned short const * end_input_m8 = input + width_times_channels - 8;- if ( width_times_channels >= 8 )- {- decode_end -= 8;- for(;;)- {- #ifdef STBIR_SIMD8- stbir__simdi i; stbir__simdi8 o;- stbir__simdf8 of;- STBIR_NO_UNROLL(decode);- stbir__simdi_load( i, input );- stbir__simdi8_expand_u16_to_u32( o, i );- stbir__simdi8_convert_i32_to_float( of, o );- stbir__decode_simdf8_flip( of );- stbir__simdf8_store( decode + 0, of );- #else- stbir__simdi i, o0, o1;- stbir__simdf of0, of1;- STBIR_NO_UNROLL(decode);- stbir__simdi_load( i, input );- stbir__simdi_expand_u16_to_u32( o0, o1, i );- stbir__simdi_convert_i32_to_float( of0, o0 );- stbir__simdi_convert_i32_to_float( of1, o1 );- stbir__decode_simdf4_flip( of0 );- stbir__decode_simdf4_flip( of1 );- stbir__simdf_store( decode + 0, of0 );- stbir__simdf_store( decode + 4, of1 );- #endif- decode += 8;- input += 8;- if ( decode <= decode_end ) - continue;- if ( decode == ( decode_end + 8 ) )- break;- decode = decode_end; // backup and do last couple- input = end_input_m8;- }- return;- }- #endif-- // try to do blocks of 4 when you can- #if stbir__coder_min_num != 3 // doesn't divide cleanly by four- decode += 4;- while( decode <= decode_end )- {- STBIR_SIMD_NO_UNROLL(decode);- decode[0-4] = ((float)(input[stbir__decode_order0]));- decode[1-4] = ((float)(input[stbir__decode_order1]));- decode[2-4] = ((float)(input[stbir__decode_order2]));- decode[3-4] = ((float)(input[stbir__decode_order3]));- decode += 4;- input += 4;- }- decode -= 4;- #endif-- // do the remnants- #if stbir__coder_min_num < 4- while( decode < decode_end )- {- STBIR_NO_UNROLL(decode);- decode[0] = ((float)(input[stbir__decode_order0]));- #if stbir__coder_min_num >= 2- decode[1] = ((float)(input[stbir__decode_order1]));- #endif- #if stbir__coder_min_num >= 3- decode[2] = ((float)(input[stbir__decode_order2]));- #endif- decode += stbir__coder_min_num;- input += stbir__coder_min_num;- }- #endif-}--static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int width_times_channels, float const * encode )-{- unsigned short STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned short*) outputp;- unsigned short * end_output = ( (unsigned short*) output ) + width_times_channels;-- #ifdef STBIR_SIMD- {- if ( width_times_channels >= stbir__simdfX_float_count*2 )- {- float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2;- end_output -= stbir__simdfX_float_count*2;- for(;;)- {- stbir__simdfX e0, e1;- stbir__simdiX i;- STBIR_SIMD_NO_UNROLL(encode);- stbir__simdfX_add_mem( e0, STBIR_simd_point5X, encode );- stbir__simdfX_add_mem( e1, STBIR_simd_point5X, encode+stbir__simdfX_float_count );- stbir__encode_simdfX_unflip( e0 );- stbir__encode_simdfX_unflip( e1 );- stbir__simdfX_pack_to_words( i, e0, e1 );- stbir__simdiX_store( output, i );- encode += stbir__simdfX_float_count*2;- output += stbir__simdfX_float_count*2;- if ( output <= end_output ) - continue;- if ( output == ( end_output + stbir__simdfX_float_count*2 ) )- break;- output = end_output; // backup and do last couple- encode = end_encode_m8;- }- return;- }- }-- // try to do blocks of 4 when you can- #if stbir__coder_min_num != 3 // doesn't divide cleanly by four- output += 4;- while( output <= end_output )- {- stbir__simdf e;- stbir__simdi i;- STBIR_NO_UNROLL(encode);- stbir__simdf_load( e, encode );- stbir__simdf_add( e, STBIR__CONSTF(STBIR_simd_point5), e );- stbir__encode_simdf4_unflip( e );- stbir__simdf_pack_to_8words( i, e, e ); // only use first 4- stbir__simdi_store2( output-4, i );- output += 4;- encode += 4;- }- output -= 4;- #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;- while( output <= end_output )- {- float f;- STBIR_SIMD_NO_UNROLL(encode);- f = encode[stbir__encode_order0] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[0-4] = (unsigned short)f;- f = encode[stbir__encode_order1] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[1-4] = (unsigned short)f;- f = encode[stbir__encode_order2] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[2-4] = (unsigned short)f;- f = encode[stbir__encode_order3] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[3-4] = (unsigned short)f;- output += 4;- encode += 4;- }- output -= 4;- #endif-- #endif-- // do the remnants- #if stbir__coder_min_num < 4- while( output < end_output )- {- float f;- STBIR_NO_UNROLL(encode);- f = encode[stbir__encode_order0] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[0] = (unsigned short)f;- #if stbir__coder_min_num >= 2- f = encode[stbir__encode_order1] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[1] = (unsigned short)f;- #endif- #if stbir__coder_min_num >= 3- f = encode[stbir__encode_order2] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[2] = (unsigned short)f;- #endif- output += stbir__coder_min_num;- encode += stbir__coder_min_num;- }- #endif-}--static void STBIR__CODER_NAME(stbir__decode_half_float_linear)( float * decodep, int width_times_channels, void const * inputp )-{- float STBIR_STREAMOUT_PTR( * ) decode = decodep;- float * decode_end = (float*) decode + width_times_channels;- stbir__FP16 const * input = (stbir__FP16 const *)inputp;-- #ifdef STBIR_SIMD- if ( width_times_channels >= 8 )- {- stbir__FP16 const * end_input_m8 = input + width_times_channels - 8;- decode_end -= 8;- for(;;)- {- STBIR_NO_UNROLL(decode);-- stbir__half_to_float_SIMD( decode, input );- #ifdef stbir__decode_swizzle- #ifdef STBIR_SIMD8- {- stbir__simdf8 of;- stbir__simdf8_load( of, decode );- stbir__decode_simdf8_flip( of );- stbir__simdf8_store( decode, of );- }- #else- {- stbir__simdf of0,of1;- stbir__simdf_load( of0, decode );- stbir__simdf_load( of1, decode+4 );- stbir__decode_simdf4_flip( of0 );- stbir__decode_simdf4_flip( of1 );- stbir__simdf_store( decode, of0 );- stbir__simdf_store( decode+4, of1 );- }- #endif- #endif- decode += 8;- input += 8;- if ( decode <= decode_end ) - continue;- if ( decode == ( decode_end + 8 ) )- break;- decode = decode_end; // backup and do last couple- input = end_input_m8;- }- return;- }- #endif-- // try to do blocks of 4 when you can- #if stbir__coder_min_num != 3 // doesn't divide cleanly by four- decode += 4;- while( decode <= decode_end )- {- STBIR_SIMD_NO_UNROLL(decode);- decode[0-4] = stbir__half_to_float(input[stbir__decode_order0]);- decode[1-4] = stbir__half_to_float(input[stbir__decode_order1]);- decode[2-4] = stbir__half_to_float(input[stbir__decode_order2]);- decode[3-4] = stbir__half_to_float(input[stbir__decode_order3]);- decode += 4;- input += 4;- }- decode -= 4;- #endif-- // do the remnants- #if stbir__coder_min_num < 4- while( decode < decode_end )- {- STBIR_NO_UNROLL(decode);- decode[0] = stbir__half_to_float(input[stbir__decode_order0]);- #if stbir__coder_min_num >= 2- decode[1] = stbir__half_to_float(input[stbir__decode_order1]);- #endif- #if stbir__coder_min_num >= 3- decode[2] = stbir__half_to_float(input[stbir__decode_order2]);- #endif- decode += stbir__coder_min_num;- input += stbir__coder_min_num;- }- #endif-}--static void STBIR__CODER_NAME( stbir__encode_half_float_linear )( void * outputp, int width_times_channels, float const * encode )-{- stbir__FP16 STBIR_SIMD_STREAMOUT_PTR( * ) output = (stbir__FP16*) outputp;- stbir__FP16 * end_output = ( (stbir__FP16*) output ) + width_times_channels;-- #ifdef STBIR_SIMD- if ( width_times_channels >= 8 )- {- float const * end_encode_m8 = encode + width_times_channels - 8;- end_output -= 8;- for(;;)- {- STBIR_SIMD_NO_UNROLL(encode);- #ifdef stbir__decode_swizzle- #ifdef STBIR_SIMD8- {- stbir__simdf8 of;- stbir__simdf8_load( of, encode );- stbir__encode_simdf8_unflip( of );- stbir__float_to_half_SIMD( output, (float*)&of );- }- #else- {- stbir__simdf of[2];- stbir__simdf_load( of[0], encode );- stbir__simdf_load( of[1], encode+4 );- stbir__encode_simdf4_unflip( of[0] );- stbir__encode_simdf4_unflip( of[1] );- stbir__float_to_half_SIMD( output, (float*)of );- }- #endif- #else- stbir__float_to_half_SIMD( output, encode );- #endif- encode += 8;- output += 8;- if ( output <= end_output ) - continue;- if ( output == ( end_output + 8 ) )- break;- output = end_output; // backup and do last couple- encode = end_encode_m8;- }- return;- }- #endif-- // try to do blocks of 4 when you can- #if stbir__coder_min_num != 3 // doesn't divide cleanly by four- output += 4;- while( output <= end_output )- {- STBIR_SIMD_NO_UNROLL(output);- output[0-4] = stbir__float_to_half(encode[stbir__encode_order0]);- output[1-4] = stbir__float_to_half(encode[stbir__encode_order1]);- output[2-4] = stbir__float_to_half(encode[stbir__encode_order2]);- output[3-4] = stbir__float_to_half(encode[stbir__encode_order3]);- output += 4;- encode += 4;- }- output -= 4;- #endif-- // do the remnants- #if stbir__coder_min_num < 4- while( output < end_output )- {- STBIR_NO_UNROLL(output);- output[0] = stbir__float_to_half(encode[stbir__encode_order0]);- #if stbir__coder_min_num >= 2- output[1] = stbir__float_to_half(encode[stbir__encode_order1]);- #endif- #if stbir__coder_min_num >= 3- output[2] = stbir__float_to_half(encode[stbir__encode_order2]);- #endif- output += stbir__coder_min_num;- encode += stbir__coder_min_num;- }- #endif-}--static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int width_times_channels, void const * inputp )-{- #ifdef stbir__decode_swizzle- float STBIR_STREAMOUT_PTR( * ) decode = decodep;- float * decode_end = (float*) decode + width_times_channels;- float const * input = (float const *)inputp;-- #ifdef STBIR_SIMD- if ( width_times_channels >= 16 )- {- float const * end_input_m16 = input + width_times_channels - 16;- decode_end -= 16;- for(;;)- {- STBIR_NO_UNROLL(decode);- #ifdef stbir__decode_swizzle- #ifdef STBIR_SIMD8- {- stbir__simdf8 of0,of1;- stbir__simdf8_load( of0, input );- stbir__simdf8_load( of1, input+8 );- stbir__decode_simdf8_flip( of0 );- stbir__decode_simdf8_flip( of1 );- stbir__simdf8_store( decode, of0 );- stbir__simdf8_store( decode+8, of1 );- }- #else- {- stbir__simdf of0,of1,of2,of3;- stbir__simdf_load( of0, input );- stbir__simdf_load( of1, input+4 );- stbir__simdf_load( of2, input+8 );- stbir__simdf_load( of3, input+12 );- stbir__decode_simdf4_flip( of0 );- stbir__decode_simdf4_flip( of1 );- stbir__decode_simdf4_flip( of2 );- stbir__decode_simdf4_flip( of3 );- stbir__simdf_store( decode, of0 );- stbir__simdf_store( decode+4, of1 );- stbir__simdf_store( decode+8, of2 );- stbir__simdf_store( decode+12, of3 );- }- #endif- #endif- decode += 16;- input += 16;- if ( decode <= decode_end ) - continue;- if ( decode == ( decode_end + 16 ) )- break;- decode = decode_end; // backup and do last couple- input = end_input_m16;- }- return;- }- #endif-- // try to do blocks of 4 when you can- #if stbir__coder_min_num != 3 // doesn't divide cleanly by four- decode += 4;- while( decode <= decode_end )- {- STBIR_SIMD_NO_UNROLL(decode);- decode[0-4] = input[stbir__decode_order0];- decode[1-4] = input[stbir__decode_order1];- decode[2-4] = input[stbir__decode_order2];- decode[3-4] = input[stbir__decode_order3];- decode += 4;- input += 4;- }- decode -= 4;- #endif-- // do the remnants- #if stbir__coder_min_num < 4- while( decode < decode_end )- {- STBIR_NO_UNROLL(decode);- decode[0] = input[stbir__decode_order0];- #if stbir__coder_min_num >= 2- decode[1] = input[stbir__decode_order1];- #endif- #if stbir__coder_min_num >= 3- decode[2] = input[stbir__decode_order2];- #endif- decode += stbir__coder_min_num;- input += stbir__coder_min_num;- }- #endif-- #else- - if ( (void*)decodep != inputp )- STBIR_MEMCPY( decodep, inputp, width_times_channels * sizeof( float ) );- - #endif-}--static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int width_times_channels, float const * encode )-{- #if !defined( STBIR_FLOAT_HIGH_CLAMP ) && !defined(STBIR_FLOAT_LO_CLAMP) && !defined(stbir__decode_swizzle)-- if ( (void*)outputp != (void*) encode )- STBIR_MEMCPY( outputp, encode, width_times_channels * sizeof( float ) );-- #else-- float STBIR_SIMD_STREAMOUT_PTR( * ) output = (float*) outputp;- float * end_output = ( (float*) output ) + width_times_channels;-- #ifdef STBIR_FLOAT_HIGH_CLAMP- #define stbir_scalar_hi_clamp( v ) if ( v > STBIR_FLOAT_HIGH_CLAMP ) v = STBIR_FLOAT_HIGH_CLAMP;- #else- #define stbir_scalar_hi_clamp( v )- #endif- #ifdef STBIR_FLOAT_LOW_CLAMP- #define stbir_scalar_lo_clamp( v ) if ( v < STBIR_FLOAT_LOW_CLAMP ) v = STBIR_FLOAT_LOW_CLAMP;- #else- #define stbir_scalar_lo_clamp( v )- #endif-- #ifdef STBIR_SIMD-- #ifdef STBIR_FLOAT_HIGH_CLAMP- const stbir__simdfX high_clamp = stbir__simdf_frepX(STBIR_FLOAT_HIGH_CLAMP);- #endif- #ifdef STBIR_FLOAT_LOW_CLAMP- const stbir__simdfX low_clamp = stbir__simdf_frepX(STBIR_FLOAT_LOW_CLAMP);- #endif-- if ( width_times_channels >= ( stbir__simdfX_float_count * 2 ) )- {- float const * end_encode_m8 = encode + width_times_channels - ( stbir__simdfX_float_count * 2 );- end_output -= ( stbir__simdfX_float_count * 2 );- for(;;)- {- stbir__simdfX e0, e1;- STBIR_SIMD_NO_UNROLL(encode);- stbir__simdfX_load( e0, encode );- stbir__simdfX_load( e1, encode+stbir__simdfX_float_count );-#ifdef STBIR_FLOAT_HIGH_CLAMP- stbir__simdfX_min( e0, e0, high_clamp );- stbir__simdfX_min( e1, e1, high_clamp );-#endif -#ifdef STBIR_FLOAT_LOW_CLAMP- stbir__simdfX_max( e0, e0, low_clamp );- stbir__simdfX_max( e1, e1, low_clamp );-#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 ) - continue;- if ( output == ( end_output + ( stbir__simdfX_float_count * 2 ) ) )- break;- output = end_output; // backup and do last couple- encode = end_encode_m8;- }- return;- }-- // try to do blocks of 4 when you can- #if stbir__coder_min_num != 3 // doesn't divide cleanly by four- output += 4;- while( output <= end_output )- {- stbir__simdf e0;- STBIR_NO_UNROLL(encode);- stbir__simdf_load( e0, encode );-#ifdef STBIR_FLOAT_HIGH_CLAMP- stbir__simdf_min( e0, e0, high_clamp );-#endif -#ifdef STBIR_FLOAT_LOW_CLAMP- stbir__simdf_max( e0, e0, low_clamp );-#endif - stbir__encode_simdf4_unflip( e0 );- stbir__simdf_store( output-4, e0 );- output += 4;- encode += 4;- }- output -= 4;- #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;- while( output <= end_output )- {- float e;- STBIR_SIMD_NO_UNROLL(encode);- e = encode[ stbir__encode_order0 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[0-4] = e;- e = encode[ stbir__encode_order1 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[1-4] = e;- e = encode[ stbir__encode_order2 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[2-4] = e;- e = encode[ stbir__encode_order3 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[3-4] = e;- output += 4;- encode += 4;- }- output -= 4;-- #endif-- #endif-- // do the remnants- #if stbir__coder_min_num < 4- while( output < end_output )- {- float e;- STBIR_NO_UNROLL(encode);- e = encode[ stbir__encode_order0 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[0] = e;- #if stbir__coder_min_num >= 2- e = encode[ stbir__encode_order1 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[1] = e;- #endif- #if stbir__coder_min_num >= 3- e = encode[ stbir__encode_order2 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[2] = e;- #endif- output += stbir__coder_min_num;- encode += stbir__coder_min_num;- }- #endif- - #endif-}--#undef stbir__decode_suffix -#undef stbir__decode_simdf8_flip-#undef stbir__decode_simdf4_flip-#undef stbir__decode_order0 -#undef stbir__decode_order1-#undef stbir__decode_order2-#undef stbir__decode_order3-#undef stbir__encode_order0 -#undef stbir__encode_order1-#undef stbir__encode_order2-#undef stbir__encode_order3-#undef stbir__encode_simdf8_unflip-#undef stbir__encode_simdf4_unflip-#undef stbir__encode_simdfX_unflip-#undef STBIR__CODER_NAME-#undef stbir__coder_min_num-#undef stbir__decode_swizzle-#undef stbir_scalar_hi_clamp-#undef stbir_scalar_lo_clamp-#undef STB_IMAGE_RESIZE_DO_CODERS--#elif defined( STB_IMAGE_RESIZE_DO_VERTICALS)--#ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE-#define STBIR_chans( start, end ) STBIR_strs_join14(start,STBIR__vertical_channels,end,_cont)-#else-#define STBIR_chans( start, end ) STBIR_strs_join1(start,STBIR__vertical_channels,end)-#endif--#if STBIR__vertical_channels >= 1-#define stbIF0( code ) code-#else-#define stbIF0( code )-#endif-#if STBIR__vertical_channels >= 2-#define stbIF1( code ) code-#else-#define stbIF1( code )-#endif-#if STBIR__vertical_channels >= 3-#define stbIF2( code ) code-#else-#define stbIF2( code )-#endif-#if STBIR__vertical_channels >= 4-#define stbIF3( code ) code-#else-#define stbIF3( code )-#endif-#if STBIR__vertical_channels >= 5-#define stbIF4( code ) code-#else-#define stbIF4( code )-#endif-#if STBIR__vertical_channels >= 6-#define stbIF5( code ) code-#else-#define stbIF5( code )-#endif-#if STBIR__vertical_channels >= 7-#define stbIF6( code ) code-#else-#define stbIF6( code )-#endif-#if STBIR__vertical_channels >= 8-#define stbIF7( code ) code-#else-#define stbIF7( code )-#endif--static void STBIR_chans( stbir__vertical_scatter_with_,_coeffs)( float ** outputs, float const * vertical_coefficients, float const * input, float const * input_end )-{- stbIF0( float STBIR_SIMD_STREAMOUT_PTR( * ) output0 = outputs[0]; float c0s = vertical_coefficients[0]; )- stbIF1( float STBIR_SIMD_STREAMOUT_PTR( * ) output1 = outputs[1]; float c1s = vertical_coefficients[1]; )- stbIF2( float STBIR_SIMD_STREAMOUT_PTR( * ) output2 = outputs[2]; float c2s = vertical_coefficients[2]; )- stbIF3( float STBIR_SIMD_STREAMOUT_PTR( * ) output3 = outputs[3]; float c3s = vertical_coefficients[3]; )- stbIF4( float STBIR_SIMD_STREAMOUT_PTR( * ) output4 = outputs[4]; float c4s = vertical_coefficients[4]; )- stbIF5( float STBIR_SIMD_STREAMOUT_PTR( * ) output5 = outputs[5]; float c5s = vertical_coefficients[5]; )- stbIF6( float STBIR_SIMD_STREAMOUT_PTR( * ) output6 = outputs[6]; float c6s = vertical_coefficients[6]; )- stbIF7( float STBIR_SIMD_STREAMOUT_PTR( * ) output7 = outputs[7]; float c7s = vertical_coefficients[7]; )-- #ifdef STBIR_SIMD- {- stbIF0(stbir__simdfX c0 = stbir__simdf_frepX( c0s ); )- stbIF1(stbir__simdfX c1 = stbir__simdf_frepX( c1s ); )- stbIF2(stbir__simdfX c2 = stbir__simdf_frepX( c2s ); )- stbIF3(stbir__simdfX c3 = stbir__simdf_frepX( c3s ); )- stbIF4(stbir__simdfX c4 = stbir__simdf_frepX( c4s ); )- 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__simdfX o0, o1, o2, o3, r0, r1, r2, r3;- STBIR_SIMD_NO_UNROLL(output0);-- stbir__simdfX_load( r0, input ); stbir__simdfX_load( r1, input+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input+(3*stbir__simdfX_float_count) );-- #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_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_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_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_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_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_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_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_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 ); - 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 ); - 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 ); - 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 ); - 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 ); - 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 ); - 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 ); - 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 ); - 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__simdf o0, r0;- STBIR_SIMD_NO_UNROLL(output0);-- stbir__simdf_load( r0, input );-- #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE- stbIF0( stbir__simdf_load( o0, output0 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c0 ) ); stbir__simdf_store( output0, o0 ); )- stbIF1( stbir__simdf_load( o0, output1 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c1 ) ); stbir__simdf_store( output1, o0 ); )- stbIF2( stbir__simdf_load( o0, output2 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c2 ) ); stbir__simdf_store( output2, o0 ); )- stbIF3( stbir__simdf_load( o0, output3 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c3 ) ); stbir__simdf_store( output3, o0 ); )- stbIF4( stbir__simdf_load( o0, output4 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c4 ) ); stbir__simdf_store( output4, o0 ); )- stbIF5( stbir__simdf_load( o0, output5 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c5 ) ); stbir__simdf_store( output5, o0 ); )- stbIF6( stbir__simdf_load( o0, output6 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c6 ) ); stbir__simdf_store( output6, o0 ); )- stbIF7( stbir__simdf_load( o0, output7 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c7 ) ); stbir__simdf_store( output7, o0 ); )- #else- stbIF0( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c0 ) ); stbir__simdf_store( output0, o0 ); )- stbIF1( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c1 ) ); stbir__simdf_store( output1, o0 ); )- stbIF2( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c2 ) ); stbir__simdf_store( output2, o0 ); )- stbIF3( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c3 ) ); stbir__simdf_store( output3, o0 ); )- stbIF4( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c4 ) ); stbir__simdf_store( output4, o0 ); )- stbIF5( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c5 ) ); stbir__simdf_store( output5, o0 ); )- 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 ) - {- float r0, r1, r2, r3;- STBIR_NO_UNROLL(input);-- r0 = input[0], r1 = input[1], r2 = input[2], r3 = input[3];-- #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE- stbIF0( output0[0] += ( r0 * c0s ); output0[1] += ( r1 * c0s ); output0[2] += ( r2 * c0s ); output0[3] += ( r3 * c0s ); )- stbIF1( output1[0] += ( r0 * c1s ); output1[1] += ( r1 * c1s ); output1[2] += ( r2 * c1s ); output1[3] += ( r3 * c1s ); )- stbIF2( output2[0] += ( r0 * c2s ); output2[1] += ( r1 * c2s ); output2[2] += ( r2 * c2s ); output2[3] += ( r3 * c2s ); )- stbIF3( output3[0] += ( r0 * c3s ); output3[1] += ( r1 * c3s ); output3[2] += ( r2 * c3s ); output3[3] += ( r3 * c3s ); )- stbIF4( output4[0] += ( r0 * c4s ); output4[1] += ( r1 * c4s ); output4[2] += ( r2 * c4s ); output4[3] += ( r3 * c4s ); )- stbIF5( output5[0] += ( r0 * c5s ); output5[1] += ( r1 * c5s ); output5[2] += ( r2 * c5s ); output5[3] += ( r3 * c5s ); )- stbIF6( output6[0] += ( r0 * c6s ); output6[1] += ( r1 * c6s ); output6[2] += ( r2 * c6s ); output6[3] += ( r3 * c6s ); )- stbIF7( output7[0] += ( r0 * c7s ); output7[1] += ( r1 * c7s ); output7[2] += ( r2 * c7s ); output7[3] += ( r3 * c7s ); )- #else- stbIF0( output0[0] = ( r0 * c0s ); output0[1] = ( r1 * c0s ); output0[2] = ( r2 * c0s ); output0[3] = ( r3 * c0s ); )- stbIF1( output1[0] = ( r0 * c1s ); output1[1] = ( r1 * c1s ); output1[2] = ( r2 * c1s ); output1[3] = ( r3 * c1s ); )- stbIF2( output2[0] = ( r0 * c2s ); output2[1] = ( r1 * c2s ); output2[2] = ( r2 * c2s ); output2[3] = ( r3 * c2s ); )- stbIF3( output3[0] = ( r0 * c3s ); output3[1] = ( r1 * c3s ); output3[2] = ( r2 * c3s ); output3[3] = ( r3 * c3s ); )- stbIF4( output4[0] = ( r0 * c4s ); output4[1] = ( r1 * c4s ); output4[2] = ( r2 * c4s ); output4[3] = ( r3 * c4s ); )- stbIF5( output5[0] = ( r0 * c5s ); output5[1] = ( r1 * c5s ); output5[2] = ( r2 * c5s ); output5[3] = ( r3 * c5s ); )- stbIF6( output6[0] = ( r0 * c6s ); output6[1] = ( r1 * c6s ); output6[2] = ( r2 * c6s ); output6[3] = ( r3 * c6s ); )- stbIF7( output7[0] = ( r0 * c7s ); output7[1] = ( r1 * c7s ); output7[2] = ( r2 * c7s ); output7[3] = ( r3 * c7s ); )- #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; )- }- #endif- while ( input < input_end ) - {- float r = input[0];- STBIR_NO_UNROLL(output0);-- #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE- stbIF0( output0[0] += ( r * c0s ); )- stbIF1( output1[0] += ( r * c1s ); )- stbIF2( output2[0] += ( r * c2s ); )- stbIF3( output3[0] += ( r * c3s ); )- stbIF4( output4[0] += ( r * c4s ); )- stbIF5( output5[0] += ( r * c5s ); )- stbIF6( output6[0] += ( r * c6s ); )- stbIF7( output7[0] += ( r * c7s ); )- #else- stbIF0( output0[0] = ( r * c0s ); )- stbIF1( output1[0] = ( r * c1s ); )- stbIF2( output2[0] = ( r * c2s ); )- stbIF3( output3[0] = ( r * c3s ); )- stbIF4( output4[0] = ( r * c4s ); )- stbIF5( output5[0] = ( r * c5s ); )- stbIF6( output6[0] = ( r * c6s ); )- stbIF7( output7[0] = ( r * c7s ); )- #endif-- ++input;- stbIF0( ++output0; ) stbIF1( ++output1; ) stbIF2( ++output2; ) stbIF3( ++output3; ) stbIF4( ++output4; ) stbIF5( ++output5; ) stbIF6( ++output6; ) stbIF7( ++output7; )- }-}--static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, float const * vertical_coefficients, float const ** inputs, float const * input0_end )-{- float STBIR_SIMD_STREAMOUT_PTR( * ) output = outputp;-- stbIF0( float const * input0 = inputs[0]; float c0s = vertical_coefficients[0]; )- stbIF1( float const * input1 = inputs[1]; float c1s = vertical_coefficients[1]; )- stbIF2( float const * input2 = inputs[2]; float c2s = vertical_coefficients[2]; )- stbIF3( float const * input3 = inputs[3]; float c3s = vertical_coefficients[3]; )- stbIF4( float const * input4 = inputs[4]; float c4s = vertical_coefficients[4]; )- stbIF5( float const * input5 = inputs[5]; float c5s = vertical_coefficients[5]; )- stbIF6( float const * input6 = inputs[6]; float c6s = vertical_coefficients[6]; )- stbIF7( float const * input7 = inputs[7]; float c7s = vertical_coefficients[7]; )--#if ( STBIR__vertical_channels == 1 ) && !defined(STB_IMAGE_RESIZE_VERTICAL_CONTINUE)- // check single channel one weight- if ( ( c0s >= (1.0f-0.000001f) ) && ( c0s <= (1.0f+0.000001f) ) )- {- STBIR_MEMCPY( output, input0, (char*)input0_end - (char*)input0 );- return;- }-#endif -- #ifdef STBIR_SIMD- {- stbIF0(stbir__simdfX c0 = stbir__simdf_frepX( c0s ); )- stbIF1(stbir__simdfX c1 = stbir__simdf_frepX( c1s ); )- stbIF2(stbir__simdfX c2 = stbir__simdf_frepX( c2s ); )- stbIF3(stbir__simdfX c3 = stbir__simdf_frepX( c3s ); )- stbIF4(stbir__simdfX c4 = stbir__simdf_frepX( c4s ); )- 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__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) ); ) - 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) ); )- stbIF4( stbir__prefetch( input4 + (16*stbir__simdfX_float_count) ); )- stbIF5( stbir__prefetch( input5 + (16*stbir__simdfX_float_count) ); )- stbIF6( stbir__prefetch( input6 + (16*stbir__simdfX_float_count) ); )- stbIF7( stbir__prefetch( input7 + (16*stbir__simdfX_float_count) ); )-- #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE- stbIF0( stbir__simdfX_load( o0, output ); stbir__simdfX_load( o1, output+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output+(3*stbir__simdfX_float_count) );- stbir__simdfX_load( r0, input0 ); stbir__simdfX_load( r1, input0+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input0+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input0+(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 ); )- #else- stbIF0( stbir__simdfX_load( r0, input0 ); stbir__simdfX_load( r1, input0+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input0+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input0+(3*stbir__simdfX_float_count) );- stbir__simdfX_mult( o0, r0, c0 ); stbir__simdfX_mult( o1, r1, c0 ); stbir__simdfX_mult( o2, r2, c0 ); stbir__simdfX_mult( o3, r3, c0 ); )- #endif-- stbIF1( stbir__simdfX_load( r0, input1 ); stbir__simdfX_load( r1, input1+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input1+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input1+(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 ); )- stbIF2( stbir__simdfX_load( r0, input2 ); stbir__simdfX_load( r1, input2+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input2+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input2+(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 ); )- stbIF3( stbir__simdfX_load( r0, input3 ); stbir__simdfX_load( r1, input3+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input3+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input3+(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 ); )- stbIF4( stbir__simdfX_load( r0, input4 ); stbir__simdfX_load( r1, input4+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input4+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input4+(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 ); )- stbIF5( stbir__simdfX_load( r0, input5 ); stbir__simdfX_load( r1, input5+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input5+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input5+(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 ); )- stbIF6( stbir__simdfX_load( r0, input6 ); stbir__simdfX_load( r1, input6+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input6+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input6+(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 ); )- stbIF7( stbir__simdfX_load( r0, input7 ); stbir__simdfX_load( r1, input7+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input7+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input7+(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_store( output, o0 ); stbir__simdfX_store( output+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output+(3*stbir__simdfX_float_count), o3 );- output += (4*stbir__simdfX_float_count);- 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__simdf o0, r0;- STBIR_SIMD_NO_UNROLL(output);-- #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE- stbIF0( stbir__simdf_load( o0, output ); stbir__simdf_load( r0, input0 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c0 ) ); )- #else- stbIF0( stbir__simdf_load( r0, input0 ); stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c0 ) ); )- #endif- stbIF1( stbir__simdf_load( r0, input1 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c1 ) ); )- stbIF2( stbir__simdf_load( r0, input2 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c2 ) ); )- stbIF3( stbir__simdf_load( r0, input3 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c3 ) ); )- stbIF4( stbir__simdf_load( r0, input4 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c4 ) ); )- stbIF5( stbir__simdf_load( r0, input5 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c5 ) ); )- stbIF6( stbir__simdf_load( r0, input6 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c6 ) ); )- stbIF7( stbir__simdf_load( r0, input7 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c7 ) ); )-- stbir__simdf_store( output, o0 );- output += 4;- stbIF0( input0 += 4; ) stbIF1( input1 += 4; ) stbIF2( input2 += 4; ) stbIF3( input3 += 4; ) stbIF4( input4 += 4; ) stbIF5( input5 += 4; ) stbIF6( input6 += 4; ) stbIF7( input7 += 4; )- }- }- #else- while ( ( (char*)input0_end - (char*) input0 ) >= 16 ) - {- float o0, o1, o2, o3;- STBIR_NO_UNROLL(output);- #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE- stbIF0( o0 = output[0] + input0[0] * c0s; o1 = output[1] + input0[1] * c0s; o2 = output[2] + input0[2] * c0s; o3 = output[3] + input0[3] * c0s; )- #else- stbIF0( o0 = input0[0] * c0s; o1 = input0[1] * c0s; o2 = input0[2] * c0s; o3 = input0[3] * c0s; )- #endif- stbIF1( o0 += input1[0] * c1s; o1 += input1[1] * c1s; o2 += input1[2] * c1s; o3 += input1[3] * c1s; )- stbIF2( o0 += input2[0] * c2s; o1 += input2[1] * c2s; o2 += input2[2] * c2s; o3 += input2[3] * c2s; )- stbIF3( o0 += input3[0] * c3s; o1 += input3[1] * c3s; o2 += input3[2] * c3s; o3 += input3[3] * c3s; )- stbIF4( o0 += input4[0] * c4s; o1 += input4[1] * c4s; o2 += input4[2] * c4s; o3 += input4[3] * c4s; )- stbIF5( o0 += input5[0] * c5s; o1 += input5[1] * c5s; o2 += input5[2] * c5s; o3 += input5[3] * c5s; )- stbIF6( o0 += input6[0] * c6s; o1 += input6[1] * c6s; o2 += input6[2] * c6s; o3 += input6[3] * c6s; )- stbIF7( o0 += input7[0] * c7s; o1 += input7[1] * c7s; o2 += input7[2] * c7s; o3 += input7[3] * c7s; )- output[0] = o0; output[1] = o1; output[2] = o2; output[3] = o3;- output += 4;- 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 ) - {- float o0;- STBIR_NO_UNROLL(output);- #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE- stbIF0( o0 = output[0] + input0[0] * c0s; )- #else- stbIF0( o0 = input0[0] * c0s; )- #endif- stbIF1( o0 += input1[0] * c1s; )- stbIF2( o0 += input2[0] * c2s; )- stbIF3( o0 += input3[0] * c3s; )- stbIF4( o0 += input4[0] * c4s; )- stbIF5( o0 += input5[0] * c5s; )- stbIF6( o0 += input6[0] * c6s; )- stbIF7( o0 += input7[0] * c7s; )- output[0] = o0; - ++output;- stbIF0( ++input0; ) stbIF1( ++input1; ) stbIF2( ++input2; ) stbIF3( ++input3; ) stbIF4( ++input4; ) stbIF5( ++input5; ) stbIF6( ++input6; ) stbIF7( ++input7; )- }-}--#undef stbIF0-#undef stbIF1-#undef stbIF2-#undef stbIF3-#undef stbIF4-#undef stbIF5-#undef stbIF6-#undef stbIF7-#undef STB_IMAGE_RESIZE_DO_VERTICALS-#undef STBIR__vertical_channels-#undef STB_IMAGE_RESIZE_DO_HORIZONTALS-#undef STBIR_strs_join24-#undef STBIR_strs_join14-#undef STBIR_chans-#ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE-#undef STB_IMAGE_RESIZE_VERTICAL_CONTINUE-#endif--#else // !STB_IMAGE_RESIZE_DO_VERTICALS--#define STBIR_chans( start, end ) STBIR_strs_join1(start,STBIR__horizontal_channels,end)--#ifndef stbir__2_coeff_only-#define stbir__2_coeff_only() \- stbir__1_coeff_only(); \- 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); -#endif- -#ifndef stbir__3_coeff_only-#define stbir__3_coeff_only() \- stbir__2_coeff_only(); \- 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); -#endif--#ifndef stbir__3_coeff_setup-#define stbir__3_coeff_setup()-#endif--#ifndef stbir__4_coeff_start-#define stbir__4_coeff_start() \- stbir__2_coeff_only(); \- 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); -#endif--#ifndef stbir__store_output_tiny-#define stbir__store_output_tiny stbir__store_output-#endif--static void STBIR_chans( stbir__horizontal_gather_,_channels_with_1_coeff)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )-{- float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;- float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;- do {- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - float const * hc = horizontal_coefficients;- stbir__1_coeff_only();- stbir__store_output_tiny();- } while ( output < output_end );-}--static void STBIR_chans( stbir__horizontal_gather_,_channels_with_2_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )-{- float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;- float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;- do {- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - float const * hc = horizontal_coefficients;- stbir__2_coeff_only();- stbir__store_output_tiny();- } while ( output < output_end );-}--static void STBIR_chans( stbir__horizontal_gather_,_channels_with_3_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )-{- float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;- float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;- do {- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - float const * hc = horizontal_coefficients;- stbir__3_coeff_only();- stbir__store_output_tiny();- } while ( output < output_end );-}--static void STBIR_chans( stbir__horizontal_gather_,_channels_with_4_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )-{- float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;- float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;- do {- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - float const * hc = horizontal_coefficients;- stbir__4_coeff_start();- stbir__store_output();- } while ( output < output_end );-}--static void STBIR_chans( stbir__horizontal_gather_,_channels_with_5_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )-{- float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;- float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;- do {- 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);- stbir__store_output();- } while ( output < output_end );-}--static void STBIR_chans( stbir__horizontal_gather_,_channels_with_6_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )-{- float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;- float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;- do {- 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);- stbir__store_output();- } while ( output < output_end );-}--static void STBIR_chans( stbir__horizontal_gather_,_channels_with_7_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )-{- float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;- float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;- stbir__3_coeff_setup();- do {- 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();- } while ( output < output_end );-}--static void STBIR_chans( stbir__horizontal_gather_,_channels_with_8_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )-{- float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;- float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;- do {- 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);- stbir__store_output();- } while ( output < output_end );-}--static void STBIR_chans( stbir__horizontal_gather_,_channels_with_9_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )-{- float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;- float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;- do {- 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);- stbir__1_coeff_remnant(8);- stbir__store_output();- } while ( output < output_end );-}--static void STBIR_chans( stbir__horizontal_gather_,_channels_with_10_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )-{- float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;- float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;- do {- 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);- stbir__2_coeff_remnant(8);- stbir__store_output();- } while ( output < output_end );-}--static void STBIR_chans( stbir__horizontal_gather_,_channels_with_11_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )-{- float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;- float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;- stbir__3_coeff_setup();- do {- 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);- stbir__3_coeff_remnant(8);- stbir__store_output();- } while ( output < output_end );-}--static void STBIR_chans( stbir__horizontal_gather_,_channels_with_12_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )-{- float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;- float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;- do {- 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);- stbir__4_coeff_continue_from_4(8);- stbir__store_output();- } while ( output < output_end );-}--static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod0 )( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )-{- float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;- float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;- 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 * hc = horizontal_coefficients;-- stbir__4_coeff_start();- do {- hc += 4;- decode += STBIR__horizontal_channels * 4;- stbir__4_coeff_continue_from_4( 0 );- --n;- } while ( n > 0 );- stbir__store_output();- } while ( output < output_end );-}--static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod1 )( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )-{- float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;- float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;- 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 * hc = horizontal_coefficients;-- stbir__4_coeff_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__store_output();- } while ( output < output_end );-}--static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod2 )( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )-{- float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;- float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;- 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 * hc = horizontal_coefficients;-- stbir__4_coeff_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__store_output();- } while ( output < output_end );-}--static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod3 )( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )-{- float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;- float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;- stbir__3_coeff_setup();- 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 * hc = horizontal_coefficients;-- stbir__4_coeff_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__store_output();- } while ( output < output_end );-}--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), -};--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_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_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), -};--#undef STBIR__horizontal_channels-#undef STB_IMAGE_RESIZE_DO_HORIZONTALS-#undef stbir__1_coeff_only-#undef stbir__1_coeff_remnant-#undef stbir__2_coeff_only-#undef stbir__2_coeff_remnant-#undef stbir__3_coeff_only-#undef stbir__3_coeff_remnant-#undef stbir__3_coeff_setup-#undef stbir__4_coeff_start-#undef stbir__4_coeff_continue_from_4-#undef stbir__store_output-#undef stbir__store_output_tiny-#undef STBIR_chans--#endif // HORIZONALS--#undef STBIR_strs_join2-#undef STBIR_strs_join1--#endif // STB_IMAGE_RESIZE_DO_HORIZONTALS/VERTICALS/CODERS--/*--------------------------------------------------------------------------------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 -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.--------------------------------------------------------------------------------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, -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 -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 +/* 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+ scaling and translation is supported, no rotations or shears.++ COMPILING & LINKING+ In one C/C++ file that #includes this file, do this:+ #define STB_IMAGE_RESIZE_IMPLEMENTATION+ before the #include. That will create the implementation in that file.++ PORTING FROM VERSION 1++ The API has changed. You can continue to use the old version of stb_image_resize.h,+ which is available in the "deprecated/" directory.++ If you're using the old simple-to-use API, porting is straightforward.+ (For more advanced APIs, read the documentation.)++ stbir_resize_uint8():+ - call `stbir_resize_uint8_linear`, cast channel count to `stbir_pixel_layout`++ stbir_resize_float():+ - call `stbir_resize_float_linear`, cast channel count to `stbir_pixel_layout`++ stbir_resize_uint8_srgb():+ - function name is unchanged+ - cast channel count to `stbir_pixel_layout`+ - above is sufficient unless your image has alpha and it's not RGBA/BGRA+ - in that case, follow the below instructions for stbir_resize_uint8_srgb_edgemode++ stbir_resize_uint8_srgb_edgemode()+ - switch to the "medium complexity" API+ - stbir_resize(), very similar API but a few more parameters:+ - pixel_layout: cast channel count to `stbir_pixel_layout`+ - data_type: STBIR_TYPE_UINT8_SRGB+ - edge: unchanged (STBIR_EDGE_WRAP, etc.)+ - filter: STBIR_FILTER_DEFAULT+ - which channel is alpha is specified in stbir_pixel_layout, see enum for details++ EASY API CALLS:+ Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation, clamps to edge.++ stbir_resize_uint8_srgb( input_pixels, input_w, input_h, input_stride_in_bytes,+ output_pixels, output_w, output_h, output_stride_in_bytes,+ pixel_layout_enum )++ stbir_resize_uint8_linear( input_pixels, input_w, input_h, input_stride_in_bytes,+ output_pixels, output_w, output_h, output_stride_in_bytes,+ pixel_layout_enum )++ stbir_resize_float_linear( input_pixels, input_w, input_h, input_stride_in_bytes,+ output_pixels, output_w, output_h, output_stride_in_bytes,+ pixel_layout_enum )++ If you pass NULL or zero for the output_pixels, we will allocate the output buffer+ for you and return it from the function (free with free() or STBIR_FREE).+ As a special case, XX_stride_in_bytes of 0 means packed continuously in memory.++ API LEVELS+ There are three levels of API - easy-to-use, medium-complexity and extended-complexity.++ See the "header file" section of the source for API documentation.++ ADDITIONAL DOCUMENTATION++ MEMORY ALLOCATION+ 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+ 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+ 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+ 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+ 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.++ 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+ 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+ 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.++ 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+ 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+ channel of an image is processed.++ When alpha represents transparency, it is important that when combining+ colors with filtering, the pixels should not be treated equally; they+ should use a weighted average based on their alpha values. For example,+ if a pixel is 1% opaque bright green and another pixel is 99% opaque+ black and you average them, the average will be 50% opaque, but the+ unweighted average and will be a middling green color, while the weighted+ average will be nearly black. This means the unweighted version introduced+ green energy that didn't exist in the source image.++ (If you want to know why this makes sense, you can work out the math for+ the following: consider what happens if you alpha composite a source image+ over a fixed color and then average the output, vs. if you average the+ source image pixels and then composite that over the same fixed color.+ Only the weighted average produces the same result as the ground truth+ composite-then-average result.)++ Therefore, it is in general best to "alpha weight" the pixels when applying+ filters to them. This essentially means multiplying the colors by the alpha+ values before combining them, and then dividing by the alpha value at the+ end.++ The computer graphics industry introduced a technique called "premultiplied+ alpha" or "associated alpha" in which image colors are stored in image files+ already multiplied by their alpha. This saves some math when compositing,+ and also avoids the need to divide by the alpha at the end (which is quite+ inefficient). However, while premultiplied alpha is common in the movie CGI+ industry, it is not commonplace in other industries like videogames, and most+ consumer file formats are generally expected to contain not-premultiplied+ colors. For example, Photoshop saves PNG files "unpremultiplied", and web+ browsers like Chrome and Firefox expect PNG images to be unpremultiplied.++ Note that there are three possibilities that might describe your image+ and resize expectation:++ 1. images are not premultiplied, alpha weighting is desired+ 2. images are not premultiplied, alpha weighting is not desired+ 3. images are premultiplied++ Both case #2 and case #3 require the exact same math: no alpha weighting+ should be applied or removed. Only case 1 requires extra math operations;+ the other two cases can be handled identically.++ 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.++ 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+ 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.++ 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+ output image is effectively premultiplied, this is actually more performant+ 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()+ 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+ options.++ PIXEL LAYOUT CONVERSION+ The resizer can convert from some pixel layouts to others. When using the+ stbir_set_pixel_layouts(), you can, for example, specify STBIR_RGBA+ on input, and STBIR_ARGB on output, and it will re-organize the channels+ during the resize. Currently, you can only convert between two pixel+ 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).+ 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+ -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.+ 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+ -fpmath=sse.++ Note that we will not be deterministic with float data containing NaNs -+ 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.++ 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.++ 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+ resolution in size_t sized integers. However, the scale ratio from input+ resolution to output resolution is calculated in float form. This means+ the effective possible scale ratio is limited to 24 bits (or 16 million+ to 1). As you get close to the size of the float resolution (again, 16+ million pixels wide or high), you might start seeing float inaccuracy+ issues in general in the pipeline. If you have to do extreme resizes,+ you can usually do this is multiple stages (using float intermediate+ 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+ 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+ use, you can change the compile-time defaults with:++ #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something+ #define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something++ 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+ 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+ 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+ STBIR_FLOORF(v) macros and we'll use them instead. In SIMD, we just use+ our own versions.++ ASSERT+ Define STBIR_ASSERT(boolval) to override assert() and not use assert.h++ FUTURE TODOS+ * For polyphase integral filters, we just memcpy the coeffs to dupe+ them, but we should indirect and use the same coeff memory.+ * Add pixel layout conversions for sensible different channel counts+ (maybe, 1->3/4, 3->4, 4->1, 3->1).+ * 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+ 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?+ * Rewrite the coefficient generator to do many at once.+ * AVX-512 vertical kernels - worried about downclocking here.+ * Convert the reincludes to macros when we know they aren't changing.+ * Experiment with pivoting the horizontal and always using the+ vertical filters (which are faster, but perhaps not enough to overcome+ 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?++ CONTRIBUTORS+ Jeff Roberts: 2.0 implementation, optimizations, SIMD+ 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+ Nathan Reed: warning fixes for 1.0++ REVISIONS+ 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+ 0.93 (2017-03-03) fixed bug with certain combinations of heights+ 0.92 (2017-01-02) fix integer overflow on large (>2GB) images+ 0.91 (2016-04-02) fix warnings; fix handling of subpixel regions+ 0.90 (2014-09-17) first released version++ LICENSE+ See end of file for license information.+*/++#if !defined(STB_IMAGE_RESIZE_DO_HORIZONTALS) && !defined(STB_IMAGE_RESIZE_DO_VERTICALS) && !defined(STB_IMAGE_RESIZE_DO_CODERS) // for internal re-includes++#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE2_H+#define STBIR_INCLUDE_STB_IMAGE_RESIZE2_H++#include <stddef.h>+#ifdef _MSC_VER+typedef unsigned char stbir_uint8;+typedef unsigned short stbir_uint16;+typedef unsigned int stbir_uint32;+typedef unsigned __int64 stbir_uint64;+#else+#include <stdint.h>+typedef uint8_t stbir_uint8;+typedef uint16_t stbir_uint16;+typedef uint32_t stbir_uint32;+typedef uint64_t stbir_uint64;+#endif++#ifdef _M_IX86_FP+#if ( _M_IX86_FP >= 1 )+#ifndef STBIR_SSE+#define STBIR_SSE+#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+ #define STBIR_SSE2+ #endif+ #if defined(__AVX__) || defined(STBIR_AVX2)+ #ifndef STBIR_AVX+ #ifndef STBIR_NO_AVX+ #define STBIR_AVX+ #endif+ #endif+ #endif+ #if defined(__AVX2__) || defined(STBIR_AVX2)+ #ifndef STBIR_NO_AVX2+ #ifndef STBIR_AVX2+ #define STBIR_AVX2+ #endif+ #if defined( _MSC_VER ) && !defined(__clang__)+ #ifndef STBIR_FP16C // FP16C instructions are on all AVX2 cpus, so we can autoselect it here on microsoft - clang needs -m16c+ #define STBIR_FP16C+ #endif+ #endif+ #endif+ #endif+ #ifdef __F16C__+ #ifndef STBIR_FP16C // turn on FP16C instructions if the define is set (for clang and gcc)+ #define STBIR_FP16C+ #endif+ #endif+#endif++#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) || defined(__arm__)+#ifdef STBIR_USE_FMA+#undef STBIR_USE_FMA // no FMA for 32-bit arm on MSVC+#endif+#endif++#if defined(__wasm__) && defined(__wasm_simd128__)+#ifndef STBIR_WASM+#define STBIR_WASM+#endif+#endif++#ifndef STBIRDEF+#ifdef STB_IMAGE_RESIZE_STATIC+#define STBIRDEF static+#else+#ifdef __cplusplus+#define STBIRDEF extern "C"+#else+#define STBIRDEF extern+#endif+#endif+#endif++//////////////////////////////////////////////////////////////////////////////+//// start "header file" ///////////////////////////////////////////////////+//+// Easy-to-use API:+//+// * 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+// * Uses edge mode clamped+// * returned result is 1 for success or 0 in case of an error.+++// stbir_pixel_layout specifies:+// number of channels+// 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+{+ STBIR_1CHANNEL = 1,+ STBIR_2CHANNEL = 2,+ 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, 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;++//===============================================================+// Simple-complexity API+//+// If output_pixels is NULL (0), then we will allocate the buffer and return it to you.+//--------------------------------++STBIRDEF unsigned char * stbir_resize_uint8_srgb( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes,+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,+ stbir_pixel_layout pixel_type );++STBIRDEF unsigned char * stbir_resize_uint8_linear( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes,+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,+ stbir_pixel_layout pixel_type );++STBIRDEF float * stbir_resize_float_linear( const float *input_pixels , int input_w , int input_h, int input_stride_in_bytes,+ float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,+ stbir_pixel_layout pixel_type );+//===============================================================++//===============================================================+// Medium-complexity API+//+// This extends the easy-to-use API as follows:+//+// * Can specify the datatype - U8, U8_SRGB, U16, FLOAT, HALF_FLOAT+// * Edge wrap can selected explicitly+// * Filter can be selected explicitly+//--------------------------------++typedef enum+{+ STBIR_EDGE_CLAMP = 0,+ STBIR_EDGE_REFLECT = 1,+ STBIR_EDGE_WRAP = 2, // this edge mode is slower and uses more memory+ STBIR_EDGE_ZERO = 3,+} stbir_edge;++typedef enum+{+ STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses+ STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios+ STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering+ STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque+ STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline+ STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3+ STBIR_FILTER_POINT_SAMPLE = 6, // Simple point sampling+ STBIR_FILTER_OTHER = 7, // User callback specified+} stbir_filter;++typedef enum+{+ STBIR_TYPE_UINT8 = 0,+ STBIR_TYPE_UINT8_SRGB = 1,+ STBIR_TYPE_UINT8_SRGB_ALPHA = 2, // alpha channel, when present, should also be SRGB (this is very unusual)+ STBIR_TYPE_UINT16 = 3,+ STBIR_TYPE_FLOAT = 4,+ STBIR_TYPE_HALF_FLOAT = 5+} stbir_datatype;++// medium api+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_edge edge, stbir_filter filter );+//===============================================================++++//===============================================================+// Extended-complexity API+//+// This API exposes all resize functionality.+//+// * Separate filter types for each axis+// * Separate edge modes for each axis+// * 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 be threaded for a single resize+// * Can be used to resize many frames without recalculating the sampler info+//+// Use this API as follows:+// 1) Call the stbir_resize_init function on a local STBIR_RESIZE structure+// 2) Call any of the stbir_set functions+// 3) Optionally call stbir_build_samplers() if you are going to resample multiple times+// with the same input and output dimensions (like resizing video frames)+// 4) Resample by calling stbir_resize_extended().+// 5) Call stbir_free_samplers() if you called stbir_build_samplers()+//--------------------------------+++// Types:++// INPUT CALLBACK: this callback is used for input scanlines+typedef void const * stbir_input_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context );++// OUTPUT CALLBACK: this callback is used for output scanlines+typedef void stbir_output_callback( void const * output_ptr, int num_pixels, int y, void * context );++// callbacks for user installed filters+typedef float stbir__kernel_callback( float x, float scale, void * user_data ); // centered at zero+typedef float stbir__support_callback( float scale, void * user_data );++// internal structure with precomputed scaling+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+{+ void * user_data;+ void const * input_pixels;+ int input_w, input_h;+ double input_s0, input_t0, input_s1, input_t1;+ stbir_input_callback * input_cb;+ void * output_pixels;+ int output_w, output_h;+ int output_subx, output_suby, output_subw, output_subh;+ stbir_output_callback * output_cb;+ int input_stride_in_bytes;+ int output_stride_in_bytes;+ int splits;+ int fast_alpha;+ int needs_rebuild;+ int called_alloc;+ stbir_pixel_layout input_pixel_layout_public;+ stbir_pixel_layout output_pixel_layout_public;+ stbir_datatype input_data_type;+ stbir_datatype output_data_type;+ stbir_filter horizontal_filter, vertical_filter;+ 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_RESIZE;++// extended complexity api+++// First off, you must ALWAYS call stbir_resize_init on your resize structure before any of the other calls!+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 );++//===============================================================+// 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_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 );++//===============================================================+++//===============================================================+// If you call any of these functions, you will trigger a sampler rebuild!+//--------------------------------++STBIRDEF int stbir_set_pixel_layouts( STBIR_RESIZE * resize, stbir_pixel_layout input_pixel_layout, stbir_pixel_layout output_pixel_layout ); // sets new buffer layouts+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_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)+STBIRDEF int stbir_set_output_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, int subw, int subh ); // sets output sub-region (full region by default)++// when inputting AND outputting non-premultiplied alpha pixels, we use a slower but higher quality technique+// that fills the zero alpha pixel's RGB values with something plausible. If you don't care about areas of+// zero alpha, you can call this function to get about a 25% speed improvement for STBIR_RGBA to STBIR_RGBA+// types of resizes.+STBIRDEF int stbir_set_non_pm_alpha_speed_over_quality( STBIR_RESIZE * resize, int non_pma_alpha_speed_over_quality );+//===============================================================+++//===============================================================+// You can call build_samplers to prebuild all the internal data we need to resample.+// Then, if you call resize_extended many times with the same resize, you only pay the+// cost once.+// If you do call build_samplers, you MUST call free_samplers eventually.+//--------------------------------++// This builds the samplers and does one allocation+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 );+//===============================================================+++// And this is the main function to perform the resize synchronously on one thread.+STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize );+++//===============================================================+// Use these functions for multithreading.+// 1) You call stbir_build_samplers_with_splits first on the main thread+// 2) Then stbir_resize_with_split on each thread+// 3) stbir_free_samplers when done on the main thread+//--------------------------------++// This will build samplers for threading.+// You can pass in the number of threads you'd like to use (try_splits).+// 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 );++// 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.++// Note that you MUST call stbir_build_samplers_with_splits before stbir_resize_extended_split!++// 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+// 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 );+//===============================================================+++//===============================================================+// Pixel Callbacks info:+//--------------------------------++// 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.+//+// 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.)+//+// You can also install just an input or just an output callback by setting the+// callback that you don't want to zero.+//+// First example, progress: (getting a callback that you can monitor the progress):+// void const * my_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context )+// {+// percentage_done = y / input_height;+// return input_ptr; // use buffer from call+// }+//+// 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):+// 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 );+// return pixels; // return pointer to your data without copying+// }+//+//+// The output callback is considerably simpler - it just calls you so that you can dump+// out each scanline. You could even directly copy out to disk if you have a simple format+// like TGA or BMP. You can also convert to other output types here if you want.+//+// Simple example:+// void const * my_output( void * output_ptr, int num_pixels, int y, void * context )+// {+// percentage_done = y / output_height;+// fwrite( output_ptr, pixel_width_in_bytes, num_pixels, output_file );+// }+//===============================================================+++++//===============================================================+// optional built-in profiling API+//--------------------------------++#ifdef STBIR_PROFILE++typedef struct STBIR_PROFILE_INFO+{+ stbir_uint64 total_clocks;++ // how many clocks spent (of total_clocks) in the various resize routines, along with a string description+ // 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;++// use after calling stbir_resize_extended (or stbir_build_samplers or stbir_build_samplers_with_splits)+STBIRDEF void stbir_resize_build_profile_info( STBIR_PROFILE_INFO * out_info, STBIR_RESIZE const * resize );++// use after calling stbir_resize_extended+STBIRDEF void stbir_resize_extended_profile_info( STBIR_PROFILE_INFO * out_info, STBIR_RESIZE const * resize );++// use after calling stbir_resize_extended_split+STBIRDEF void stbir_resize_split_profile_info( STBIR_PROFILE_INFO * out_info, STBIR_RESIZE const * resize, int split_start, int split_num );++//===============================================================++#endif+++//// end header file /////////////////////////////////////////////////////+#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE2_H++#if defined(STB_IMAGE_RESIZE_IMPLEMENTATION) || defined(STB_IMAGE_RESIZE2_IMPLEMENTATION)++#ifndef STBIR_ASSERT+#include <assert.h>+#define STBIR_ASSERT(x) assert(x)+#endif++#ifndef STBIR_MALLOC+#include <stdlib.h>+#define STBIR_MALLOC(size,user_data) ((void)(user_data), malloc(size))+#define STBIR_FREE(ptr,user_data) ((void)(user_data), free(ptr))+// (we used the comma operator to evaluate user_data, to avoid "unused parameter" warnings)+#endif++#ifdef _MSC_VER++#define stbir__inline __forceinline++#else++#define stbir__inline __inline__++// Clang address sanitizer+#if defined(__has_feature)+ #if __has_feature(address_sanitizer) || __has_feature(memory_sanitizer)+ #ifndef STBIR__SEPARATE_ALLOCATIONS+ #define STBIR__SEPARATE_ALLOCATIONS+ #endif+ #endif+#endif++#endif++// GCC and MSVC+#if defined(__SANITIZE_ADDRESS__)+ #ifndef STBIR__SEPARATE_ALLOCATIONS+ #define STBIR__SEPARATE_ALLOCATIONS+ #endif+#endif++// Always turn off automatic FMA use - use STBIR_USE_FMA if you want.+// Otherwise, this is a determinism disaster.+#ifndef STBIR_DONT_CHANGE_FP_CONTRACT // override in case you don't want this behavior+#if defined(_MSC_VER) && !defined(__clang__)+#if _MSC_VER > 1200+#pragma fp_contract(off)+#endif+#elif defined(__GNUC__) && !defined(__clang__)+#pragma GCC optimize("fp-contract=off")+#else+#pragma STDC FP_CONTRACT OFF+#endif+#endif++#ifdef _MSC_VER+#define STBIR__UNUSED(v) (void)(v)+#else+#define STBIR__UNUSED(v) (void)sizeof(v)+#endif++#define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0]))+++#ifndef STBIR_DEFAULT_FILTER_UPSAMPLE+#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM+#endif++#ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE+#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL+#endif+++#ifndef STBIR__HEADER_FILENAME+#define STBIR__HEADER_FILENAME "stb_image_resize2.h"+#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+{+ STBIRI_1CHANNEL = 0,+ STBIRI_2CHANNEL = 1,+ STBIRI_RGB = 2,+ STBIRI_BGR = 3,+ STBIRI_4CHANNEL = 4,++ STBIRI_RGBA = 5,+ STBIRI_BGRA = 6,+ STBIRI_ARGB = 7,+ STBIRI_ABGR = 8,+ STBIRI_RA = 9,+ STBIRI_AR = 10,++ STBIRI_RGBA_PM = 11,+ STBIRI_BGRA_PM = 12,+ STBIRI_ARGB_PM = 13,+ STBIRI_ABGR_PM = 14,+ STBIRI_RA_PM = 15,+ STBIRI_AR_PM = 16,+} stbir_internal_pixel_layout;++// define the public pixel layouts to not compile inside the implementation (to avoid accidental use)+#define STBIR_BGR bad_dont_use_in_implementation+#define STBIR_1CHANNEL STBIR_BGR+#define STBIR_2CHANNEL STBIR_BGR+#define STBIR_RGB STBIR_BGR+#define STBIR_RGBA STBIR_BGR+#define STBIR_4CHANNEL STBIR_BGR+#define STBIR_BGRA STBIR_BGR+#define STBIR_ARGB STBIR_BGR+#define STBIR_ABGR STBIR_BGR+#define STBIR_RA STBIR_BGR+#define STBIR_AR STBIR_BGR+#define STBIR_RGBA_PM STBIR_BGR+#define STBIR_BGRA_PM STBIR_BGR+#define STBIR_ARGB_PM STBIR_BGR+#define STBIR_ABGR_PM STBIR_BGR+#define STBIR_RA_PM STBIR_BGR+#define STBIR_AR_PM STBIR_BGR++// must match stbir_datatype+static unsigned char stbir__type_size[] = {+ 1,1,1,2,4,2 // STBIR_TYPE_UINT8,STBIR_TYPE_UINT8_SRGB,STBIR_TYPE_UINT8_SRGB_ALPHA,STBIR_TYPE_UINT16,STBIR_TYPE_FLOAT,STBIR_TYPE_HALF_FLOAT+};++// When gathering, the contributors are which source pixels contribute.+// When scattering, the contributors are which destination pixels are contributed to.+typedef struct+{+ int n0; // First contributing pixel+ int n1; // Last contributing pixel+} stbir__contributors;++typedef struct+{+ int lowest; // First sample index for whole filter+ int highest; // Last sample index for whole filter+ int widest; // widest single set of samples for an output+} stbir__filter_extent_info;++typedef struct+{+ int n0; // First pixel of decode buffer to write to+ int n1; // Last pixel of decode that will be written to+ int pixel_offset_for_input; // Pixel offset into input_scanline+} stbir__span;++typedef struct stbir__scale_info+{+ int input_full_size;+ int output_sub_size;+ float scale;+ float inv_scale;+ float pixel_shift; // starting shift in output pixel space (in pixels)+ int scale_is_rational;+ stbir_uint32 scale_numerator, scale_denominator;+} stbir__scale_info;++typedef struct+{+ stbir__contributors * contributors;+ float* coefficients;+ stbir__contributors * gather_prescatter_contributors;+ float * gather_prescatter_coefficients;+ stbir__scale_info scale_info;+ float support;+ stbir_filter filter_enum;+ stbir__kernel_callback * filter_kernel;+ stbir__support_callback * filter_support;+ stbir_edge edge;+ int coefficient_width;+ int filter_pixel_width;+ int filter_pixel_margin;+ int num_contributors;+ int contributors_size;+ int coefficients_size;+ stbir__filter_extent_info extent_info;+ int is_gather; // 0 = scatter, 1 = gather with scale >= 1, 2 = gather with scale < 1+ int gather_prescatter_num_contributors;+ int gather_prescatter_coefficient_width;+ int gather_prescatter_contributors_size;+ int gather_prescatter_coefficients_size;+} stbir__sampler;++typedef struct+{+ stbir__contributors conservative;+ int edge_sizes[2]; // this can be less than filter_pixel_margin, if the filter and scaling falls off+ stbir__span spans[2]; // can be two spans, if doing input subrect with clamp mode WRAP+} stbir__extents;++typedef struct+{+#ifdef STBIR_PROFILE+ union+ {+ struct { stbir_uint64 total, looping, vertical, horizontal, decode, encode, alpha, unalpha; } named;+ stbir_uint64 array[8];+ } profile;+ stbir_uint64 * current_zone_excluded_ptr;+#endif+ float* decode_buffer;++ int ring_buffer_first_scanline;+ int ring_buffer_last_scanline;+ int ring_buffer_begin_index; // first_scanline is at this index in the ring buffer+ int start_output_y, end_output_y;+ int start_input_y, end_input_y; // used in scatter only++ #ifdef STBIR__SEPARATE_ALLOCATIONS+ float** ring_buffers; // one pointer for each ring buffer+ #else+ float* ring_buffer; // one big buffer that we index into+ #endif++ float* vertical_buffer;++ char no_cache_straddle[64];+} stbir__per_split_info;++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,+ 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 );++struct stbir__info+{+#ifdef STBIR_PROFILE+ union+ {+ struct { stbir_uint64 total, build, alloc, horizontal, vertical, cleanup, pivot; } named;+ stbir_uint64 array[7];+ } profile;+ stbir_uint64 * current_zone_excluded_ptr;+#endif+ stbir__sampler horizontal;+ stbir__sampler vertical;++ void const * input_data;+ void * output_data;++ int input_stride_bytes;+ int output_stride_bytes;+ int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)+ int ring_buffer_num_entries; // Total number of entries in the ring buffer.++ stbir_datatype input_type;+ stbir_datatype output_type;++ stbir_input_callback * in_pixels_cb;+ void * user_data;+ stbir_output_callback * out_pixels_cb;++ stbir__extents scanline_extents;++ void * alloced_mem;+ stbir__per_split_info * split_info; // by default 1, but there will be N of these allocated based on the thread init you did++ stbir__decode_pixels_func * decode_pixels;+ stbir__alpha_weight_func * alpha_weight;+ stbir__horizontal_gather_channels_func * horizontal_gather_channels;+ stbir__alpha_unweight_func * alpha_unweight;+ stbir__encode_pixels_func * encode_pixels;++ 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;++ int input_color_and_type;+ int offset_x, offset_y; // offset within output_data+ int vertical_first;+ int channels;+ int effective_channels; // same as channels, except on RGBA/ARGB (7), or XA/AX (3)+ size_t alloced_total;+};+++#define stbir__max_uint8_as_float 255.0f+#define stbir__max_uint16_as_float 65535.0f+#define stbir__max_uint8_as_float_inverted (1.0f/255.0f)+#define stbir__max_uint16_as_float_inverted (1.0f/65535.0f)+#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) for(;;) { \+ if ( (x) < (xmin) ) (x) = (xmin); \+ if ( (x) > (xmax) ) (x) = (xmax); \+ break; \+}++static stbir__inline int stbir__min(int a, int b)+{+ return a < b ? a : b;+}++static stbir__inline int stbir__max(int a, int b)+{+ return a > b ? a : b;+}++static float stbir__srgb_uchar_to_linear_float[256] = {+ 0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f,+ 0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f,+ 0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f,+ 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f,+ 0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f,+ 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f,+ 0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f,+ 0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f,+ 0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f,+ 0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f,+ 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f,+ 0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f,+ 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f,+ 0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f,+ 0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f,+ 0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f,+ 0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f,+ 0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f,+ 0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f,+ 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f,+ 0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f,+ 0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f,+ 0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f,+ 0.982251f, 0.991102f, 1.0f+};++typedef union+{+ unsigned int u;+ float f;+} stbir__FP32;++// From https://gist.github.com/rygorous/2203834++static const stbir_uint32 fp32_to_srgb8_tab4[104] = {+ 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,+ 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,+ 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,+ 0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,+ 0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,+ 0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,+ 0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,+ 0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,+ 0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,+ 0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,+ 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,+ 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+ static const stbir__FP32 minval = { (127-13) << 23 };+ stbir_uint32 tab,bias,scale,t;+ stbir__FP32 f;++ // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively.+ // The tests are carefully written so that NaNs map to 0, same as in the reference+ // implementation.+ if (!(in > minval.f)) // written this way to catch NaNs+ return 0;+ if (in > almostone.f)+ return 255;++ // Do the table lookup and unpack bias, scale+ f.f = in;+ tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20];+ bias = (tab >> 16) << 9;+ scale = tab & 0xffff;++ // Grab next-highest mantissa bits and perform linear interpolation+ t = (f.u >> 12) & 0xff;+ return (unsigned char) ((bias + scale*t) >> 16);+}++#ifndef STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT+#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++#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+ #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++// force simd off overrides everything else, so clear it all++#ifdef STBIR_SSE2+#undef STBIR_SSE2+#endif++#ifdef STBIR_AVX+#undef STBIR_AVX+#endif++#ifdef STBIR_NEON+#undef STBIR_NEON+#endif++#ifdef STBIR_AVX2+#undef STBIR_AVX2+#endif++#ifdef STBIR_FP16C+#undef STBIR_FP16C+#endif++#ifdef STBIR_WASM+#undef STBIR_WASM+#endif++#ifdef STBIR_SIMD+#undef STBIR_SIMD+#endif++#else // STBIR_SIMD++#ifdef STBIR_SSE2+ #include <emmintrin.h>++ #define stbir__simdf __m128+ #define stbir__simdi __m128i++ #define stbir_simdi_castf( reg ) _mm_castps_si128(reg)+ #define stbir_simdf_casti( reg ) _mm_castsi128_ps(reg)++ #define stbir__simdf_load( reg, ptr ) (reg) = _mm_loadu_ps( (float const*)(ptr) )+ #define stbir__simdi_load( reg, ptr ) (reg) = _mm_loadu_si128 ( (stbir__simdi const*)(ptr) )+ #define stbir__simdf_load1( out, ptr ) (out) = _mm_load_ss( (float const*)(ptr) ) // top values can be random (not denormal or nan for perf)+ #define stbir__simdi_load1( out, ptr ) (out) = _mm_castps_si128( _mm_load_ss( (float const*)(ptr) ))+ #define stbir__simdf_load1z( out, ptr ) (out) = _mm_load_ss( (float const*)(ptr) ) // top values must be zero+ #define stbir__simdf_frep4( fvar ) _mm_set_ps1( fvar )+ #define stbir__simdf_load1frep4( out, fvar ) (out) = _mm_set_ps1( fvar )+ #define stbir__simdf_load2( out, ptr ) (out) = _mm_castsi128_ps( _mm_loadl_epi64( (__m128i*)(ptr)) ) // top values can be random (not denormal or nan for perf)+ #define stbir__simdf_load2z( out, ptr ) (out) = _mm_castsi128_ps( _mm_loadl_epi64( (__m128i*)(ptr)) ) // top values must be zero+ #define stbir__simdf_load2hmerge( out, reg, ptr ) (out) = _mm_castpd_ps(_mm_loadh_pd( _mm_castps_pd(reg), (double*)(ptr) ))++ #define stbir__simdf_zeroP() _mm_setzero_ps()+ #define stbir__simdf_zero( reg ) (reg) = _mm_setzero_ps()++ #define stbir__simdf_store( ptr, reg ) _mm_storeu_ps( (float*)(ptr), reg )+ #define stbir__simdf_store1( ptr, reg ) _mm_store_ss( (float*)(ptr), reg )+ #define stbir__simdf_store2( ptr, reg ) _mm_storel_epi64( (__m128i*)(ptr), _mm_castps_si128(reg) )+ #define stbir__simdf_store2h( ptr, reg ) _mm_storeh_pd( (double*)(ptr), _mm_castps_pd(reg) )++ #define stbir__simdi_store( ptr, reg ) _mm_storeu_si128( (__m128i*)(ptr), reg )+ #define stbir__simdi_store1( ptr, reg ) _mm_store_ss( (float*)(ptr), _mm_castsi128_ps(reg) )+ #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(); \+ out2 = _mm_unpacklo_epi8( ireg, zero ); \+ out3 = _mm_unpackhi_epi8( ireg, zero ); \+ out0 = _mm_unpacklo_epi16( out2, zero ); \+ out1 = _mm_unpackhi_epi16( out2, zero ); \+ out2 = _mm_unpacklo_epi16( out3, zero ); \+ out3 = _mm_unpackhi_epi16( out3, zero ); \+ }++#define stbir__simdi_expand_u8_to_1u32(out,ireg) \+ { \+ stbir__simdi zero = _mm_setzero_si128(); \+ out = _mm_unpacklo_epi8( ireg, zero ); \+ out = _mm_unpacklo_epi16( out, zero ); \+ }++ #define stbir__simdi_expand_u16_to_u32(out0,out1,ireg) \+ { \+ stbir__simdi zero = _mm_setzero_si128(); \+ out0 = _mm_unpacklo_epi16( ireg, zero ); \+ out1 = _mm_unpackhi_epi16( ireg, zero ); \+ }++ #define stbir__simdf_convert_float_to_i32( i, f ) (i) = _mm_cvttps_epi32(f)+ #define stbir__simdf_convert_float_to_int( f ) _mm_cvtt_ss2si(f)+ #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_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 )+ #define stbir__simdf_mult_mem( out, reg, ptr ) (out) = _mm_mul_ps( reg, _mm_loadu_ps( (float const*)(ptr) ) )+ #define stbir__simdf_mult1_mem( out, reg, ptr ) (out) = _mm_mul_ss( reg, _mm_load_ss( (float const*)(ptr) ) )+ #define stbir__simdf_add_mem( out, reg, ptr ) (out) = _mm_add_ps( reg, _mm_loadu_ps( (float const*)(ptr) ) )+ #define stbir__simdf_add1_mem( out, reg, ptr ) (out) = _mm_add_ss( reg, _mm_load_ss( (float const*)(ptr) ) )++ #ifdef STBIR_USE_FMA // not on by default to maintain bit identical simd to non-simd+ #include <immintrin.h>+ #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = _mm_fmadd_ps( mul1, mul2, add )+ #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = _mm_fmadd_ss( mul1, mul2, add )+ #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = _mm_fmadd_ps( mul, _mm_loadu_ps( (float const*)(ptr) ), add )+ #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = _mm_fmadd_ss( mul, _mm_load_ss( (float const*)(ptr) ), add )+ #else+ #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = _mm_add_ps( add, _mm_mul_ps( mul1, mul2 ) )+ #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = _mm_add_ss( add, _mm_mul_ss( mul1, mul2 ) )+ #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = _mm_add_ps( add, _mm_mul_ps( mul, _mm_loadu_ps( (float const*)(ptr) ) ) )+ #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = _mm_add_ss( add, _mm_mul_ss( mul, _mm_load_ss( (float const*)(ptr) ) ) )+ #endif++ #define stbir__simdf_add1( out, reg0, reg1 ) (out) = _mm_add_ss( reg0, reg1 )+ #define stbir__simdf_mult1( out, reg0, reg1 ) (out) = _mm_mul_ss( reg0, reg1 )++ #define stbir__simdf_and( out, reg0, reg1 ) (out) = _mm_and_ps( reg0, reg1 )+ #define stbir__simdf_or( out, reg0, reg1 ) (out) = _mm_or_ps( reg0, reg1 )++ #define stbir__simdf_min( out, reg0, reg1 ) (out) = _mm_min_ps( reg0, reg1 )+ #define stbir__simdf_max( out, reg0, reg1 ) (out) = _mm_max_ps( reg0, reg1 )+ #define stbir__simdf_min1( out, reg0, reg1 ) (out) = _mm_min_ss( reg0, reg1 )+ #define stbir__simdf_max1( out, reg0, reg1 ) (out) = _mm_max_ss( reg0, reg1 )++ #define stbir__simdf_0123ABCDto3ABx( out, reg0, reg1 ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_shuffle_ps( reg1,reg0, (0<<0) + (1<<2) + (2<<4) + (3<<6) )), (3<<0) + (0<<2) + (1<<4) + (2<<6) ) )+ #define stbir__simdf_0123ABCDto23Ax( out, reg0, reg1 ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_shuffle_ps( reg1,reg0, (0<<0) + (1<<2) + (2<<4) + (3<<6) )), (2<<0) + (3<<2) + (0<<4) + (1<<6) ) )++ static const stbir__simdf STBIR_zeroones = { 0.0f,1.0f,0.0f,1.0f };+ static const stbir__simdf STBIR_onezeros = { 1.0f,0.0f,1.0f,0.0f };+ #define stbir__simdf_aaa1( out, alp, ones ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_movehl_ps( ones, alp ) ), (1<<0) + (1<<2) + (1<<4) + (2<<6) ) )+ #define stbir__simdf_1aaa( out, alp, ones ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_movelh_ps( ones, alp ) ), (0<<0) + (2<<2) + (2<<4) + (2<<6) ) )+ #define stbir__simdf_a1a1( out, alp, ones) (out) = _mm_or_ps( _mm_castsi128_ps( _mm_srli_epi64( _mm_castps_si128(alp), 32 ) ), STBIR_zeroones )+ #define stbir__simdf_1a1a( out, alp, ones) (out) = _mm_or_ps( _mm_castsi128_ps( _mm_slli_epi64( _mm_castps_si128(alp), 32 ) ), STBIR_onezeros )++ #define stbir__simdf_swiz( reg, one, two, three, four ) _mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( reg ), (one<<0) + (two<<2) + (three<<4) + (four<<6) ) )++ #define stbir__simdi_and( out, reg0, reg1 ) (out) = _mm_and_si128( reg0, reg1 )+ #define stbir__simdi_or( out, reg0, reg1 ) (out) = _mm_or_si128( reg0, reg1 )+ #define stbir__simdi_16madd( out, reg0, reg1 ) (out) = _mm_madd_epi16( reg0, reg1 )++ #define stbir__simdf_pack_to_8bytes(out,aa,bb) \+ { \+ stbir__simdf af,bf; \+ stbir__simdi a,b; \+ af = _mm_min_ps( aa, STBIR_max_uint8_as_float ); \+ bf = _mm_min_ps( bb, STBIR_max_uint8_as_float ); \+ af = _mm_max_ps( af, _mm_setzero_ps() ); \+ bf = _mm_max_ps( bf, _mm_setzero_ps() ); \+ a = _mm_cvttps_epi32( af ); \+ b = _mm_cvttps_epi32( bf ); \+ a = _mm_packs_epi32( a, b ); \+ out = _mm_packus_epi16( a, a ); \+ }++ #define stbir__simdf_load4_transposed( o0, o1, o2, o3, ptr ) \+ stbir__simdf_load( o0, (ptr) ); \+ stbir__simdf_load( o1, (ptr)+4 ); \+ stbir__simdf_load( o2, (ptr)+8 ); \+ stbir__simdf_load( o3, (ptr)+12 ); \+ { \+ __m128 tmp0, tmp1, tmp2, tmp3; \+ tmp0 = _mm_unpacklo_ps(o0, o1); \+ tmp2 = _mm_unpacklo_ps(o2, o3); \+ tmp1 = _mm_unpackhi_ps(o0, o1); \+ tmp3 = _mm_unpackhi_ps(o2, o3); \+ o0 = _mm_movelh_ps(tmp0, tmp2); \+ o1 = _mm_movehl_ps(tmp2, tmp0); \+ o2 = _mm_movelh_ps(tmp1, tmp3); \+ o3 = _mm_movehl_ps(tmp3, tmp1); \+ }++ #define stbir__interleave_pack_and_store_16_u8( ptr, r0, r1, r2, r3 ) \+ r0 = _mm_packs_epi32( r0, r1 ); \+ r2 = _mm_packs_epi32( r2, r3 ); \+ r1 = _mm_unpacklo_epi16( r0, r2 ); \+ r3 = _mm_unpackhi_epi16( r0, r2 ); \+ r0 = _mm_unpacklo_epi16( r1, r3 ); \+ r2 = _mm_unpackhi_epi16( r1, r3 ); \+ r0 = _mm_packus_epi16( r0, r2 ); \+ stbir__simdi_store( ptr, r0 ); \++ #define stbir__simdi_32shr( out, reg, imm ) out = _mm_srli_epi32( reg, imm )++ #if defined(_MSC_VER) && !defined(__clang__)+ // msvc inits with 8 bytes+ #define STBIR__CONST_32_TO_8( v ) (char)(unsigned char)((v)&255),(char)(unsigned char)(((v)>>8)&255),(char)(unsigned char)(((v)>>16)&255),(char)(unsigned char)(((v)>>24)&255)+ #define STBIR__CONST_4_32i( v ) STBIR__CONST_32_TO_8( v ), STBIR__CONST_32_TO_8( v ), STBIR__CONST_32_TO_8( v ), STBIR__CONST_32_TO_8( v )+ #define STBIR__CONST_4d_32i( v0, v1, v2, v3 ) STBIR__CONST_32_TO_8( v0 ), STBIR__CONST_32_TO_8( v1 ), STBIR__CONST_32_TO_8( v2 ), STBIR__CONST_32_TO_8( v3 )+ #else+ // everything else inits with long long's+ #define STBIR__CONST_4_32i( v ) (long long)((((stbir_uint64)(stbir_uint32)(v))<<32)|((stbir_uint64)(stbir_uint32)(v))),(long long)((((stbir_uint64)(stbir_uint32)(v))<<32)|((stbir_uint64)(stbir_uint32)(v)))+ #define STBIR__CONST_4d_32i( v0, v1, v2, v3 ) (long long)((((stbir_uint64)(stbir_uint32)(v1))<<32)|((stbir_uint64)(stbir_uint32)(v0))),(long long)((((stbir_uint64)(stbir_uint32)(v3))<<32)|((stbir_uint64)(stbir_uint32)(v2)))+ #endif++ #define STBIR__SIMDF_CONST(var, x) stbir__simdf var = { x, x, x, x }+ #define STBIR__SIMDI_CONST(var, x) stbir__simdi var = { STBIR__CONST_4_32i(x) }+ #define STBIR__CONSTF(var) (var)+ #define STBIR__CONSTI(var) (var)++ #if defined(STBIR_AVX) || defined(__SSE4_1__)+ #include <smmintrin.h>+ #define stbir__simdf_pack_to_8words(out,reg0,reg1) out = _mm_packus_epi32(_mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg0,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())), _mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg1,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())))+ #else+ STBIR__SIMDI_CONST(stbir__s32_32768, 32768);+ STBIR__SIMDI_CONST(stbir__s16_32768, ((32768<<16)|32768));++ #define stbir__simdf_pack_to_8words(out,reg0,reg1) \+ { \+ stbir__simdi tmp0,tmp1; \+ tmp0 = _mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg0,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())); \+ tmp1 = _mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg1,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())); \+ tmp0 = _mm_sub_epi32( tmp0, stbir__s32_32768 ); \+ tmp1 = _mm_sub_epi32( tmp1, stbir__s32_32768 ); \+ out = _mm_packs_epi32( tmp0, tmp1 ); \+ out = _mm_sub_epi16( out, stbir__s16_32768 ); \+ }++ #endif++ #define STBIR_SIMD++ // if we detect AVX, set the simd8 defines+ #ifdef STBIR_AVX+ #include <immintrin.h>+ #define STBIR_SIMD8+ #define stbir__simdf8 __m256+ #define stbir__simdi8 __m256i+ #define stbir__simdf8_load( out, ptr ) (out) = _mm256_loadu_ps( (float const *)(ptr) )+ #define stbir__simdi8_load( out, ptr ) (out) = _mm256_loadu_si256( (__m256i const *)(ptr) )+ #define stbir__simdf8_mult( out, a, b ) (out) = _mm256_mul_ps( (a), (b) )+ #define stbir__simdf8_store( ptr, out ) _mm256_storeu_ps( (float*)(ptr), out )+ #define stbir__simdi8_store( ptr, reg ) _mm256_storeu_si256( (__m256i*)(ptr), reg )+ #define stbir__simdf8_frep8( fval ) _mm256_set1_ps( fval )++ #define stbir__simdf8_min( out, reg0, reg1 ) (out) = _mm256_min_ps( reg0, reg1 )+ #define stbir__simdf8_max( out, reg0, reg1 ) (out) = _mm256_max_ps( reg0, reg1 )++ #define stbir__simdf8_add4halves( out, bot4, top8 ) (out) = _mm_add_ps( bot4, _mm256_extractf128_ps( top8, 1 ) )+ #define stbir__simdf8_mult_mem( out, reg, ptr ) (out) = _mm256_mul_ps( reg, _mm256_loadu_ps( (float const*)(ptr) ) )+ #define stbir__simdf8_add_mem( out, reg, ptr ) (out) = _mm256_add_ps( reg, _mm256_loadu_ps( (float const*)(ptr) ) )+ #define stbir__simdf8_add( out, a, b ) (out) = _mm256_add_ps( a, b )+ #define stbir__simdf8_load1b( out, ptr ) (out) = _mm256_broadcast_ss( ptr )+ #define stbir__simdf_load1rep4( out, ptr ) (out) = _mm_broadcast_ss( ptr ) // avx load instruction++ #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++ #define stbir__simdi8_expand_u8_to_u32(out0,out1,ireg) \+ { \+ stbir__simdi8 a, zero =_mm256_setzero_si256();\+ a = _mm256_permute4x64_epi64( _mm256_unpacklo_epi8( _mm256_permute4x64_epi64(_mm256_castsi128_si256(ireg),(0<<0)+(2<<2)+(1<<4)+(3<<6)), zero ),(0<<0)+(2<<2)+(1<<4)+(3<<6)); \+ out0 = _mm256_unpacklo_epi16( a, zero ); \+ out1 = _mm256_unpackhi_epi16( a, zero ); \+ }++ #define stbir__simdf8_pack_to_16bytes(out,aa,bb) \+ { \+ stbir__simdi8 t; \+ stbir__simdf8 af,bf; \+ stbir__simdi8 a,b; \+ af = _mm256_min_ps( aa, STBIR_max_uint8_as_floatX ); \+ bf = _mm256_min_ps( bb, STBIR_max_uint8_as_floatX ); \+ af = _mm256_max_ps( af, _mm256_setzero_ps() ); \+ bf = _mm256_max_ps( bf, _mm256_setzero_ps() ); \+ a = _mm256_cvttps_epi32( af ); \+ b = _mm256_cvttps_epi32( bf ); \+ t = _mm256_permute4x64_epi64( _mm256_packs_epi32( a, b ), (0<<0)+(2<<2)+(1<<4)+(3<<6) ); \+ 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__simdf8_pack_to_16words(out,aa,bb) \+ { \+ stbir__simdf8 af,bf; \+ stbir__simdi8 a,b; \+ af = _mm256_min_ps( aa, STBIR_max_uint16_as_floatX ); \+ bf = _mm256_min_ps( bb, STBIR_max_uint16_as_floatX ); \+ af = _mm256_max_ps( af, _mm256_setzero_ps() ); \+ bf = _mm256_max_ps( bf, _mm256_setzero_ps() ); \+ a = _mm256_cvttps_epi32( af ); \+ b = _mm256_cvttps_epi32( bf ); \+ (out) = _mm256_permute4x64_epi64( _mm256_packus_epi32(a, b), (0<<0)+(2<<2)+(1<<4)+(3<<6) ); \+ }++ #else++ #define stbir__simdi8_expand_u8_to_u32(out0,out1,ireg) \+ { \+ stbir__simdi a,zero = _mm_setzero_si128(); \+ a = _mm_unpacklo_epi8( ireg, zero ); \+ out0 = _mm256_setr_m128i( _mm_unpacklo_epi16( a, zero ), _mm_unpackhi_epi16( a, zero ) ); \+ 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; \+ stbir__simdf8 af,bf; \+ stbir__simdi8 a,b; \+ af = _mm256_min_ps( aa, STBIR_max_uint8_as_floatX ); \+ bf = _mm256_min_ps( bb, STBIR_max_uint8_as_floatX ); \+ af = _mm256_max_ps( af, _mm256_setzero_ps() ); \+ bf = _mm256_max_ps( bf, _mm256_setzero_ps() ); \+ a = _mm256_cvttps_epi32( af ); \+ b = _mm256_cvttps_epi32( bf ); \+ out = _mm_packs_epi32( _mm256_castsi256_si128(a), _mm256_extractf128_si256( a, 1 ) ); \+ out = _mm_packus_epi16( out, out ); \+ t = _mm_packs_epi32( _mm256_castsi256_si128(b), _mm256_extractf128_si256( b, 1 ) ); \+ 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(); \+ a = _mm_unpacklo_epi16( ireg, zero ); \+ b = _mm_unpackhi_epi16( ireg, zero ); \+ out = _mm256_insertf128_si256( _mm256_castsi128_si256( a ), b, 1 ); \+ }++ #define stbir__simdf8_pack_to_16words(out,aa,bb) \+ { \+ stbir__simdi t0,t1; \+ stbir__simdf8 af,bf; \+ stbir__simdi8 a,b; \+ af = _mm256_min_ps( aa, STBIR_max_uint16_as_floatX ); \+ bf = _mm256_min_ps( bb, STBIR_max_uint16_as_floatX ); \+ af = _mm256_max_ps( af, _mm256_setzero_ps() ); \+ bf = _mm256_max_ps( bf, _mm256_setzero_ps() ); \+ a = _mm256_cvttps_epi32( af ); \+ b = _mm256_cvttps_epi32( bf ); \+ t0 = _mm_packus_epi32( _mm256_castsi256_si128(a), _mm256_extractf128_si256( a, 1 ) ); \+ t1 = _mm_packus_epi32( _mm256_castsi256_si128(b), _mm256_extractf128_si256( b, 1 ) ); \+ out = _mm256_setr_m128i( t0, t1 ); \+ }++ #endif++ static __m256i stbir_00001111 = { STBIR__CONST_4d_32i( 0, 0, 0, 0 ), STBIR__CONST_4d_32i( 1, 1, 1, 1 ) };+ #define stbir__simdf8_0123to00001111( out, in ) (out) = _mm256_permutevar_ps ( in, stbir_00001111 )++ static __m256i stbir_22223333 = { STBIR__CONST_4d_32i( 2, 2, 2, 2 ), STBIR__CONST_4d_32i( 3, 3, 3, 3 ) };+ #define stbir__simdf8_0123to22223333( out, in ) (out) = _mm256_permutevar_ps ( in, stbir_22223333 )++ #define stbir__simdf8_0123to2222( out, in ) (out) = stbir__simdf_swiz(_mm256_castps256_ps128(in), 2,2,2,2 )++ #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 ) };+ #define stbir__simdf8_0123to00112233( out, in ) (out) = _mm256_permutevar_ps ( in, stbir_00112233 )+ #define stbir__simdf8_add4( out, a8, b ) (out) = _mm256_add_ps( a8, _mm256_castps128_ps256( b ) )++ static __m256i stbir_load6 = { STBIR__CONST_4_32i( 0x80000000 ), STBIR__CONST_4d_32i( 0x80000000, 0x80000000, 0, 0 ) };+ #define stbir__simdf8_load6z( out, ptr ) (out) = _mm256_maskload_ps( ptr, stbir_load6 )++ #define stbir__simdf8_0123to00000000( out, in ) (out) = _mm256_shuffle_ps ( in, in, (0<<0)+(0<<2)+(0<<4)+(0<<6) )+ #define stbir__simdf8_0123to11111111( out, in ) (out) = _mm256_shuffle_ps ( in, in, (1<<0)+(1<<2)+(1<<4)+(1<<6) )+ #define stbir__simdf8_0123to22222222( out, in ) (out) = _mm256_shuffle_ps ( in, in, (2<<0)+(2<<2)+(2<<4)+(2<<6) )+ #define stbir__simdf8_0123to33333333( out, in ) (out) = _mm256_shuffle_ps ( in, in, (3<<0)+(3<<2)+(3<<4)+(3<<6) )+ #define stbir__simdf8_0123to21032103( out, in ) (out) = _mm256_shuffle_ps ( in, in, (2<<0)+(1<<2)+(0<<4)+(3<<6) )+ #define stbir__simdf8_0123to32103210( out, in ) (out) = _mm256_shuffle_ps ( in, in, (3<<0)+(2<<2)+(1<<4)+(0<<6) )+ #define stbir__simdf8_0123to12301230( out, in ) (out) = _mm256_shuffle_ps ( in, in, (1<<0)+(2<<2)+(3<<4)+(0<<6) )+ #define stbir__simdf8_0123to10321032( out, in ) (out) = _mm256_shuffle_ps ( in, in, (1<<0)+(0<<2)+(3<<4)+(2<<6) )+ #define stbir__simdf8_0123to30123012( out, in ) (out) = _mm256_shuffle_ps ( in, in, (3<<0)+(0<<2)+(1<<4)+(2<<6) )++ #define stbir__simdf8_0123to11331133( out, in ) (out) = _mm256_shuffle_ps ( in, in, (1<<0)+(1<<2)+(3<<4)+(3<<6) )+ #define stbir__simdf8_0123to00220022( out, in ) (out) = _mm256_shuffle_ps ( in, in, (0<<0)+(0<<2)+(2<<4)+(2<<6) )++ #define stbir__simdf8_aaa1( out, alp, ones ) (out) = _mm256_blend_ps( alp, ones, (1<<0)+(1<<1)+(1<<2)+(0<<3)+(1<<4)+(1<<5)+(1<<6)+(0<<7)); (out)=_mm256_shuffle_ps( out,out, (3<<0) + (3<<2) + (3<<4) + (0<<6) )+ #define stbir__simdf8_1aaa( out, alp, ones ) (out) = _mm256_blend_ps( alp, ones, (0<<0)+(1<<1)+(1<<2)+(1<<3)+(0<<4)+(1<<5)+(1<<6)+(1<<7)); (out)=_mm256_shuffle_ps( out,out, (1<<0) + (0<<2) + (0<<4) + (0<<6) )+ #define stbir__simdf8_a1a1( out, alp, ones) (out) = _mm256_blend_ps( alp, ones, (1<<0)+(0<<1)+(1<<2)+(0<<3)+(1<<4)+(0<<5)+(1<<6)+(0<<7)); (out)=_mm256_shuffle_ps( out,out, (1<<0) + (0<<2) + (3<<4) + (2<<6) )+ #define stbir__simdf8_1a1a( out, alp, ones) (out) = _mm256_blend_ps( alp, ones, (0<<0)+(1<<1)+(0<<2)+(1<<3)+(0<<4)+(1<<5)+(0<<6)+(1<<7)); (out)=_mm256_shuffle_ps( out,out, (1<<0) + (0<<2) + (3<<4) + (2<<6) )++ #define stbir__simdf8_zero( reg ) (reg) = _mm256_setzero_ps()++ #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_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_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 )++ #endif++ #ifdef STBIR_FLOORF+ #undef STBIR_FLOORF+ #endif+ #define STBIR_FLOORF stbir_simd_floorf+ static stbir__inline float stbir_simd_floorf(float x) // martins floorf+ {+ #if defined(STBIR_AVX) || defined(__SSE4_1__) || defined(STBIR_SSE41)+ __m128 t = _mm_set_ss(x);+ return _mm_cvtss_f32( _mm_floor_ss(t, t) );+ #else+ __m128 f = _mm_set_ss(x);+ __m128 t = _mm_cvtepi32_ps(_mm_cvttps_epi32(f));+ __m128 r = _mm_add_ss(t, _mm_and_ps(_mm_cmplt_ss(f, t), _mm_set_ss(-1.0f)));+ return _mm_cvtss_f32(r);+ #endif+ }++ #ifdef STBIR_CEILF+ #undef STBIR_CEILF+ #endif+ #define STBIR_CEILF stbir_simd_ceilf+ static stbir__inline float stbir_simd_ceilf(float x) // martins ceilf+ {+ #if defined(STBIR_AVX) || defined(__SSE4_1__) || defined(STBIR_SSE41)+ __m128 t = _mm_set_ss(x);+ return _mm_cvtss_f32( _mm_ceil_ss(t, t) );+ #else+ __m128 f = _mm_set_ss(x);+ __m128 t = _mm_cvtepi32_ps(_mm_cvttps_epi32(f));+ __m128 r = _mm_add_ss(t, _mm_and_ps(_mm_cmplt_ss(t, f), _mm_set_ss(1.0f)));+ return _mm_cvtss_f32(r);+ #endif+ }++#elif defined(STBIR_NEON)++ #include <arm_neon.h>++ #define stbir__simdf float32x4_t+ #define stbir__simdi uint32x4_t++ #define stbir_simdi_castf( reg ) vreinterpretq_u32_f32(reg)+ #define stbir_simdf_casti( reg ) vreinterpretq_f32_u32(reg)++ #define stbir__simdf_load( reg, ptr ) (reg) = vld1q_f32( (float const*)(ptr) )+ #define stbir__simdi_load( reg, ptr ) (reg) = vld1q_u32( (uint32_t const*)(ptr) )+ #define stbir__simdf_load1( out, ptr ) (out) = vld1q_dup_f32( (float const*)(ptr) ) // top values can be random (not denormal or nan for perf)+ #define stbir__simdi_load1( out, ptr ) (out) = vld1q_dup_u32( (uint32_t const*)(ptr) )+ #define stbir__simdf_load1z( out, ptr ) (out) = vld1q_lane_f32( (float const*)(ptr), vdupq_n_f32(0), 0 ) // top values must be zero+ #define stbir__simdf_frep4( fvar ) vdupq_n_f32( fvar )+ #define stbir__simdf_load1frep4( out, fvar ) (out) = vdupq_n_f32( fvar )+ #define stbir__simdf_load2( out, ptr ) (out) = vcombine_f32( vld1_f32( (float const*)(ptr) ), vcreate_f32(0) ) // top values can be random (not denormal or nan for perf)+ #define stbir__simdf_load2z( out, ptr ) (out) = vcombine_f32( vld1_f32( (float const*)(ptr) ), vcreate_f32(0) ) // top values must be zero+ #define stbir__simdf_load2hmerge( out, reg, ptr ) (out) = vcombine_f32( vget_low_f32(reg), vld1_f32( (float const*)(ptr) ) )++ #define stbir__simdf_zeroP() vdupq_n_f32(0)+ #define stbir__simdf_zero( reg ) (reg) = vdupq_n_f32(0)++ #define stbir__simdf_store( ptr, reg ) vst1q_f32( (float*)(ptr), reg )+ #define stbir__simdf_store1( ptr, reg ) vst1q_lane_f32( (float*)(ptr), reg, 0)+ #define stbir__simdf_store2( ptr, reg ) vst1_f32( (float*)(ptr), vget_low_f32(reg) )+ #define stbir__simdf_store2h( ptr, reg ) vst1_f32( (float*)(ptr), vget_high_f32(reg) )++ #define stbir__simdi_store( ptr, reg ) vst1q_u32( (uint32_t*)(ptr), reg )+ #define stbir__simdi_store1( ptr, reg ) vst1q_lane_u32( (uint32_t*)(ptr), reg, 0 )+ #define stbir__simdi_store2( ptr, reg ) vst1_u32( (uint32_t*)(ptr), vget_low_u32(reg) )++ #define stbir__prefetch( ptr )++ #define stbir__simdi_expand_u8_to_u32(out0,out1,out2,out3,ireg) \+ { \+ uint16x8_t l = vmovl_u8( vget_low_u8 ( vreinterpretq_u8_u32(ireg) ) ); \+ uint16x8_t h = vmovl_u8( vget_high_u8( vreinterpretq_u8_u32(ireg) ) ); \+ out0 = vmovl_u16( vget_low_u16 ( l ) ); \+ out1 = vmovl_u16( vget_high_u16( l ) ); \+ out2 = vmovl_u16( vget_low_u16 ( h ) ); \+ out3 = vmovl_u16( vget_high_u16( h ) ); \+ }++ #define stbir__simdi_expand_u8_to_1u32(out,ireg) \+ { \+ uint16x8_t tmp = vmovl_u8( vget_low_u8( vreinterpretq_u8_u32(ireg) ) ); \+ out = vmovl_u16( vget_low_u16( tmp ) ); \+ }++ #define stbir__simdi_expand_u16_to_u32(out0,out1,ireg) \+ { \+ uint16x8_t tmp = vreinterpretq_u16_u32(ireg); \+ out0 = vmovl_u16( vget_low_u16 ( tmp ) ); \+ out1 = vmovl_u16( vget_high_u16( tmp ) ); \+ }++ #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__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) )+ #define stbir__simdf_add( out, reg0, reg1 ) (out) = vaddq_f32( reg0, reg1 )+ #define stbir__simdf_mult( out, reg0, reg1 ) (out) = vmulq_f32( reg0, reg1 )+ #define stbir__simdf_mult_mem( out, reg, ptr ) (out) = vmulq_f32( reg, vld1q_f32( (float const*)(ptr) ) )+ #define stbir__simdf_mult1_mem( out, reg, ptr ) (out) = vmulq_f32( reg, vld1q_dup_f32( (float const*)(ptr) ) )+ #define stbir__simdf_add_mem( out, reg, ptr ) (out) = vaddq_f32( reg, vld1q_f32( (float const*)(ptr) ) )+ #define stbir__simdf_add1_mem( out, reg, ptr ) (out) = vaddq_f32( reg, vld1q_dup_f32( (float const*)(ptr) ) )++ #ifdef STBIR_USE_FMA // not on by default to maintain bit identical simd to non-simd (and also x64 no madd to arm madd)+ #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = vfmaq_f32( add, mul1, mul2 )+ #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = vfmaq_f32( add, mul1, mul2 )+ #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = vfmaq_f32( add, mul, vld1q_f32( (float const*)(ptr) ) )+ #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = vfmaq_f32( add, mul, vld1q_dup_f32( (float const*)(ptr) ) )+ #else+ #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = vaddq_f32( add, vmulq_f32( mul1, mul2 ) )+ #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = vaddq_f32( add, vmulq_f32( mul1, mul2 ) )+ #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = vaddq_f32( add, vmulq_f32( mul, vld1q_f32( (float const*)(ptr) ) ) )+ #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = vaddq_f32( add, vmulq_f32( mul, vld1q_dup_f32( (float const*)(ptr) ) ) )+ #endif++ #define stbir__simdf_add1( out, reg0, reg1 ) (out) = vaddq_f32( reg0, reg1 )+ #define stbir__simdf_mult1( out, reg0, reg1 ) (out) = vmulq_f32( reg0, reg1 )++ #define stbir__simdf_and( out, reg0, reg1 ) (out) = vreinterpretq_f32_u32( vandq_u32( vreinterpretq_u32_f32(reg0), vreinterpretq_u32_f32(reg1) ) )+ #define stbir__simdf_or( out, reg0, reg1 ) (out) = vreinterpretq_f32_u32( vorrq_u32( vreinterpretq_u32_f32(reg0), vreinterpretq_u32_f32(reg1) ) )++ #define stbir__simdf_min( out, reg0, reg1 ) (out) = vminq_f32( reg0, reg1 )+ #define stbir__simdf_max( out, reg0, reg1 ) (out) = vmaxq_f32( reg0, reg1 )+ #define stbir__simdf_min1( out, reg0, reg1 ) (out) = vminq_f32( reg0, reg1 )+ #define stbir__simdf_max1( out, reg0, reg1 ) (out) = vmaxq_f32( reg0, reg1 )++ #define stbir__simdf_0123ABCDto3ABx( out, reg0, reg1 ) (out) = vextq_f32( reg0, reg1, 3 )+ #define stbir__simdf_0123ABCDto23Ax( out, reg0, reg1 ) (out) = vextq_f32( reg0, reg1, 2 )++ #define stbir__simdf_a1a1( out, alp, ones ) (out) = vzipq_f32(vuzpq_f32(alp, alp).val[1], ones).val[0]+ #define stbir__simdf_1a1a( out, alp, ones ) (out) = vzipq_f32(ones, vuzpq_f32(alp, alp).val[0]).val[0]++ #if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ )++ #define stbir__simdf_aaa1( out, alp, ones ) (out) = vcopyq_laneq_f32(vdupq_n_f32(vgetq_lane_f32(alp, 3)), 3, ones, 3)+ #define stbir__simdf_1aaa( out, alp, ones ) (out) = vcopyq_laneq_f32(vdupq_n_f32(vgetq_lane_f32(alp, 0)), 0, ones, 0)++ #if defined( _MSC_VER ) && !defined(__clang__)+ #define stbir_make16(a,b,c,d) vcombine_u8( \+ vcreate_u8( (4*a+0) | ((4*a+1)<<8) | ((4*a+2)<<16) | ((4*a+3)<<24) | \+ ((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); \+ int16x8_t r1 = vreinterpretq_s16_u32(reg1); \+ int32x4_t tmp0 = vmull_s16( vget_low_s16(r0), vget_low_s16(r1) ); \+ int32x4_t tmp1 = vmull_s16( vget_high_s16(r0), vget_high_s16(r1) ); \+ (out) = vreinterpretq_u32_s32( vpaddq_s32(tmp0, tmp1) ); \+ }++ #else++ #define stbir__simdf_aaa1( out, alp, ones ) (out) = vsetq_lane_f32(1.0f, vdupq_n_f32(vgetq_lane_f32(alp, 3)), 3)+ #define stbir__simdf_1aaa( out, alp, ones ) (out) = vsetq_lane_f32(1.0f, vdupq_n_f32(vgetq_lane_f32(alp, 0)), 0)++ #if defined( _MSC_VER ) && !defined(__clang__)+ static stbir__inline uint8x8x2_t stbir_make8x2(float32x4_t reg)+ {+ uint8x8x2_t r = { { vget_low_u8(vreinterpretq_u8_f32(reg)), vget_high_u8(vreinterpretq_u8_f32(reg)) } };+ return r;+ }+ #define stbir_make8(a,b) vcreate_u8( \+ (4*a+0) | ((4*a+1)<<8) | ((4*a+2)<<16) | ((4*a+3)<<24) | \+ ((stbir_uint64)(4*b+0)<<32) | ((stbir_uint64)(4*b+1)<<40) | ((stbir_uint64)(4*b+2)<<48) | ((stbir_uint64)(4*b+3)<<56) )+ #else+ #define stbir_make8x2(reg) (uint8x8x2_t){ { vget_low_u8(vreinterpretq_u8_f32(reg)), vget_high_u8(vreinterpretq_u8_f32(reg)) } }+ #define stbir_make8(a,b) (uint8x8_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}+ #endif++ #define stbir__simdf_swiz( reg, one, two, three, four ) vreinterpretq_f32_u8( vcombine_u8( \+ vtbl2_u8( stbir_make8x2( reg ), stbir_make8( one, two ) ), \+ vtbl2_u8( stbir_make8x2( reg ), stbir_make8( three, four ) ) ) )++ #define stbir__simdi_16madd( out, reg0, reg1 ) \+ { \+ int16x8_t r0 = vreinterpretq_s16_u32(reg0); \+ int16x8_t r1 = vreinterpretq_s16_u32(reg1); \+ int32x4_t tmp0 = vmull_s16( vget_low_s16(r0), vget_low_s16(r1) ); \+ int32x4_t tmp1 = vmull_s16( vget_high_s16(r0), vget_high_s16(r1) ); \+ int32x2_t out0 = vpadd_s32( vget_low_s32(tmp0), vget_high_s32(tmp0) ); \+ int32x2_t out1 = vpadd_s32( vget_low_s32(tmp1), vget_high_s32(tmp1) ); \+ (out) = vreinterpretq_u32_s32( vcombine_s32(out0, out1) ); \+ }++ #endif++ #define stbir__simdi_and( out, reg0, reg1 ) (out) = vandq_u32( reg0, reg1 )+ #define stbir__simdi_or( out, reg0, reg1 ) (out) = vorrq_u32( reg0, reg1 )++ #define stbir__simdf_pack_to_8bytes(out,aa,bb) \+ { \+ float32x4_t af = vmaxq_f32( vminq_f32(aa,STBIR__CONSTF(STBIR_max_uint8_as_float) ), vdupq_n_f32(0) ); \+ float32x4_t bf = vmaxq_f32( vminq_f32(bb,STBIR__CONSTF(STBIR_max_uint8_as_float) ), vdupq_n_f32(0) ); \+ int16x4_t ai = vqmovn_s32( vcvtq_s32_f32( af ) ); \+ int16x4_t bi = vqmovn_s32( vcvtq_s32_f32( bf ) ); \+ uint8x8_t out8 = vqmovun_s16( vcombine_s16(ai, bi) ); \+ out = vreinterpretq_u32_u8( vcombine_u8(out8, out8) ); \+ }++ #define stbir__simdf_pack_to_8words(out,aa,bb) \+ { \+ float32x4_t af = vmaxq_f32( vminq_f32(aa,STBIR__CONSTF(STBIR_max_uint16_as_float) ), vdupq_n_f32(0) ); \+ float32x4_t bf = vmaxq_f32( vminq_f32(bb,STBIR__CONSTF(STBIR_max_uint16_as_float) ), vdupq_n_f32(0) ); \+ int32x4_t ai = vcvtq_s32_f32( af ); \+ int32x4_t bi = vcvtq_s32_f32( bf ); \+ out = vreinterpretq_u32_u16( vcombine_u16(vqmovun_s32(ai), vqmovun_s32(bi)) ); \+ }++ #define stbir__interleave_pack_and_store_16_u8( ptr, r0, r1, r2, r3 ) \+ { \+ int16x4x2_t tmp0 = vzip_s16( vqmovn_s32(vreinterpretq_s32_u32(r0)), vqmovn_s32(vreinterpretq_s32_u32(r2)) ); \+ int16x4x2_t tmp1 = vzip_s16( vqmovn_s32(vreinterpretq_s32_u32(r1)), vqmovn_s32(vreinterpretq_s32_u32(r3)) ); \+ uint8x8x2_t out = \+ { { \+ vqmovun_s16( vcombine_s16(tmp0.val[0], tmp0.val[1]) ), \+ vqmovun_s16( vcombine_s16(tmp1.val[0], tmp1.val[1]) ), \+ } }; \+ vst2_u8(ptr, out); \+ }++ #define stbir__simdf_load4_transposed( o0, o1, o2, o3, ptr ) \+ { \+ float32x4x4_t tmp = vld4q_f32(ptr); \+ o0 = tmp.val[0]; \+ o1 = tmp.val[1]; \+ o2 = tmp.val[2]; \+ o3 = tmp.val[3]; \+ }++ #define stbir__simdi_32shr( out, reg, imm ) out = vshrq_n_u32( reg, imm )++ #if defined( _MSC_VER ) && !defined(__clang__)+ #define STBIR__SIMDF_CONST(var, x) __declspec(align(8)) float var[] = { x, x, x, x }+ #define STBIR__SIMDI_CONST(var, x) __declspec(align(8)) uint32_t var[] = { x, x, x, x }+ #define STBIR__CONSTF(var) (*(const float32x4_t*)var)+ #define STBIR__CONSTI(var) (*(const uint32x4_t*)var)+ #else+ #define STBIR__SIMDF_CONST(var, x) stbir__simdf var = { x, x, x, x }+ #define STBIR__SIMDI_CONST(var, x) stbir__simdi var = { x, x, x, x }+ #define STBIR__CONSTF(var) (var)+ #define STBIR__CONSTI(var) (var)+ #endif++ #ifdef STBIR_FLOORF+ #undef STBIR_FLOORF+ #endif+ #define STBIR_FLOORF stbir_simd_floorf+ static stbir__inline float stbir_simd_floorf(float x)+ {+ #if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ )+ return vget_lane_f32( vrndm_f32( vdup_n_f32(x) ), 0);+ #else+ float32x2_t f = vdup_n_f32(x);+ float32x2_t t = vcvt_f32_s32(vcvt_s32_f32(f));+ uint32x2_t a = vclt_f32(f, t);+ uint32x2_t b = vreinterpret_u32_f32(vdup_n_f32(-1.0f));+ float32x2_t r = vadd_f32(t, vreinterpret_f32_u32(vand_u32(a, b)));+ return vget_lane_f32(r, 0);+ #endif+ }++ #ifdef STBIR_CEILF+ #undef STBIR_CEILF+ #endif+ #define STBIR_CEILF stbir_simd_ceilf+ static stbir__inline float stbir_simd_ceilf(float x)+ {+ #if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ )+ return vget_lane_f32( vrndp_f32( vdup_n_f32(x) ), 0);+ #else+ float32x2_t f = vdup_n_f32(x);+ float32x2_t t = vcvt_f32_s32(vcvt_s32_f32(f));+ uint32x2_t a = vclt_f32(t, f);+ uint32x2_t b = vreinterpret_u32_f32(vdup_n_f32(1.0f));+ float32x2_t r = vadd_f32(t, vreinterpret_f32_u32(vand_u32(a, b)));+ return vget_lane_f32(r, 0);+ #endif+ }++ #define STBIR_SIMD++#elif defined(STBIR_WASM)++ #include <wasm_simd128.h>++ #define stbir__simdf v128_t+ #define stbir__simdi v128_t++ #define stbir_simdi_castf( reg ) (reg)+ #define stbir_simdf_casti( reg ) (reg)++ #define stbir__simdf_load( reg, ptr ) (reg) = wasm_v128_load( (void const*)(ptr) )+ #define stbir__simdi_load( reg, ptr ) (reg) = wasm_v128_load( (void const*)(ptr) )+ #define stbir__simdf_load1( out, ptr ) (out) = wasm_v128_load32_splat( (void const*)(ptr) ) // top values can be random (not denormal or nan for perf)+ #define stbir__simdi_load1( out, ptr ) (out) = wasm_v128_load32_splat( (void const*)(ptr) )+ #define stbir__simdf_load1z( out, ptr ) (out) = wasm_v128_load32_zero( (void const*)(ptr) ) // top values must be zero+ #define stbir__simdf_frep4( fvar ) wasm_f32x4_splat( fvar )+ #define stbir__simdf_load1frep4( out, fvar ) (out) = wasm_f32x4_splat( fvar )+ #define stbir__simdf_load2( out, ptr ) (out) = wasm_v128_load64_splat( (void const*)(ptr) ) // top values can be random (not denormal or nan for perf)+ #define stbir__simdf_load2z( out, ptr ) (out) = wasm_v128_load64_zero( (void const*)(ptr) ) // top values must be zero+ #define stbir__simdf_load2hmerge( out, reg, ptr ) (out) = wasm_v128_load64_lane( (void const*)(ptr), reg, 1 )++ #define stbir__simdf_zeroP() wasm_f32x4_const_splat(0)+ #define stbir__simdf_zero( reg ) (reg) = wasm_f32x4_const_splat(0)++ #define stbir__simdf_store( ptr, reg ) wasm_v128_store( (void*)(ptr), reg )+ #define stbir__simdf_store1( ptr, reg ) wasm_v128_store32_lane( (void*)(ptr), reg, 0 )+ #define stbir__simdf_store2( ptr, reg ) wasm_v128_store64_lane( (void*)(ptr), reg, 0 )+ #define stbir__simdf_store2h( ptr, reg ) wasm_v128_store64_lane( (void*)(ptr), reg, 1 )++ #define stbir__simdi_store( ptr, reg ) wasm_v128_store( (void*)(ptr), reg )+ #define stbir__simdi_store1( ptr, reg ) wasm_v128_store32_lane( (void*)(ptr), reg, 0 )+ #define stbir__simdi_store2( ptr, reg ) wasm_v128_store64_lane( (void*)(ptr), reg, 0 )++ #define stbir__prefetch( ptr )++ #define stbir__simdi_expand_u8_to_u32(out0,out1,out2,out3,ireg) \+ { \+ v128_t l = wasm_u16x8_extend_low_u8x16 ( ireg ); \+ v128_t h = wasm_u16x8_extend_high_u8x16( ireg ); \+ out0 = wasm_u32x4_extend_low_u16x8 ( l ); \+ out1 = wasm_u32x4_extend_high_u16x8( l ); \+ out2 = wasm_u32x4_extend_low_u16x8 ( h ); \+ out3 = wasm_u32x4_extend_high_u16x8( h ); \+ }++ #define stbir__simdi_expand_u8_to_1u32(out,ireg) \+ { \+ v128_t tmp = wasm_u16x8_extend_low_u8x16(ireg); \+ out = wasm_u32x4_extend_low_u16x8(tmp); \+ }++ #define stbir__simdi_expand_u16_to_u32(out0,out1,ireg) \+ { \+ out0 = wasm_u32x4_extend_low_u16x8 ( ireg ); \+ out1 = wasm_u32x4_extend_high_u16x8( ireg ); \+ }++ #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__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)+ #define stbir__simdf_add( out, reg0, reg1 ) (out) = wasm_f32x4_add( reg0, reg1 )+ #define stbir__simdf_mult( out, reg0, reg1 ) (out) = wasm_f32x4_mul( reg0, reg1 )+ #define stbir__simdf_mult_mem( out, reg, ptr ) (out) = wasm_f32x4_mul( reg, wasm_v128_load( (void const*)(ptr) ) )+ #define stbir__simdf_mult1_mem( out, reg, ptr ) (out) = wasm_f32x4_mul( reg, wasm_v128_load32_splat( (void const*)(ptr) ) )+ #define stbir__simdf_add_mem( out, reg, ptr ) (out) = wasm_f32x4_add( reg, wasm_v128_load( (void const*)(ptr) ) )+ #define stbir__simdf_add1_mem( out, reg, ptr ) (out) = wasm_f32x4_add( reg, wasm_v128_load32_splat( (void const*)(ptr) ) )++ #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul1, mul2 ) )+ #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul1, mul2 ) )+ #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul, wasm_v128_load( (void const*)(ptr) ) ) )+ #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul, wasm_v128_load32_splat( (void const*)(ptr) ) ) )++ #define stbir__simdf_add1( out, reg0, reg1 ) (out) = wasm_f32x4_add( reg0, reg1 )+ #define stbir__simdf_mult1( out, reg0, reg1 ) (out) = wasm_f32x4_mul( reg0, reg1 )++ #define stbir__simdf_and( out, reg0, reg1 ) (out) = wasm_v128_and( reg0, reg1 )+ #define stbir__simdf_or( out, reg0, reg1 ) (out) = wasm_v128_or( reg0, reg1 )++ #define stbir__simdf_min( out, reg0, reg1 ) (out) = wasm_f32x4_min( reg0, reg1 )+ #define stbir__simdf_max( out, reg0, reg1 ) (out) = wasm_f32x4_max( reg0, reg1 )+ #define stbir__simdf_min1( out, reg0, reg1 ) (out) = wasm_f32x4_min( reg0, reg1 )+ #define stbir__simdf_max1( out, reg0, reg1 ) (out) = wasm_f32x4_max( reg0, reg1 )++ #define stbir__simdf_0123ABCDto3ABx( out, reg0, reg1 ) (out) = wasm_i32x4_shuffle( reg0, reg1, 3, 4, 5, -1 )+ #define stbir__simdf_0123ABCDto23Ax( out, reg0, reg1 ) (out) = wasm_i32x4_shuffle( reg0, reg1, 2, 3, 4, -1 )++ #define stbir__simdf_aaa1(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 3, 3, 3, 4)+ #define stbir__simdf_1aaa(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 4, 0, 0, 0)+ #define stbir__simdf_a1a1(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 1, 4, 3, 4)+ #define stbir__simdf_1a1a(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 4, 0, 4, 2)++ #define stbir__simdf_swiz( reg, one, two, three, four ) wasm_i32x4_shuffle(reg, reg, one, two, three, four)++ #define stbir__simdi_and( out, reg0, reg1 ) (out) = wasm_v128_and( reg0, reg1 )+ #define stbir__simdi_or( out, reg0, reg1 ) (out) = wasm_v128_or( reg0, reg1 )+ #define stbir__simdi_16madd( out, reg0, reg1 ) (out) = wasm_i32x4_dot_i16x8( reg0, reg1 )++ #define stbir__simdf_pack_to_8bytes(out,aa,bb) \+ { \+ v128_t af = wasm_f32x4_max( wasm_f32x4_min(aa, STBIR_max_uint8_as_float), wasm_f32x4_const_splat(0) ); \+ v128_t bf = wasm_f32x4_max( wasm_f32x4_min(bb, STBIR_max_uint8_as_float), wasm_f32x4_const_splat(0) ); \+ v128_t ai = wasm_i32x4_trunc_sat_f32x4( af ); \+ v128_t bi = wasm_i32x4_trunc_sat_f32x4( bf ); \+ v128_t out16 = wasm_i16x8_narrow_i32x4( ai, bi ); \+ out = wasm_u8x16_narrow_i16x8( out16, out16 ); \+ }++ #define stbir__simdf_pack_to_8words(out,aa,bb) \+ { \+ v128_t af = wasm_f32x4_max( wasm_f32x4_min(aa, STBIR_max_uint16_as_float), wasm_f32x4_const_splat(0)); \+ v128_t bf = wasm_f32x4_max( wasm_f32x4_min(bb, STBIR_max_uint16_as_float), wasm_f32x4_const_splat(0)); \+ v128_t ai = wasm_i32x4_trunc_sat_f32x4( af ); \+ v128_t bi = wasm_i32x4_trunc_sat_f32x4( bf ); \+ out = wasm_u16x8_narrow_i32x4( ai, bi ); \+ }++ #define stbir__interleave_pack_and_store_16_u8( ptr, r0, r1, r2, r3 ) \+ { \+ v128_t tmp0 = wasm_i16x8_narrow_i32x4(r0, r1); \+ v128_t tmp1 = wasm_i16x8_narrow_i32x4(r2, r3); \+ v128_t tmp = wasm_u8x16_narrow_i16x8(tmp0, tmp1); \+ tmp = wasm_i8x16_shuffle(tmp, tmp, 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); \+ wasm_v128_store( (void*)(ptr), tmp); \+ }++ #define stbir__simdf_load4_transposed( o0, o1, o2, o3, ptr ) \+ { \+ v128_t t0 = wasm_v128_load( ptr ); \+ v128_t t1 = wasm_v128_load( ptr+4 ); \+ v128_t t2 = wasm_v128_load( ptr+8 ); \+ v128_t t3 = wasm_v128_load( ptr+12 ); \+ v128_t s0 = wasm_i32x4_shuffle(t0, t1, 0, 4, 2, 6); \+ v128_t s1 = wasm_i32x4_shuffle(t0, t1, 1, 5, 3, 7); \+ v128_t s2 = wasm_i32x4_shuffle(t2, t3, 0, 4, 2, 6); \+ v128_t s3 = wasm_i32x4_shuffle(t2, t3, 1, 5, 3, 7); \+ o0 = wasm_i32x4_shuffle(s0, s2, 0, 1, 4, 5); \+ o1 = wasm_i32x4_shuffle(s1, s3, 0, 1, 4, 5); \+ o2 = wasm_i32x4_shuffle(s0, s2, 2, 3, 6, 7); \+ o3 = wasm_i32x4_shuffle(s1, s3, 2, 3, 6, 7); \+ }++ #define stbir__simdi_32shr( out, reg, imm ) out = wasm_u32x4_shr( reg, imm )++ typedef float stbir__f32x4 __attribute__((__vector_size__(16), __aligned__(16)));+ #define STBIR__SIMDF_CONST(var, x) stbir__simdf var = (v128_t)(stbir__f32x4){ x, x, x, x }+ #define STBIR__SIMDI_CONST(var, x) stbir__simdi var = { x, x, x, x }+ #define STBIR__CONSTF(var) (var)+ #define STBIR__CONSTI(var) (var)++ #ifdef STBIR_FLOORF+ #undef STBIR_FLOORF+ #endif+ #define STBIR_FLOORF stbir_simd_floorf+ static stbir__inline float stbir_simd_floorf(float x)+ {+ return wasm_f32x4_extract_lane( wasm_f32x4_floor( wasm_f32x4_splat(x) ), 0);+ }++ #ifdef STBIR_CEILF+ #undef STBIR_CEILF+ #endif+ #define STBIR_CEILF stbir_simd_ceilf+ static stbir__inline float stbir_simd_ceilf(float x)+ {+ return wasm_f32x4_extract_lane( wasm_f32x4_ceil( wasm_f32x4_splat(x) ), 0);+ }++ #define STBIR_SIMD++#endif // SSE2/NEON/WASM++#endif // NO SIMD++#ifdef STBIR_SIMD8+ #define stbir__simdfX stbir__simdf8+ #define stbir__simdiX stbir__simdi8+ #define stbir__simdfX_load stbir__simdf8_load+ #define stbir__simdiX_load stbir__simdi8_load+ #define stbir__simdfX_mult stbir__simdf8_mult+ #define stbir__simdfX_add_mem stbir__simdf8_add_mem+ #define stbir__simdfX_madd_mem stbir__simdf8_madd_mem+ #define stbir__simdfX_store stbir__simdf8_store+ #define stbir__simdiX_store stbir__simdi8_store+ #define stbir__simdf_frepX stbir__simdf8_frep8+ #define stbir__simdfX_madd stbir__simdf8_madd+ #define stbir__simdfX_min stbir__simdf8_min+ #define stbir__simdfX_max stbir__simdf8_max+ #define stbir__simdfX_aaa1 stbir__simdf8_aaa1+ #define stbir__simdfX_1aaa stbir__simdf8_1aaa+ #define stbir__simdfX_a1a1 stbir__simdf8_a1a1+ #define stbir__simdfX_1a1a stbir__simdf8_1a1a+ #define stbir__simdfX_convert_float_to_i32 stbir__simdf8_convert_float_to_i32+ #define stbir__simdfX_pack_to_words stbir__simdf8_pack_to_16words+ #define stbir__simdfX_zero stbir__simdf8_zero+ #define STBIR_onesX STBIR_ones8+ #define STBIR_max_uint8_as_floatX STBIR_max_uint8_as_float8+ #define STBIR_max_uint16_as_floatX STBIR_max_uint16_as_float8+ #define STBIR_simd_point5X STBIR_simd_point58+ #define stbir__simdfX_float_count 8+ #define stbir__simdfX_0123to1230 stbir__simdf8_0123to12301230+ #define stbir__simdfX_0123to2103 stbir__simdf8_0123to21032103+ static const stbir__simdf8 STBIR_max_uint16_as_float_inverted8 = { stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted };+ static const stbir__simdf8 STBIR_max_uint8_as_float_inverted8 = { stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted };+ static const stbir__simdf8 STBIR_ones8 = { 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 };+ static const stbir__simdf8 STBIR_simd_point58 = { 0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5 };+ static const stbir__simdf8 STBIR_max_uint8_as_float8 = { stbir__max_uint8_as_float,stbir__max_uint8_as_float,stbir__max_uint8_as_float,stbir__max_uint8_as_float, stbir__max_uint8_as_float,stbir__max_uint8_as_float,stbir__max_uint8_as_float,stbir__max_uint8_as_float };+ static const stbir__simdf8 STBIR_max_uint16_as_float8 = { stbir__max_uint16_as_float,stbir__max_uint16_as_float,stbir__max_uint16_as_float,stbir__max_uint16_as_float, stbir__max_uint16_as_float,stbir__max_uint16_as_float,stbir__max_uint16_as_float,stbir__max_uint16_as_float };+#else+ #define stbir__simdfX stbir__simdf+ #define stbir__simdiX stbir__simdi+ #define stbir__simdfX_load stbir__simdf_load+ #define stbir__simdiX_load stbir__simdi_load+ #define stbir__simdfX_mult stbir__simdf_mult+ #define stbir__simdfX_add_mem stbir__simdf_add_mem+ #define stbir__simdfX_madd_mem stbir__simdf_madd_mem+ #define stbir__simdfX_store stbir__simdf_store+ #define stbir__simdiX_store stbir__simdi_store+ #define stbir__simdf_frepX stbir__simdf_frep4+ #define stbir__simdfX_madd stbir__simdf_madd+ #define stbir__simdfX_min stbir__simdf_min+ #define stbir__simdfX_max stbir__simdf_max+ #define stbir__simdfX_aaa1 stbir__simdf_aaa1+ #define stbir__simdfX_1aaa stbir__simdf_1aaa+ #define stbir__simdfX_a1a1 stbir__simdf_a1a1+ #define stbir__simdfX_1a1a stbir__simdf_1a1a+ #define stbir__simdfX_convert_float_to_i32 stbir__simdf_convert_float_to_i32+ #define stbir__simdfX_pack_to_words stbir__simdf_pack_to_8words+ #define stbir__simdfX_zero stbir__simdf_zero+ #define STBIR_onesX STBIR__CONSTF(STBIR_ones)+ #define STBIR_simd_point5X STBIR__CONSTF(STBIR_simd_point5)+ #define STBIR_max_uint8_as_floatX STBIR__CONSTF(STBIR_max_uint8_as_float)+ #define STBIR_max_uint16_as_floatX STBIR__CONSTF(STBIR_max_uint16_as_float)+ #define stbir__simdfX_float_count 4+ #define stbir__if_simdf8_cast_to_simdf4( val ) ( val )+ #define stbir__simdfX_0123to1230 stbir__simdf_0123to1230+ #define stbir__simdfX_0123to2103 stbir__simdf_0123to2103+#endif+++#if defined(STBIR_NEON) && !defined(_M_ARM) && !defined(__arm__)++ #if defined( _MSC_VER ) && !defined(__clang__)+ typedef __int16 stbir__FP16;+ #else+ typedef float16_t stbir__FP16;+ #endif++#else // no NEON, or 32-bit ARM for MSVC++ typedef union stbir__FP16+ {+ unsigned short u;+ } stbir__FP16;++#endif++#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++ static stbir__inline float stbir__half_to_float( stbir__FP16 h )+ {+ static const stbir__FP32 magic = { (254 - 15) << 23 };+ static const stbir__FP32 was_infnan = { (127 + 16) << 23 };+ stbir__FP32 o;++ o.u = (h.u & 0x7fff) << 13; // exponent/mantissa bits+ o.f *= magic.f; // exponent adjust+ if (o.f >= was_infnan.f) // make sure Inf/NaN survive+ o.u |= 255 << 23;+ o.u |= (h.u & 0x8000) << 16; // sign bit+ return o.f;+ }++ static stbir__inline stbir__FP16 stbir__float_to_half(float val)+ {+ stbir__FP32 f32infty = { 255 << 23 };+ stbir__FP32 f16max = { (127 + 16) << 23 };+ stbir__FP32 denorm_magic = { ((127 - 15) + (23 - 10) + 1) << 23 };+ unsigned int sign_mask = 0x80000000u;+ stbir__FP16 o = { 0 };+ stbir__FP32 f;+ unsigned int sign;++ f.f = val;+ sign = f.u & sign_mask;+ f.u ^= sign;++ if (f.u >= f16max.u) // result is Inf or NaN (all exponent bits set)+ o.u = (f.u > f32infty.u) ? 0x7e00 : 0x7c00; // NaN->qNaN and Inf->Inf+ else // (De)normalized number or zero+ {+ if (f.u < (113 << 23)) // resulting FP16 is subnormal or zero+ {+ // use a magic value to align our 10 mantissa bits at the bottom of+ // the float. as long as FP addition is round-to-nearest-even this+ // just works.+ f.f += denorm_magic.f;+ // and one integer subtract of the bias later, we have our final float!+ o.u = (unsigned short) ( f.u - denorm_magic.u );+ }+ else+ {+ unsigned int mant_odd = (f.u >> 13) & 1; // resulting mantissa is odd+ // update exponent, rounding bias part 1+ f.u = f.u + ((15u - 127) << 23) + 0xfff;+ // rounding bias part 2+ f.u += mant_odd;+ // take the bits!+ o.u = (unsigned short) ( f.u >> 13 );+ }+ }++ o.u |= sign >> 16;+ return o;+ }++#endif+++#if defined(STBIR_FP16C)++ #include <immintrin.h>++ static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input)+ {+ _mm256_storeu_ps( (float*)output, _mm256_cvtph_ps( _mm_loadu_si128( (__m128i const* )input ) ) );+ }++ static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input)+ {+ _mm_storeu_si128( (__m128i*)output, _mm256_cvtps_ph( _mm256_loadu_ps( input ), 0 ) );+ }++ static stbir__inline float stbir__half_to_float( stbir__FP16 h )+ {+ return _mm_cvtss_f32( _mm_cvtph_ps( _mm_cvtsi32_si128( (int)h.u ) ) );+ }++ static stbir__inline stbir__FP16 stbir__float_to_half( float f )+ {+ stbir__FP16 h;+ h.u = (unsigned short) _mm_cvtsi128_si32( _mm_cvtps_ph( _mm_set_ss( f ), 0 ) );+ return h;+ }++#elif defined(STBIR_SSE2)++ // Fabian's half float routines, see: https://gist.github.com/rygorous/2156668+ stbir__inline static void stbir__half_to_float_SIMD(float * output, void const * input)+ {+ static const STBIR__SIMDI_CONST(mask_nosign, 0x7fff);+ static const STBIR__SIMDI_CONST(smallest_normal, 0x0400);+ static const STBIR__SIMDI_CONST(infinity, 0x7c00);+ static const STBIR__SIMDI_CONST(expadjust_normal, (127 - 15) << 23);+ static const STBIR__SIMDI_CONST(magic_denorm, 113 << 23);++ __m128i i = _mm_loadu_si128 ( (__m128i const*)(input) );+ __m128i h = _mm_unpacklo_epi16 ( i, _mm_setzero_si128() );+ __m128i mnosign = STBIR__CONSTI(mask_nosign);+ __m128i eadjust = STBIR__CONSTI(expadjust_normal);+ __m128i smallest = STBIR__CONSTI(smallest_normal);+ __m128i infty = STBIR__CONSTI(infinity);+ __m128i expmant = _mm_and_si128(mnosign, h);+ __m128i justsign = _mm_xor_si128(h, expmant);+ __m128i b_notinfnan = _mm_cmpgt_epi32(infty, expmant);+ __m128i b_isdenorm = _mm_cmpgt_epi32(smallest, expmant);+ __m128i shifted = _mm_slli_epi32(expmant, 13);+ __m128i adj_infnan = _mm_andnot_si128(b_notinfnan, eadjust);+ __m128i adjusted = _mm_add_epi32(eadjust, shifted);+ __m128i den1 = _mm_add_epi32(shifted, STBIR__CONSTI(magic_denorm));+ __m128i adjusted2 = _mm_add_epi32(adjusted, adj_infnan);+ __m128 den2 = _mm_sub_ps(_mm_castsi128_ps(den1), *(const __m128 *)&magic_denorm);+ __m128 adjusted3 = _mm_and_ps(den2, _mm_castsi128_ps(b_isdenorm));+ __m128 adjusted4 = _mm_andnot_ps(_mm_castsi128_ps(b_isdenorm), _mm_castsi128_ps(adjusted2));+ __m128 adjusted5 = _mm_or_ps(adjusted3, adjusted4);+ __m128i sign = _mm_slli_epi32(justsign, 16);+ __m128 final = _mm_or_ps(adjusted5, _mm_castsi128_ps(sign));+ stbir__simdf_store( output + 0, final );++ h = _mm_unpackhi_epi16 ( i, _mm_setzero_si128() );+ expmant = _mm_and_si128(mnosign, h);+ justsign = _mm_xor_si128(h, expmant);+ b_notinfnan = _mm_cmpgt_epi32(infty, expmant);+ b_isdenorm = _mm_cmpgt_epi32(smallest, expmant);+ shifted = _mm_slli_epi32(expmant, 13);+ adj_infnan = _mm_andnot_si128(b_notinfnan, eadjust);+ adjusted = _mm_add_epi32(eadjust, shifted);+ den1 = _mm_add_epi32(shifted, STBIR__CONSTI(magic_denorm));+ adjusted2 = _mm_add_epi32(adjusted, adj_infnan);+ den2 = _mm_sub_ps(_mm_castsi128_ps(den1), *(const __m128 *)&magic_denorm);+ adjusted3 = _mm_and_ps(den2, _mm_castsi128_ps(b_isdenorm));+ adjusted4 = _mm_andnot_ps(_mm_castsi128_ps(b_isdenorm), _mm_castsi128_ps(adjusted2));+ adjusted5 = _mm_or_ps(adjusted3, adjusted4);+ sign = _mm_slli_epi32(justsign, 16);+ final = _mm_or_ps(adjusted5, _mm_castsi128_ps(sign));+ stbir__simdf_store( output + 4, final );++ // ~38 SSE2 ops for 8 values+ }++ // Fabian's round-to-nearest-even float to half+ // ~48 SSE2 ops for 8 output+ stbir__inline static void stbir__float_to_half_SIMD(void * output, float const * input)+ {+ static const STBIR__SIMDI_CONST(mask_sign, 0x80000000u);+ static const STBIR__SIMDI_CONST(c_f16max, (127 + 16) << 23); // all FP32 values >=this round to +inf+ static const STBIR__SIMDI_CONST(c_nanbit, 0x200);+ static const STBIR__SIMDI_CONST(c_infty_as_fp16, 0x7c00);+ static const STBIR__SIMDI_CONST(c_min_normal, (127 - 14) << 23); // smallest FP32 that yields a normalized FP16+ static const STBIR__SIMDI_CONST(c_subnorm_magic, ((127 - 15) + (23 - 10) + 1) << 23);+ static const STBIR__SIMDI_CONST(c_normal_bias, 0xfff - ((127 - 15) << 23)); // adjust exponent and add mantissa rounding++ __m128 f = _mm_loadu_ps(input);+ __m128 msign = _mm_castsi128_ps(STBIR__CONSTI(mask_sign));+ __m128 justsign = _mm_and_ps(msign, f);+ __m128 absf = _mm_xor_ps(f, justsign);+ __m128i absf_int = _mm_castps_si128(absf); // the cast is "free" (extra bypass latency, but no thruput hit)+ __m128i f16max = STBIR__CONSTI(c_f16max);+ __m128 b_isnan = _mm_cmpunord_ps(absf, absf); // is this a NaN?+ __m128i b_isregular = _mm_cmpgt_epi32(f16max, absf_int); // (sub)normalized or special?+ __m128i nanbit = _mm_and_si128(_mm_castps_si128(b_isnan), STBIR__CONSTI(c_nanbit));+ __m128i inf_or_nan = _mm_or_si128(nanbit, STBIR__CONSTI(c_infty_as_fp16)); // output for specials++ __m128i min_normal = STBIR__CONSTI(c_min_normal);+ __m128i b_issub = _mm_cmpgt_epi32(min_normal, absf_int);++ // "result is subnormal" path+ __m128 subnorm1 = _mm_add_ps(absf, _mm_castsi128_ps(STBIR__CONSTI(c_subnorm_magic))); // magic value to round output mantissa+ __m128i subnorm2 = _mm_sub_epi32(_mm_castps_si128(subnorm1), STBIR__CONSTI(c_subnorm_magic)); // subtract out bias++ // "result is normal" path+ __m128i mantoddbit = _mm_slli_epi32(absf_int, 31 - 13); // shift bit 13 (mantissa LSB) to sign+ __m128i mantodd = _mm_srai_epi32(mantoddbit, 31); // -1 if FP16 mantissa odd, else 0++ __m128i round1 = _mm_add_epi32(absf_int, STBIR__CONSTI(c_normal_bias));+ __m128i round2 = _mm_sub_epi32(round1, mantodd); // if mantissa LSB odd, bias towards rounding up (RTNE)+ __m128i normal = _mm_srli_epi32(round2, 13); // rounded result++ // combine the two non-specials+ __m128i nonspecial = _mm_or_si128(_mm_and_si128(subnorm2, b_issub), _mm_andnot_si128(b_issub, normal));++ // merge in specials as well+ __m128i joined = _mm_or_si128(_mm_and_si128(nonspecial, b_isregular), _mm_andnot_si128(b_isregular, inf_or_nan));++ __m128i sign_shift = _mm_srai_epi32(_mm_castps_si128(justsign), 16);+ __m128i final2, final= _mm_or_si128(joined, sign_shift);++ f = _mm_loadu_ps(input+4);+ justsign = _mm_and_ps(msign, f);+ absf = _mm_xor_ps(f, justsign);+ absf_int = _mm_castps_si128(absf); // the cast is "free" (extra bypass latency, but no thruput hit)+ b_isnan = _mm_cmpunord_ps(absf, absf); // is this a NaN?+ b_isregular = _mm_cmpgt_epi32(f16max, absf_int); // (sub)normalized or special?+ nanbit = _mm_and_si128(_mm_castps_si128(b_isnan), c_nanbit);+ inf_or_nan = _mm_or_si128(nanbit, STBIR__CONSTI(c_infty_as_fp16)); // output for specials++ b_issub = _mm_cmpgt_epi32(min_normal, absf_int);++ // "result is subnormal" path+ subnorm1 = _mm_add_ps(absf, _mm_castsi128_ps(STBIR__CONSTI(c_subnorm_magic))); // magic value to round output mantissa+ subnorm2 = _mm_sub_epi32(_mm_castps_si128(subnorm1), STBIR__CONSTI(c_subnorm_magic)); // subtract out bias++ // "result is normal" path+ mantoddbit = _mm_slli_epi32(absf_int, 31 - 13); // shift bit 13 (mantissa LSB) to sign+ mantodd = _mm_srai_epi32(mantoddbit, 31); // -1 if FP16 mantissa odd, else 0++ round1 = _mm_add_epi32(absf_int, STBIR__CONSTI(c_normal_bias));+ round2 = _mm_sub_epi32(round1, mantodd); // if mantissa LSB odd, bias towards rounding up (RTNE)+ normal = _mm_srli_epi32(round2, 13); // rounded result++ // combine the two non-specials+ nonspecial = _mm_or_si128(_mm_and_si128(subnorm2, b_issub), _mm_andnot_si128(b_issub, normal));++ // merge in specials as well+ joined = _mm_or_si128(_mm_and_si128(nonspecial, b_isregular), _mm_andnot_si128(b_isregular, inf_or_nan));++ sign_shift = _mm_srai_epi32(_mm_castps_si128(justsign), 16);+ final2 = _mm_or_si128(joined, sign_shift);+ final = _mm_packs_epi32(final, final2);+ stbir__simdi_store( output,final );+ }++#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)+ {+ float16x4_t in0 = vld1_f16(input + 0);+ float16x4_t in1 = vld1_f16(input + 4);+ vst1q_f32(output + 0, vcvt_f32_f16(in0));+ vst1q_f32(output + 4, vcvt_f32_f16(in1));+ }++ static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input)+ {+ float16x4_t out0 = vcvt_f16_f32(vld1q_f32(input + 0));+ float16x4_t out1 = vcvt_f16_f32(vld1q_f32(input + 4));+ vst1_f16(output+0, out0);+ vst1_f16(output+4, out1);+ }++ static stbir__inline float stbir__half_to_float( stbir__FP16 h )+ {+ return vgetq_lane_f32(vcvt_f32_f16(vld1_dup_f16(&h)), 0);+ }++ static stbir__inline stbir__FP16 stbir__float_to_half( float f )+ {+ return vget_lane_f16(vcvt_f16_f32(vdupq_n_f32(f)), 0).n16_u16[0];+ }++#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)+ {+ float16x8_t in = vld1q_f16(input);+ vst1q_f32(output + 0, vcvt_f32_f16(vget_low_f16(in)));+ vst1q_f32(output + 4, vcvt_f32_f16(vget_high_f16(in)));+ }++ static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input)+ {+ float16x4_t out0 = vcvt_f16_f32(vld1q_f32(input + 0));+ float16x4_t out1 = vcvt_f16_f32(vld1q_f32(input + 4));+ vst1q_f16(output, vcombine_f16(out0, out1));+ }++ static stbir__inline float stbir__half_to_float( stbir__FP16 h )+ {+ return vgetq_lane_f32(vcvt_f32_f16(vdup_n_f16(h)), 0);+ }++ static stbir__inline stbir__FP16 stbir__float_to_half( float f )+ {+ 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+++#ifdef STBIR_SIMD++#define stbir__simdf_0123to3333( out, reg ) (out) = stbir__simdf_swiz( reg, 3,3,3,3 )+#define stbir__simdf_0123to2222( out, reg ) (out) = stbir__simdf_swiz( reg, 2,2,2,2 )+#define stbir__simdf_0123to1111( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,1,1 )+#define stbir__simdf_0123to0000( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,0,0 )+#define stbir__simdf_0123to0003( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,0,3 )+#define stbir__simdf_0123to0001( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,0,1 )+#define stbir__simdf_0123to1122( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,2,2 )+#define stbir__simdf_0123to2333( out, reg ) (out) = stbir__simdf_swiz( reg, 2,3,3,3 )+#define stbir__simdf_0123to0023( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,2,3 )+#define stbir__simdf_0123to1230( out, reg ) (out) = stbir__simdf_swiz( reg, 1,2,3,0 )+#define stbir__simdf_0123to2103( out, reg ) (out) = stbir__simdf_swiz( reg, 2,1,0,3 )+#define stbir__simdf_0123to3210( out, reg ) (out) = stbir__simdf_swiz( reg, 3,2,1,0 )+#define stbir__simdf_0123to2301( out, reg ) (out) = stbir__simdf_swiz( reg, 2,3,0,1 )+#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 )++typedef union stbir__simdi_u32+{+ stbir_uint32 m128i_u32[4];+ int m128i_i32[4];+ stbir__simdi m128i_i128;+} stbir__simdi_u32;++static const int STBIR_mask[9] = { 0,0,0,-1,-1,-1,0,0,0 };++static const STBIR__SIMDF_CONST(STBIR_max_uint8_as_float, stbir__max_uint8_as_float);+static const STBIR__SIMDF_CONST(STBIR_max_uint16_as_float, stbir__max_uint16_as_float);+static const STBIR__SIMDF_CONST(STBIR_max_uint8_as_float_inverted, stbir__max_uint8_as_float_inverted);+static const STBIR__SIMDF_CONST(STBIR_max_uint16_as_float_inverted, stbir__max_uint16_as_float_inverted);++static const STBIR__SIMDF_CONST(STBIR_simd_point5, 0.5f);+static const STBIR__SIMDF_CONST(STBIR_ones, 1.0f);+static const STBIR__SIMDI_CONST(STBIR_almost_zero, (127 - 13) << 23);+static const STBIR__SIMDI_CONST(STBIR_almost_one, 0x3f7fffff);+static const STBIR__SIMDI_CONST(STBIR_mastissa_mask, 0xff);+static const STBIR__SIMDI_CONST(STBIR_topscale, 0x02000000);++// Basically, in simd mode, we unroll the proper amount, and we don't want+// the non-simd remnant loops to be unroll because they only run a few times+// 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+#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 )+{+ char STBIR_SIMD_STREAMOUT_PTR (*) d = (char*) dest;+ char STBIR_SIMD_STREAMOUT_PTR( * ) d_end = ((char*) dest) + bytes;+ ptrdiff_t ofs_to_src = (char*)src - (char*)dest;++ // check overlaps+ STBIR_ASSERT( ( ( d >= ( (char*)src) + bytes ) ) || ( ( d + bytes ) <= (char*)src ) );++ if ( bytes < (16*stbir__simdfX_float_count) )+ {+ if ( bytes < 16 )+ {+ if ( bytes )+ {+ STBIR_SIMD_NO_UNROLL_LOOP_START+ do+ {+ STBIR_SIMD_NO_UNROLL(d);+ d[ 0 ] = d[ ofs_to_src ];+ ++d;+ } while ( d < d_end );+ }+ }+ else+ {+ stbir__simdf x;+ // 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*)( ( ( (size_t)d ) + 16 ) & ~15 );++ STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR+ for(;;)+ {+ STBIR_SIMD_NO_UNROLL(d);++ if ( d > ( d_end - 16 ) )+ {+ if ( d == d_end )+ return;+ d = d_end - 16;+ }++ stbir__simdf_load( x, ( d + ofs_to_src ) );+ stbir__simdf_store( d, x );+ d += 16;+ }+ }+ }+ else+ {+ stbir__simdfX x0,x1,x2,x3;++ // do one unaligned to get us aligned for the stream out below+ stbir__simdfX_load( x0, ( d + ofs_to_src ) + 0*stbir__simdfX_float_count );+ stbir__simdfX_load( x1, ( d + ofs_to_src ) + 4*stbir__simdfX_float_count );+ stbir__simdfX_load( x2, ( d + ofs_to_src ) + 8*stbir__simdfX_float_count );+ stbir__simdfX_load( x3, ( d + ofs_to_src ) + 12*stbir__simdfX_float_count );+ stbir__simdfX_store( d + 0*stbir__simdfX_float_count, x0 );+ 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*)( ( ( (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 )+ return;+ d = d_end - (16*stbir__simdfX_float_count);+ }++ stbir__simdfX_load( x0, ( d + ofs_to_src ) + 0*stbir__simdfX_float_count );+ stbir__simdfX_load( x1, ( d + ofs_to_src ) + 4*stbir__simdfX_float_count );+ stbir__simdfX_load( x2, ( d + ofs_to_src ) + 8*stbir__simdfX_float_count );+ stbir__simdfX_load( x3, ( d + ofs_to_src ) + 12*stbir__simdfX_float_count );+ stbir__simdfX_store( d + 0*stbir__simdfX_float_count, x0 );+ 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 += (16*stbir__simdfX_float_count);+ }+ }+}++// 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 )+{+ char STBIR_SIMD_STREAMOUT_PTR (*) sd = (char*) src;+ char STBIR_SIMD_STREAMOUT_PTR( * ) s_end = ((char*) src) + bytes;+ ptrdiff_t ofs_to_dest = (char*)dest - (char*)src;++ 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;+ STBIR_SIMD_NO_UNROLL(sd);+ stbir__simdf_load( x, sd );+ stbir__simdf_store( ( sd + ofs_to_dest ), x );+ sd += 16;+ } while ( sd < s_end16 );++ if ( sd == s_end )+ return;+ }++ do+ {+ STBIR_SIMD_NO_UNROLL(sd);+ *(int*)( sd + ofs_to_dest ) = *(int*) sd;+ sd += 4;+ } while ( sd < s_end );+}++#else // no SSE2++// 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_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++ STBIRDEF stbir_uint64 __rdtsc();+ #define STBIR_PROFILE_FUNC() __rdtsc()++#else // non msvc++ static stbir__inline stbir_uint64 STBIR_PROFILE_FUNC()+ {+ stbir_uint32 lo, hi;+ asm volatile ("rdtsc" : "=a" (lo), "=d" (hi) );+ return ( ( (stbir_uint64) hi ) << 32 ) | ( (stbir_uint64) lo );+ }++#endif // msvc++#elif defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(__ARM_NEON__)++#if defined( _MSC_VER ) && !defined(__clang__)++ #define STBIR_PROFILE_FUNC() _ReadStatusReg(ARM64_CNTVCT)++#else++ static stbir__inline stbir_uint64 STBIR_PROFILE_FUNC()+ {+ stbir_uint64 tsc;+ asm volatile("mrs %0, cntvct_el0" : "=r" (tsc));+ return tsc;+ }++#endif++#else // x64, arm++#error Unknown platform for profiling.++#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++#define STBIR_ONLY_PROFILE_BUILD_GET_INFO ,stbir__info * profile_info+#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_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;i<STBIR__ARRAY_SIZE(info->profile.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;i<STBIR__ARRAY_SIZE((info)->profile.array);i++) (info)[extra].profile.array[i]=0; } }++// for thread data+#define STBIR_PROFILE_START( wh ) STBIR_PROFILE_START_ll( split_info, wh )+#define STBIR_PROFILE_END( wh ) STBIR_PROFILE_END_ll( split_info, wh )+#define STBIR_PROFILE_FIRST_START( wh ) STBIR_PROFILE_FIRST_START_ll( split_info, wh )+#define STBIR_PROFILE_CLEAR_EXTRAS() STBIR_PROFILE_CLEAR_EXTRAS_ll( split_info, split_count )++// for build data+#define STBIR_PROFILE_BUILD_START( wh ) STBIR_PROFILE_START_ll( profile_info, wh )+#define STBIR_PROFILE_BUILD_END( wh ) STBIR_PROFILE_END_ll( profile_info, wh )+#define STBIR_PROFILE_BUILD_FIRST_START( wh ) STBIR_PROFILE_FIRST_START_ll( profile_info, wh )+#define STBIR_PROFILE_BUILD_CLEAR( info ) { int i; for(i=0;i<STBIR__ARRAY_SIZE(info->profile.array);i++) info->profile.array[i]=0; }++#else // no profile++#define STBIR_ONLY_PROFILE_GET_SPLIT_INFO+#define STBIR_ONLY_PROFILE_SET_SPLIT_INFO++#define STBIR_ONLY_PROFILE_BUILD_GET_INFO+#define STBIR_ONLY_PROFILE_BUILD_SET_INFO++#define STBIR_PROFILE_START( wh )+#define STBIR_PROFILE_END( wh )+#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_FIRST_START( wh )+#define STBIR_PROFILE_BUILD_CLEAR( info )++#endif // stbir_profile++#ifndef STBIR_CEILF+#include <math.h>+#if _MSC_VER <= 1200 // support VC6 for Sean+#define STBIR_CEILF(x) ((float)ceil((float)(x)))+#define STBIR_FLOORF(x) ((float)floor((float)(x)))+#else+#define STBIR_CEILF(x) ceilf(x)+#define STBIR_FLOORF(x) floorf(x)+#endif+#endif++#ifndef STBIR_MEMCPY+// For memcpy+#include <string.h>+#define STBIR_MEMCPY( dest, src, len ) memcpy( dest, src, len )+#endif++#ifndef STBIR_SIMD++// 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 )+{+ char STBIR_SIMD_STREAMOUT_PTR (*) sd = (char*) src;+ char STBIR_SIMD_STREAMOUT_PTR( * ) s_end = ((char*) src) + bytes;+ ptrdiff_t ofs_to_dest = (char*)dest - (char*)src;++ 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;+ sd += 8;+ } while ( sd < s_end8 );++ if ( sd == s_end )+ return;+ }++ STBIR_NO_UNROLL_LOOP_START+ do+ {+ STBIR_NO_UNROLL(sd);+ *(int*)( sd + ofs_to_dest ) = *(int*) sd;+ sd += 4;+ } while ( sd < s_end );+}++#endif++static float stbir__filter_trapezoid(float x, float scale, void * user_data)+{+ float halfscale = scale / 2;+ float t = 0.5f + halfscale;+ STBIR_ASSERT(scale <= 1);+ STBIR__UNUSED(user_data);++ if ( x < 0.0f ) x = -x;++ if (x >= t)+ return 0.0f;+ else+ {+ float r = 0.5f - halfscale;+ if (x <= r)+ return 1.0f;+ else+ return (t - x) / scale;+ }+}++static float stbir__support_trapezoid(float scale, void * user_data)+{+ STBIR__UNUSED(user_data);+ return 0.5f + scale / 2.0f;+}++static float stbir__filter_triangle(float x, float s, void * user_data)+{+ STBIR__UNUSED(s);+ STBIR__UNUSED(user_data);++ if ( x < 0.0f ) x = -x;++ if (x <= 1.0f)+ return 1.0f - x;+ else+ return 0.0f;+}++static float stbir__filter_point(float x, float s, void * user_data)+{+ STBIR__UNUSED(x);+ STBIR__UNUSED(s);+ STBIR__UNUSED(user_data);++ return 1.0f;+}++static float stbir__filter_cubic(float x, float s, void * user_data)+{+ STBIR__UNUSED(s);+ STBIR__UNUSED(user_data);++ if ( x < 0.0f ) x = -x;++ if (x < 1.0f)+ return (4.0f + x*x*(3.0f*x - 6.0f))/6.0f;+ else if (x < 2.0f)+ return (8.0f + x*(-12.0f + x*(6.0f - x)))/6.0f;++ return (0.0f);+}++static float stbir__filter_catmullrom(float x, float s, void * user_data)+{+ STBIR__UNUSED(s);+ STBIR__UNUSED(user_data);++ if ( x < 0.0f ) x = -x;++ if (x < 1.0f)+ return 1.0f - x*x*(2.5f - 1.5f*x);+ else if (x < 2.0f)+ return 2.0f - x*(4.0f + x*(0.5f*x - 2.5f));++ return (0.0f);+}++static float stbir__filter_mitchell(float x, float s, void * user_data)+{+ STBIR__UNUSED(s);+ STBIR__UNUSED(user_data);++ if ( x < 0.0f ) x = -x;++ if (x < 1.0f)+ return (16.0f + x*x*(21.0f * x - 36.0f))/18.0f;+ else if (x < 2.0f)+ return (32.0f + x*(-60.0f + x*(36.0f - 7.0f*x)))/18.0f;++ return (0.0f);+}++static float stbir__support_zeropoint5(float s, void * user_data)+{+ STBIR__UNUSED(s);+ STBIR__UNUSED(user_data);+ return 0.5f;+}++static float stbir__support_one(float s, void * user_data)+{+ STBIR__UNUSED(s);+ STBIR__UNUSED(user_data);+ return 1;+}++static float stbir__support_two(float s, void * user_data)+{+ STBIR__UNUSED(s);+ STBIR__UNUSED(user_data);+ return 2;+}++// This is the maximum number of input samples that can affect an output sample+// with the given filter from the output pixel's perspective+static int stbir__get_filter_pixel_width(stbir__support_callback * support, float scale, void * user_data)+{+ STBIR_ASSERT(support != 0);++ if ( scale >= ( 1.0f-stbir__small_float ) ) // upscale+ return (int)STBIR_CEILF(support(1.0f/scale,user_data) * 2.0f);+ else+ return (int)STBIR_CEILF(support(scale,user_data) * 2.0f / scale);+}++// 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)+{+ float scale = samp->scale_info.scale;+ stbir__support_callback * support = samp->filter_support;++ switch( is_gather )+ {+ case 1:+ return (int)STBIR_CEILF(support(1.0f / scale, user_data) * 2.0f);+ case 2:+ return (int)STBIR_CEILF(support(scale, user_data) * 2.0f / scale);+ case 0:+ return (int)STBIR_CEILF(support(scale, user_data) * 2.0f);+ default:+ STBIR_ASSERT( (is_gather >= 0 ) && (is_gather <= 2 ) );+ return 0;+ }+}++static int stbir__get_contributors(stbir__sampler * samp, int is_gather)+{+ if (is_gather)+ return samp->scale_info.output_sub_size;+ else+ return (samp->scale_info.input_full_size + samp->filter_pixel_margin * 2);+}++static int stbir__edge_zero_full( int n, int max )+{+ STBIR__UNUSED(n);+ STBIR__UNUSED(max);+ return 0; // NOTREACHED+}++static int stbir__edge_clamp_full( int n, int max )+{+ if (n < 0)+ return 0;++ if (n >= max)+ return max - 1;++ return n; // NOTREACHED+}++static int stbir__edge_reflect_full( int n, int max )+{+ if (n < 0)+ {+ if (n > -max)+ return -n;+ else+ return max - 1;+ }++ if (n >= max)+ {+ int max2 = max * 2;+ if (n >= max2)+ return 0;+ else+ return max2 - n - 1;+ }++ return n; // NOTREACHED+}++static int stbir__edge_wrap_full( int n, int max )+{+ if (n >= 0)+ return (n % max);+ else+ {+ int m = (-n) % max;++ if (m != 0)+ m = max - m;++ return (m);+ }+}++typedef int stbir__edge_wrap_func( int n, int max );+static stbir__edge_wrap_func * stbir__edge_wrap_slow[] =+{+ stbir__edge_clamp_full, // STBIR_EDGE_CLAMP+ stbir__edge_reflect_full, // STBIR_EDGE_REFLECT+ stbir__edge_wrap_full, // STBIR_EDGE_WRAP+ stbir__edge_zero_full, // STBIR_EDGE_ZERO+};++stbir__inline static int stbir__edge_wrap(stbir_edge edge, int n, int max)+{+ // avoid per-pixel switch+ if (n >= 0 && n < max)+ return n;+ return stbir__edge_wrap_slow[edge]( n, max );+}++#define STBIR__MERGE_RUNS_PIXEL_THRESHOLD 16++// get information on the extents of a sampler+static void stbir__get_extents( stbir__sampler * samp, stbir__extents * scanline_extents )+{+ int j, stop;+ int left_margin, right_margin;+ int min_n = 0x7fffffff, max_n = -0x7fffffff;+ int min_left = 0x7fffffff, max_left = -0x7fffffff;+ int min_right = 0x7fffffff, max_right = -0x7fffffff;+ stbir_edge edge = samp->edge;+ stbir__contributors* contributors = samp->contributors;+ int output_sub_size = samp->scale_info.output_sub_size;+ int input_full_size = samp->scale_info.input_full_size;+ int filter_pixel_margin = samp->filter_pixel_margin;++ STBIR_ASSERT( samp->is_gather );++ stop = output_sub_size;+ for (j = 0; j < stop; j++ )+ {+ STBIR_ASSERT( contributors[j].n1 >= contributors[j].n0 );+ if ( contributors[j].n0 < min_n )+ {+ min_n = contributors[j].n0;+ stop = j + filter_pixel_margin; // if we find a new min, only scan another filter width+ if ( stop > output_sub_size ) stop = output_sub_size;+ }+ }++ stop = 0;+ for (j = output_sub_size - 1; j >= stop; j-- )+ {+ STBIR_ASSERT( contributors[j].n1 >= contributors[j].n0 );+ if ( contributors[j].n1 > max_n )+ {+ max_n = contributors[j].n1;+ stop = j - filter_pixel_margin; // if we find a new max, only scan another filter width+ if (stop<0) stop = 0;+ }+ }++ STBIR_ASSERT( scanline_extents->conservative.n0 <= min_n );+ STBIR_ASSERT( scanline_extents->conservative.n1 >= max_n );++ // now calculate how much into the margins we really read+ left_margin = 0;+ if ( min_n < 0 )+ {+ left_margin = -min_n;+ min_n = 0;+ }++ right_margin = 0;+ if ( max_n >= input_full_size )+ {+ right_margin = max_n - input_full_size + 1;+ max_n = input_full_size - 1;+ }++ // index 1 is margin pixel extents (how many pixels we hang over the edge)+ scanline_extents->edge_sizes[0] = left_margin;+ scanline_extents->edge_sizes[1] = right_margin;++ // index 2 is pixels read from the input+ scanline_extents->spans[0].n0 = min_n;+ scanline_extents->spans[0].n1 = max_n;+ scanline_extents->spans[0].pixel_offset_for_input = min_n;++ // default to no other input range+ scanline_extents->spans[1].n0 = 0;+ scanline_extents->spans[1].n1 = -1;+ scanline_extents->spans[1].pixel_offset_for_input = 0;++ // 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++ )+ {+ int p = stbir__edge_wrap( edge, j, input_full_size );+ if ( p < min_left )+ min_left = p;+ if ( p > max_left )+ max_left = p;+ }++ for( j = input_full_size ; j < (input_full_size + right_margin) ; j++ )+ {+ int p = stbir__edge_wrap( edge, j, input_full_size );+ if ( p < min_right )+ min_right = p;+ if ( p > max_right )+ max_right = p;+ }++ // merge the left margin pixel region if it connects within 4 pixels of main pixel region+ if ( min_left != 0x7fffffff )+ {+ if ( ( ( min_left <= min_n ) && ( ( max_left + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= min_n ) ) ||+ ( ( min_n <= min_left ) && ( ( max_n + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= max_left ) ) )+ {+ scanline_extents->spans[0].n0 = min_n = stbir__min( min_n, min_left );+ scanline_extents->spans[0].n1 = max_n = stbir__max( max_n, max_left );+ scanline_extents->spans[0].pixel_offset_for_input = min_n;+ left_margin = 0;+ }+ }++ // merge the right margin pixel region if it connects within 4 pixels of main pixel region+ if ( min_right != 0x7fffffff )+ {+ if ( ( ( min_right <= min_n ) && ( ( max_right + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= min_n ) ) ||+ ( ( min_n <= min_right ) && ( ( max_n + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= max_right ) ) )+ {+ scanline_extents->spans[0].n0 = min_n = stbir__min( min_n, min_right );+ scanline_extents->spans[0].n1 = max_n = stbir__max( max_n, max_right );+ scanline_extents->spans[0].pixel_offset_for_input = min_n;+ right_margin = 0;+ }+ }++ STBIR_ASSERT( scanline_extents->conservative.n0 <= min_n );+ STBIR_ASSERT( scanline_extents->conservative.n1 >= max_n );++ // you get two ranges when you have the WRAP edge mode and you are doing just the a piece of the resize+ // so you need to get a second run of pixels from the opposite side of the scanline (which you+ // wouldn't need except for WRAP)+++ // if we can't merge the min_left range, add it as a second range+ if ( ( left_margin ) && ( min_left != 0x7fffffff ) )+ {+ stbir__span * newspan = scanline_extents->spans + 1;+ STBIR_ASSERT( right_margin == 0 );+ if ( min_left < scanline_extents->spans[0].n0 )+ {+ scanline_extents->spans[1].pixel_offset_for_input = scanline_extents->spans[0].n0;+ scanline_extents->spans[1].n0 = scanline_extents->spans[0].n0;+ scanline_extents->spans[1].n1 = scanline_extents->spans[0].n1;+ --newspan;+ }+ newspan->pixel_offset_for_input = min_left;+ newspan->n0 = -left_margin;+ newspan->n1 = ( max_left - min_left ) - left_margin;+ scanline_extents->edge_sizes[0] = 0; // don't need to copy the left margin, since we are directly decoding into the margin+ return;+ }++ // if we can't merge the min_left range, add it as a second range+ if ( ( right_margin ) && ( min_right != 0x7fffffff ) )+ {+ stbir__span * newspan = scanline_extents->spans + 1;+ if ( min_right < scanline_extents->spans[0].n0 )+ {+ scanline_extents->spans[1].pixel_offset_for_input = scanline_extents->spans[0].n0;+ scanline_extents->spans[1].n0 = scanline_extents->spans[0].n0;+ scanline_extents->spans[1].n1 = scanline_extents->spans[0].n1;+ --newspan;+ }+ newspan->pixel_offset_for_input = min_right;+ newspan->n0 = scanline_extents->spans[1].n1 + 1;+ newspan->n1 = scanline_extents->spans[1].n1 + 1 + ( max_right - min_right );+ scanline_extents->edge_sizes[1] = 0; // don't need to copy the right margin, since we are directly decoding into the margin+ return;+ }+}++static void stbir__calculate_in_pixel_range( int * first_pixel, int * last_pixel, float out_pixel_center, float out_filter_radius, float inv_scale, float out_shift, int input_size, stbir_edge edge )+{+ int first, last;+ 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;++ 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;+ if ( last >= (input_size*2))+ last = (input_size*2) - 1;+ }++ *first_pixel = first;+ *last_pixel = last;+}++static void stbir__calculate_coefficients_for_gather_upsample( float out_filter_radius, stbir__kernel_callback * kernel, stbir__scale_info * scale_info, int num_contributors, stbir__contributors* contributors, float* coefficient_group, int coefficient_width, stbir_edge edge, void * user_data )+{+ int n, end;+ float inv_scale = scale_info->inv_scale;+ float out_shift = scale_info->pixel_shift;+ int input_size = scale_info->input_full_size;+ int numerator = scale_info->scale_numerator;+ int polyphase = ( ( scale_info->scale_is_rational ) && ( numerator < num_contributors ) );++ // Looping through out pixels+ end = num_contributors; if ( polyphase ) end = numerator;+ for (n = 0; n < end; n++)+ {+ 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;++ 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;+ for (i = 0; i <= in_last_pixel - in_first_pixel; i++)+ {+ float in_pixel_center = (float)(i + in_first_pixel) + 0.5f;+ float coeff = kernel(in_center_of_out - in_pixel_center, inv_scale, user_data);++ // kill denormals+ 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--;+ continue;+ }+ coeff = 0; // make sure is fully zero (should keep denormals away)+ }+ 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;++ STBIR_ASSERT(contributors->n1 >= contributors->n0);++ ++contributors;+ coefficient_group += coefficient_width;+ }+}++static void stbir__insert_coeff( stbir__contributors * contribs, float * coeffs, int new_pixel, float new_coeff )+{+ if ( new_pixel <= contribs->n1 ) // before the end+ {+ if ( new_pixel < contribs->n0 ) // before the front?+ {+ int j, o = contribs->n0 - new_pixel;+ for ( j = contribs->n1 - contribs->n0 ; j <= 0 ; j-- )+ coeffs[ j + o ] = coeffs[ j ];+ for ( j = 1 ; j < o ; j-- )+ coeffs[ j ] = coeffs[ 0 ];+ coeffs[ 0 ] = new_coeff;+ contribs->n0 = new_pixel;+ }+ else+ {+ coeffs[ new_pixel - contribs->n0 ] += new_coeff;+ }+ }+ else+ {+ int j, e = new_pixel - contribs->n0;+ for( j = ( contribs->n1 - contribs->n0 ) + 1 ; j < e ; j++ ) // clear in-betweens coeffs if there are any+ coeffs[j] = 0;++ coeffs[ e ] = new_coeff;+ contribs->n1 = new_pixel;+ }+}++static void stbir__calculate_out_pixel_range( int * first_pixel, int * last_pixel, float in_pixel_center, float in_pixels_radius, float scale, float out_shift, int out_size )+{+ float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius;+ float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius;+ float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale - out_shift;+ float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale - out_shift;+ int out_first_pixel = (int)(STBIR_FLOORF(out_pixel_influence_lowerbound + 0.5f));+ int out_last_pixel = (int)(STBIR_FLOORF(out_pixel_influence_upperbound - 0.5f));++ if ( out_first_pixel < 0 )+ out_first_pixel = 0;+ if ( out_last_pixel >= out_size )+ out_last_pixel = out_size - 1;+ *first_pixel = out_first_pixel;+ *last_pixel = out_last_pixel;+}++static void stbir__calculate_coefficients_for_gather_downsample( int start, int end, float in_pixels_radius, stbir__kernel_callback * kernel, stbir__scale_info * scale_info, int coefficient_width, int num_contributors, stbir__contributors * contributors, float * coefficient_group, void * user_data )+{+ int in_pixel;+ int i;+ int first_out_inited = -1;+ float scale = scale_info->scale;+ float out_shift = scale_info->pixel_shift;+ int out_size = scale_info->output_sub_size;+ int numerator = scale_info->scale_numerator;+ int polyphase = ( ( scale_info->scale_is_rational ) && ( numerator < out_size ) );++ STBIR__UNUSED(num_contributors);++ // Loop through the input pixels+ for (in_pixel = start; in_pixel < end; in_pixel++)+ {+ float in_pixel_center = (float)in_pixel + 0.5f;+ float out_center_of_in = in_pixel_center * scale - out_shift;+ int out_first_pixel, out_last_pixel;++ stbir__calculate_out_pixel_range( &out_first_pixel, &out_last_pixel, in_pixel_center, in_pixels_radius, scale, out_shift, out_size );++ if ( out_first_pixel > out_last_pixel )+ continue;++ // clamp or exit if we are using polyphase filtering, and the limit is up+ if ( polyphase )+ {+ // when polyphase, you only have to do coeffs up to the numerator count+ if ( out_first_pixel == numerator )+ break;++ // don't do any extra work, clamp last pixel at numerator too+ if ( out_last_pixel >= numerator )+ out_last_pixel = numerator - 1;+ }++ for (i = 0; i <= out_last_pixel - out_first_pixel; i++)+ {+ float out_pixel_center = (float)(i + out_first_pixel) + 0.5f;+ float x = out_pixel_center - out_center_of_in;+ float coeff = kernel(x, scale, user_data) * scale;++ // kill the coeff if it's too small (avoid denormals)+ if ( ( ( coeff < stbir__small_float ) && ( coeff > -stbir__small_float ) ) )+ coeff = 0.0f;++ {+ int out = i + out_first_pixel;+ float * coeffs = coefficient_group + out * coefficient_width;+ stbir__contributors * contribs = contributors + out;++ // is this the first time this output pixel has been seen? Init it.+ if ( out > first_out_inited )+ {+ STBIR_ASSERT( out == ( first_out_inited + 1 ) ); // ensure we have only advanced one at time+ first_out_inited = out;+ contribs->n0 = in_pixel;+ contribs->n1 = in_pixel;+ coeffs[0] = coeff;+ }+ else+ {+ // insert on end (always in order)+ if ( coeffs[0] == 0.0f ) // if the first coefficent is zero, then zap it for this coeffs+ {+ STBIR_ASSERT( ( in_pixel - contribs->n0 ) == 1 ); // ensure that when we zap, we're at the 2nd pos+ contribs->n0 = in_pixel;+ }+ contribs->n1 = in_pixel;+ STBIR_ASSERT( ( in_pixel - contribs->n0 ) < coefficient_width );+ coeffs[in_pixel - contribs->n0] = coeff;+ }+ }+ }+ }+}++#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 n, end;+ int lowest = 0x7fffffff;+ int highest = -0x7fffffff;+ int widest = -1;+ int numerator = scale_info->scale_numerator;+ int denominator = scale_info->scale_denominator;+ int polyphase = ( ( scale_info->scale_is_rational ) && ( numerator < num_contributors ) );+ float * coeffs;+ stbir__contributors * contribs;++ // weight all the coeffs for each sample+ coeffs = coefficient_group;+ contribs = contributors;+ end = num_contributors; if ( polyphase ) end = numerator;+ for (n = 0; n < end; n++)+ {+ int i;+ 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 += (STBIR_RENORM_TYPE) coeffs[i];+ STBIR_ASSERT( ( coeffs[i] >= -2.0f ) && ( coeffs[i] <= 2.0f ) ); // check for wonky weights+ }++ // rescale+ if ( ( total_filter < stbir__small_float ) && ( total_filter > -stbir__small_float ) )+ {+ // all coeffs are extremely small, just zero it+ contribs->n1 = contribs->n0;+ coeffs[0] = 0.0f;+ }+ else+ {+ // 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 = ((STBIR_RENORM_TYPE)1.0) / total_filter;++ // scale them all+ for (i = 0; i <= e; i++)+ coeffs[i] = (float) ( coeffs[i] * filter_scale );+ }+ }+ ++contribs;+ coeffs += coefficient_width;+ }++ // if we have a rational for the scale, we can exploit the polyphaseness to not calculate+ // most of the coefficients, so we copy them here+ if ( polyphase )+ {+ stbir__contributors * prev_contribs = contributors;+ stbir__contributors * cur_contribs = contributors + numerator;++ for( n = numerator ; n < num_contributors ; n++ )+ {+ cur_contribs->n0 = prev_contribs->n0 + denominator;+ cur_contribs->n1 = prev_contribs->n1 + denominator;+ ++cur_contribs;+ ++prev_contribs;+ }+ stbir_overlapping_memcpy( coefficient_group + numerator * coefficient_width, coefficient_group, ( num_contributors - numerator ) * coefficient_width * sizeof( coeffs[ 0 ] ) );+ }++ coeffs = coefficient_group;+ contribs = contributors;+ for (n = 0; n < num_contributors; n++)+ {+ int i;++ // in zero edge mode, just remove out of bounds contribs completely (since their weights are accounted for now)+ if ( edge == STBIR_EDGE_ZERO )+ {+ // shrink the right side if necessary+ if ( contribs->n1 > input_last_n1 )+ contribs->n1 = input_last_n1;++ // shrink the left side+ if ( contribs->n0 < 0 )+ {+ int j, left, skips = 0;++ skips = -contribs->n0;+ contribs->n0 = 0;++ // now move down the weights+ left = contribs->n1 - contribs->n0 + 1;+ if ( left > 0 )+ {+ for( j = 0 ; j < left ; j++ )+ coeffs[ j ] = coeffs[ j + skips ];+ }+ }+ }+ 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;+ for( i = input_size; i <= endi; i++ )+ stbir__insert_coeff( contribs, coeffs, stbir__edge_wrap_slow[edge]( i, input_size ), coeffs[i-start] );+ }++ // now check left hand edge+ if ( contribs->n0 < 0 )+ {+ 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-- )+ 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;+ 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 );+ }+ }++ if ( contribs->n0 <= contribs->n1 )+ {+ int diff = contribs->n1 - contribs->n0 + 1;+ while ( diff && ( coeffs[ diff-1 ] == 0.0f ) )+ --diff;+ contribs->n1 = contribs->n0 + diff - 1;++ if ( contribs->n0 <= contribs->n1 )+ {+ if ( contribs->n0 < lowest )+ lowest = contribs->n0;+ if ( contribs->n1 > highest )+ highest = contribs->n1;+ if ( diff > widest )+ widest = diff;+ }++ // re-zero out unused coefficients (if any)+ for( i = diff ; i < coefficient_width ; i++ )+ coeffs[i] = 0.0f;+ }++ ++contribs;+ coeffs += coefficient_width;+ }+ filter_info->lowest = lowest;+ filter_info->highest = highest;+ filter_info->widest = widest;+}++#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]; }+ #ifdef STBIR_SIMD+ #define STBIR_MOVE_4( dest, src ) { stbir__simdf t; STBIR_NO_UNROLL(dest); stbir__simdf_load( t, src ); stbir__simdf_store( dest, t ); }+ #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;+ float * coeffs = coefficents;+ float * pc_end = coefficents + num_contributors * widest;+ switch( widest )+ {+ case 1:+ STBIR_NO_UNROLL_LOOP_START+ do {+ STBIR_MOVE_1( pc, coeffs );+ ++pc;+ coeffs += coefficient_width;+ } while ( pc < pc_end );+ break;+ case 2:+ STBIR_NO_UNROLL_LOOP_START+ do {+ STBIR_MOVE_2( pc, coeffs );+ pc += 2;+ coeffs += coefficient_width;+ } 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 );+ pc += 3;+ coeffs += coefficient_width;+ } while ( pc < pc_end );+ break;+ case 4:+ STBIR_NO_UNROLL_LOOP_START+ do {+ STBIR_MOVE_4( pc, coeffs );+ pc += 4;+ coeffs += coefficient_width;+ } 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 );+ pc += 5;+ coeffs += coefficient_width;+ } 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 );+ pc += 6;+ coeffs += coefficient_width;+ } 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 );+ STBIR_MOVE_1( pc+6, coeffs+6 );+ pc += 7;+ coeffs += coefficient_width;+ } 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 );+ pc += 8;+ coeffs += coefficient_width;+ } 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 );+ STBIR_MOVE_1( pc+8, coeffs+8 );+ pc += 9;+ coeffs += coefficient_width;+ } 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 );+ STBIR_MOVE_2( pc+8, coeffs+8 );+ pc += 10;+ coeffs += coefficient_width;+ } 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 );+ STBIR_MOVE_2( pc+8, coeffs+8 );+ STBIR_MOVE_1( pc+10, coeffs+10 );+ pc += 11;+ coeffs += coefficient_width;+ } 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 );+ STBIR_MOVE_4( pc+8, coeffs+8 );+ pc += 12;+ coeffs += coefficient_width;+ } while ( pc < pc_end );+ break;+ default:+ STBIR_NO_UNROLL_LOOP_START+ do {+ float * copy_end = pc + widest - 4;+ float * c = coeffs;+ do {+ STBIR_NO_UNROLL( pc );+ STBIR_MOVE_4( pc, c );+ pc += 4;+ c += 4;+ } while ( pc <= copy_end );+ copy_end += 4;+ STBIR_NO_UNROLL_LOOP_START+ while ( pc < copy_end )+ {+ STBIR_MOVE_1( pc, c );+ ++pc; ++c;+ }+ coeffs += coefficient_width;+ } while ( pc < pc_end );+ break;+ }+ }++ // some horizontal routines read one float off the end (which is then masked off), so put in a sentinal so we don't read an snan or denormal+ 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+ // 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).+ {+ stbir__contributors * contribs = contributors + num_contributors - 1;+ float * coeffs = coefficents + widest * ( num_contributors - 1 );++ // go until no chance of clipping (this is usually less than 8 lops)+ while ( ( contribs >= contributors ) && ( ( contribs->n0 + widest*2 ) >= row_end ) )+ {+ // might we clip??+ 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 )+ {+ int mod;++ // 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;++ // 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_end )+ {+ 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 >= row0 ) && ( new_n0 < contribs->n0 ) );++ // move the coeffs over+ while( num )+ {+ *to_co-- = *from_co--;+ --num;+ }+ // zero new positions+ while ( to_co >= coeffs )+ *to_co-- = 0;+ // set new start point+ contribs->n0 = new_n0;+ if ( widest > 12 )+ {+ int mod;++ // 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;++ // the n_coeff loops do a minimum amount of coeffs, so factor that in!+ if ( stop_range < ( 8 + mod ) ) stop_range = 8 + mod;+ }+ }+ }+ --contribs;+ coeffs -= widest;+ }+ }++ return widest;+ #undef STBIR_MOVE_1+ #undef STBIR_MOVE_2+ #undef STBIR_MOVE_4+}++static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * other_axis_for_pivot, void * user_data STBIR_ONLY_PROFILE_BUILD_GET_INFO )+{+ int n;+ float scale = samp->scale_info.scale;+ stbir__kernel_callback * kernel = samp->filter_kernel;+ stbir__support_callback * support = samp->filter_support;+ float inv_scale = samp->scale_info.inv_scale;+ 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;+ int gather_coefficient_width = samp->coefficient_width;++ switch ( samp->is_gather )+ {+ case 1: // gather upsample+ {+ float out_pixels_radius = support(inv_scale,user_data) * scale;++ stbir__calculate_coefficients_for_gather_upsample( out_pixels_radius, kernel, &samp->scale_info, gather_num_contributors, gather_contributors, gather_coeffs, gather_coefficient_width, samp->edge, user_data );++ STBIR_PROFILE_BUILD_START( cleanup );+ stbir__cleanup_gathered_coefficients( samp->edge, &samp->extent_info, &samp->scale_info, gather_num_contributors, gather_contributors, gather_coeffs, gather_coefficient_width );+ STBIR_PROFILE_BUILD_END( cleanup );+ }+ break;++ case 0: // scatter downsample (only on vertical)+ 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,+ // if so, then we don't have to generate them, we can just pivot from the horizontal.+ if ( other_axis_for_pivot )+ {+ gather_contributors = other_axis_for_pivot->contributors;+ gather_coeffs = other_axis_for_pivot->coefficients;+ gather_coefficient_width = other_axis_for_pivot->coefficient_width;+ gather_num_contributors = other_axis_for_pivot->num_contributors;+ samp->extent_info.lowest = other_axis_for_pivot->extent_info.lowest;+ samp->extent_info.highest = other_axis_for_pivot->extent_info.highest;+ samp->extent_info.widest = other_axis_for_pivot->extent_info.widest;+ goto jump_right_to_pivot;+ }++ gather_contributors = samp->gather_prescatter_contributors;+ gather_coeffs = samp->gather_prescatter_coefficients;+ gather_coefficient_width = samp->gather_prescatter_coefficient_width;+ gather_num_contributors = samp->gather_prescatter_num_contributors;+ }++ stbir__calculate_coefficients_for_gather_downsample( -filter_pixel_margin, input_end, in_pixels_radius, kernel, &samp->scale_info, gather_coefficient_width, gather_num_contributors, gather_contributors, gather_coeffs, user_data );++ STBIR_PROFILE_BUILD_START( cleanup );+ stbir__cleanup_gathered_coefficients( samp->edge, &samp->extent_info, &samp->scale_info, gather_num_contributors, gather_contributors, gather_coeffs, gather_coefficient_width );+ STBIR_PROFILE_BUILD_END( cleanup );++ if ( !samp->is_gather )+ {+ // if this is a scatter (vertical only), then we need to pivot the coeffs+ stbir__contributors * scatter_contributors;+ int highest_set;++ jump_right_to_pivot:++ STBIR_PROFILE_BUILD_START( pivot );++ highest_set = (-filter_pixel_margin) - 1;+ for (n = 0; n < gather_num_contributors; n++)+ {+ int k;+ int gn0 = gather_contributors->n0, gn1 = gather_contributors->n1;+ int scatter_coefficient_width = samp->coefficient_width;+ 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++;+ + // 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;+ }+ }+ 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 );+ }+ STBIR_ASSERT( ( scatter_contributors->n1 - scatter_contributors->n0 + 1 ) <= scatter_coefficient_width );+ }+ ++scatter_contributors;+ scatter_coeffs += scatter_coefficient_width;+ }++ ++gather_contributors;+ gather_coeffs += gather_coefficient_width;+ }++ // now clear any unset contribs+ {+ stbir__contributors * clear_contributors = samp->contributors + ( highest_set + filter_pixel_margin + 1);+ stbir__contributors * end_contributors = samp->contributors + samp->num_contributors;+ while ( clear_contributors < end_contributors )+ {+ clear_contributors->n0 = 0;+ clear_contributors->n1 = -1;+ ++clear_contributors;+ }+ }++ STBIR_PROFILE_BUILD_END( pivot );+ }+ }+ break;+ }+}+++//========================================================================================================+// scanline decoders and encoders++#define stbir__coder_min_num 1+#define STB_IMAGE_RESIZE_DO_CODERS+#include STBIR__HEADER_FILENAME++#define stbir__decode_suffix BGRA+#define stbir__decode_swizzle+#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_order1 1+#define stbir__encode_order2 0+#define stbir__encode_order3 3+#define stbir__coder_min_num 4+#define STB_IMAGE_RESIZE_DO_CODERS+#include STBIR__HEADER_FILENAME++#define stbir__decode_suffix ARGB+#define stbir__decode_swizzle+#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_order1 0+#define stbir__encode_order2 1+#define stbir__encode_order3 2+#define stbir__coder_min_num 4+#define STB_IMAGE_RESIZE_DO_CODERS+#include STBIR__HEADER_FILENAME++#define stbir__decode_suffix ABGR+#define stbir__decode_swizzle+#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_order1 2+#define stbir__encode_order2 1+#define stbir__encode_order3 0+#define stbir__coder_min_num 4+#define STB_IMAGE_RESIZE_DO_CODERS+#include STBIR__HEADER_FILENAME++#define stbir__decode_suffix AR+#define stbir__decode_swizzle+#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_order2 3+#define stbir__encode_order3 2+#define stbir__coder_min_num 2+#define STB_IMAGE_RESIZE_DO_CODERS+#include STBIR__HEADER_FILENAME+++// fancy alpha means we expand to keep both premultipied and non-premultiplied color channels+static void stbir__fancy_alpha_weight_4ch( float * out_buffer, int width_times_channels )+{+ float STBIR_STREAMOUT_PTR(*) out = out_buffer;+ float const * end_decode = out_buffer + ( width_times_channels / 4 ) * 7; // decode buffer aligned to end of out_buffer+ float STBIR_STREAMOUT_PTR(*) decode = (float*)end_decode - width_times_channels;++ // 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;+ STBIR_NO_UNROLL(decode);+ stbir__simdf8_load( d0, decode-16 );+ stbir__simdf8_load( d1, decode-16+8 );+ stbir__simdf8_0123to33333333( a0, d0 );+ stbir__simdf8_0123to33333333( a1, d1 );+ stbir__simdf8_mult( p0, a0, d0 );+ stbir__simdf8_mult( p1, a1, d1 );+ stbir__simdf8_bot4s( a0, d0, p0 );+ stbir__simdf8_bot4s( a1, d1, p1 );+ stbir__simdf8_top4s( d0, d0, p0 );+ stbir__simdf8_top4s( d1, d1, p1 );+ stbir__simdf8_store ( out, a0 );+ stbir__simdf8_store ( out+7, d0 );+ stbir__simdf8_store ( out+14, a1 );+ stbir__simdf8_store ( out+21, d1 );+ decode += 16;+ out += 28;+ }+ decode -= 16;+ #else+ decode += 8;+ STBIR_NO_UNROLL_LOOP_START+ while ( decode <= end_decode )+ {+ stbir__simdf d0,a0,d1,a1,p0,p1;+ STBIR_NO_UNROLL(decode);+ stbir__simdf_load( d0, decode-8 );+ stbir__simdf_load( d1, decode-8+4 );+ stbir__simdf_0123to3333( a0, d0 );+ stbir__simdf_0123to3333( a1, d1 );+ stbir__simdf_mult( p0, a0, d0 );+ stbir__simdf_mult( p1, a1, d1 );+ stbir__simdf_store ( out, d0 );+ stbir__simdf_store ( out+4, p0 );+ stbir__simdf_store ( out+7, d1 );+ stbir__simdf_store ( out+7+4, p1 );+ decode += 8;+ out += 14;+ }+ decode -= 8;+ #endif++ // 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 );+ stbir__simdf_store ( out, d );+ stbir__simdf_store ( out+4, p );+ decode += 4;+ out += 7;+ }++ #else++ while( decode < end_decode )+ {+ float r = decode[0], g = decode[1], b = decode[2], alpha = decode[3];+ out[0] = r;+ out[1] = g;+ out[2] = b;+ out[3] = alpha;+ out[4] = r * alpha;+ out[5] = g * alpha;+ out[6] = b * alpha;+ out += 7;+ decode += 4;+ }++ #endif+}++static void stbir__fancy_alpha_weight_2ch( float * out_buffer, int width_times_channels )+{+ float STBIR_STREAMOUT_PTR(*) out = out_buffer;+ float const * end_decode = out_buffer + ( width_times_channels / 2 ) * 3;+ float STBIR_STREAMOUT_PTR(*) decode = (float*)end_decode - width_times_channels;++ // for fancy alpha, turns into: [X A Xpm][X A Xpm],etc++ #ifdef STBIR_SIMD++ decode += 8;+ if ( decode <= end_decode )+ {+ STBIR_NO_UNROLL_LOOP_START+ do {+ #ifdef STBIR_SIMD8+ stbir__simdf8 d0,a0,p0;+ STBIR_NO_UNROLL(decode);+ stbir__simdf8_load( d0, decode-8 );+ 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 ) );+ #else+ stbir__simdf d0,a0,d1,a1,p0,p1;+ STBIR_NO_UNROLL(decode);+ stbir__simdf_load( d0, decode-8 );+ stbir__simdf_load( d1, decode-8+4 );+ stbir__simdf_0123to1133( p0, d0 );+ stbir__simdf_0123to1133( p1, d1 );+ stbir__simdf_0123to0022( a0, d0 );+ stbir__simdf_0123to0022( a1, d1 );+ stbir__simdf_mult( p0, p0, a0 );+ stbir__simdf_mult( p1, p1, a1 );++ stbir__simdf_store2( out, d0 );+ stbir__simdf_store( out+2, p0 );+ stbir__simdf_store2h( out+3, d0 );++ stbir__simdf_store2( out+6, d1 );+ stbir__simdf_store( out+8, p1 );+ stbir__simdf_store2h( out+9, d1 );+ #endif+ decode += 8;+ out += 12;+ } while ( decode <= end_decode );+ }+ decode -= 8;+ #endif++ STBIR_SIMD_NO_UNROLL_LOOP_START+ while( decode < end_decode )+ {+ float x = decode[0], y = decode[1];+ STBIR_SIMD_NO_UNROLL(decode);+ out[0] = x;+ out[1] = y;+ out[2] = x * y;+ out += 3;+ decode += 2;+ }+}++static void stbir__fancy_alpha_unweight_4ch( float * encode_buffer, int width_times_channels )+{+ float STBIR_SIMD_STREAMOUT_PTR(*) encode = encode_buffer;+ float STBIR_SIMD_STREAMOUT_PTR(*) input = encode_buffer;+ float const * end_output = encode_buffer + width_times_channels;++ // 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+ stbir__simdf i,ia;+ STBIR_SIMD_NO_UNROLL(encode);+ if ( alpha < stbir__small_float )+ {+ stbir__simdf_load( i, input );+ stbir__simdf_store( encode, i );+ }+ else+ {+ stbir__simdf_load1frep4( ia, 1.0f / alpha );+ stbir__simdf_load( i, input+4 );+ stbir__simdf_mult( i, i, ia );+ stbir__simdf_store( encode, i );+ encode[3] = alpha;+ }+#else+ if ( alpha < stbir__small_float )+ {+ encode[0] = input[0];+ encode[1] = input[1];+ encode[2] = input[2];+ }+ else+ {+ float ialpha = 1.0f / alpha;+ encode[0] = input[4] * ialpha;+ encode[1] = input[5] * ialpha;+ encode[2] = input[6] * ialpha;+ }+ encode[3] = alpha;+#endif++ input += 7;+ encode += 4;+ } while ( encode < end_output );+}++// format: [X A Xpm][X A Xpm] etc+static void stbir__fancy_alpha_unweight_2ch( float * encode_buffer, int width_times_channels )+{+ float STBIR_SIMD_STREAMOUT_PTR(*) encode = encode_buffer;+ float STBIR_SIMD_STREAMOUT_PTR(*) input = encode_buffer;+ float const * end_output = encode_buffer + width_times_channels;++ do {+ float alpha = input[1];+ encode[0] = input[0];+ if ( alpha >= stbir__small_float )+ encode[0] = input[2] / alpha;+ encode[1] = alpha;++ input += 3;+ encode += 2;+ } while ( encode < end_output );+}++static void stbir__simple_alpha_weight_4ch( float * decode_buffer, int width_times_channels )+{+ float STBIR_STREAMOUT_PTR(*) decode = decode_buffer;+ float const * end_decode = decode_buffer + width_times_channels;++ #ifdef STBIR_SIMD+ {+ decode += 2 * stbir__simdfX_float_count;+ STBIR_NO_UNROLL_LOOP_START+ while ( decode <= end_decode )+ {+ stbir__simdfX d0,a0,d1,a1;+ STBIR_NO_UNROLL(decode);+ stbir__simdfX_load( d0, decode-2*stbir__simdfX_float_count );+ stbir__simdfX_load( d1, decode-2*stbir__simdfX_float_count+stbir__simdfX_float_count );+ stbir__simdfX_aaa1( a0, d0, STBIR_onesX );+ stbir__simdfX_aaa1( a1, d1, STBIR_onesX );+ stbir__simdfX_mult( d0, d0, a0 );+ stbir__simdfX_mult( d1, d1, a1 );+ stbir__simdfX_store ( decode-2*stbir__simdfX_float_count, d0 );+ stbir__simdfX_store ( decode-2*stbir__simdfX_float_count+stbir__simdfX_float_count, d1 );+ decode += 2 * stbir__simdfX_float_count;+ }+ decode -= 2 * stbir__simdfX_float_count;++ // few last pixels remnants+ #ifdef STBIR_SIMD8+ STBIR_NO_UNROLL_LOOP_START+ while ( decode < end_decode )+ #else+ if ( decode < end_decode )+ #endif+ {+ stbir__simdf d,a;+ stbir__simdf_load( d, decode );+ stbir__simdf_aaa1( a, d, STBIR__CONSTF(STBIR_ones) );+ stbir__simdf_mult( d, d, a );+ stbir__simdf_store ( decode, d );+ decode += 4;+ }+ }++ #else++ while( decode < end_decode )+ {+ float alpha = decode[3];+ decode[0] *= alpha;+ decode[1] *= alpha;+ decode[2] *= alpha;+ decode += 4;+ }++ #endif+}++static void stbir__simple_alpha_weight_2ch( float * decode_buffer, int width_times_channels )+{+ float STBIR_STREAMOUT_PTR(*) decode = decode_buffer;+ float const * end_decode = decode_buffer + width_times_channels;++ #ifdef STBIR_SIMD+ decode += 2 * stbir__simdfX_float_count;+ STBIR_NO_UNROLL_LOOP_START+ while ( decode <= end_decode )+ {+ stbir__simdfX d0,a0,d1,a1;+ STBIR_NO_UNROLL(decode);+ stbir__simdfX_load( d0, decode-2*stbir__simdfX_float_count );+ stbir__simdfX_load( d1, decode-2*stbir__simdfX_float_count+stbir__simdfX_float_count );+ stbir__simdfX_a1a1( a0, d0, STBIR_onesX );+ stbir__simdfX_a1a1( a1, d1, STBIR_onesX );+ stbir__simdfX_mult( d0, d0, a0 );+ stbir__simdfX_mult( d1, d1, a1 );+ stbir__simdfX_store ( decode-2*stbir__simdfX_float_count, d0 );+ stbir__simdfX_store ( decode-2*stbir__simdfX_float_count+stbir__simdfX_float_count, d1 );+ decode += 2 * stbir__simdfX_float_count;+ }+ decode -= 2 * stbir__simdfX_float_count;+ #endif++ STBIR_SIMD_NO_UNROLL_LOOP_START+ while( decode < end_decode )+ {+ float alpha = decode[1];+ STBIR_SIMD_NO_UNROLL(decode);+ decode[0] *= alpha;+ decode += 2;+ }+}++static void stbir__simple_alpha_unweight_4ch( float * encode_buffer, int width_times_channels )+{+ 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];++#ifdef STBIR_SIMD+ stbir__simdf i,ia;+ STBIR_SIMD_NO_UNROLL(encode);+ if ( alpha >= stbir__small_float )+ {+ stbir__simdf_load1frep4( ia, 1.0f / alpha );+ stbir__simdf_load( i, encode );+ stbir__simdf_mult( i, i, ia );+ stbir__simdf_store( encode, i );+ encode[3] = alpha;+ }+#else+ if ( alpha >= stbir__small_float )+ {+ float ialpha = 1.0f / alpha;+ encode[0] *= ialpha;+ encode[1] *= ialpha;+ encode[2] *= ialpha;+ }+#endif+ encode += 4;+ } while ( encode < end_output );+}++static void stbir__simple_alpha_unweight_2ch( float * encode_buffer, int width_times_channels )+{+ float STBIR_SIMD_STREAMOUT_PTR(*) encode = encode_buffer;+ float const * end_output = encode_buffer + width_times_channels;++ do {+ float alpha = encode[1];+ if ( alpha >= stbir__small_float )+ encode[0] /= alpha;+ encode += 2;+ } while ( encode < end_output );+}+++// only used in RGB->BGR or BGR->RGB+static void stbir__simple_flip_3ch( float * decode_buffer, int width_times_channels )+{+ float STBIR_STREAMOUT_PTR(*) decode = decode_buffer;+ float const * end_decode = decode_buffer + width_times_channels;++#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];+ decode[0] = decode[2]; decode[3] = decode[5]; decode[6] = decode[8]; decode[9] = decode[11];+ decode[2] = t0; decode[5] = t1; decode[8] = t2; decode[11] = t3;+ decode += 12;+ }+ end_decode += 12;+#endif++ STBIR_NO_UNROLL_LOOP_START+ while( decode < end_decode )+ {+ float t = decode[0];+ STBIR_NO_UNROLL(decode);+ decode[0] = decode[2];+ decode[2] = t;+ decode += 3;+ }+}++++static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float * output_buffer STBIR_ONLY_PROFILE_GET_SPLIT_INFO )+{+ int channels = stbir_info->channels;+ int effective_channels = stbir_info->effective_channels;+ int input_sample_in_bytes = stbir__type_size[stbir_info->input_type] * channels;+ 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 ) + (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+ {+ float * decode_buffer;+ void const * input_data;+ float * end_decode;+ int width_times_channels;+ int width;++ if ( spans->n1 < spans->n0 )+ break;++ width = spans->n1 + 1 - spans->n0;+ decode_buffer = full_decode_buffer + spans->n0 * effective_channels;+ end_decode = full_decode_buffer + ( spans->n1 + 1 ) * effective_channels;+ width_times_channels = width * channels;++ // read directly out of input plane by default+ input_data = ( (char*)input_plane_data ) + spans->pixel_offset_for_input * input_sample_in_bytes;++ // if we have an input callback, call it to get the input data+ if ( stbir_info->in_pixels_cb )+ {+ // 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 channels<effective_channels, we are right justified in the buffer)+ stbir_info->decode_pixels( (float*)end_decode - width_times_channels, width_times_channels, input_data );+ STBIR_PROFILE_END( decode );++ if (stbir_info->alpha_weight)+ {+ STBIR_PROFILE_START( alpha );+ stbir_info->alpha_weight( decode_buffer, width_times_channels );+ STBIR_PROFILE_END( alpha );+ }++ ++spans;+ } while ( spans <= ( &stbir_info->scanline_extents.spans[1] ) );++ // handle the edge_wrap filter (all other types are handled back out at the calculate_filter stage)+ // basically the idea here is that if we have the whole scanline in memory, we don't redecode the+ // wrapped edge pixels, and instead just memcpy them from the scanline into the edge positions+ if ( ( edge_horizontal == STBIR_EDGE_WRAP ) && ( stbir_info->scanline_extents.edge_sizes[0] | stbir_info->scanline_extents.edge_sizes[1] ) )+ {+ // 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++ for( e = 0; e < 2 ; e++ )+ {+ // do each margin+ int margin = stbir_info->scanline_extents.edge_sizes[e];+ if ( margin )+ {+ int x = start_x[e];+ float * marg = full_decode_buffer + x * effective_channels;+ float const * src = full_decode_buffer + stbir__edge_wrap(edge_horizontal, x, input_full_size) * effective_channels;+ STBIR_MEMCPY( marg, src, margin * effective_channels * sizeof(float) );+ }+ }+ }+}+++//=================+// Do 1 channel horizontal routines++#ifdef STBIR_SIMD++#define stbir__1_coeff_only() \+ stbir__simdf tot,c; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load1( c, hc ); \+ stbir__simdf_mult1_mem( tot, c, decode );++#define stbir__2_coeff_only() \+ stbir__simdf tot,c,d; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load2z( c, hc ); \+ stbir__simdf_load2( d, decode ); \+ stbir__simdf_mult( tot, c, d ); \+ stbir__simdf_0123to1230( c, tot ); \+ stbir__simdf_add1( tot, tot, c );++#define stbir__3_coeff_only() \+ stbir__simdf tot,c,t; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load( c, hc ); \+ stbir__simdf_mult_mem( tot, c, decode ); \+ stbir__simdf_0123to1230( c, tot ); \+ stbir__simdf_0123to2301( t, tot ); \+ stbir__simdf_add1( tot, tot, c ); \+ stbir__simdf_add1( tot, tot, t );++#define stbir__store_output_tiny() \+ stbir__simdf_store1( output, tot ); \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 1;++#define stbir__4_coeff_start() \+ stbir__simdf tot,c; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load( c, hc ); \+ stbir__simdf_mult_mem( tot, c, decode ); \++#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) );++#define stbir__1_coeff_remnant( ofs ) \+ { stbir__simdf d; \+ stbir__simdf_load1z( c, hc + (ofs) ); \+ stbir__simdf_load1( d, decode + (ofs) ); \+ stbir__simdf_madd( tot, tot, d, c ); }++#define stbir__2_coeff_remnant( ofs ) \+ { stbir__simdf d; \+ stbir__simdf_load2z( c, hc+(ofs) ); \+ stbir__simdf_load2( d, decode+(ofs) ); \+ stbir__simdf_madd( tot, tot, d, c ); }++#define stbir__3_coeff_setup() \+ stbir__simdf mask; \+ stbir__simdf_load( mask, STBIR_mask + 3 );++#define stbir__3_coeff_remnant( ofs ) \+ stbir__simdf_load( c, hc+(ofs) ); \+ stbir__simdf_and( c, c, mask ); \+ stbir__simdf_madd_mem( tot, tot, c, decode+(ofs) );++#define stbir__store_output() \+ stbir__simdf_0123to2301( c, tot ); \+ stbir__simdf_add( tot, tot, c ); \+ stbir__simdf_0123to1230( c, tot ); \+ stbir__simdf_add1( tot, tot, c ); \+ stbir__simdf_store1( output, tot ); \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 1;++#else++#define stbir__1_coeff_only() \+ float tot; \+ tot = decode[0]*hc[0];++#define stbir__2_coeff_only() \+ float tot; \+ tot = decode[0] * hc[0]; \+ 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];++#define stbir__store_output_tiny() \+ output[0] = tot; \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 1;++#define stbir__4_coeff_start() \+ float tot0,tot1,tot2,tot3; \+ tot0 = decode[0] * hc[0]; \+ tot1 = decode[1] * hc[1]; \+ tot2 = decode[2] * hc[2]; \+ 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)];++#define stbir__1_coeff_remnant( ofs ) \+ tot0 += decode[0+(ofs)] * hc[0+(ofs)];++#define stbir__2_coeff_remnant( ofs ) \+ tot0 += decode[0+(ofs)] * hc[0+(ofs)]; \+ tot1 += decode[1+(ofs)] * hc[1+(ofs)]; \++#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)];++#define stbir__store_output() \+ output[0] = (tot0+tot2)+(tot1+tot3); \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 1;++#endif++#define STBIR__horizontal_channels 1+#define STB_IMAGE_RESIZE_DO_HORIZONTALS+#include STBIR__HEADER_FILENAME+++//=================+// Do 2 channel horizontal routines++#ifdef STBIR_SIMD++#define stbir__1_coeff_only() \+ stbir__simdf tot,c,d; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load1z( c, hc ); \+ stbir__simdf_0123to0011( c, c ); \+ stbir__simdf_load2( d, decode ); \+ 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 );++#define stbir__3_coeff_only() \+ stbir__simdf tot,c,cs,d; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load( cs, hc ); \+ stbir__simdf_0123to0011( c, cs ); \+ 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 );++#define stbir__store_output_tiny() \+ stbir__simdf_0123to2301( c, tot ); \+ stbir__simdf_add( tot, tot, c ); \+ stbir__simdf_store2( output, tot ); \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 2;++#ifdef STBIR_SIMD8++#define stbir__4_coeff_start() \+ stbir__simdf8 tot0,c,cs; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf8_load4b( cs, hc ); \+ stbir__simdf8_0123to00112233( c, cs ); \+ stbir__simdf8_mult_mem( tot0, c, decode );++#define stbir__4_coeff_continue_from_4( ofs ) \+ 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 );++#define stbir__1_coeff_remnant( ofs ) \+ { stbir__simdf t; \+ stbir__simdf_load1z( t, hc + (ofs) ); \+ stbir__simdf_0123to0011( t, t ); \+ stbir__simdf_mult_mem( t, t, decode+(ofs)*2 ); \+ stbir__simdf8_add4( tot0, tot0, t ); }++#define stbir__2_coeff_remnant( ofs ) \+ { stbir__simdf t; \+ stbir__simdf_load2( t, hc + (ofs) ); \+ stbir__simdf_0123to0011( t, t ); \+ stbir__simdf_mult_mem( t, t, decode+(ofs)*2 ); \+ stbir__simdf8_add4( tot0, tot0, t ); }++#define stbir__3_coeff_remnant( ofs ) \+ { stbir__simdf8 d; \+ 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 ); }++#define stbir__store_output() \+ { stbir__simdf t,d; \+ stbir__simdf8_add4halves( t, stbir__if_simdf8_cast_to_simdf4(tot0), tot0 ); \+ stbir__simdf_0123to2301( d, t ); \+ stbir__simdf_add( t, t, d ); \+ stbir__simdf_store2( output, t ); \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 2; }++#else++#define stbir__4_coeff_start() \+ stbir__simdf tot0,tot1,c,cs; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load( cs, hc ); \+ 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 );++#define stbir__4_coeff_continue_from_4( ofs ) \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load( cs, hc + (ofs) ); \+ 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 );++#define stbir__1_coeff_remnant( ofs ) \+ { stbir__simdf d; \+ stbir__simdf_load1z( cs, hc + (ofs) ); \+ stbir__simdf_0123to0011( c, cs ); \+ stbir__simdf_load2( d, decode + (ofs) * 2 ); \+ stbir__simdf_madd( tot0, tot0, d, c ); }++#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 );++#define stbir__3_coeff_remnant( ofs ) \+ { stbir__simdf d; \+ stbir__simdf_load( cs, hc + (ofs) ); \+ stbir__simdf_0123to0011( c, cs ); \+ 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 ); }++#define stbir__store_output() \+ stbir__simdf_add( tot0, tot0, tot1 ); \+ stbir__simdf_0123to2301( c, tot0 ); \+ stbir__simdf_add( tot0, tot0, c ); \+ stbir__simdf_store2( output, tot0 ); \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 2;++#endif++#else++#define stbir__1_coeff_only() \+ float tota,totb,c; \+ c = hc[0]; \+ tota = decode[0]*c; \+ totb = decode[1]*c;++#define stbir__2_coeff_only() \+ float tota,totb,c; \+ c = hc[0]; \+ tota = decode[0]*c; \+ totb = decode[1]*c; \+ c = hc[1]; \+ tota += decode[2]*c; \+ totb += decode[3]*c;++// this weird order of add matches the simd+#define stbir__3_coeff_only() \+ float tota,totb,c; \+ c = hc[0]; \+ tota = decode[0]*c; \+ totb = decode[1]*c; \+ c = hc[2]; \+ tota += decode[4]*c; \+ totb += decode[5]*c; \+ c = hc[1]; \+ tota += decode[2]*c; \+ totb += decode[3]*c;++#define stbir__store_output_tiny() \+ output[0] = tota; \+ output[1] = totb; \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 2;++#define stbir__4_coeff_start() \+ float tota0,tota1,tota2,tota3,totb0,totb1,totb2,totb3,c; \+ c = hc[0]; \+ tota0 = decode[0]*c; \+ totb0 = decode[1]*c; \+ c = hc[1]; \+ tota1 = decode[2]*c; \+ totb1 = decode[3]*c; \+ c = hc[2]; \+ tota2 = decode[4]*c; \+ totb2 = decode[5]*c; \+ c = hc[3]; \+ tota3 = decode[6]*c; \+ totb3 = decode[7]*c;++#define stbir__4_coeff_continue_from_4( ofs ) \+ c = hc[0+(ofs)]; \+ tota0 += decode[0+(ofs)*2]*c; \+ totb0 += decode[1+(ofs)*2]*c; \+ c = hc[1+(ofs)]; \+ tota1 += decode[2+(ofs)*2]*c; \+ totb1 += decode[3+(ofs)*2]*c; \+ c = hc[2+(ofs)]; \+ tota2 += decode[4+(ofs)*2]*c; \+ totb2 += decode[5+(ofs)*2]*c; \+ c = hc[3+(ofs)]; \+ tota3 += decode[6+(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;++#define stbir__2_coeff_remnant( ofs ) \+ c = hc[0+(ofs)]; \+ tota0 += decode[0+(ofs)*2] * c; \+ totb0 += decode[1+(ofs)*2] * c; \+ c = hc[1+(ofs)]; \+ tota1 += decode[2+(ofs)*2] * c; \+ totb1 += decode[3+(ofs)*2] * c;++#define stbir__3_coeff_remnant( ofs ) \+ c = hc[0+(ofs)]; \+ tota0 += decode[0+(ofs)*2] * c; \+ totb0 += decode[1+(ofs)*2] * c; \+ c = hc[1+(ofs)]; \+ tota1 += decode[2+(ofs)*2] * c; \+ totb1 += decode[3+(ofs)*2] * c; \+ c = hc[2+(ofs)]; \+ tota2 += decode[4+(ofs)*2] * c; \+ totb2 += decode[5+(ofs)*2] * c;++#define stbir__store_output() \+ output[0] = (tota0+tota2)+(tota1+tota3); \+ output[1] = (totb0+totb2)+(totb1+totb3); \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 2;++#endif++#define STBIR__horizontal_channels 2+#define STB_IMAGE_RESIZE_DO_HORIZONTALS+#include STBIR__HEADER_FILENAME+++//=================+// Do 3 channel horizontal routines++#ifdef STBIR_SIMD++#define stbir__1_coeff_only() \+ stbir__simdf tot,c,d; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load1z( c, hc ); \+ stbir__simdf_0123to0001( c, c ); \+ stbir__simdf_load( d, decode ); \+ stbir__simdf_mult( tot, d, c );++#define stbir__2_coeff_only() \+ stbir__simdf tot,c,cs,d; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load2( cs, hc ); \+ stbir__simdf_0123to0000( c, cs ); \+ stbir__simdf_load( d, decode ); \+ stbir__simdf_mult( tot, d, c ); \+ stbir__simdf_0123to1111( c, cs ); \+ stbir__simdf_load( d, decode+3 ); \+ stbir__simdf_madd( tot, tot, d, c );++#define stbir__3_coeff_only() \+ stbir__simdf tot,c,d,cs; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load( cs, hc ); \+ stbir__simdf_0123to0000( c, cs ); \+ stbir__simdf_load( d, decode ); \+ 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_0123to2222( c, cs ); \+ stbir__simdf_load( d, decode+6 ); \+ stbir__simdf_madd( tot, tot, d, c );++#define stbir__store_output_tiny() \+ stbir__simdf_store2( output, tot ); \+ stbir__simdf_0123to2301( tot, tot ); \+ stbir__simdf_store1( output+2, tot ); \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 3;++#ifdef STBIR_SIMD8++// we're loading from the XXXYYY decode by -1 to get the XXXYYY into different halves of the AVX reg fyi+#define stbir__4_coeff_start() \+ stbir__simdf8 tot0,tot1,c,cs; stbir__simdf t; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf8_load4b( cs, hc ); \+ 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 );++#define stbir__4_coeff_continue_from_4( 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_0123to22223333( c, cs ); \+ 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 );++#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 );++ #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 );++#define stbir__store_output() \+ stbir__simdf8_add( tot0, tot0, tot1 ); \+ stbir__simdf_0123to1230( t, stbir__if_simdf8_cast_to_simdf4( tot0 ) ); \+ stbir__simdf8_add4halves( t, t, tot0 ); \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 3; \+ if ( output < output_end ) \+ { \+ stbir__simdf_store( output-3, t ); \+ continue; \+ } \+ { stbir__simdf tt; stbir__simdf_0123to2301( tt, t ); \+ stbir__simdf_store2( output-3, t ); \+ stbir__simdf_store1( output+2-3, tt ); } \+ break;+++#else++#define stbir__4_coeff_start() \+ stbir__simdf tot0,tot1,tot2,c,cs; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load( cs, hc ); \+ stbir__simdf_0123to0001( c, cs ); \+ stbir__simdf_mult_mem( tot0, c, decode ); \+ 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 );++#define stbir__4_coeff_continue_from_4( ofs ) \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load( cs, hc + (ofs) ); \+ stbir__simdf_0123to0001( c, cs ); \+ stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 ); \+ 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 );++#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 );++#define stbir__2_coeff_remnant( ofs ) \+ { stbir__simdf d; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load2z( cs, hc + (ofs) ); \+ stbir__simdf_0123to0001( c, cs ); \+ 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 ); }++#define stbir__3_coeff_remnant( ofs ) \+ { stbir__simdf d; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load( cs, hc + (ofs) ); \+ stbir__simdf_0123to0001( c, cs ); \+ stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 ); \+ stbir__simdf_0123to1122( c, cs ); \+ 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 ); }++#define stbir__store_output() \+ stbir__simdf_0123ABCDto3ABx( c, tot0, tot1 ); \+ stbir__simdf_0123ABCDto23Ax( cs, tot1, tot2 ); \+ stbir__simdf_0123to1230( tot2, tot2 ); \+ stbir__simdf_add( tot0, tot0, cs ); \+ stbir__simdf_add( c, c, tot2 ); \+ stbir__simdf_add( tot0, tot0, c ); \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 3; \+ if ( output < output_end ) \+ { \+ stbir__simdf_store( output-3, tot0 ); \+ continue; \+ } \+ stbir__simdf_0123to2301( tot1, tot0 ); \+ stbir__simdf_store2( output-3, tot0 ); \+ stbir__simdf_store1( output+2-3, tot1 ); \+ break;++#endif++#else++#define stbir__1_coeff_only() \+ float tot0, tot1, tot2, c; \+ c = hc[0]; \+ tot0 = decode[0]*c; \+ tot1 = decode[1]*c; \+ tot2 = decode[2]*c;++#define stbir__2_coeff_only() \+ float tot0, tot1, tot2, c; \+ c = hc[0]; \+ tot0 = decode[0]*c; \+ tot1 = decode[1]*c; \+ tot2 = decode[2]*c; \+ c = hc[1]; \+ tot0 += decode[3]*c; \+ tot1 += decode[4]*c; \+ tot2 += decode[5]*c;++#define stbir__3_coeff_only() \+ float tot0, tot1, tot2, c; \+ c = hc[0]; \+ tot0 = decode[0]*c; \+ tot1 = decode[1]*c; \+ tot2 = decode[2]*c; \+ c = hc[1]; \+ tot0 += decode[3]*c; \+ tot1 += decode[4]*c; \+ tot2 += decode[5]*c; \+ c = hc[2]; \+ tot0 += decode[6]*c; \+ tot1 += decode[7]*c; \+ tot2 += decode[8]*c;++#define stbir__store_output_tiny() \+ output[0] = tot0; \+ output[1] = tot1; \+ output[2] = tot2; \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 3;++#define stbir__4_coeff_start() \+ float tota0,tota1,tota2,totb0,totb1,totb2,totc0,totc1,totc2,totd0,totd1,totd2,c; \+ c = hc[0]; \+ tota0 = decode[0]*c; \+ tota1 = decode[1]*c; \+ tota2 = decode[2]*c; \+ c = hc[1]; \+ totb0 = decode[3]*c; \+ totb1 = decode[4]*c; \+ totb2 = decode[5]*c; \+ c = hc[2]; \+ totc0 = decode[6]*c; \+ totc1 = decode[7]*c; \+ totc2 = decode[8]*c; \+ c = hc[3]; \+ totd0 = decode[9]*c; \+ totd1 = decode[10]*c; \+ totd2 = decode[11]*c;++#define stbir__4_coeff_continue_from_4( ofs ) \+ c = hc[0+(ofs)]; \+ tota0 += decode[0+(ofs)*3]*c; \+ tota1 += decode[1+(ofs)*3]*c; \+ tota2 += decode[2+(ofs)*3]*c; \+ c = hc[1+(ofs)]; \+ totb0 += decode[3+(ofs)*3]*c; \+ totb1 += decode[4+(ofs)*3]*c; \+ totb2 += decode[5+(ofs)*3]*c; \+ c = hc[2+(ofs)]; \+ totc0 += decode[6+(ofs)*3]*c; \+ totc1 += decode[7+(ofs)*3]*c; \+ totc2 += decode[8+(ofs)*3]*c; \+ c = hc[3+(ofs)]; \+ totd0 += decode[9+(ofs)*3]*c; \+ totd1 += decode[10+(ofs)*3]*c; \+ totd2 += decode[11+(ofs)*3]*c;++#define stbir__1_coeff_remnant( ofs ) \+ c = hc[0+(ofs)]; \+ tota0 += decode[0+(ofs)*3]*c; \+ tota1 += decode[1+(ofs)*3]*c; \+ tota2 += decode[2+(ofs)*3]*c;++#define stbir__2_coeff_remnant( ofs ) \+ c = hc[0+(ofs)]; \+ tota0 += decode[0+(ofs)*3]*c; \+ tota1 += decode[1+(ofs)*3]*c; \+ tota2 += decode[2+(ofs)*3]*c; \+ c = hc[1+(ofs)]; \+ totb0 += decode[3+(ofs)*3]*c; \+ totb1 += decode[4+(ofs)*3]*c; \+ totb2 += decode[5+(ofs)*3]*c; \++#define stbir__3_coeff_remnant( ofs ) \+ c = hc[0+(ofs)]; \+ tota0 += decode[0+(ofs)*3]*c; \+ tota1 += decode[1+(ofs)*3]*c; \+ tota2 += decode[2+(ofs)*3]*c; \+ c = hc[1+(ofs)]; \+ totb0 += decode[3+(ofs)*3]*c; \+ totb1 += decode[4+(ofs)*3]*c; \+ totb2 += decode[5+(ofs)*3]*c; \+ c = hc[2+(ofs)]; \+ totc0 += decode[6+(ofs)*3]*c; \+ totc1 += decode[7+(ofs)*3]*c; \+ totc2 += decode[8+(ofs)*3]*c;++#define stbir__store_output() \+ output[0] = (tota0+totc0)+(totb0+totd0); \+ output[1] = (tota1+totc1)+(totb1+totd1); \+ output[2] = (tota2+totc2)+(totb2+totd2); \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 3;++#endif++#define STBIR__horizontal_channels 3+#define STB_IMAGE_RESIZE_DO_HORIZONTALS+#include STBIR__HEADER_FILENAME++//=================+// Do 4 channel horizontal routines++#ifdef STBIR_SIMD++#define stbir__1_coeff_only() \+ stbir__simdf tot,c; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load1( c, hc ); \+ stbir__simdf_0123to0000( c, c ); \+ stbir__simdf_mult_mem( tot, c, decode );++#define stbir__2_coeff_only() \+ stbir__simdf tot,c,cs; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load2( cs, hc ); \+ 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 );++#define stbir__3_coeff_only() \+ stbir__simdf tot,c,cs; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load( cs, hc ); \+ 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_0123to2222( c, cs ); \+ stbir__simdf_madd_mem( tot, tot, c, decode+8 );++#define stbir__store_output_tiny() \+ stbir__simdf_store( output, tot ); \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 4;++#ifdef STBIR_SIMD8++#define stbir__4_coeff_start() \+ stbir__simdf8 tot0,c,cs; stbir__simdf t; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf8_load4b( cs, hc ); \+ 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 );++#define stbir__4_coeff_continue_from_4( 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_0123to22223333( c, cs ); \+ 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 );++#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 );++ #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 );++#define stbir__store_output() \+ stbir__simdf8_add4halves( t, stbir__if_simdf8_cast_to_simdf4(tot0), tot0 ); \+ stbir__simdf_store( output, t ); \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 4;++#else++#define stbir__4_coeff_start() \+ stbir__simdf tot0,tot1,c,cs; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load( cs, hc ); \+ stbir__simdf_0123to0000( c, cs ); \+ stbir__simdf_mult_mem( tot0, c, decode ); \+ stbir__simdf_0123to1111( c, cs ); \+ stbir__simdf_mult_mem( tot1, c, decode+4 ); \+ 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 );++#define stbir__4_coeff_continue_from_4( ofs ) \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load( cs, hc + (ofs) ); \+ 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_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 );++#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 );++#define stbir__2_coeff_remnant( ofs ) \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load2( cs, hc + (ofs) ); \+ 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 );++#define stbir__3_coeff_remnant( ofs ) \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load( cs, hc + (ofs) ); \+ 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_0123to2222( c, cs ); \+ stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4+8 );++#define stbir__store_output() \+ stbir__simdf_add( tot0, tot0, tot1 ); \+ stbir__simdf_store( output, tot0 ); \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 4;++#endif++#else++#define stbir__1_coeff_only() \+ float p0,p1,p2,p3,c; \+ STBIR_SIMD_NO_UNROLL(decode); \+ c = hc[0]; \+ p0 = decode[0] * c; \+ p1 = decode[1] * c; \+ p2 = decode[2] * c; \+ p3 = decode[3] * c;++#define stbir__2_coeff_only() \+ float p0,p1,p2,p3,c; \+ STBIR_SIMD_NO_UNROLL(decode); \+ c = hc[0]; \+ p0 = decode[0] * c; \+ p1 = decode[1] * c; \+ p2 = decode[2] * c; \+ p3 = decode[3] * c; \+ c = hc[1]; \+ p0 += decode[4] * c; \+ p1 += decode[5] * c; \+ p2 += decode[6] * c; \+ p3 += decode[7] * c;++#define stbir__3_coeff_only() \+ float p0,p1,p2,p3,c; \+ STBIR_SIMD_NO_UNROLL(decode); \+ c = hc[0]; \+ p0 = decode[0] * c; \+ p1 = decode[1] * c; \+ p2 = decode[2] * c; \+ p3 = decode[3] * c; \+ c = hc[1]; \+ p0 += decode[4] * c; \+ p1 += decode[5] * c; \+ p2 += decode[6] * c; \+ p3 += decode[7] * c; \+ c = hc[2]; \+ p0 += decode[8] * c; \+ p1 += decode[9] * c; \+ p2 += decode[10] * c; \+ p3 += decode[11] * c;++#define stbir__store_output_tiny() \+ output[0] = p0; \+ output[1] = p1; \+ output[2] = p2; \+ output[3] = p3; \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 4;++#define stbir__4_coeff_start() \+ float x0,x1,x2,x3,y0,y1,y2,y3,c; \+ STBIR_SIMD_NO_UNROLL(decode); \+ c = hc[0]; \+ x0 = decode[0] * c; \+ x1 = decode[1] * c; \+ x2 = decode[2] * c; \+ x3 = decode[3] * c; \+ c = hc[1]; \+ y0 = decode[4] * c; \+ y1 = decode[5] * c; \+ y2 = decode[6] * c; \+ y3 = decode[7] * c; \+ c = hc[2]; \+ x0 += decode[8] * c; \+ x1 += decode[9] * c; \+ x2 += decode[10] * c; \+ x3 += decode[11] * c; \+ c = hc[3]; \+ y0 += decode[12] * c; \+ y1 += decode[13] * c; \+ y2 += decode[14] * c; \+ y3 += decode[15] * c;++#define stbir__4_coeff_continue_from_4( ofs ) \+ STBIR_SIMD_NO_UNROLL(decode); \+ c = hc[0+(ofs)]; \+ x0 += decode[0+(ofs)*4] * c; \+ x1 += decode[1+(ofs)*4] * c; \+ x2 += decode[2+(ofs)*4] * c; \+ x3 += decode[3+(ofs)*4] * c; \+ c = hc[1+(ofs)]; \+ y0 += decode[4+(ofs)*4] * c; \+ y1 += decode[5+(ofs)*4] * c; \+ y2 += decode[6+(ofs)*4] * c; \+ y3 += decode[7+(ofs)*4] * c; \+ c = hc[2+(ofs)]; \+ x0 += decode[8+(ofs)*4] * c; \+ x1 += decode[9+(ofs)*4] * c; \+ x2 += decode[10+(ofs)*4] * c; \+ x3 += decode[11+(ofs)*4] * c; \+ c = hc[3+(ofs)]; \+ y0 += decode[12+(ofs)*4] * c; \+ y1 += decode[13+(ofs)*4] * c; \+ y2 += decode[14+(ofs)*4] * c; \+ y3 += decode[15+(ofs)*4] * c;++#define stbir__1_coeff_remnant( ofs ) \+ STBIR_SIMD_NO_UNROLL(decode); \+ c = hc[0+(ofs)]; \+ x0 += decode[0+(ofs)*4] * c; \+ x1 += decode[1+(ofs)*4] * c; \+ x2 += decode[2+(ofs)*4] * c; \+ x3 += decode[3+(ofs)*4] * c;++#define stbir__2_coeff_remnant( ofs ) \+ STBIR_SIMD_NO_UNROLL(decode); \+ c = hc[0+(ofs)]; \+ x0 += decode[0+(ofs)*4] * c; \+ x1 += decode[1+(ofs)*4] * c; \+ x2 += decode[2+(ofs)*4] * c; \+ x3 += decode[3+(ofs)*4] * c; \+ c = hc[1+(ofs)]; \+ y0 += decode[4+(ofs)*4] * c; \+ y1 += decode[5+(ofs)*4] * c; \+ y2 += decode[6+(ofs)*4] * c; \+ y3 += decode[7+(ofs)*4] * c;++#define stbir__3_coeff_remnant( ofs ) \+ STBIR_SIMD_NO_UNROLL(decode); \+ c = hc[0+(ofs)]; \+ x0 += decode[0+(ofs)*4] * c; \+ x1 += decode[1+(ofs)*4] * c; \+ x2 += decode[2+(ofs)*4] * c; \+ x3 += decode[3+(ofs)*4] * c; \+ c = hc[1+(ofs)]; \+ y0 += decode[4+(ofs)*4] * c; \+ y1 += decode[5+(ofs)*4] * c; \+ y2 += decode[6+(ofs)*4] * c; \+ y3 += decode[7+(ofs)*4] * c; \+ c = hc[2+(ofs)]; \+ x0 += decode[8+(ofs)*4] * c; \+ x1 += decode[9+(ofs)*4] * c; \+ x2 += decode[10+(ofs)*4] * c; \+ x3 += decode[11+(ofs)*4] * c;++#define stbir__store_output() \+ output[0] = x0 + y0; \+ output[1] = x1 + y1; \+ output[2] = x2 + y2; \+ output[3] = x3 + y3; \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 4;++#endif++#define STBIR__horizontal_channels 4+#define STB_IMAGE_RESIZE_DO_HORIZONTALS+#include STBIR__HEADER_FILENAME++++//=================+// Do 7 channel horizontal routines++#ifdef STBIR_SIMD++#define stbir__1_coeff_only() \+ stbir__simdf tot0,tot1,c; \+ STBIR_SIMD_NO_UNROLL(decode); \+ 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 );++#define stbir__2_coeff_only() \+ stbir__simdf tot0,tot1,c,cs; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load2( cs, hc ); \+ stbir__simdf_0123to0000( c, cs ); \+ stbir__simdf_mult_mem( tot0, c, decode ); \+ 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 );++#define stbir__3_coeff_only() \+ stbir__simdf tot0,tot1,c,cs; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load( cs, hc ); \+ stbir__simdf_0123to0000( c, cs ); \+ stbir__simdf_mult_mem( tot0, c, decode ); \+ 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_0123to2222( c, cs ); \+ stbir__simdf_madd_mem( tot0, tot0, c, decode+14 ); \+ stbir__simdf_madd_mem( tot1, tot1, c, decode+17 );++#define stbir__store_output_tiny() \+ stbir__simdf_store( output+3, tot1 ); \+ stbir__simdf_store( output, tot0 ); \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 7;++#ifdef STBIR_SIMD8++#define stbir__4_coeff_start() \+ stbir__simdf8 tot0,tot1,c,cs; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf8_load4b( cs, hc ); \+ stbir__simdf8_0123to00000000( c, cs ); \+ stbir__simdf8_mult_mem( tot0, c, decode ); \+ stbir__simdf8_0123to11111111( c, cs ); \+ stbir__simdf8_mult_mem( tot1, c, decode+7 ); \+ 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 );++#define stbir__4_coeff_continue_from_4( ofs ) \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf8_load4b( cs, hc + (ofs) ); \+ stbir__simdf8_0123to00000000( c, cs ); \+ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \+ 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_0123to33333333( c, cs ); \+ 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 );++#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 );++#define stbir__3_coeff_remnant( ofs ) \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf8_load4b( cs, hc + (ofs) ); \+ stbir__simdf8_0123to00000000( c, cs ); \+ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \+ 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 );++#define stbir__store_output() \+ stbir__simdf8_add( tot0, tot0, tot1 ); \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 7; \+ if ( output < output_end ) \+ { \+ stbir__simdf8_store( output-7, tot0 ); \+ continue; \+ } \+ stbir__simdf_store( output-7+3, stbir__simdf_swiz(stbir__simdf8_gettop4(tot0),0,0,1,2) ); \+ stbir__simdf_store( output-7, stbir__if_simdf8_cast_to_simdf4(tot0) ); \+ break;++#else++#define stbir__4_coeff_start() \+ stbir__simdf tot0,tot1,tot2,tot3,c,cs; \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load( cs, hc ); \+ stbir__simdf_0123to0000( c, cs ); \+ stbir__simdf_mult_mem( tot0, c, decode ); \+ stbir__simdf_mult_mem( tot1, c, decode+3 ); \+ stbir__simdf_0123to1111( c, cs ); \+ stbir__simdf_mult_mem( tot2, c, decode+7 ); \+ stbir__simdf_mult_mem( tot3, 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_0123to3333( c, cs ); \+ stbir__simdf_madd_mem( tot2, tot2, c, decode+21 ); \+ stbir__simdf_madd_mem( tot3, tot3, c, decode+24 );++#define stbir__4_coeff_continue_from_4( ofs ) \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load( cs, hc + (ofs) ); \+ stbir__simdf_0123to0000( c, cs ); \+ stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \+ 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_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_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 );++#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)*7 ); \+ stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+3 ); \++#define stbir__2_coeff_remnant( ofs ) \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load2( cs, hc + (ofs) ); \+ stbir__simdf_0123to0000( c, cs ); \+ stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \+ 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 );++#define stbir__3_coeff_remnant( ofs ) \+ STBIR_SIMD_NO_UNROLL(decode); \+ stbir__simdf_load( cs, hc + (ofs) ); \+ stbir__simdf_0123to0000( c, cs ); \+ stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \+ 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_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 );++#define stbir__store_output() \+ stbir__simdf_add( tot0, tot0, tot2 ); \+ stbir__simdf_add( tot1, tot1, tot3 ); \+ stbir__simdf_store( output+3, tot1 ); \+ stbir__simdf_store( output, tot0 ); \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 7;++#endif++#else++#define stbir__1_coeff_only() \+ float tot0, tot1, tot2, tot3, tot4, tot5, tot6, c; \+ c = hc[0]; \+ tot0 = decode[0]*c; \+ tot1 = decode[1]*c; \+ tot2 = decode[2]*c; \+ tot3 = decode[3]*c; \+ tot4 = decode[4]*c; \+ tot5 = decode[5]*c; \+ tot6 = decode[6]*c;++#define stbir__2_coeff_only() \+ float tot0, tot1, tot2, tot3, tot4, tot5, tot6, c; \+ c = hc[0]; \+ tot0 = decode[0]*c; \+ tot1 = decode[1]*c; \+ tot2 = decode[2]*c; \+ tot3 = decode[3]*c; \+ tot4 = decode[4]*c; \+ tot5 = decode[5]*c; \+ tot6 = decode[6]*c; \+ c = hc[1]; \+ tot0 += decode[7]*c; \+ tot1 += decode[8]*c; \+ tot2 += decode[9]*c; \+ tot3 += decode[10]*c; \+ tot4 += decode[11]*c; \+ tot5 += decode[12]*c; \+ tot6 += decode[13]*c; \++#define stbir__3_coeff_only() \+ float tot0, tot1, tot2, tot3, tot4, tot5, tot6, c; \+ c = hc[0]; \+ tot0 = decode[0]*c; \+ tot1 = decode[1]*c; \+ tot2 = decode[2]*c; \+ tot3 = decode[3]*c; \+ tot4 = decode[4]*c; \+ tot5 = decode[5]*c; \+ tot6 = decode[6]*c; \+ c = hc[1]; \+ tot0 += decode[7]*c; \+ tot1 += decode[8]*c; \+ tot2 += decode[9]*c; \+ tot3 += decode[10]*c; \+ tot4 += decode[11]*c; \+ tot5 += decode[12]*c; \+ tot6 += decode[13]*c; \+ c = hc[2]; \+ tot0 += decode[14]*c; \+ tot1 += decode[15]*c; \+ tot2 += decode[16]*c; \+ tot3 += decode[17]*c; \+ tot4 += decode[18]*c; \+ tot5 += decode[19]*c; \+ tot6 += decode[20]*c; \++#define stbir__store_output_tiny() \+ output[0] = tot0; \+ output[1] = tot1; \+ output[2] = tot2; \+ output[3] = tot3; \+ output[4] = tot4; \+ output[5] = tot5; \+ output[6] = tot6; \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 7;++#define stbir__4_coeff_start() \+ float x0,x1,x2,x3,x4,x5,x6,y0,y1,y2,y3,y4,y5,y6,c; \+ STBIR_SIMD_NO_UNROLL(decode); \+ c = hc[0]; \+ x0 = decode[0] * c; \+ x1 = decode[1] * c; \+ x2 = decode[2] * c; \+ x3 = decode[3] * c; \+ x4 = decode[4] * c; \+ x5 = decode[5] * c; \+ x6 = decode[6] * c; \+ c = hc[1]; \+ y0 = decode[7] * c; \+ y1 = decode[8] * c; \+ y2 = decode[9] * c; \+ y3 = decode[10] * c; \+ y4 = decode[11] * c; \+ y5 = decode[12] * c; \+ y6 = decode[13] * c; \+ c = hc[2]; \+ x0 += decode[14] * c; \+ x1 += decode[15] * c; \+ x2 += decode[16] * c; \+ x3 += decode[17] * c; \+ x4 += decode[18] * c; \+ x5 += decode[19] * c; \+ x6 += decode[20] * c; \+ c = hc[3]; \+ y0 += decode[21] * c; \+ y1 += decode[22] * c; \+ y2 += decode[23] * c; \+ y3 += decode[24] * c; \+ y4 += decode[25] * c; \+ y5 += decode[26] * c; \+ y6 += decode[27] * c;++#define stbir__4_coeff_continue_from_4( ofs ) \+ STBIR_SIMD_NO_UNROLL(decode); \+ c = hc[0+(ofs)]; \+ x0 += decode[0+(ofs)*7] * c; \+ x1 += decode[1+(ofs)*7] * c; \+ x2 += decode[2+(ofs)*7] * c; \+ x3 += decode[3+(ofs)*7] * c; \+ x4 += decode[4+(ofs)*7] * c; \+ x5 += decode[5+(ofs)*7] * c; \+ x6 += decode[6+(ofs)*7] * c; \+ c = hc[1+(ofs)]; \+ y0 += decode[7+(ofs)*7] * c; \+ y1 += decode[8+(ofs)*7] * c; \+ y2 += decode[9+(ofs)*7] * c; \+ y3 += decode[10+(ofs)*7] * c; \+ y4 += decode[11+(ofs)*7] * c; \+ y5 += decode[12+(ofs)*7] * c; \+ y6 += decode[13+(ofs)*7] * c; \+ c = hc[2+(ofs)]; \+ x0 += decode[14+(ofs)*7] * c; \+ x1 += decode[15+(ofs)*7] * c; \+ x2 += decode[16+(ofs)*7] * c; \+ x3 += decode[17+(ofs)*7] * c; \+ x4 += decode[18+(ofs)*7] * c; \+ x5 += decode[19+(ofs)*7] * c; \+ x6 += decode[20+(ofs)*7] * c; \+ c = hc[3+(ofs)]; \+ y0 += decode[21+(ofs)*7] * c; \+ y1 += decode[22+(ofs)*7] * c; \+ y2 += decode[23+(ofs)*7] * c; \+ y3 += decode[24+(ofs)*7] * c; \+ y4 += decode[25+(ofs)*7] * c; \+ y5 += decode[26+(ofs)*7] * c; \+ y6 += decode[27+(ofs)*7] * c;++#define stbir__1_coeff_remnant( ofs ) \+ STBIR_SIMD_NO_UNROLL(decode); \+ c = hc[0+(ofs)]; \+ x0 += decode[0+(ofs)*7] * c; \+ x1 += decode[1+(ofs)*7] * c; \+ x2 += decode[2+(ofs)*7] * c; \+ x3 += decode[3+(ofs)*7] * c; \+ x4 += decode[4+(ofs)*7] * c; \+ x5 += decode[5+(ofs)*7] * c; \+ x6 += decode[6+(ofs)*7] * c; \++#define stbir__2_coeff_remnant( ofs ) \+ STBIR_SIMD_NO_UNROLL(decode); \+ c = hc[0+(ofs)]; \+ x0 += decode[0+(ofs)*7] * c; \+ x1 += decode[1+(ofs)*7] * c; \+ x2 += decode[2+(ofs)*7] * c; \+ x3 += decode[3+(ofs)*7] * c; \+ x4 += decode[4+(ofs)*7] * c; \+ x5 += decode[5+(ofs)*7] * c; \+ x6 += decode[6+(ofs)*7] * c; \+ c = hc[1+(ofs)]; \+ y0 += decode[7+(ofs)*7] * c; \+ y1 += decode[8+(ofs)*7] * c; \+ y2 += decode[9+(ofs)*7] * c; \+ y3 += decode[10+(ofs)*7] * c; \+ 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)]; \+ x0 += decode[0+(ofs)*7] * c; \+ x1 += decode[1+(ofs)*7] * c; \+ x2 += decode[2+(ofs)*7] * c; \+ x3 += decode[3+(ofs)*7] * c; \+ x4 += decode[4+(ofs)*7] * c; \+ x5 += decode[5+(ofs)*7] * c; \+ x6 += decode[6+(ofs)*7] * c; \+ c = hc[1+(ofs)]; \+ y0 += decode[7+(ofs)*7] * c; \+ y1 += decode[8+(ofs)*7] * c; \+ y2 += decode[9+(ofs)*7] * c; \+ y3 += decode[10+(ofs)*7] * c; \+ y4 += decode[11+(ofs)*7] * c; \+ y5 += decode[12+(ofs)*7] * c; \+ y6 += decode[13+(ofs)*7] * c; \+ c = hc[2+(ofs)]; \+ x0 += decode[14+(ofs)*7] * c; \+ x1 += decode[15+(ofs)*7] * c; \+ x2 += decode[16+(ofs)*7] * c; \+ x3 += decode[17+(ofs)*7] * c; \+ x4 += decode[18+(ofs)*7] * c; \+ x5 += decode[19+(ofs)*7] * c; \+ x6 += decode[20+(ofs)*7] * c; \++#define stbir__store_output() \+ output[0] = x0 + y0; \+ output[1] = x1 + y1; \+ output[2] = x2 + y2; \+ output[3] = x3 + y3; \+ output[4] = x4 + y4; \+ output[5] = x5 + y5; \+ output[6] = x6 + y6; \+ horizontal_coefficients += coefficient_width; \+ ++horizontal_contributors; \+ output += 7;++#endif++#define STBIR__horizontal_channels 7+#define STB_IMAGE_RESIZE_DO_HORIZONTALS+#include STBIR__HEADER_FILENAME+++// include all of the vertical resamplers (both scatter and gather versions)++#define STBIR__vertical_channels 1+#define STB_IMAGE_RESIZE_DO_VERTICALS+#include STBIR__HEADER_FILENAME++#define STBIR__vertical_channels 1+#define STB_IMAGE_RESIZE_DO_VERTICALS+#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE+#include STBIR__HEADER_FILENAME++#define STBIR__vertical_channels 2+#define STB_IMAGE_RESIZE_DO_VERTICALS+#include STBIR__HEADER_FILENAME++#define STBIR__vertical_channels 2+#define STB_IMAGE_RESIZE_DO_VERTICALS+#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE+#include STBIR__HEADER_FILENAME++#define STBIR__vertical_channels 3+#define STB_IMAGE_RESIZE_DO_VERTICALS+#include STBIR__HEADER_FILENAME++#define STBIR__vertical_channels 3+#define STB_IMAGE_RESIZE_DO_VERTICALS+#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE+#include STBIR__HEADER_FILENAME++#define STBIR__vertical_channels 4+#define STB_IMAGE_RESIZE_DO_VERTICALS+#include STBIR__HEADER_FILENAME++#define STBIR__vertical_channels 4+#define STB_IMAGE_RESIZE_DO_VERTICALS+#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE+#include STBIR__HEADER_FILENAME++#define STBIR__vertical_channels 5+#define STB_IMAGE_RESIZE_DO_VERTICALS+#include STBIR__HEADER_FILENAME++#define STBIR__vertical_channels 5+#define STB_IMAGE_RESIZE_DO_VERTICALS+#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE+#include STBIR__HEADER_FILENAME++#define STBIR__vertical_channels 6+#define STB_IMAGE_RESIZE_DO_VERTICALS+#include STBIR__HEADER_FILENAME++#define STBIR__vertical_channels 6+#define STB_IMAGE_RESIZE_DO_VERTICALS+#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE+#include STBIR__HEADER_FILENAME++#define STBIR__vertical_channels 7+#define STB_IMAGE_RESIZE_DO_VERTICALS+#include STBIR__HEADER_FILENAME++#define STBIR__vertical_channels 7+#define STB_IMAGE_RESIZE_DO_VERTICALS+#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE+#include STBIR__HEADER_FILENAME++#define STBIR__vertical_channels 8+#define STB_IMAGE_RESIZE_DO_VERTICALS+#include STBIR__HEADER_FILENAME++#define STBIR__vertical_channels 8+#define STB_IMAGE_RESIZE_DO_VERTICALS+#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE+#include STBIR__HEADER_FILENAME++typedef void STBIR_VERTICAL_GATHERFUNC( float * output, float const * coeffs, float const ** inputs, float const * input0_end );++static STBIR_VERTICAL_GATHERFUNC * stbir__vertical_gathers[ 8 ] =+{+ stbir__vertical_gather_with_1_coeffs,stbir__vertical_gather_with_2_coeffs,stbir__vertical_gather_with_3_coeffs,stbir__vertical_gather_with_4_coeffs,stbir__vertical_gather_with_5_coeffs,stbir__vertical_gather_with_6_coeffs,stbir__vertical_gather_with_7_coeffs,stbir__vertical_gather_with_8_coeffs+};++static STBIR_VERTICAL_GATHERFUNC * stbir__vertical_gathers_continues[ 8 ] =+{+ stbir__vertical_gather_with_1_coeffs_cont,stbir__vertical_gather_with_2_coeffs_cont,stbir__vertical_gather_with_3_coeffs_cont,stbir__vertical_gather_with_4_coeffs_cont,stbir__vertical_gather_with_5_coeffs_cont,stbir__vertical_gather_with_6_coeffs_cont,stbir__vertical_gather_with_7_coeffs_cont,stbir__vertical_gather_with_8_coeffs_cont+};++typedef void STBIR_VERTICAL_SCATTERFUNC( float ** outputs, float const * coeffs, float const * input, float const * input_end );++static STBIR_VERTICAL_SCATTERFUNC * stbir__vertical_scatter_sets[ 8 ] =+{+ stbir__vertical_scatter_with_1_coeffs,stbir__vertical_scatter_with_2_coeffs,stbir__vertical_scatter_with_3_coeffs,stbir__vertical_scatter_with_4_coeffs,stbir__vertical_scatter_with_5_coeffs,stbir__vertical_scatter_with_6_coeffs,stbir__vertical_scatter_with_7_coeffs,stbir__vertical_scatter_with_8_coeffs+};++static STBIR_VERTICAL_SCATTERFUNC * stbir__vertical_scatter_blends[ 8 ] =+{+ stbir__vertical_scatter_with_1_coeffs_cont,stbir__vertical_scatter_with_2_coeffs_cont,stbir__vertical_scatter_with_3_coeffs_cont,stbir__vertical_scatter_with_4_coeffs_cont,stbir__vertical_scatter_with_5_coeffs_cont,stbir__vertical_scatter_with_6_coeffs_cont,stbir__vertical_scatter_with_7_coeffs_cont,stbir__vertical_scatter_with_8_coeffs_cont+};+++static void stbir__encode_scanline( stbir__info const * stbir_info, void *output_buffer_data, float * encode_buffer, int row STBIR_ONLY_PROFILE_GET_SPLIT_INFO )+{+ int num_pixels = stbir_info->horizontal.scale_info.output_sub_size;+ int channels = stbir_info->channels;+ int width_times_channels = num_pixels * channels;+ void * output_buffer;++ // un-alpha weight if we need to+ if ( stbir_info->alpha_unweight )+ {+ STBIR_PROFILE_START( unalpha );+ stbir_info->alpha_unweight( encode_buffer, width_times_channels );+ STBIR_PROFILE_END( unalpha );+ }++ // write directly into output by default+ output_buffer = output_buffer_data;++ // 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 );+ STBIR_PROFILE_END( encode );++ // 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, num_pixels, row, stbir_info->user_data );+}+++// Get the ring buffer pointer for an index+static float* stbir__get_ring_buffer_entry(stbir__info const * stbir_info, stbir__per_split_info const * split_info, int index )+{+ STBIR_ASSERT( index < stbir_info->ring_buffer_num_entries );++ #ifdef STBIR__SEPARATE_ALLOCATIONS+ return split_info->ring_buffers[ index ];+ #else+ return (float*) ( ( (char*) split_info->ring_buffer ) + ( index * stbir_info->ring_buffer_length_bytes ) );+ #endif+}++// Get the specified scan line from the ring buffer+static float* stbir__get_ring_buffer_scanline(stbir__info const * stbir_info, stbir__per_split_info const * split_info, int get_scanline)+{+ int ring_buffer_index = (split_info->ring_buffer_begin_index + (get_scanline - split_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries;+ return stbir__get_ring_buffer_entry( stbir_info, split_info, ring_buffer_index );+}++static void stbir__resample_horizontal_gather(stbir__info const * stbir_info, float* output_buffer, float const * input_buffer STBIR_ONLY_PROFILE_GET_SPLIT_INFO )+{+ float const * decode_buffer = input_buffer - ( stbir_info->scanline_extents.conservative.n0 * stbir_info->effective_channels );++ STBIR_PROFILE_START( horizontal );+ if ( ( stbir_info->horizontal.filter_enum == STBIR_FILTER_POINT_SAMPLE ) && ( stbir_info->horizontal.scale_info.scale == 1.0f ) )+ STBIR_MEMCPY( output_buffer, input_buffer, stbir_info->horizontal.scale_info.output_sub_size * sizeof( float ) * stbir_info->effective_channels );+ else+ stbir_info->horizontal_gather_channels( output_buffer, stbir_info->horizontal.scale_info.output_sub_size, decode_buffer, stbir_info->horizontal.contributors, stbir_info->horizontal.coefficients, stbir_info->horizontal.coefficient_width );+ STBIR_PROFILE_END( horizontal );+}++static void stbir__resample_vertical_gather(stbir__info const * stbir_info, stbir__per_split_info* split_info, int n, int contrib_n0, int contrib_n1, float const * vertical_coefficients )+{+ float* encode_buffer = split_info->vertical_buffer;+ float* decode_buffer = split_info->decode_buffer;+ int vertical_first = stbir_info->vertical_first;+ int width = (vertical_first) ? ( stbir_info->scanline_extents.conservative.n1-stbir_info->scanline_extents.conservative.n0+1 ) : stbir_info->horizontal.scale_info.output_sub_size;+ int width_times_channels = stbir_info->effective_channels * width;++ STBIR_ASSERT( stbir_info->vertical.is_gather );++ // loop over the contributing scanlines and scale into the buffer+ STBIR_PROFILE_START( vertical );+ {+ int k = 0, total = contrib_n1 - contrib_n0 + 1;+ STBIR_ASSERT( total > 0 );+ do {+ float const * inputs[8];+ int i, cnt = total; if ( cnt > 8 ) cnt = 8;+ for( i = 0 ; i < cnt ; i++ )+ inputs[ i ] = stbir__get_ring_buffer_scanline(stbir_info, split_info, k+i+contrib_n0 );++ // call the N scanlines at a time function (up to 8 scanlines of blending at once)+ ((k==0)?stbir__vertical_gathers:stbir__vertical_gathers_continues)[cnt-1]( (vertical_first) ? decode_buffer : encode_buffer, vertical_coefficients + k, inputs, inputs[0] + width_times_channels );+ k += cnt;+ total -= cnt;+ } while ( total );+ }+ STBIR_PROFILE_END( vertical );++ if ( vertical_first )+ {+ // Now resample the gathered vertical data in the horizontal axis into the encode buffer+ 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 ) + ((size_t)n * (size_t)stbir_info->output_stride_bytes),+ encode_buffer, n STBIR_ONLY_PROFILE_SET_SPLIT_INFO );+}++static void stbir__decode_and_resample_for_vertical_gather_loop(stbir__info const * stbir_info, stbir__per_split_info* split_info, int n)+{+ int ring_buffer_index;+ float* ring_buffer;++ // Decode the nth scanline from the source image into the decode buffer.+ stbir__decode_scanline( stbir_info, n, split_info->decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO );++ // update new end scanline+ split_info->ring_buffer_last_scanline = n;++ // 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);++ // Now resample it into the ring buffer.+ stbir__resample_horizontal_gather( stbir_info, ring_buffer, split_info->decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO );++ // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling.+}++static void stbir__vertical_gather_loop( stbir__info const * stbir_info, stbir__per_split_info* split_info, int split_count )+{+ int y, start_output_y, end_output_y;+ stbir__contributors* vertical_contributors = stbir_info->vertical.contributors;+ float const * vertical_coefficients = stbir_info->vertical.coefficients;++ STBIR_ASSERT( stbir_info->vertical.is_gather );++ start_output_y = split_info->start_output_y;+ end_output_y = split_info[split_count-1].end_output_y;++ vertical_contributors += start_output_y;+ vertical_coefficients += start_output_y * stbir_info->vertical.coefficient_width;++ // initialize the ring buffer for gathering+ split_info->ring_buffer_begin_index = 0;+ 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++)+ {+ int in_first_scanline, in_last_scanline;++ in_first_scanline = vertical_contributors->n0;+ in_last_scanline = vertical_contributors->n1;++ // make sure the indexing hasn't broken+ STBIR_ASSERT( in_first_scanline >= split_info->ring_buffer_first_scanline );++ // Load in new scanlines+ while (in_last_scanline > split_info->ring_buffer_last_scanline)+ {+ STBIR_ASSERT( ( split_info->ring_buffer_last_scanline - split_info->ring_buffer_first_scanline + 1 ) <= stbir_info->ring_buffer_num_entries );++ // make sure there was room in the ring buffer when we add new scanlines+ if ( ( split_info->ring_buffer_last_scanline - split_info->ring_buffer_first_scanline + 1 ) == stbir_info->ring_buffer_num_entries )+ {+ 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 );+ }+ else+ {+ stbir__decode_and_resample_for_vertical_gather_loop(stbir_info, split_info, split_info->ring_buffer_last_scanline + 1);+ }+ }++ // Now all buffers should be ready to write a row of vertical sampling, so do it.+ stbir__resample_vertical_gather(stbir_info, split_info, y, in_first_scanline, in_last_scanline, vertical_coefficients );++ ++vertical_contributors;+ vertical_coefficients += stbir_info->vertical.coefficient_width;+ }+}++#define STBIR__FLOAT_EMPTY_MARKER 3.0e+38F+#define STBIR__FLOAT_BUFFER_IS_EMPTY(ptr) ((ptr)[0]==STBIR__FLOAT_EMPTY_MARKER)++static void stbir__encode_first_scanline_from_scatter(stbir__info const * stbir_info, stbir__per_split_info* split_info)+{+ // 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 ) + ( (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;++ // advance the first scanline+ split_info->ring_buffer_first_scanline++;+ if ( ++split_info->ring_buffer_begin_index == stbir_info->ring_buffer_num_entries )+ split_info->ring_buffer_begin_index = 0;+}++static void stbir__horizontal_resample_and_encode_first_scanline_from_scatter(stbir__info const * stbir_info, stbir__per_split_info* split_info)+{+ // 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 );++ // 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 ) + ( (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;++ // advance the first scanline+ split_info->ring_buffer_first_scanline++;+ if ( ++split_info->ring_buffer_begin_index == stbir_info->ring_buffer_num_entries )+ split_info->ring_buffer_begin_index = 0;+}++static void stbir__resample_vertical_scatter(stbir__info const * stbir_info, stbir__per_split_info* split_info, int n0, int n1, float const * vertical_coefficients, float const * vertical_buffer, float const * vertical_buffer_end )+{+ STBIR_ASSERT( !stbir_info->vertical.is_gather );++ STBIR_PROFILE_START( vertical );+ {+ int k = 0, total = n1 - n0 + 1;+ STBIR_ASSERT( total > 0 );+ do {+ float * outputs[8];+ int i, n = total; if ( n > 8 ) n = 8;+ for( i = 0 ; i < n ; i++ )+ {+ outputs[ i ] = stbir__get_ring_buffer_scanline(stbir_info, split_info, k+i+n0 );+ if ( ( i ) && ( STBIR__FLOAT_BUFFER_IS_EMPTY( outputs[i] ) != STBIR__FLOAT_BUFFER_IS_EMPTY( outputs[0] ) ) ) // make sure runs are of the same type+ {+ n = i;+ break;+ }+ }+ // call the scatter to N scanlines at a time function (up to 8 scanlines of scattering at once)+ ((STBIR__FLOAT_BUFFER_IS_EMPTY( outputs[0] ))?stbir__vertical_scatter_sets:stbir__vertical_scatter_blends)[n-1]( outputs, vertical_coefficients + k, vertical_buffer, vertical_buffer_end );+ k += n;+ total -= n;+ } while ( total );+ }++ STBIR_PROFILE_END( vertical );+}++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 )+{+ int y, start_output_y, end_output_y, start_input_y, end_input_y;+ stbir__contributors* vertical_contributors = stbir_info->vertical.contributors;+ float const * vertical_coefficients = stbir_info->vertical.coefficients;+ stbir__handle_scanline_for_scatter_func * handle_scanline_for_scatter;+ void * scanline_scatter_buffer;+ void * scanline_scatter_buffer_end;+ int on_first_input_y, last_input_y;++ STBIR_ASSERT( !stbir_info->vertical.is_gather );++ start_output_y = split_info->start_output_y;+ end_output_y = split_info[split_count-1].end_output_y; // may do multiple split counts++ start_input_y = split_info->start_input_y;+ 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;+ vertical_contributors += y ;+ vertical_coefficients += stbir_info->vertical.coefficient_width * y;++ if ( stbir_info->vertical_first )+ {+ handle_scanline_for_scatter = stbir__horizontal_resample_and_encode_first_scanline_from_scatter;+ scanline_scatter_buffer = split_info->decode_buffer;+ scanline_scatter_buffer_end = ( (char*) scanline_scatter_buffer ) + sizeof( float ) * stbir_info->effective_channels * (stbir_info->scanline_extents.conservative.n1-stbir_info->scanline_extents.conservative.n0+1);+ }+ else+ {+ handle_scanline_for_scatter = stbir__encode_first_scanline_from_scatter;+ scanline_scatter_buffer = split_info->vertical_buffer;+ scanline_scatter_buffer_end = ( (char*) scanline_scatter_buffer ) + sizeof( float ) * stbir_info->effective_channels * stbir_info->horizontal.scale_info.output_sub_size;+ }++ // initialize the ring buffer for scattering+ split_info->ring_buffer_first_scanline = start_output_y;+ split_info->ring_buffer_last_scanline = -1;+ split_info->ring_buffer_begin_index = -1;++ // mark all the buffers as empty to start+ for( y = 0 ; y < stbir_info->ring_buffer_num_entries ; y++ )+ stbir__get_ring_buffer_entry( stbir_info, split_info, y )[0] = STBIR__FLOAT_EMPTY_MARKER; // only used on scatter++ // do the loop in input space+ on_first_input_y = 1; last_input_y = start_input_y;+ for (y = start_input_y ; y < end_input_y; y++)+ {+ int out_first_scanline, out_last_scanline;++ out_first_scanline = vertical_contributors->n0;+ out_last_scanline = vertical_contributors->n1;++ STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);++ if ( ( out_last_scanline >= out_first_scanline ) && ( ( ( out_first_scanline >= start_output_y ) && ( out_first_scanline < end_output_y ) ) || ( ( out_last_scanline >= start_output_y ) && ( out_last_scanline < end_output_y ) ) ) )+ {+ float const * vc = vertical_coefficients;++ // keep track of the range actually seen for the next resize+ last_input_y = y;+ if ( ( on_first_input_y ) && ( y > start_input_y ) )+ split_info->start_input_y = y;+ on_first_input_y = 0;++ // clip the region+ if ( out_first_scanline < start_output_y )+ {+ vc += start_output_y - out_first_scanline;+ out_first_scanline = start_output_y;+ }++ if ( out_last_scanline >= end_output_y )+ out_last_scanline = end_output_y - 1;++ // 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 );++ // When horizontal first, we resample horizontally into the vertical buffer before we scatter it out+ if ( !stbir_info->vertical_first )+ stbir__resample_horizontal_gather( stbir_info, split_info->vertical_buffer, split_info->decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO );++ // Now it's sitting in the buffer ready to be distributed into the ring buffers.++ // evict from the ringbuffer, if we need are full+ 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 );++ // update the end of the buffer+ if ( out_last_scanline > split_info->ring_buffer_last_scanline )+ split_info->ring_buffer_last_scanline = out_last_scanline;+ }+ ++vertical_contributors;+ vertical_coefficients += stbir_info->vertical.coefficient_width;+ }++ // now evict the scanlines that are left over in the ring buffer+ while ( split_info->ring_buffer_first_scanline < end_output_y )+ handle_scanline_for_scatter(stbir_info, split_info);++ // update the end_input_y if we do multiple resizes with the same data+ ++last_input_y;+ for( y = 0 ; y < split_count; y++ )+ if ( split_info[y].end_input_y > last_input_y )+ split_info[y].end_input_y = last_input_y;+}+++static stbir__kernel_callback * stbir__builtin_kernels[] = { 0, stbir__filter_trapezoid, stbir__filter_triangle, stbir__filter_cubic, stbir__filter_catmullrom, stbir__filter_mitchell, stbir__filter_point };+static stbir__support_callback * stbir__builtin_supports[] = { 0, stbir__support_trapezoid, stbir__support_one, stbir__support_two, stbir__support_two, stbir__support_two, stbir__support_zeropoint5 };++static void stbir__set_sampler(stbir__sampler * samp, stbir_filter filter, stbir__kernel_callback * kernel, stbir__support_callback * support, stbir_edge edge, stbir__scale_info * scale_info, int always_gather, void * user_data )+{+ // set filter+ if (filter == 0)+ {+ filter = STBIR_DEFAULT_FILTER_DOWNSAMPLE; // default to downsample+ 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;+ else+ filter = STBIR_DEFAULT_FILTER_UPSAMPLE;+ }+ }+ samp->filter_enum = filter;++ STBIR_ASSERT(samp->filter_enum != 0);+ STBIR_ASSERT((unsigned)samp->filter_enum < STBIR_FILTER_OTHER);+ samp->filter_kernel = stbir__builtin_kernels[ filter ];+ samp->filter_support = stbir__builtin_supports[ filter ];++ if ( kernel && support )+ {+ samp->filter_kernel = kernel;+ samp->filter_support = support;+ samp->filter_enum = STBIR_FILTER_OTHER;+ }++ samp->edge = edge;+ samp->filter_pixel_width = stbir__get_filter_pixel_width (samp->filter_support, scale_info->scale, user_data );+ // Gather is always better, but in extreme downsamples, you have to most or all of the data in memory+ // For horizontal, we always have all the pixels, so we always use gather here (always_gather==1).+ // For vertical, we use gather if scaling up (which means we will have samp->filter_pixel_width+ // scanlines in memory at once).+ samp->is_gather = 0;+ if ( scale_info->scale >= ( 1.0f - stbir__small_float ) )+ samp->is_gather = 1;+ else if ( ( always_gather ) || ( samp->filter_pixel_width <= STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT ) )+ samp->is_gather = 2;++ // 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 * 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++ samp->gather_prescatter_contributors = 0;+ samp->gather_prescatter_coefficients = 0;+ if ( samp->is_gather == 0 )+ {+ samp->gather_prescatter_coefficient_width = samp->filter_pixel_width;+ samp->gather_prescatter_num_contributors = stbir__get_contributors(samp, 2);+ samp->gather_prescatter_contributors_size = samp->gather_prescatter_num_contributors * sizeof(stbir__contributors);+ samp->gather_prescatter_coefficients_size = samp->gather_prescatter_num_contributors * samp->gather_prescatter_coefficient_width * sizeof(float);+ }+}++static void stbir__get_conservative_extents( stbir__sampler * samp, stbir__contributors * range, void * user_data )+{+ float scale = samp->scale_info.scale;+ float out_shift = samp->scale_info.pixel_shift;+ stbir__support_callback * support = samp->filter_support;+ int input_full_size = samp->scale_info.input_full_size;+ stbir_edge edge = samp->edge;+ float inv_scale = samp->scale_info.inv_scale;++ STBIR_ASSERT( samp->is_gather != 0 );++ if ( samp->is_gather == 1 )+ {+ int in_first_pixel, in_last_pixel;+ float out_filter_radius = support(inv_scale, user_data) * scale;++ stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, 0.5, out_filter_radius, inv_scale, out_shift, input_full_size, edge );+ range->n0 = in_first_pixel;+ stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, ( (float)(samp->scale_info.output_sub_size-1) ) + 0.5f, out_filter_radius, inv_scale, out_shift, input_full_size, edge );+ range->n1 = in_last_pixel;+ }+ else if ( samp->is_gather == 2 ) // downsample gather, refine+ {+ float in_pixels_radius = support(scale, user_data) * inv_scale;+ int filter_pixel_margin = samp->filter_pixel_margin;+ int output_sub_size = samp->scale_info.output_sub_size;+ int input_end;+ int n;+ int in_first_pixel, in_last_pixel;++ // get a conservative area of the input range+ stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, 0, 0, inv_scale, out_shift, input_full_size, edge );+ 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+ n = range->n0 + 1;+ input_end = -filter_pixel_margin;+ while( n >= input_end )+ {+ int out_first_pixel, out_last_pixel;+ stbir__calculate_out_pixel_range( &out_first_pixel, &out_last_pixel, ((float)n)+0.5f, in_pixels_radius, scale, out_shift, output_sub_size );+ if ( out_first_pixel > out_last_pixel )+ break;++ if ( ( out_first_pixel < output_sub_size ) || ( out_last_pixel >= 0 ) )+ range->n0 = n;+ --n;+ }++ // 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 )+ {+ int out_first_pixel, out_last_pixel;+ stbir__calculate_out_pixel_range( &out_first_pixel, &out_last_pixel, ((float)n)+0.5f, in_pixels_radius, scale, out_shift, output_sub_size );+ if ( out_first_pixel > out_last_pixel )+ break;+ if ( ( out_first_pixel < output_sub_size ) || ( out_last_pixel >= 0 ) )+ range->n1 = n;+ ++n;+ }+ }++ if ( samp->edge == STBIR_EDGE_WRAP )+ {+ // if we are wrapping, and we are very close to the image size (so the edges might merge), just use the scanline up to the edge+ if ( ( range->n0 > 0 ) && ( range->n1 >= input_full_size ) )+ {+ int marg = range->n1 - input_full_size + 1;+ if ( ( marg + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= range->n0 )+ range->n0 = 0;+ }+ if ( ( range->n0 < 0 ) && ( range->n1 < (input_full_size-1) ) )+ {+ int marg = -range->n0;+ if ( ( input_full_size - marg - STBIR__MERGE_RUNS_PIXEL_THRESHOLD - 1 ) <= range->n1 )+ range->n1 = input_full_size - 1;+ }+ }+ else+ {+ // for non-edge-wrap modes, we never read over the edge, so clamp+ if ( range->n0 < 0 )+ range->n0 = 0;+ if ( range->n1 >= input_full_size )+ range->n1 = input_full_size - 1;+ }+}++static void stbir__get_split_info( stbir__per_split_info* split_info, int splits, int output_height, int vertical_pixel_margin, int input_full_height )+{+ int i, cur;+ int left = output_height;++ cur = 0;+ for( i = 0 ; i < splits ; i++ )+ {+ int each;+ split_info[i].start_output_y = cur;+ each = left / ( splits - i );+ split_info[i].end_output_y = cur + each;+ cur += each;+ left -= each;++ // scatter range (updated to minimum as you run it)+ split_info[i].start_input_y = -vertical_pixel_margin;+ split_info[i].end_input_y = input_full_height + vertical_pixel_margin;+ }+}++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+ STBIR__FREE_AND_CLEAR( info->alloced_mem );+ #else+ int i,j;++ if ( ( info->vertical.gather_prescatter_contributors ) && ( (void*)info->vertical.gather_prescatter_contributors != (void*)info->split_info[0].decode_buffer ) )+ {+ STBIR__FREE_AND_CLEAR( info->vertical.gather_prescatter_coefficients );+ STBIR__FREE_AND_CLEAR( info->vertical.gather_prescatter_contributors );+ }+ for( i = 0 ; i < info->splits ; i++ )+ {+ for( j = 0 ; j < info->alloc_ring_buffer_num_entries ; j++ )+ {+ #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+ STBIR__FREE_AND_CLEAR( info->split_info[i].ring_buffers[j] );+ }++ #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+ 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 );+ }+ STBIR__FREE_AND_CLEAR( info->split_info );+ if ( info->vertical.coefficients != info->horizontal.coefficients )+ {+ STBIR__FREE_AND_CLEAR( info->vertical.coefficients );+ STBIR__FREE_AND_CLEAR( info->vertical.contributors );+ }+ STBIR__FREE_AND_CLEAR( info->horizontal.coefficients );+ STBIR__FREE_AND_CLEAR( info->horizontal.contributors );+ STBIR__FREE_AND_CLEAR( info->alloced_mem );+ STBIR__FREE_AND_CLEAR( info );+ #endif+ }++ #undef STBIR__FREE_AND_CLEAR+}++static int stbir__get_max_split( int splits, int height )+{+ int i;+ int max = 0;++ for( i = 0 ; i < splits ; i++ )+ {+ int each = height / ( splits - i );+ if ( each > max )+ max = each;+ height -= each;+ }+ return max;+}++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] =+{+ 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+};++// there are six resize classifications: 0 == vertical scatter, 1 == vertical gather < 1x scale, 2 == vertical gather 1x-2x scale, 4 == vertical gather < 3x scale, 4 == vertical gather > 3x scale, 5 == <=4 pixel height, 6 == <=4 pixel wide column+#define STBIR_RESIZE_CLASSIFICATIONS 8++static float stbir__compute_weights[5][STBIR_RESIZE_CLASSIFICATIONS][4]= // 5 = 0=1chan, 1=2chan, 2=3chan, 3=4chan, 4=7chan+{+ {+ { 1.00000f, 1.00000f, 0.31250f, 1.00000f },+ { 0.56250f, 0.59375f, 0.00000f, 0.96875f },+ { 1.00000f, 0.06250f, 0.00000f, 1.00000f },+ { 0.00000f, 0.09375f, 1.00000f, 1.00000f },+ { 1.00000f, 1.00000f, 1.00000f, 1.00000f },+ { 0.03125f, 0.12500f, 1.00000f, 1.00000f },+ { 0.06250f, 0.12500f, 0.00000f, 1.00000f },+ { 0.00000f, 1.00000f, 0.00000f, 0.03125f },+ }, {+ { 0.00000f, 0.84375f, 0.00000f, 0.03125f },+ { 0.09375f, 0.93750f, 0.00000f, 0.78125f },+ { 0.87500f, 0.21875f, 0.00000f, 0.96875f },+ { 0.09375f, 0.09375f, 1.00000f, 1.00000f },+ { 1.00000f, 1.00000f, 1.00000f, 1.00000f },+ { 0.03125f, 0.12500f, 1.00000f, 1.00000f },+ { 0.06250f, 0.12500f, 0.00000f, 1.00000f },+ { 0.00000f, 1.00000f, 0.00000f, 0.53125f },+ }, {+ { 0.00000f, 0.53125f, 0.00000f, 0.03125f },+ { 0.06250f, 0.96875f, 0.00000f, 0.53125f },+ { 0.87500f, 0.18750f, 0.00000f, 0.93750f },+ { 0.00000f, 0.09375f, 1.00000f, 1.00000f },+ { 1.00000f, 1.00000f, 1.00000f, 1.00000f },+ { 0.03125f, 0.12500f, 1.00000f, 1.00000f },+ { 0.06250f, 0.12500f, 0.00000f, 1.00000f },+ { 0.00000f, 1.00000f, 0.00000f, 0.56250f },+ }, {+ { 0.00000f, 0.50000f, 0.00000f, 0.71875f },+ { 0.06250f, 0.84375f, 0.00000f, 0.87500f },+ { 1.00000f, 0.50000f, 0.50000f, 0.96875f },+ { 1.00000f, 0.09375f, 0.31250f, 0.50000f },+ { 1.00000f, 1.00000f, 1.00000f, 1.00000f },+ { 1.00000f, 0.03125f, 0.03125f, 0.53125f },+ { 0.18750f, 0.12500f, 0.00000f, 1.00000f },+ { 0.00000f, 1.00000f, 0.03125f, 0.18750f },+ }, {+ { 0.00000f, 0.59375f, 0.00000f, 0.96875f },+ { 0.06250f, 0.81250f, 0.06250f, 0.59375f },+ { 0.75000f, 0.43750f, 0.12500f, 0.96875f },+ { 0.87500f, 0.06250f, 0.18750f, 0.43750f },+ { 1.00000f, 1.00000f, 1.00000f, 1.00000f },+ { 0.15625f, 0.12500f, 1.00000f, 1.00000f },+ { 0.06250f, 0.12500f, 0.00000f, 1.00000f },+ { 0.00000f, 1.00000f, 0.03125f, 0.34375f },+ }+};++// structure that allow us to query and override info for training the costs+typedef struct STBIR__V_FIRST_INFO+{+ double v_cost, h_cost;+ int control_v_first; // 0 = no control, 1 = force hori, 2 = force vert+ int v_first;+ int v_resize_classification;+ int is_gather;+} STBIR__V_FIRST_INFO;++#ifdef STBIR__V_FIRST_INFO_BUFFER+static STBIR__V_FIRST_INFO STBIR__V_FIRST_INFO_BUFFER = {0};+#define STBIR__V_FIRST_INFO_POINTER &STBIR__V_FIRST_INFO_BUFFER+#else+#define STBIR__V_FIRST_INFO_POINTER 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+// in that order.+//+// 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+// fancy caches and SIMD and high IPC abilities, so there's just a lot+// more that goes into it.+//+// 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+// 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 )+{+ double v_cost, h_cost;+ float * weights;+ int vertical_first;+ int v_classification;++ // categorize the resize into buckets+ if ( ( vertical_output_size <= 4 ) || ( horizontal_output_size <= 4 ) )+ 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)+ v_classification = 2;+ else if ( vertical_scale <= 3.0f)+ v_classification = 3;+ else if ( vertical_scale <= 4.0f)+ v_classification = 5;+ else+ v_classification = 6;++ // use the right weights+ weights = weights_table[ v_classification ];++ // this is the costs when you don't take into account modern CPUs with high ipc and simd and caches - wish we had a better estimate+ h_cost = (float)horizontal_filter_pixel_width * weights[0] + horizontal_scale * (float)vertical_filter_pixel_width * weights[1];+ v_cost = (float)vertical_filter_pixel_width * weights[2] + vertical_scale * (float)horizontal_filter_pixel_width * weights[3];++ // use computation estimate to decide vertical first or not+ vertical_first = ( v_cost <= h_cost ) ? 1 : 0;++ // save these, if requested+ if ( info )+ {+ info->h_cost = h_cost;+ info->v_cost = v_cost;+ info->v_resize_classification = v_classification;+ info->v_first = vertical_first;+ info->is_gather = is_gather;+ }++ // 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;+}++// layout lookups - must match stbir_internal_pixel_layout+static unsigned char stbir__pixel_channels[] = {+ 1,2,3,3,4, // 1ch, 2ch, rgb, bgr, 4ch+ 4,4,4,4,2,2, // RGBA,BGRA,ARGB,ABGR,RA,AR+ 4,4,4,4,2,2, // RGBA_PM,BGRA_PM,ARGB_PM,ABGR_PM,RA_PM,AR_PM+};++// 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+static stbir_internal_pixel_layout stbir__pixel_layout_convert_public_to_internal[] = {+ 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,+};++static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sampler * horizontal, stbir__sampler * vertical, stbir__contributors * conservative, stbir_pixel_layout input_pixel_layout_public, stbir_pixel_layout output_pixel_layout_public, int splits, int new_x, int new_y, int fast_alpha, void * user_data STBIR_ONLY_PROFILE_BUILD_GET_INFO )+{+ static char stbir_channel_count_index[8]={ 9,0,1,2, 3,9,9,4 };++ stbir__info * info = 0;+ void * alloced = 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 ];+ 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 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+ {+ if ( ( input_pixel_layout >= STBIRI_RGBA ) && ( input_pixel_layout <= STBIRI_AR ) && ( output_pixel_layout >= STBIRI_RGBA ) && ( output_pixel_layout <= STBIRI_AR ) )+ {+ if ( fast_alpha )+ {+ alpha_weighting_type = 4;+ }+ else+ {+ static int fancy_alpha_effective_cnts[6] = { 7, 7, 7, 7, 3, 3 };+ alpha_weighting_type = 2;+ effective_channels = fancy_alpha_effective_cnts[ input_pixel_layout - STBIRI_RGBA ];+ }+ }+ else if ( ( input_pixel_layout >= STBIRI_RGBA_PM ) && ( input_pixel_layout <= STBIRI_AR_PM ) && ( output_pixel_layout >= STBIRI_RGBA ) && ( output_pixel_layout <= STBIRI_AR ) )+ {+ // input premult, output non-premult+ alpha_weighting_type = 3;+ }+ else if ( ( input_pixel_layout >= STBIRI_RGBA ) && ( input_pixel_layout <= STBIRI_AR ) && ( output_pixel_layout >= STBIRI_RGBA_PM ) && ( output_pixel_layout <= STBIRI_AR_PM ) )+ {+ // input non-premult, output premult+ alpha_weighting_type = 1;+ }+ }++ // channel in and out count must match currently+ if ( channels != stbir__pixel_channels[ output_pixel_layout ] )+ return 0;++ // get vertical first+ vertical_first = stbir__should_do_vertical_first( stbir__compute_weights[ (int)stbir_channel_count_index[ effective_channels ] ], horizontal->filter_pixel_width, horizontal->scale_info.scale, horizontal->scale_info.output_sub_size, vertical->filter_pixel_width, vertical->scale_info.scale, vertical->scale_info.output_sub_size, vertical->is_gather, STBIR__V_FIRST_INFO_POINTER );++ // 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++ ring_buffer_length_bytes = horizontal->scale_info.output_sub_size * effective_channels * sizeof(float) + sizeof(float); // extra float for padding++ // if we do vertical first, the ring buffer holds a whole decoded line+ if ( vertical_first )+ ring_buffer_length_bytes = ( decode_buffer_size + 15 ) & ~15;++ if ( ( ring_buffer_length_bytes & 4095 ) == 0 ) ring_buffer_length_bytes += 64*3; // avoid 4k alias++ // One extra entry because floating point precision problems sometimes cause an extra to be necessary.+ alloc_ring_buffer_num_entries = vertical->filter_pixel_width + 1;++ // we never need more ring buffer entries than the scanlines we're outputting when in scatter mode+ if ( ( !vertical->is_gather ) && ( alloc_ring_buffer_num_entries > conservative_split_output_size ) )+ alloc_ring_buffer_num_entries = conservative_split_output_size;++ ring_buffer_size = alloc_ring_buffer_num_entries * ring_buffer_length_bytes;++ // The vertical buffer is used differently, depending on whether we are scattering+ // the vertical scanlines, or gathering them.+ // If scattering, it's used at the temp buffer to accumulate each output.+ // If gathering, it's just the output buffer.+ vertical_buffer_size = horizontal->scale_info.output_sub_size * effective_channels * sizeof(float) + sizeof(float); // extra float for padding++ // we make two passes through this loop, 1st to add everything up, 2nd to allocate and init+ for(;;)+ {+ int i;+ void * advance_mem = alloced;+ int copy_horizontal = 0;+ stbir__sampler * possibly_use_horizontal_for_pivot = 0;++#ifdef STBIR__SEPARATE_ALLOCATIONS+ #define STBIR__NEXT_PTR( ptr, size, ntype ) if ( alloced ) { void * p = STBIR_MALLOC( size, user_data); if ( p == 0 ) { stbir__free_internal_mem( info ); return 0; } (ptr) = (ntype*)p; }+#else+ #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->split_info, sizeof( stbir__per_split_info ) * splits, stbir__per_split_info );++ if ( info )+ {+ static stbir__alpha_weight_func * fancy_alpha_weights[6] = { stbir__fancy_alpha_weight_4ch, stbir__fancy_alpha_weight_4ch, stbir__fancy_alpha_weight_4ch, stbir__fancy_alpha_weight_4ch, stbir__fancy_alpha_weight_2ch, stbir__fancy_alpha_weight_2ch };+ static stbir__alpha_unweight_func * fancy_alpha_unweights[6] = { stbir__fancy_alpha_unweight_4ch, stbir__fancy_alpha_unweight_4ch, stbir__fancy_alpha_unweight_4ch, stbir__fancy_alpha_unweight_4ch, stbir__fancy_alpha_unweight_2ch, stbir__fancy_alpha_unweight_2ch };+ static stbir__alpha_weight_func * simple_alpha_weights[6] = { stbir__simple_alpha_weight_4ch, stbir__simple_alpha_weight_4ch, stbir__simple_alpha_weight_4ch, stbir__simple_alpha_weight_4ch, stbir__simple_alpha_weight_2ch, stbir__simple_alpha_weight_2ch };+ static stbir__alpha_unweight_func * simple_alpha_unweights[6] = { stbir__simple_alpha_unweight_4ch, stbir__simple_alpha_unweight_4ch, stbir__simple_alpha_unweight_4ch, stbir__simple_alpha_unweight_4ch, stbir__simple_alpha_unweight_2ch, stbir__simple_alpha_unweight_2ch };++ // initialize info fields+ info->alloced_mem = alloced;+ info->alloced_total = alloced_total;++ 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_length_bytes = ring_buffer_length_bytes;+ info->splits = splits;+ info->vertical_first = vertical_first;++ 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_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_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 ];+ }+ else if ( alpha_weighting_type == 3 )+ {+ // incoming is premultiplied, fast alpha dividing on the way out - non-premultiplied output+ info->alpha_unweight = simple_alpha_unweights[ output_pixel_layout - STBIRI_RGBA ];+ }++ // handle 3-chan color flipping, using the alpha weight path+ if ( ( ( input_pixel_layout == STBIRI_RGB ) && ( output_pixel_layout == STBIRI_BGR ) ) ||+ ( ( input_pixel_layout == STBIRI_BGR ) && ( output_pixel_layout == STBIRI_RGB ) ) )+ {+ // do the flipping on the smaller of the two ends+ if ( horizontal->scale_info.scale < 1.0f )+ info->alpha_unweight = stbir__simple_flip_3ch;+ else+ info->alpha_weight = stbir__simple_flip_3ch;+ }++ }++ // get all the per-split buffers+ for( i = 0 ; i < splits ; i++ )+ {+ STBIR__NEXT_PTR( info->split_info[i].decode_buffer, decode_buffer_size, float );++#ifdef STBIR__SEPARATE_ALLOCATIONS++ #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++ STBIR__NEXT_PTR( info->split_info[i].ring_buffers, alloc_ring_buffer_num_entries * sizeof(float*), float* );+ {+ int j;+ for( j = 0 ; j < alloc_ring_buffer_num_entries ; j++ )+ {+ STBIR__NEXT_PTR( info->split_info[i].ring_buffers[j], ring_buffer_length_bytes, float );+ #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+ }+ }+#else+ STBIR__NEXT_PTR( info->split_info[i].ring_buffer, ring_buffer_size, float );+#endif+ STBIR__NEXT_PTR( info->split_info[i].vertical_buffer, vertical_buffer_size, float );+ }++ // alloc memory for to-be-pivoted coeffs (if necessary)+ if ( vertical->is_gather == 0 )+ {+ int both;+ int temp_mem_amt;++ // when in vertical scatter mode, we first build the coefficients in gather mode, and then pivot after,+ // that means we need two buffers, so we try to use the decode buffer and ring buffer for this. if that+ // is too small, we just allocate extra memory to use as this temp.++ both = vertical->gather_prescatter_contributors_size + vertical->gather_prescatter_coefficients_size;++#ifdef STBIR__SEPARATE_ALLOCATIONS+ temp_mem_amt = decode_buffer_size;+#else+ temp_mem_amt = ( decode_buffer_size + ring_buffer_size + vertical_buffer_size ) * splits;+#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 );+ }+ }+ else+ {+ // ring+decode memory is too small, so allocate temp memory+ STBIR__NEXT_PTR( vertical->gather_prescatter_contributors, vertical->gather_prescatter_contributors_size, stbir__contributors );+ STBIR__NEXT_PTR( vertical->gather_prescatter_coefficients, vertical->gather_prescatter_coefficients_size, float );+ }+ }++ STBIR__NEXT_PTR( horizontal->contributors, horizontal->contributors_size, stbir__contributors );+ STBIR__NEXT_PTR( horizontal->coefficients, horizontal->coefficients_size, float );++ // are the two filters identical?? (happens a lot with mipmap generation)+ if ( ( horizontal->filter_kernel == vertical->filter_kernel ) && ( horizontal->filter_support == vertical->filter_support ) && ( horizontal->edge == vertical->edge ) && ( horizontal->scale_info.output_sub_size == vertical->scale_info.output_sub_size ) )+ {+ float diff_scale = horizontal->scale_info.scale - vertical->scale_info.scale;+ float diff_shift = horizontal->scale_info.pixel_shift - vertical->scale_info.pixel_shift;+ if ( diff_scale < 0.0f ) diff_scale = -diff_scale;+ 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 )+ {+ copy_horizontal = 1;+ goto no_vert_alloc;+ }+ // everything matches, but vertical is scatter, horizontal is gather, use horizontal coeffs for vertical pivot coeffs+ possibly_use_horizontal_for_pivot = horizontal;+ }+ }++ STBIR__NEXT_PTR( vertical->contributors, vertical->contributors_size, stbir__contributors );+ STBIR__NEXT_PTR( vertical->coefficients, vertical->coefficients_size, float );++ no_vert_alloc:++ if ( info )+ {+ STBIR_PROFILE_BUILD_START( horizontal );++ stbir__calculate_filters( horizontal, 0, user_data STBIR_ONLY_PROFILE_BUILD_SET_INFO );++ // setup the horizontal gather functions+ // start with defaulting to the n_coeffs functions (specialized on channels and remnant leftover)+ info->horizontal_gather_channels = stbir__horizontal_gather_n_coeffs_funcs[ effective_channels ][ horizontal->extent_info.widest & 3 ];+ // 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.n0, info->scanline_extents.conservative.n1 );++ STBIR_MEMCPY( &info->horizontal, horizontal, sizeof( stbir__sampler ) );++ STBIR_PROFILE_BUILD_END( horizontal );++ if ( copy_horizontal )+ {+ STBIR_MEMCPY( &info->vertical, horizontal, sizeof( stbir__sampler ) );+ }+ else+ {+ STBIR_PROFILE_BUILD_START( vertical );++ stbir__calculate_filters( vertical, possibly_use_horizontal_for_pivot, user_data STBIR_ONLY_PROFILE_BUILD_SET_INFO );+ STBIR_MEMCPY( &info->vertical, vertical, sizeof( stbir__sampler ) );++ STBIR_PROFILE_BUILD_END( vertical );+ }++ // setup the vertical split ranges+ stbir__get_split_info( info->split_info, info->splits, info->vertical.scale_info.output_sub_size, info->vertical.filter_pixel_margin, info->vertical.scale_info.input_full_size );++ // now we know precisely how many entries we need+ info->ring_buffer_num_entries = info->vertical.extent_info.widest;++ // we never need more ring buffer entries than the scanlines we're outputting+ if ( ( !info->vertical.is_gather ) && ( info->ring_buffer_num_entries > conservative_split_output_size ) )+ 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 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 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_first )+ {+ int j;+ for( j = 0; j < info->ring_buffer_num_entries ; j++ )+ {+ for( t = start ; t < ofs; t++ )+ stbir__get_ring_buffer_entry( info, info->split_info + i, j )[ t ] = 9999.0f;+ }+ }+ }+ }++ #undef STBIR__NEXT_PTR+++ // is this the first time through loop?+ if ( info == 0 )+ {+ alloced_total = ( 15 + (size_t)advance_mem );+ alloced = STBIR_MALLOC( alloced_total, user_data );+ if ( alloced == 0 )+ return 0;+ }+ else+ return info; // success+ }+}++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;++ STBIR_PROFILE_CLEAR_EXTRAS();++ STBIR_PROFILE_FIRST_START( looping );+ if (info->vertical.is_gather)+ stbir__vertical_gather_loop( info, split_info, split_count );+ else+ stbir__vertical_scatter_loop( info, split_info, split_count );+ STBIR_PROFILE_END( looping );++ return 1;+}++static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * resize )+{+ 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,+ };++ static stbir__decode_pixels_func * decode_alphas[STBIRI_AR-STBIRI_RGBA+1][STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]=+ {+ { /* RGBA */ stbir__decode_uint8_srgb4_linearalpha, stbir__decode_uint8_srgb, 0, stbir__decode_float_linear, stbir__decode_half_float_linear },+ { /* BGRA */ stbir__decode_uint8_srgb4_linearalpha_BGRA, stbir__decode_uint8_srgb_BGRA, 0, stbir__decode_float_linear_BGRA, stbir__decode_half_float_linear_BGRA },+ { /* ARGB */ stbir__decode_uint8_srgb4_linearalpha_ARGB, stbir__decode_uint8_srgb_ARGB, 0, stbir__decode_float_linear_ARGB, stbir__decode_half_float_linear_ARGB },+ { /* ABGR */ stbir__decode_uint8_srgb4_linearalpha_ABGR, stbir__decode_uint8_srgb_ABGR, 0, stbir__decode_float_linear_ABGR, stbir__decode_half_float_linear_ABGR },+ { /* RA */ stbir__decode_uint8_srgb2_linearalpha, stbir__decode_uint8_srgb, 0, stbir__decode_float_linear, stbir__decode_half_float_linear },+ { /* AR */ stbir__decode_uint8_srgb2_linearalpha_AR, stbir__decode_uint8_srgb_AR, 0, stbir__decode_float_linear_AR, stbir__decode_half_float_linear_AR },+ };++ static stbir__decode_pixels_func * decode_simple_scaled_or_not[2][2]=+ {+ { stbir__decode_uint8_linear_scaled, stbir__decode_uint8_linear }, { stbir__decode_uint16_linear_scaled, stbir__decode_uint16_linear },+ };++ static stbir__decode_pixels_func * decode_alphas_scaled_or_not[STBIRI_AR-STBIRI_RGBA+1][2][2]=+ {+ { /* RGBA */ { stbir__decode_uint8_linear_scaled, stbir__decode_uint8_linear }, { stbir__decode_uint16_linear_scaled, stbir__decode_uint16_linear } },+ { /* BGRA */ { stbir__decode_uint8_linear_scaled_BGRA, stbir__decode_uint8_linear_BGRA }, { stbir__decode_uint16_linear_scaled_BGRA, stbir__decode_uint16_linear_BGRA } },+ { /* ARGB */ { stbir__decode_uint8_linear_scaled_ARGB, stbir__decode_uint8_linear_ARGB }, { stbir__decode_uint16_linear_scaled_ARGB, stbir__decode_uint16_linear_ARGB } },+ { /* ABGR */ { stbir__decode_uint8_linear_scaled_ABGR, stbir__decode_uint8_linear_ABGR }, { stbir__decode_uint16_linear_scaled_ABGR, stbir__decode_uint16_linear_ABGR } },+ { /* RA */ { stbir__decode_uint8_linear_scaled, stbir__decode_uint8_linear }, { stbir__decode_uint16_linear_scaled, stbir__decode_uint16_linear } },+ { /* AR */ { stbir__decode_uint8_linear_scaled_AR, stbir__decode_uint8_linear_AR }, { stbir__decode_uint16_linear_scaled_AR, stbir__decode_uint16_linear_AR } }+ };++ static stbir__encode_pixels_func * encode_simple[STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]=+ {+ /* 1ch-4ch */ stbir__encode_uint8_srgb, stbir__encode_uint8_srgb, 0, stbir__encode_float_linear, stbir__encode_half_float_linear,+ };++ static stbir__encode_pixels_func * encode_alphas[STBIRI_AR-STBIRI_RGBA+1][STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]=+ {+ { /* RGBA */ stbir__encode_uint8_srgb4_linearalpha, stbir__encode_uint8_srgb, 0, stbir__encode_float_linear, stbir__encode_half_float_linear },+ { /* BGRA */ stbir__encode_uint8_srgb4_linearalpha_BGRA, stbir__encode_uint8_srgb_BGRA, 0, stbir__encode_float_linear_BGRA, stbir__encode_half_float_linear_BGRA },+ { /* ARGB */ stbir__encode_uint8_srgb4_linearalpha_ARGB, stbir__encode_uint8_srgb_ARGB, 0, stbir__encode_float_linear_ARGB, stbir__encode_half_float_linear_ARGB },+ { /* ABGR */ stbir__encode_uint8_srgb4_linearalpha_ABGR, stbir__encode_uint8_srgb_ABGR, 0, stbir__encode_float_linear_ABGR, stbir__encode_half_float_linear_ABGR },+ { /* RA */ stbir__encode_uint8_srgb2_linearalpha, stbir__encode_uint8_srgb, 0, stbir__encode_float_linear, stbir__encode_half_float_linear },+ { /* AR */ stbir__encode_uint8_srgb2_linearalpha_AR, stbir__encode_uint8_srgb_AR, 0, stbir__encode_float_linear_AR, stbir__encode_half_float_linear_AR }+ };++ static stbir__encode_pixels_func * encode_simple_scaled_or_not[2][2]=+ {+ { stbir__encode_uint8_linear_scaled, stbir__encode_uint8_linear }, { stbir__encode_uint16_linear_scaled, stbir__encode_uint16_linear },+ };++ static stbir__encode_pixels_func * encode_alphas_scaled_or_not[STBIRI_AR-STBIRI_RGBA+1][2][2]=+ {+ { /* RGBA */ { stbir__encode_uint8_linear_scaled, stbir__encode_uint8_linear }, { stbir__encode_uint16_linear_scaled, stbir__encode_uint16_linear } },+ { /* BGRA */ { stbir__encode_uint8_linear_scaled_BGRA, stbir__encode_uint8_linear_BGRA }, { stbir__encode_uint16_linear_scaled_BGRA, stbir__encode_uint16_linear_BGRA } },+ { /* ARGB */ { stbir__encode_uint8_linear_scaled_ARGB, stbir__encode_uint8_linear_ARGB }, { stbir__encode_uint16_linear_scaled_ARGB, stbir__encode_uint16_linear_ARGB } },+ { /* ABGR */ { stbir__encode_uint8_linear_scaled_ABGR, stbir__encode_uint8_linear_ABGR }, { stbir__encode_uint16_linear_scaled_ABGR, stbir__encode_uint16_linear_ABGR } },+ { /* RA */ { stbir__encode_uint8_linear_scaled, stbir__encode_uint8_linear }, { stbir__encode_uint16_linear_scaled, stbir__encode_uint16_linear } },+ { /* AR */ { stbir__encode_uint8_linear_scaled_AR, stbir__encode_uint8_linear_AR }, { stbir__encode_uint16_linear_scaled_AR, stbir__encode_uint16_linear_AR } }+ };++ stbir__decode_pixels_func * decode_pixels = 0;+ stbir__encode_pixels_func * encode_pixels = 0;+ stbir_datatype input_type, output_type;++ input_type = resize->input_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;++ // 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 ) ) &&+ ( ( output_type == STBIR_TYPE_UINT8_SRGB ) || ( output_type == STBIR_TYPE_UINT8_SRGB_ALPHA ) ) )+ {+ input_type = STBIR_TYPE_UINT8;+ output_type = STBIR_TYPE_UINT8;+ }+ }++ // 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];++ if ( info->output_stride_bytes == 0 )+ 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 ) + ( (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;+ info->out_pixels_cb = resize->output_cb;++ // setup the input format converters+ if ( ( input_type == STBIR_TYPE_UINT8 ) || ( input_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 ) ) )+ non_scaled = 1;++ if ( info->input_pixel_layout_internal <= STBIRI_4CHANNEL )+ decode_pixels = decode_simple_scaled_or_not[ input_type == STBIR_TYPE_UINT16 ][ non_scaled ];+ else+ decode_pixels = decode_alphas_scaled_or_not[ ( info->input_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR-STBIRI_RGBA+1 ) ][ input_type == STBIR_TYPE_UINT16 ][ non_scaled ];+ }+ else+ {+ if ( info->input_pixel_layout_internal <= STBIRI_4CHANNEL )+ decode_pixels = decode_simple[ input_type - STBIR_TYPE_UINT8_SRGB ];+ else+ decode_pixels = decode_alphas[ ( info->input_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR-STBIRI_RGBA+1 ) ][ input_type - STBIR_TYPE_UINT8_SRGB ];+ }++ // setup the output format converters+ 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 ) ) )+ non_scaled = 1;++ if ( info->output_pixel_layout_internal <= STBIRI_4CHANNEL )+ encode_pixels = encode_simple_scaled_or_not[ output_type == STBIR_TYPE_UINT16 ][ non_scaled ];+ else+ encode_pixels = encode_alphas_scaled_or_not[ ( info->output_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR-STBIRI_RGBA+1 ) ][ output_type == STBIR_TYPE_UINT16 ][ non_scaled ];+ }+ else+ {+ if ( info->output_pixel_layout_internal <= STBIRI_4CHANNEL )+ encode_pixels = encode_simple[ output_type - STBIR_TYPE_UINT8_SRGB ];+ else+ encode_pixels = encode_alphas[ ( info->output_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR-STBIRI_RGBA+1 ) ][ output_type - STBIR_TYPE_UINT8_SRGB ];+ }++ info->input_type = input_type;+ info->output_type = output_type;+ info->decode_pixels = decode_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 )+ {+ per = ( (double)*outx ) / ( (double)*outsubw ); // is negative+ adj = per * ( *u1 - *u0 );+ *u0 -= adj; // increases u0+ *outx = 0;+ }++ // do right/bot edge+ over = outw - ( *outx + *outsubw );+ if ( over < 0 )+ {+ per = ( (double)over ) / ( (double)*outsubw ); // is negative+ adj = per * ( *u1 - *u0 );+ *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)+{+ double err;+ stbir_uint64 top, bot;+ stbir_uint64 numer_last = 0;+ stbir_uint64 denom_last = 1;+ stbir_uint64 numer_estimate = 1;+ stbir_uint64 denom_estimate = 0;++ // scale to past float error range+ top = (stbir_uint64)( f * (double)(1 << 25) );+ bot = 1 << 25;++ // keep refining, but usually stops in a few loops - usually 5 for bad cases+ for(;;)+ {+ stbir_uint64 est, temp;++ // hit limit, break out and do best full range estimate+ if ( ( ( limit_denom ) ? denom_estimate : numer_estimate ) >= limit )+ break;++ // is the current error less than 1 bit of a float? if so, we're done+ if ( denom_estimate )+ {+ err = ( (double)numer_estimate / (double)denom_estimate ) - f;+ if ( err < 0.0 ) err = -err;+ if ( err < ( 1.0 / (double)(1<<24) ) )+ {+ // yup, found it+ *numer = (stbir_uint32) numer_estimate;+ *denom = (stbir_uint32) denom_estimate;+ return 1;+ }+ }++ // no more refinement bits left? break out and do full range estimate+ if ( bot == 0 )+ break;++ // gcd the estimate bits+ est = top / bot;+ temp = top % bot;+ top = bot;+ bot = temp;++ // move remainders+ 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;+ numer_estimate = temp;+ }++ // we didn't fine anything good enough for float, use a full range estimate+ if ( limit_denom )+ {+ numer_estimate= (stbir_uint64)( f * (double)limit + 0.5 );+ denom_estimate = limit;+ }+ else+ {+ numer_estimate = limit;+ denom_estimate = (stbir_uint64)( ( (double)limit / f ) + 0.5 );+ }++ *numer = (stbir_uint32) numer_estimate;+ *denom = (stbir_uint32) denom_estimate;++ err = ( denom_estimate ) ? ( ( (double)(stbir_uint32)numer_estimate / (double)(stbir_uint32)denom_estimate ) - f ) : 1.0;+ if ( err < 0.0 ) err = -err;+ return ( err < ( 1.0 / (double)(1<<24) ) ) ? 1 : 0;+}++static int stbir__calculate_region_transform( stbir__scale_info * scale_info, int output_full_range, int * output_offset, int output_sub_range, int input_full_range, double input_s0, double input_s1 )+{+ double output_range, input_range, output_s, input_s, ratio, scale;++ input_s = input_s1 - input_s0;++ // null area+ if ( ( output_full_range == 0 ) || ( input_full_range == 0 ) ||+ ( output_sub_range == 0 ) || ( input_s <= stbir__small_float ) )+ return 0;++ // are either of the ranges completely out of bounds?+ if ( ( *output_offset >= output_full_range ) || ( ( *output_offset + output_sub_range ) <= 0 ) || ( input_s0 >= (1.0f-stbir__small_float) ) || ( input_s1 <= stbir__small_float ) )+ return 0;++ output_range = (double)output_full_range;+ input_range = (double)input_full_range;++ output_s = ( (double)output_sub_range) / output_range;++ // figure out the scaling to use+ ratio = output_s / input_s;++ // save scale before clipping+ scale = ( output_range / input_range ) * ratio;+ scale_info->scale = (float)scale;+ scale_info->inv_scale = (float)( 1.0 / scale );++ // clip output area to left/right output edges (and adjust input area)+ stbir__clip( output_offset, &output_sub_range, output_full_range, &input_s0, &input_s1 );++ // recalc input area+ input_s = input_s1 - input_s0;++ // after clipping do we have zero input area?+ 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 );++ 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 ) );++ scale_info->input_full_size = input_full_range;+ scale_info->output_sub_size = output_sub_range;++ return 1;+}+++static void stbir__init_and_set_layout( STBIR_RESIZE * resize, stbir_pixel_layout pixel_layout, stbir_datatype data_type )+{+ resize->input_cb = 0;+ resize->output_cb = 0;+ resize->user_data = resize;+ resize->samplers = 0;+ resize->called_alloc = 0;+ resize->horizontal_filter = STBIR_FILTER_DEFAULT;+ resize->horizontal_filter_kernel = 0; resize->horizontal_filter_support = 0;+ resize->vertical_filter = STBIR_FILTER_DEFAULT;+ resize->vertical_filter_kernel = 0; resize->vertical_filter_support = 0;+ resize->horizontal_edge = STBIR_EDGE_CLAMP;+ resize->vertical_edge = STBIR_EDGE_CLAMP;+ resize->input_s0 = 0; resize->input_t0 = 0; resize->input_s1 = 1; resize->input_t1 = 1;+ resize->output_subx = 0; resize->output_suby = 0; resize->output_subw = resize->output_w; resize->output_subh = resize->output_h;+ resize->input_data_type = data_type;+ 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,+ 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 )+{+ resize->input_pixels = input_pixels;+ resize->input_w = input_w;+ resize->input_h = input_h;+ resize->input_stride_in_bytes = input_stride_in_bytes;+ resize->output_pixels = output_pixels;+ resize->output_w = output_w;+ resize->output_h = output_h;+ resize->output_stride_in_bytes = output_stride_in_bytes;+ resize->fast_alpha = 0;++ stbir__init_and_set_layout( resize, pixel_layout, data_type );+}++// You can update parameters any time after resize_init+STBIRDEF void stbir_set_datatypes( STBIR_RESIZE * resize, stbir_datatype input_type, stbir_datatype output_type ) // by default, datatype from resize_init+{+ 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 )+{+ resize->input_pixels = input_pixels;+ 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 );+}+++STBIRDEF int stbir_set_edgemodes( STBIR_RESIZE * resize, stbir_edge horizontal_edge, stbir_edge vertical_edge ) // CLAMP by default+{+ resize->horizontal_edge = horizontal_edge;+ resize->vertical_edge = vertical_edge;+ resize->needs_rebuild = 1;+ return 1;+}++STBIRDEF int stbir_set_filters( STBIR_RESIZE * resize, stbir_filter horizontal_filter, stbir_filter vertical_filter ) // STBIR_DEFAULT_FILTER_UPSAMPLE/DOWNSAMPLE by default+{+ resize->horizontal_filter = horizontal_filter;+ resize->vertical_filter = vertical_filter;+ resize->needs_rebuild = 1;+ return 1;+}++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 )+{+ resize->horizontal_filter_kernel = horizontal_filter; resize->horizontal_filter_support = horizontal_support;+ resize->vertical_filter_kernel = vertical_filter; resize->vertical_filter_support = vertical_support;+ resize->needs_rebuild = 1;+ return 1;+}++STBIRDEF int stbir_set_pixel_layouts( STBIR_RESIZE * resize, stbir_pixel_layout input_pixel_layout, stbir_pixel_layout output_pixel_layout ) // sets new pixel layouts+{+ resize->input_pixel_layout_public = input_pixel_layout;+ resize->output_pixel_layout_public = output_pixel_layout;+ resize->needs_rebuild = 1;+ return 1;+}+++STBIRDEF int stbir_set_non_pm_alpha_speed_over_quality( STBIR_RESIZE * resize, int non_pma_alpha_speed_over_quality ) // sets alpha speed+{+ resize->fast_alpha = non_pma_alpha_speed_over_quality;+ resize->needs_rebuild = 1;+ return 1;+}++STBIRDEF int stbir_set_input_subrect( STBIR_RESIZE * resize, double s0, double t0, double s1, double t1 ) // sets input region (full region by default)+{+ resize->input_s0 = s0;+ resize->input_t0 = t0;+ resize->input_s1 = s1;+ resize->input_t1 = t1;+ resize->needs_rebuild = 1;++ // are we inbounds?+ if ( ( s1 < stbir__small_float ) || ( (s1-s0) < stbir__small_float ) ||+ ( t1 < stbir__small_float ) || ( (t1-t0) < stbir__small_float ) ||+ ( s0 > (1.0f-stbir__small_float) ) ||+ ( t0 > (1.0f-stbir__small_float) ) )+ return 0;++ return 1;+}++STBIRDEF int stbir_set_output_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, int subw, int subh ) // sets input region (full region by default)+{+ resize->output_subx = subx;+ resize->output_suby = suby;+ resize->output_subw = subw;+ resize->output_subh = subh;+ resize->needs_rebuild = 1;++ // are we inbounds?+ if ( ( subx >= resize->output_w ) || ( ( subx + subw ) <= 0 ) || ( suby >= resize->output_h ) || ( ( suby + subh ) <= 0 ) || ( subw == 0 ) || ( subh == 0 ) )+ return 0;++ return 1;+}++STBIRDEF int stbir_set_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, int subw, int subh ) // sets both regions (full regions by default)+{+ double s0, t0, s1, t1;++ s0 = ( (double)subx ) / ( (double)resize->output_w );+ t0 = ( (double)suby ) / ( (double)resize->output_h );+ s1 = ( (double)(subx+subw) ) / ( (double)resize->output_w );+ t1 = ( (double)(suby+subh) ) / ( (double)resize->output_h );++ resize->input_s0 = s0;+ resize->input_t0 = t0;+ resize->input_s1 = s1;+ resize->input_t1 = t1;+ resize->output_subx = subx;+ resize->output_suby = suby;+ resize->output_subw = subw;+ resize->output_subh = subh;+ resize->needs_rebuild = 1;++ // are we inbounds?+ if ( ( subx >= resize->output_w ) || ( ( subx + subw ) <= 0 ) || ( suby >= resize->output_h ) || ( ( suby + subh ) <= 0 ) || ( subw == 0 ) || ( subh == 0 ) )+ return 0;++ return 1;+}++static int stbir__perform_build( STBIR_RESIZE * resize, int splits )+{+ stbir__contributors conservative = { 0, 0 };+ stbir__sampler horizontal, vertical;+ int new_output_subx, new_output_suby;+ stbir__info * out_info;+ #ifdef STBIR_PROFILE+ stbir__info profile_infod; // used to contain building profile info before everything is allocated+ stbir__info * profile_info = &profile_infod;+ #endif++ // 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 )+ return 0;++ STBIR_PROFILE_BUILD_FIRST_START( build );++ new_output_subx = resize->output_subx;+ new_output_suby = resize->output_suby;++ // do horizontal clip and scale calcs+ if ( !stbir__calculate_region_transform( &horizontal.scale_info, resize->output_w, &new_output_subx, resize->output_subw, resize->input_w, resize->input_s0, resize->input_s1 ) )+ return 0;++ // do vertical clip and scale calcs+ if ( !stbir__calculate_region_transform( &vertical.scale_info, resize->output_h, &new_output_suby, resize->output_subh, resize->input_h, resize->input_t0, resize->input_t1 ) )+ return 0;++ // if nothing to do, just return+ if ( ( horizontal.scale_info.output_sub_size == 0 ) || ( vertical.scale_info.output_sub_size == 0 ) )+ return 0;++ stbir__set_sampler(&horizontal, resize->horizontal_filter, resize->horizontal_filter_kernel, resize->horizontal_filter_support, resize->horizontal_edge, &horizontal.scale_info, 1, resize->user_data );+ 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 ) < STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS ) // each split should be a minimum of 4 scanlines (handwavey choice)+ {+ splits = vertical.scale_info.output_sub_size / STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS;+ if ( splits == 0 ) splits = 1;+ }++ STBIR_PROFILE_BUILD_START( alloc );+ 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;+ resize->samplers = out_info;+ resize->needs_rebuild = 0;+ #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;+ }++ return 0;+}++void stbir_free_samplers( STBIR_RESIZE * resize )+{+ if ( resize->samplers )+ {+ stbir__free_internal_mem( resize->samplers );+ resize->samplers = 0;+ resize->called_alloc = 0;+ }+}++STBIRDEF int stbir_build_samplers_with_splits( STBIR_RESIZE * resize, int splits )+{+ if ( ( resize->samplers == 0 ) || ( resize->needs_rebuild ) )+ {+ if ( resize->samplers )+ stbir_free_samplers( resize );++ resize->called_alloc = 1;+ return stbir__perform_build( resize, splits );+ }++ STBIR_PROFILE_BUILD_CLEAR( resize->samplers );++ return 1;+}++STBIRDEF int stbir_build_samplers( STBIR_RESIZE * resize )+{+ return stbir_build_samplers_with_splits( resize, 1 );+}++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++ if ( resize->samplers )+ {+ stbir__free_internal_mem( resize->samplers );+ resize->samplers = 0;+ }++ if ( !stbir_build_samplers( resize ) )+ return 0;++ resize->called_alloc = alloc_state;++ // 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 )+ return 1;+ }+ else+ {+ // didn't build anything - clear it+ STBIR_PROFILE_BUILD_CLEAR( resize->samplers );+ }++ // do resize+ result = stbir__perform_resize( resize->samplers, 0, resize->splits );++ // if we alloced, then free+ if ( !resize->called_alloc )+ {+ stbir_free_samplers( resize );+ resize->samplers = 0;+ }++ return result;+}++STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start, int split_count )+{+ STBIR_ASSERT( resize->samplers );++ // if we're just doing the whole thing, call full+ if ( ( split_start == -1 ) || ( ( split_start == 0 ) && ( split_count == resize->splits ) ) )+ return stbir_resize_extended( resize );++ // you **must** build samplers first when using split resize+ if ( ( resize->samplers == 0 ) || ( resize->needs_rebuild ) )+ return 0;++ if ( ( split_start >= resize->splits ) || ( split_start < 0 ) || ( ( split_start + split_count ) > resize->splits ) || ( split_count <= 0 ) )+ return 0;++ // do resize+ return stbir__perform_resize( resize->samplers, split_start, split_count );+}++static int stbir__check_output_stuff( void ** ret_ptr, int * ret_pitch, void * output_pixels, int type_size, int output_w, int output_h, int output_stride_in_bytes, stbir_internal_pixel_layout pixel_layout )+{+ size_t size;+ int pitch;+ void * ptr;++ pitch = output_w * type_size * stbir__pixel_channels[ pixel_layout ];+ if ( pitch == 0 )+ return 0;++ if ( output_stride_in_bytes == 0 )+ output_stride_in_bytes = pitch;++ if ( output_stride_in_bytes < pitch )+ return 0;++ size = (size_t)output_stride_in_bytes * (size_t)output_h;+ if ( size == 0 )+ return 0;++ *ret_ptr = 0;+ *ret_pitch = output_stride_in_bytes;++ if ( output_pixels == 0 )+ {+ ptr = STBIR_MALLOC( size, 0 );+ if ( ptr == 0 )+ return 0;++ *ret_ptr = ptr;+ *ret_pitch = pitch;+ }++ return 1;+}+++STBIRDEF unsigned char * stbir_resize_uint8_linear( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes,+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,+ stbir_pixel_layout pixel_layout )+{+ STBIR_RESIZE resize;+ unsigned char * optr;+ int opitch;++ 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,+ pixel_layout, STBIR_TYPE_UINT8 );++ if ( !stbir_resize_extended( &resize ) )+ {+ if ( optr )+ STBIR_FREE( optr, 0 );+ return 0;+ }++ return (optr) ? optr : output_pixels;+}++STBIRDEF unsigned char * stbir_resize_uint8_srgb( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes,+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,+ stbir_pixel_layout pixel_layout )+{+ STBIR_RESIZE resize;+ unsigned char * optr;+ int opitch;++ 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,+ pixel_layout, STBIR_TYPE_UINT8_SRGB );++ if ( !stbir_resize_extended( &resize ) )+ {+ if ( optr )+ STBIR_FREE( optr, 0 );+ return 0;+ }++ return (optr) ? optr : output_pixels;+}+++STBIRDEF float * stbir_resize_float_linear( const float *input_pixels , int input_w , int input_h, int input_stride_in_bytes,+ float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,+ stbir_pixel_layout pixel_layout )+{+ STBIR_RESIZE resize;+ float * optr;+ int opitch;++ 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,+ pixel_layout, STBIR_TYPE_FLOAT );++ if ( !stbir_resize_extended( &resize ) )+ {+ if ( optr )+ STBIR_FREE( optr, 0 );+ return 0;+ }++ return (optr) ? optr : output_pixels;+}+++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_edge edge, stbir_filter filter )+{+ STBIR_RESIZE resize;+ float * optr;+ int opitch;++ 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,+ pixel_layout, data_type );++ resize.horizontal_edge = edge;+ resize.vertical_edge = edge;+ resize.horizontal_filter = filter;+ resize.vertical_filter = filter;++ if ( !stbir_resize_extended( &resize ) )+ {+ if ( optr )+ STBIR_FREE( optr, 0 );+ return 0;+ }++ return (optr) ? optr : output_pixels;+}++#ifdef STBIR_PROFILE++STBIRDEF void stbir_resize_build_profile_info( STBIR_PROFILE_INFO * info, STBIR_RESIZE const * resize )+{+ static char const * bdescriptions[6] = { "Building", "Allocating", "Horizontal sampler", "Vertical sampler", "Coefficient cleanup", "Coefficient piovot" } ;+ stbir__info* samp = resize->samplers;+ int i;++ typedef int testa[ (STBIR__ARRAY_SIZE( bdescriptions ) == (STBIR__ARRAY_SIZE( samp->profile.array )-1) )?1:-1];+ typedef int testb[ (sizeof( samp->profile.array ) == (sizeof(samp->profile.named)) )?1:-1];+ typedef int testc[ (sizeof( info->clocks ) >= (sizeof(samp->profile.named)) )?1:-1];++ for( i = 0 ; i < STBIR__ARRAY_SIZE( bdescriptions ) ; i++)+ info->clocks[i] = samp->profile.array[i+1];++ info->total_clocks = samp->profile.named.total;+ info->descriptions = bdescriptions;+ info->count = STBIR__ARRAY_SIZE( bdescriptions );+}++STBIRDEF void stbir_resize_split_profile_info( STBIR_PROFILE_INFO * info, STBIR_RESIZE const * resize, int split_start, int split_count )+{+ static char const * descriptions[7] = { "Looping", "Vertical sampling", "Horizontal sampling", "Scanline input", "Scanline output", "Alpha weighting", "Alpha unweighting" };+ stbir__per_split_info * split_info;+ int s, i;++ typedef int testa[ (STBIR__ARRAY_SIZE( descriptions ) == (STBIR__ARRAY_SIZE( split_info->profile.array )-1) )?1:-1];+ typedef int testb[ (sizeof( split_info->profile.array ) == (sizeof(split_info->profile.named)) )?1:-1];+ typedef int testc[ (sizeof( info->clocks ) >= (sizeof(split_info->profile.named)) )?1:-1];++ if ( split_start == -1 )+ {+ split_start = 0;+ split_count = resize->samplers->splits;+ }++ if ( ( split_start >= resize->splits ) || ( split_start < 0 ) || ( ( split_start + split_count ) > resize->splits ) || ( split_count <= 0 ) )+ {+ info->total_clocks = 0;+ info->descriptions = 0;+ info->count = 0;+ return;+ }++ split_info = resize->samplers->split_info + split_start;++ // sum up the profile from all the splits+ for( i = 0 ; i < STBIR__ARRAY_SIZE( descriptions ) ; i++ )+ {+ stbir_uint64 sum = 0;+ for( s = 0 ; s < split_count ; s++ )+ sum += split_info[s].profile.array[i+1];+ info->clocks[i] = sum;+ }++ info->total_clocks = split_info->profile.named.total;+ info->descriptions = descriptions;+ info->count = STBIR__ARRAY_SIZE( descriptions );+}++STBIRDEF void stbir_resize_extended_profile_info( STBIR_PROFILE_INFO * info, STBIR_RESIZE const * resize )+{+ stbir_resize_split_profile_info( info, resize, -1, 0 );+}++#endif // STBIR_PROFILE++#undef STBIR_BGR+#undef STBIR_1CHANNEL+#undef STBIR_2CHANNEL+#undef STBIR_RGB+#undef STBIR_RGBA+#undef STBIR_4CHANNEL+#undef STBIR_BGRA+#undef STBIR_ARGB+#undef STBIR_ABGR+#undef STBIR_RA+#undef STBIR_AR+#undef STBIR_RGBA_PM+#undef STBIR_BGRA_PM+#undef STBIR_ARGB_PM+#undef STBIR_ABGR_PM+#undef STBIR_RA_PM+#undef STBIR_AR_PM++#endif // STB_IMAGE_RESIZE_IMPLEMENTATION++#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*++// by including the header file again this way, we can still debug the functions++#define STBIR_strs_join2( start, mid, end ) start##mid##end+#define STBIR_strs_join1( start, mid, end ) STBIR_strs_join2( start, mid, end )++#define STBIR_strs_join24( start, mid1, mid2, end ) start##mid1##mid2##end+#define STBIR_strs_join14( start, mid1, mid2, end ) STBIR_strs_join24( start, mid1, mid2, end )++#ifdef STB_IMAGE_RESIZE_DO_CODERS++#ifdef stbir__decode_suffix+#define STBIR__CODER_NAME( name ) STBIR_strs_join1( name, _, stbir__decode_suffix )+#else+#define STBIR__CODER_NAME( name ) name+#endif++#ifdef stbir__decode_swizzle+#define stbir__decode_simdf8_flip(reg) STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( stbir__simdf8_0123to,stbir__decode_order0,stbir__decode_order1),stbir__decode_order2,stbir__decode_order3),stbir__decode_order0,stbir__decode_order1),stbir__decode_order2,stbir__decode_order3)(reg, reg)+#define stbir__decode_simdf4_flip(reg) STBIR_strs_join1( STBIR_strs_join1( stbir__simdf_0123to,stbir__decode_order0,stbir__decode_order1),stbir__decode_order2,stbir__decode_order3)(reg, reg)+#define stbir__encode_simdf8_unflip(reg) STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( stbir__simdf8_0123to,stbir__encode_order0,stbir__encode_order1),stbir__encode_order2,stbir__encode_order3),stbir__encode_order0,stbir__encode_order1),stbir__encode_order2,stbir__encode_order3)(reg, reg)+#define stbir__encode_simdf4_unflip(reg) STBIR_strs_join1( STBIR_strs_join1( stbir__simdf_0123to,stbir__encode_order0,stbir__encode_order1),stbir__encode_order2,stbir__encode_order3)(reg, reg)+#else+#define stbir__decode_order0 0+#define stbir__decode_order1 1+#define stbir__decode_order2 2+#define stbir__decode_order3 3+#define stbir__encode_order0 0+#define stbir__encode_order1 1+#define stbir__encode_order2 2+#define stbir__encode_order3 3+#define stbir__decode_simdf8_flip(reg)+#define stbir__decode_simdf4_flip(reg)+#define stbir__encode_simdf8_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++static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * decodep, int width_times_channels, void const * inputp )+{+ float STBIR_STREAMOUT_PTR( * ) decode = decodep;+ float * decode_end = (float*) decode + width_times_channels;+ unsigned char const * input = (unsigned char const*)inputp;++ #ifdef STBIR_SIMD+ unsigned char const * end_input_m16 = input + width_times_channels - 16;+ if ( width_times_channels >= 16 )+ {+ decode_end -= 16;+ STBIR_NO_UNROLL_LOOP_START_INF_FOR+ for(;;)+ {+ #ifdef STBIR_SIMD8+ stbir__simdi i; stbir__simdi8 o0,o1;+ stbir__simdf8 of0, of1;+ STBIR_NO_UNROLL(decode);+ stbir__simdi_load( i, input );+ stbir__simdi8_expand_u8_to_u32( o0, o1, i );+ stbir__simdi8_convert_i32_to_float( of0, o0 );+ stbir__simdi8_convert_i32_to_float( of1, o1 );+ stbir__simdf8_mult( of0, of0, STBIR_max_uint8_as_float_inverted8);+ stbir__simdf8_mult( of1, of1, STBIR_max_uint8_as_float_inverted8);+ stbir__decode_simdf8_flip( of0 );+ stbir__decode_simdf8_flip( of1 );+ stbir__simdf8_store( decode + 0, of0 );+ stbir__simdf8_store( decode + 8, of1 );+ #else+ stbir__simdi i, o0, o1, o2, o3;+ stbir__simdf of0, of1, of2, of3;+ STBIR_NO_UNROLL(decode);+ stbir__simdi_load( i, input );+ stbir__simdi_expand_u8_to_u32( o0,o1,o2,o3,i);+ stbir__simdi_convert_i32_to_float( of0, o0 );+ stbir__simdi_convert_i32_to_float( of1, o1 );+ stbir__simdi_convert_i32_to_float( of2, o2 );+ stbir__simdi_convert_i32_to_float( of3, o3 );+ stbir__simdf_mult( of0, of0, STBIR__CONSTF(STBIR_max_uint8_as_float_inverted) );+ stbir__simdf_mult( of1, of1, STBIR__CONSTF(STBIR_max_uint8_as_float_inverted) );+ stbir__simdf_mult( of2, of2, STBIR__CONSTF(STBIR_max_uint8_as_float_inverted) );+ stbir__simdf_mult( of3, of3, STBIR__CONSTF(STBIR_max_uint8_as_float_inverted) );+ stbir__decode_simdf4_flip( of0 );+ stbir__decode_simdf4_flip( of1 );+ stbir__decode_simdf4_flip( of2 );+ stbir__decode_simdf4_flip( of3 );+ stbir__simdf_store( decode + 0, of0 );+ stbir__simdf_store( decode + 4, of1 );+ stbir__simdf_store( decode + 8, of2 );+ stbir__simdf_store( decode + 12, of3 );+ #endif+ decode += 16;+ input += 16;+ if ( decode <= decode_end )+ continue;+ if ( decode == ( decode_end + 16 ) )+ break;+ decode = decode_end; // backup and do last couple+ input = end_input_m16;+ }+ return;+ }+ #endif++ // 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);+ decode[0-4] = ((float)(input[stbir__decode_order0])) * stbir__max_uint8_as_float_inverted;+ decode[1-4] = ((float)(input[stbir__decode_order1])) * stbir__max_uint8_as_float_inverted;+ decode[2-4] = ((float)(input[stbir__decode_order2])) * stbir__max_uint8_as_float_inverted;+ decode[3-4] = ((float)(input[stbir__decode_order3])) * stbir__max_uint8_as_float_inverted;+ decode += 4;+ input += 4;+ }+ decode -= 4;+ #endif++ // do the remnants+ #if stbir__coder_min_num < 4+ STBIR_NO_UNROLL_LOOP_START+ while( decode < decode_end )+ {+ STBIR_NO_UNROLL(decode);+ decode[0] = ((float)(input[stbir__decode_order0])) * stbir__max_uint8_as_float_inverted;+ #if stbir__coder_min_num >= 2+ decode[1] = ((float)(input[stbir__decode_order1])) * stbir__max_uint8_as_float_inverted;+ #endif+ #if stbir__coder_min_num >= 3+ decode[2] = ((float)(input[stbir__decode_order2])) * stbir__max_uint8_as_float_inverted;+ #endif+ decode += stbir__coder_min_num;+ input += stbir__coder_min_num;+ }+ #endif+}++static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outputp, int width_times_channels, float const * encode )+{+ unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char *) outputp;+ unsigned char * end_output = ( (unsigned char *) output ) + width_times_channels;++ #ifdef STBIR_SIMD+ if ( width_times_channels >= stbir__simdfX_float_count*2 )+ {+ 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;+ stbir__simdi i;+ STBIR_SIMD_NO_UNROLL(encode);+ stbir__simdfX_madd_mem( e0, STBIR_simd_point5X, STBIR_max_uint8_as_floatX, encode );+ stbir__simdfX_madd_mem( e1, STBIR_simd_point5X, STBIR_max_uint8_as_floatX, encode+stbir__simdfX_float_count );+ stbir__encode_simdfX_unflip( e0 );+ stbir__encode_simdfX_unflip( e1 );+ #ifdef STBIR_SIMD8+ stbir__simdf8_pack_to_16bytes( i, e0, e1 );+ stbir__simdi_store( output, i );+ #else+ 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 )+ continue;+ if ( output == ( end_output + stbir__simdfX_float_count*2 ) )+ break;+ output = end_output; // backup and do last couple+ encode = end_encode_m8;+ }+ return;+ }++ // 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;+ stbir__simdi i0;+ STBIR_NO_UNROLL(encode);+ stbir__simdf_load( e0, encode );+ stbir__simdf_madd( e0, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint8_as_float), e0 );+ stbir__encode_simdf4_unflip( e0 );+ stbir__simdf_pack_to_8bytes( i0, e0, e0 ); // only use first 4+ *(int*)(output-4) = stbir__simdi_to_int( i0 );+ output += 4;+ encode += 4;+ }+ output -= 4;+ #endif++ // do the remnants+ #if stbir__coder_min_num < 4+ STBIR_NO_UNROLL_LOOP_START+ while( output < end_output )+ {+ 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+ stbir__simdf_madd1_mem( e0, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint8_as_float), encode+stbir__encode_order1 ); output[1] = stbir__simdf_convert_float_to_uint8( e0 );+ #endif+ #if stbir__coder_min_num >= 3+ stbir__simdf_madd1_mem( e0, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint8_as_float), encode+stbir__encode_order2 ); output[2] = stbir__simdf_convert_float_to_uint8( e0 );+ #endif+ output += stbir__coder_min_num;+ 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;+ while( output <= end_output )+ {+ float f;+ f = encode[stbir__encode_order0] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[0-4] = (unsigned char)f;+ f = encode[stbir__encode_order1] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[1-4] = (unsigned char)f;+ f = encode[stbir__encode_order2] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[2-4] = (unsigned char)f;+ f = encode[stbir__encode_order3] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[3-4] = (unsigned char)f;+ output += 4;+ encode += 4;+ }+ output -= 4;+ #endif++ // do the remnants+ #if stbir__coder_min_num < 4+ STBIR_NO_UNROLL_LOOP_START+ while( output < end_output )+ {+ float f;+ STBIR_NO_UNROLL(encode);+ f = encode[stbir__encode_order0] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[0] = (unsigned char)f;+ #if stbir__coder_min_num >= 2+ f = encode[stbir__encode_order1] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[1] = (unsigned char)f;+ #endif+ #if stbir__coder_min_num >= 3+ f = encode[stbir__encode_order2] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[2] = (unsigned char)f;+ #endif+ output += stbir__coder_min_num;+ encode += stbir__coder_min_num;+ }+ #endif+ #endif+}++static void STBIR__CODER_NAME(stbir__decode_uint8_linear)( float * decodep, int width_times_channels, void const * inputp )+{+ float STBIR_STREAMOUT_PTR( * ) decode = decodep;+ float * decode_end = (float*) decode + width_times_channels;+ unsigned char const * input = (unsigned char const*)inputp;++ #ifdef STBIR_SIMD+ unsigned char const * end_input_m16 = input + width_times_channels - 16;+ if ( width_times_channels >= 16 )+ {+ decode_end -= 16;+ STBIR_NO_UNROLL_LOOP_START_INF_FOR+ for(;;)+ {+ #ifdef STBIR_SIMD8+ stbir__simdi i; stbir__simdi8 o0,o1;+ stbir__simdf8 of0, of1;+ STBIR_NO_UNROLL(decode);+ stbir__simdi_load( i, input );+ stbir__simdi8_expand_u8_to_u32( o0, o1, i );+ stbir__simdi8_convert_i32_to_float( of0, o0 );+ stbir__simdi8_convert_i32_to_float( of1, o1 );+ stbir__decode_simdf8_flip( of0 );+ stbir__decode_simdf8_flip( of1 );+ stbir__simdf8_store( decode + 0, of0 );+ stbir__simdf8_store( decode + 8, of1 );+ #else+ stbir__simdi i, o0, o1, o2, o3;+ stbir__simdf of0, of1, of2, of3;+ STBIR_NO_UNROLL(decode);+ stbir__simdi_load( i, input );+ stbir__simdi_expand_u8_to_u32( o0,o1,o2,o3,i);+ stbir__simdi_convert_i32_to_float( of0, o0 );+ stbir__simdi_convert_i32_to_float( of1, o1 );+ stbir__simdi_convert_i32_to_float( of2, o2 );+ stbir__simdi_convert_i32_to_float( of3, o3 );+ stbir__decode_simdf4_flip( of0 );+ stbir__decode_simdf4_flip( of1 );+ stbir__decode_simdf4_flip( of2 );+ stbir__decode_simdf4_flip( of3 );+ stbir__simdf_store( decode + 0, of0 );+ stbir__simdf_store( decode + 4, of1 );+ stbir__simdf_store( decode + 8, of2 );+ stbir__simdf_store( decode + 12, of3 );+#endif+ decode += 16;+ input += 16;+ if ( decode <= decode_end )+ continue;+ if ( decode == ( decode_end + 16 ) )+ break;+ decode = decode_end; // backup and do last couple+ input = end_input_m16;+ }+ return;+ }+ #endif++ // 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);+ decode[0-4] = ((float)(input[stbir__decode_order0]));+ decode[1-4] = ((float)(input[stbir__decode_order1]));+ decode[2-4] = ((float)(input[stbir__decode_order2]));+ decode[3-4] = ((float)(input[stbir__decode_order3]));+ decode += 4;+ input += 4;+ }+ decode -= 4;+ #endif++ // do the remnants+ #if stbir__coder_min_num < 4+ STBIR_NO_UNROLL_LOOP_START+ while( decode < decode_end )+ {+ STBIR_NO_UNROLL(decode);+ decode[0] = ((float)(input[stbir__decode_order0]));+ #if stbir__coder_min_num >= 2+ decode[1] = ((float)(input[stbir__decode_order1]));+ #endif+ #if stbir__coder_min_num >= 3+ decode[2] = ((float)(input[stbir__decode_order2]));+ #endif+ decode += stbir__coder_min_num;+ input += stbir__coder_min_num;+ }+ #endif+}++static void STBIR__CODER_NAME( stbir__encode_uint8_linear )( void * outputp, int width_times_channels, float const * encode )+{+ unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char *) outputp;+ unsigned char * end_output = ( (unsigned char *) output ) + width_times_channels;++ #ifdef STBIR_SIMD+ if ( width_times_channels >= stbir__simdfX_float_count*2 )+ {+ 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;+ stbir__simdi i;+ STBIR_SIMD_NO_UNROLL(encode);+ stbir__simdfX_add_mem( e0, STBIR_simd_point5X, encode );+ stbir__simdfX_add_mem( e1, STBIR_simd_point5X, encode+stbir__simdfX_float_count );+ stbir__encode_simdfX_unflip( e0 );+ stbir__encode_simdfX_unflip( e1 );+ #ifdef STBIR_SIMD8+ stbir__simdf8_pack_to_16bytes( i, e0, e1 );+ stbir__simdi_store( output, i );+ #else+ 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 )+ continue;+ if ( output == ( end_output + stbir__simdfX_float_count*2 ) )+ break;+ output = end_output; // backup and do last couple+ encode = end_encode_m8;+ }+ return;+ }++ // 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;+ stbir__simdi i0;+ STBIR_NO_UNROLL(encode);+ stbir__simdf_load( e0, encode );+ stbir__simdf_add( e0, STBIR__CONSTF(STBIR_simd_point5), e0 );+ stbir__encode_simdf4_unflip( e0 );+ stbir__simdf_pack_to_8bytes( i0, e0, e0 ); // only use first 4+ *(int*)(output-4) = stbir__simdi_to_int( i0 );+ output += 4;+ encode += 4;+ }+ output -= 4;+ #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;+ while( output <= end_output )+ {+ float f;+ f = encode[stbir__encode_order0] + 0.5f; STBIR_CLAMP(f, 0, 255); output[0-4] = (unsigned char)f;+ f = encode[stbir__encode_order1] + 0.5f; STBIR_CLAMP(f, 0, 255); output[1-4] = (unsigned char)f;+ f = encode[stbir__encode_order2] + 0.5f; STBIR_CLAMP(f, 0, 255); output[2-4] = (unsigned char)f;+ f = encode[stbir__encode_order3] + 0.5f; STBIR_CLAMP(f, 0, 255); output[3-4] = (unsigned char)f;+ output += 4;+ encode += 4;+ }+ output -= 4;+ #endif++ #endif++ // do the remnants+ #if stbir__coder_min_num < 4+ STBIR_NO_UNROLL_LOOP_START+ while( output < end_output )+ {+ float f;+ STBIR_NO_UNROLL(encode);+ f = encode[stbir__encode_order0] + 0.5f; STBIR_CLAMP(f, 0, 255); output[0] = (unsigned char)f;+ #if stbir__coder_min_num >= 2+ f = encode[stbir__encode_order1] + 0.5f; STBIR_CLAMP(f, 0, 255); output[1] = (unsigned char)f;+ #endif+ #if stbir__coder_min_num >= 3+ f = encode[stbir__encode_order2] + 0.5f; STBIR_CLAMP(f, 0, 255); output[2] = (unsigned char)f;+ #endif+ output += stbir__coder_min_num;+ encode += stbir__coder_min_num;+ }+ #endif+}++static void STBIR__CODER_NAME(stbir__decode_uint8_srgb)( float * decodep, int width_times_channels, void const * inputp )+{+ float STBIR_STREAMOUT_PTR( * ) decode = decodep;+ float const * decode_end = (float*) decode + width_times_channels;+ unsigned char const * input = (unsigned char const *)inputp;++ // try to do blocks of 4 when you can+ #if stbir__coder_min_num != 3 // doesn't divide cleanly by four+ decode += 4;+ while( decode <= decode_end )+ {+ decode[0-4] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order0 ] ];+ decode[1-4] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order1 ] ];+ decode[2-4] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order2 ] ];+ decode[3-4] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order3 ] ];+ decode += 4;+ input += 4;+ }+ decode -= 4;+ #endif++ // do the remnants+ #if stbir__coder_min_num < 4+ STBIR_NO_UNROLL_LOOP_START+ while( decode < decode_end )+ {+ STBIR_NO_UNROLL(decode);+ decode[0] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order0 ] ];+ #if stbir__coder_min_num >= 2+ decode[1] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order1 ] ];+ #endif+ #if stbir__coder_min_num >= 3+ decode[2] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order2 ] ];+ #endif+ decode += stbir__coder_min_num;+ input += stbir__coder_min_num;+ }+ #endif+}++#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 );++#define stbir__scale_and_convert( i, f ) \+ stbir__simdf_madd( f, STBIR__CONSTF( STBIR_simd_point5 ), STBIR__CONSTF( STBIR_max_uint8_as_float ), f ); \+ stbir__simdf_max( f, f, stbir__simdf_zeroP() ); \+ stbir__simdf_min( f, f, STBIR__CONSTF( STBIR_max_uint8_as_float ) ); \+ stbir__simdf_convert_float_to_i32( i, f );++#define stbir__linear_to_srgb_finish( i, f ) \+{ \+ stbir__simdi temp; \+ stbir__simdi_32shr( temp, stbir_simdi_castf( f ), 12 ) ; \+ stbir__simdi_and( temp, temp, STBIR__CONSTI(STBIR_mastissa_mask) ); \+ stbir__simdi_or( temp, temp, STBIR__CONSTI(STBIR_topscale) ); \+ stbir__simdi_16madd( i, i, temp ); \+ stbir__simdi_32shr( i, i, 16 ); \+}++#define stbir__simdi_table_lookup2( v0,v1, table ) \+{ \+ stbir__simdi_u32 temp0,temp1; \+ temp0.m128i_i128 = v0; \+ temp1.m128i_i128 = v1; \+ temp0.m128i_u32[0] = table[temp0.m128i_i32[0]]; temp0.m128i_u32[1] = table[temp0.m128i_i32[1]]; temp0.m128i_u32[2] = table[temp0.m128i_i32[2]]; temp0.m128i_u32[3] = table[temp0.m128i_i32[3]]; \+ 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 ) \+{ \+ stbir__simdi_u32 temp0,temp1,temp2; \+ temp0.m128i_i128 = v0; \+ temp1.m128i_i128 = v1; \+ temp2.m128i_i128 = v2; \+ temp0.m128i_u32[0] = table[temp0.m128i_i32[0]]; temp0.m128i_u32[1] = table[temp0.m128i_i32[1]]; temp0.m128i_u32[2] = table[temp0.m128i_i32[2]]; temp0.m128i_u32[3] = table[temp0.m128i_i32[3]]; \+ 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]]; \+ temp2.m128i_u32[0] = table[temp2.m128i_i32[0]]; temp2.m128i_u32[1] = table[temp2.m128i_i32[1]]; temp2.m128i_u32[2] = table[temp2.m128i_i32[2]]; temp2.m128i_u32[3] = table[temp2.m128i_i32[3]]; \+ v0 = temp0.m128i_i128; \+ v1 = temp1.m128i_i128; \+ v2 = temp2.m128i_i128; \+}++#define stbir__simdi_table_lookup4( v0,v1,v2,v3, table ) \+{ \+ stbir__simdi_u32 temp0,temp1,temp2,temp3; \+ temp0.m128i_i128 = v0; \+ temp1.m128i_i128 = v1; \+ temp2.m128i_i128 = v2; \+ temp3.m128i_i128 = v3; \+ temp0.m128i_u32[0] = table[temp0.m128i_i32[0]]; temp0.m128i_u32[1] = table[temp0.m128i_i32[1]]; temp0.m128i_u32[2] = table[temp0.m128i_i32[2]]; temp0.m128i_u32[3] = table[temp0.m128i_i32[3]]; \+ 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]]; \+ temp2.m128i_u32[0] = table[temp2.m128i_i32[0]]; temp2.m128i_u32[1] = table[temp2.m128i_i32[1]]; temp2.m128i_u32[2] = table[temp2.m128i_i32[2]]; temp2.m128i_u32[3] = table[temp2.m128i_i32[3]]; \+ temp3.m128i_u32[0] = table[temp3.m128i_i32[0]]; temp3.m128i_u32[1] = table[temp3.m128i_i32[1]]; temp3.m128i_u32[2] = table[temp3.m128i_i32[2]]; temp3.m128i_u32[3] = table[temp3.m128i_i32[3]]; \+ v0 = temp0.m128i_i128; \+ 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 )+{+ unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char*) outputp;+ unsigned char * end_output = ( (unsigned char*) output ) + width_times_channels;++ #ifdef STBIR_SIMD++ 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_SIMD_NO_UNROLL(encode);++ stbir__simdf_load4_transposed( f0, f1, f2, f3, encode );++ stbir__min_max_shift20( i0, f0 );+ 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, ( 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 );+ stbir__linear_to_srgb_finish( i3, f3 );++ stbir__interleave_pack_and_store_16_u8( output, STBIR_strs_join1(i, ,stbir__encode_order0), STBIR_strs_join1(i, ,stbir__encode_order1), STBIR_strs_join1(i, ,stbir__encode_order2), STBIR_strs_join1(i, ,stbir__encode_order3) );++ encode += 16;+ output += 16;+ if ( output <= end_output )+ continue;+ if ( output == ( end_output + 16 ) )+ break;+ output = end_output; // backup and do last couple+ encode = end_encode_m16;+ }+ return;+ }+ #endif++ // 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);++ output[0-4] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order0] );+ output[1-4] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order1] );+ output[2-4] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order2] );+ output[3-4] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order3] );++ output += 4;+ encode += 4;+ }+ output -= 4;+ #endif++ // do the remnants+ #if stbir__coder_min_num < 4+ STBIR_NO_UNROLL_LOOP_START+ while( output < end_output )+ {+ STBIR_NO_UNROLL(encode);+ output[0] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order0] );+ #if stbir__coder_min_num >= 2+ output[1] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order1] );+ #endif+ #if stbir__coder_min_num >= 3+ output[2] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order2] );+ #endif+ output += stbir__coder_min_num;+ encode += stbir__coder_min_num;+ }+ #endif+}++#if ( stbir__coder_min_num == 4 ) || ( ( stbir__coder_min_num == 1 ) && ( !defined(stbir__decode_swizzle) ) )++static void STBIR__CODER_NAME(stbir__decode_uint8_srgb4_linearalpha)( float * decodep, int width_times_channels, void const * inputp )+{+ float STBIR_STREAMOUT_PTR( * ) decode = decodep;+ float const * decode_end = (float*) decode + width_times_channels;+ unsigned char const * input = (unsigned char const *)inputp;+ do {+ decode[0] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order0] ];+ decode[1] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order1] ];+ decode[2] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order2] ];+ decode[3] = ( (float) input[stbir__decode_order3] ) * stbir__max_uint8_as_float_inverted;+ input += 4;+ decode += 4;+ } while( decode < decode_end );+}+++static void STBIR__CODER_NAME( stbir__encode_uint8_srgb4_linearalpha )( void * outputp, int width_times_channels, float const * encode )+{+ unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char*) outputp;+ unsigned char * end_output = ( (unsigned char*) output ) + width_times_channels;++ #ifdef STBIR_SIMD++ 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_SIMD_NO_UNROLL(encode);+ stbir__simdf_load4_transposed( f0, f1, f2, f3, encode );++ 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, ( 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 );++ stbir__interleave_pack_and_store_16_u8( output, STBIR_strs_join1(i, ,stbir__encode_order0), STBIR_strs_join1(i, ,stbir__encode_order1), STBIR_strs_join1(i, ,stbir__encode_order2), STBIR_strs_join1(i, ,stbir__encode_order3) );++ output += 16;+ encode += 16;++ if ( output <= end_output )+ continue;+ if ( output == ( end_output + 16 ) )+ break;+ output = end_output; // backup and do last couple+ encode = end_encode_m16;+ }+ return;+ }+ #endif++ STBIR_SIMD_NO_UNROLL_LOOP_START+ do {+ float f;+ 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] );+ output[stbir__decode_order2] = stbir__linear_to_srgb_uchar( encode[2] );++ f = encode[3] * stbir__max_uint8_as_float + 0.5f;+ STBIR_CLAMP(f, 0, 255);+ output[stbir__decode_order3] = (unsigned char) f;++ output += 4;+ encode += 4;+ } while( output < end_output );+}++#endif++#if ( stbir__coder_min_num == 2 ) || ( ( stbir__coder_min_num == 1 ) && ( !defined(stbir__decode_swizzle) ) )++static void STBIR__CODER_NAME(stbir__decode_uint8_srgb2_linearalpha)( float * decodep, int width_times_channels, void const * inputp )+{+ float STBIR_STREAMOUT_PTR( * ) decode = decodep;+ float const * decode_end = (float*) decode + width_times_channels;+ unsigned char const * input = (unsigned char const *)inputp;+ decode += 4;+ while( decode <= decode_end )+ {+ decode[0-4] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order0] ];+ decode[1-4] = ( (float) input[stbir__decode_order1] ) * stbir__max_uint8_as_float_inverted;+ decode[2-4] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order0+2] ];+ decode[3-4] = ( (float) input[stbir__decode_order1+2] ) * stbir__max_uint8_as_float_inverted;+ input += 4;+ decode += 4;+ }+ decode -= 4;+ 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;+ }+}++static void STBIR__CODER_NAME( stbir__encode_uint8_srgb2_linearalpha )( void * outputp, int width_times_channels, float const * encode )+{+ unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char*) outputp;+ unsigned char * end_output = ( (unsigned char*) output ) + width_times_channels;++ #ifdef STBIR_SIMD++ 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_SIMD_NO_UNROLL(encode);+ stbir__simdf_load4_transposed( f0, f1, f2, f3, encode );++ stbir__min_max_shift20( i0, f0 );+ stbir__scale_and_convert( i1, f1 );+ stbir__min_max_shift20( i2, f2 );+ stbir__scale_and_convert( i3, f3 );++ 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 );++ stbir__interleave_pack_and_store_16_u8( output, STBIR_strs_join1(i, ,stbir__encode_order0), STBIR_strs_join1(i, ,stbir__encode_order1), STBIR_strs_join1(i, ,stbir__encode_order2), STBIR_strs_join1(i, ,stbir__encode_order3) );++ output += 16;+ encode += 16;+ if ( output <= end_output )+ continue;+ if ( output == ( end_output + 16 ) )+ break;+ output = end_output; // backup and do last couple+ encode = end_encode_m16;+ }+ return;+ }+ #endif++ STBIR_SIMD_NO_UNROLL_LOOP_START+ do {+ float f;+ STBIR_SIMD_NO_UNROLL(encode);++ output[stbir__decode_order0] = stbir__linear_to_srgb_uchar( encode[0] );++ f = encode[1] * stbir__max_uint8_as_float + 0.5f;+ STBIR_CLAMP(f, 0, 255);+ output[stbir__decode_order1] = (unsigned char) f;++ output += 2;+ encode += 2;+ } while( output < end_output );+}++#endif++static void STBIR__CODER_NAME(stbir__decode_uint16_linear_scaled)( float * decodep, int width_times_channels, void const * inputp )+{+ float STBIR_STREAMOUT_PTR( * ) decode = decodep;+ float * decode_end = (float*) decode + width_times_channels;+ unsigned short const * input = (unsigned short const *)inputp;++ #ifdef STBIR_SIMD+ unsigned short const * end_input_m8 = input + width_times_channels - 8;+ if ( width_times_channels >= 8 )+ {+ decode_end -= 8;+ STBIR_NO_UNROLL_LOOP_START_INF_FOR+ for(;;)+ {+ #ifdef STBIR_SIMD8+ stbir__simdi i; stbir__simdi8 o;+ stbir__simdf8 of;+ STBIR_NO_UNROLL(decode);+ stbir__simdi_load( i, input );+ stbir__simdi8_expand_u16_to_u32( o, i );+ stbir__simdi8_convert_i32_to_float( of, o );+ stbir__simdf8_mult( of, of, STBIR_max_uint16_as_float_inverted8);+ stbir__decode_simdf8_flip( of );+ stbir__simdf8_store( decode + 0, of );+ #else+ stbir__simdi i, o0, o1;+ stbir__simdf of0, of1;+ STBIR_NO_UNROLL(decode);+ stbir__simdi_load( i, input );+ stbir__simdi_expand_u16_to_u32( o0,o1,i );+ stbir__simdi_convert_i32_to_float( of0, o0 );+ stbir__simdi_convert_i32_to_float( of1, o1 );+ stbir__simdf_mult( of0, of0, STBIR__CONSTF(STBIR_max_uint16_as_float_inverted) );+ stbir__simdf_mult( of1, of1, STBIR__CONSTF(STBIR_max_uint16_as_float_inverted));+ stbir__decode_simdf4_flip( of0 );+ stbir__decode_simdf4_flip( of1 );+ stbir__simdf_store( decode + 0, of0 );+ stbir__simdf_store( decode + 4, of1 );+ #endif+ decode += 8;+ input += 8;+ if ( decode <= decode_end )+ continue;+ if ( decode == ( decode_end + 8 ) )+ break;+ decode = decode_end; // backup and do last couple+ input = end_input_m8;+ }+ return;+ }+ #endif++ // 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);+ decode[0-4] = ((float)(input[stbir__decode_order0])) * stbir__max_uint16_as_float_inverted;+ decode[1-4] = ((float)(input[stbir__decode_order1])) * stbir__max_uint16_as_float_inverted;+ decode[2-4] = ((float)(input[stbir__decode_order2])) * stbir__max_uint16_as_float_inverted;+ decode[3-4] = ((float)(input[stbir__decode_order3])) * stbir__max_uint16_as_float_inverted;+ decode += 4;+ input += 4;+ }+ decode -= 4;+ #endif++ // do the remnants+ #if stbir__coder_min_num < 4+ STBIR_NO_UNROLL_LOOP_START+ while( decode < decode_end )+ {+ STBIR_NO_UNROLL(decode);+ decode[0] = ((float)(input[stbir__decode_order0])) * stbir__max_uint16_as_float_inverted;+ #if stbir__coder_min_num >= 2+ decode[1] = ((float)(input[stbir__decode_order1])) * stbir__max_uint16_as_float_inverted;+ #endif+ #if stbir__coder_min_num >= 3+ decode[2] = ((float)(input[stbir__decode_order2])) * stbir__max_uint16_as_float_inverted;+ #endif+ decode += stbir__coder_min_num;+ input += stbir__coder_min_num;+ }+ #endif+}+++static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * outputp, int width_times_channels, float const * encode )+{+ unsigned short STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned short*) outputp;+ unsigned short * end_output = ( (unsigned short*) output ) + width_times_channels;++ #ifdef STBIR_SIMD+ {+ if ( width_times_channels >= stbir__simdfX_float_count*2 )+ {+ 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;+ stbir__simdiX i;+ STBIR_SIMD_NO_UNROLL(encode);+ stbir__simdfX_madd_mem( e0, STBIR_simd_point5X, STBIR_max_uint16_as_floatX, encode );+ stbir__simdfX_madd_mem( e1, STBIR_simd_point5X, STBIR_max_uint16_as_floatX, encode+stbir__simdfX_float_count );+ stbir__encode_simdfX_unflip( e0 );+ stbir__encode_simdfX_unflip( e1 );+ stbir__simdfX_pack_to_words( i, e0, e1 );+ stbir__simdiX_store( output, i );+ encode += stbir__simdfX_float_count*2;+ output += stbir__simdfX_float_count*2;+ if ( output <= end_output )+ continue;+ if ( output == ( end_output + stbir__simdfX_float_count*2 ) )+ break;+ output = end_output; // backup and do last couple+ encode = end_encode_m8;+ }+ return;+ }+ }++ // 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;+ stbir__simdi i;+ STBIR_NO_UNROLL(encode);+ stbir__simdf_load( e, encode );+ stbir__simdf_madd( e, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint16_as_float), e );+ stbir__encode_simdf4_unflip( e );+ stbir__simdf_pack_to_8words( i, e, e ); // only use first 4+ stbir__simdi_store2( output-4, i );+ output += 4;+ encode += 4;+ }+ output -= 4;+ #endif++ // do the remnants+ #if stbir__coder_min_num < 4+ STBIR_NO_UNROLL_LOOP_START+ while( output < end_output )+ {+ stbir__simdf e;+ STBIR_NO_UNROLL(encode);+ stbir__simdf_madd1_mem( e, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint16_as_float), encode+stbir__encode_order0 ); output[0] = stbir__simdf_convert_float_to_short( e );+ #if stbir__coder_min_num >= 2+ stbir__simdf_madd1_mem( e, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint16_as_float), encode+stbir__encode_order1 ); output[1] = stbir__simdf_convert_float_to_short( e );+ #endif+ #if stbir__coder_min_num >= 3+ stbir__simdf_madd1_mem( e, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint16_as_float), encode+stbir__encode_order2 ); output[2] = stbir__simdf_convert_float_to_short( e );+ #endif+ output += stbir__coder_min_num;+ 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;+ STBIR_SIMD_NO_UNROLL(encode);+ f = encode[stbir__encode_order0] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[0-4] = (unsigned short)f;+ f = encode[stbir__encode_order1] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[1-4] = (unsigned short)f;+ f = encode[stbir__encode_order2] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[2-4] = (unsigned short)f;+ f = encode[stbir__encode_order3] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[3-4] = (unsigned short)f;+ output += 4;+ encode += 4;+ }+ output -= 4;+ #endif++ // do the remnants+ #if stbir__coder_min_num < 4+ STBIR_NO_UNROLL_LOOP_START+ while( output < end_output )+ {+ float f;+ STBIR_NO_UNROLL(encode);+ f = encode[stbir__encode_order0] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[0] = (unsigned short)f;+ #if stbir__coder_min_num >= 2+ f = encode[stbir__encode_order1] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[1] = (unsigned short)f;+ #endif+ #if stbir__coder_min_num >= 3+ f = encode[stbir__encode_order2] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[2] = (unsigned short)f;+ #endif+ output += stbir__coder_min_num;+ encode += stbir__coder_min_num;+ }+ #endif+ #endif+}++static void STBIR__CODER_NAME(stbir__decode_uint16_linear)( float * decodep, int width_times_channels, void const * inputp )+{+ float STBIR_STREAMOUT_PTR( * ) decode = decodep;+ float * decode_end = (float*) decode + width_times_channels;+ unsigned short const * input = (unsigned short const *)inputp;++ #ifdef STBIR_SIMD+ unsigned short const * end_input_m8 = input + width_times_channels - 8;+ if ( width_times_channels >= 8 )+ {+ decode_end -= 8;+ STBIR_NO_UNROLL_LOOP_START_INF_FOR+ for(;;)+ {+ #ifdef STBIR_SIMD8+ stbir__simdi i; stbir__simdi8 o;+ stbir__simdf8 of;+ STBIR_NO_UNROLL(decode);+ stbir__simdi_load( i, input );+ stbir__simdi8_expand_u16_to_u32( o, i );+ stbir__simdi8_convert_i32_to_float( of, o );+ stbir__decode_simdf8_flip( of );+ stbir__simdf8_store( decode + 0, of );+ #else+ stbir__simdi i, o0, o1;+ stbir__simdf of0, of1;+ STBIR_NO_UNROLL(decode);+ stbir__simdi_load( i, input );+ stbir__simdi_expand_u16_to_u32( o0, o1, i );+ stbir__simdi_convert_i32_to_float( of0, o0 );+ stbir__simdi_convert_i32_to_float( of1, o1 );+ stbir__decode_simdf4_flip( of0 );+ stbir__decode_simdf4_flip( of1 );+ stbir__simdf_store( decode + 0, of0 );+ stbir__simdf_store( decode + 4, of1 );+ #endif+ decode += 8;+ input += 8;+ if ( decode <= decode_end )+ continue;+ if ( decode == ( decode_end + 8 ) )+ break;+ decode = decode_end; // backup and do last couple+ input = end_input_m8;+ }+ return;+ }+ #endif++ // 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);+ decode[0-4] = ((float)(input[stbir__decode_order0]));+ decode[1-4] = ((float)(input[stbir__decode_order1]));+ decode[2-4] = ((float)(input[stbir__decode_order2]));+ decode[3-4] = ((float)(input[stbir__decode_order3]));+ decode += 4;+ input += 4;+ }+ decode -= 4;+ #endif++ // do the remnants+ #if stbir__coder_min_num < 4+ STBIR_NO_UNROLL_LOOP_START+ while( decode < decode_end )+ {+ STBIR_NO_UNROLL(decode);+ decode[0] = ((float)(input[stbir__decode_order0]));+ #if stbir__coder_min_num >= 2+ decode[1] = ((float)(input[stbir__decode_order1]));+ #endif+ #if stbir__coder_min_num >= 3+ decode[2] = ((float)(input[stbir__decode_order2]));+ #endif+ decode += stbir__coder_min_num;+ input += stbir__coder_min_num;+ }+ #endif+}++static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int width_times_channels, float const * encode )+{+ unsigned short STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned short*) outputp;+ unsigned short * end_output = ( (unsigned short*) output ) + width_times_channels;++ #ifdef STBIR_SIMD+ {+ if ( width_times_channels >= stbir__simdfX_float_count*2 )+ {+ 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;+ stbir__simdiX i;+ STBIR_SIMD_NO_UNROLL(encode);+ stbir__simdfX_add_mem( e0, STBIR_simd_point5X, encode );+ stbir__simdfX_add_mem( e1, STBIR_simd_point5X, encode+stbir__simdfX_float_count );+ stbir__encode_simdfX_unflip( e0 );+ stbir__encode_simdfX_unflip( e1 );+ stbir__simdfX_pack_to_words( i, e0, e1 );+ stbir__simdiX_store( output, i );+ encode += stbir__simdfX_float_count*2;+ output += stbir__simdfX_float_count*2;+ if ( output <= end_output )+ continue;+ if ( output == ( end_output + stbir__simdfX_float_count*2 ) )+ break;+ output = end_output; // backup and do last couple+ encode = end_encode_m8;+ }+ return;+ }+ }++ // 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;+ stbir__simdi i;+ STBIR_NO_UNROLL(encode);+ stbir__simdf_load( e, encode );+ stbir__simdf_add( e, STBIR__CONSTF(STBIR_simd_point5), e );+ stbir__encode_simdf4_unflip( e );+ stbir__simdf_pack_to_8words( i, e, e ); // only use first 4+ stbir__simdi_store2( output-4, i );+ output += 4;+ encode += 4;+ }+ output -= 4;+ #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;+ STBIR_SIMD_NO_UNROLL(encode);+ f = encode[stbir__encode_order0] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[0-4] = (unsigned short)f;+ f = encode[stbir__encode_order1] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[1-4] = (unsigned short)f;+ f = encode[stbir__encode_order2] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[2-4] = (unsigned short)f;+ f = encode[stbir__encode_order3] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[3-4] = (unsigned short)f;+ output += 4;+ encode += 4;+ }+ output -= 4;+ #endif++ #endif++ // do the remnants+ #if stbir__coder_min_num < 4+ STBIR_NO_UNROLL_LOOP_START+ while( output < end_output )+ {+ float f;+ STBIR_NO_UNROLL(encode);+ f = encode[stbir__encode_order0] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[0] = (unsigned short)f;+ #if stbir__coder_min_num >= 2+ f = encode[stbir__encode_order1] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[1] = (unsigned short)f;+ #endif+ #if stbir__coder_min_num >= 3+ f = encode[stbir__encode_order2] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[2] = (unsigned short)f;+ #endif+ output += stbir__coder_min_num;+ encode += stbir__coder_min_num;+ }+ #endif+}++static void STBIR__CODER_NAME(stbir__decode_half_float_linear)( float * decodep, int width_times_channels, void const * inputp )+{+ float STBIR_STREAMOUT_PTR( * ) decode = decodep;+ float * decode_end = (float*) decode + width_times_channels;+ stbir__FP16 const * input = (stbir__FP16 const *)inputp;++ #ifdef STBIR_SIMD+ if ( width_times_channels >= 8 )+ {+ 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);++ stbir__half_to_float_SIMD( decode, input );+ #ifdef stbir__decode_swizzle+ #ifdef STBIR_SIMD8+ {+ stbir__simdf8 of;+ stbir__simdf8_load( of, decode );+ stbir__decode_simdf8_flip( of );+ stbir__simdf8_store( decode, of );+ }+ #else+ {+ stbir__simdf of0,of1;+ stbir__simdf_load( of0, decode );+ stbir__simdf_load( of1, decode+4 );+ stbir__decode_simdf4_flip( of0 );+ stbir__decode_simdf4_flip( of1 );+ stbir__simdf_store( decode, of0 );+ stbir__simdf_store( decode+4, of1 );+ }+ #endif+ #endif+ decode += 8;+ input += 8;+ if ( decode <= decode_end )+ continue;+ if ( decode == ( decode_end + 8 ) )+ break;+ decode = decode_end; // backup and do last couple+ input = end_input_m8;+ }+ return;+ }+ #endif++ // 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);+ decode[0-4] = stbir__half_to_float(input[stbir__decode_order0]);+ decode[1-4] = stbir__half_to_float(input[stbir__decode_order1]);+ decode[2-4] = stbir__half_to_float(input[stbir__decode_order2]);+ decode[3-4] = stbir__half_to_float(input[stbir__decode_order3]);+ decode += 4;+ input += 4;+ }+ decode -= 4;+ #endif++ // do the remnants+ #if stbir__coder_min_num < 4+ STBIR_NO_UNROLL_LOOP_START+ while( decode < decode_end )+ {+ STBIR_NO_UNROLL(decode);+ decode[0] = stbir__half_to_float(input[stbir__decode_order0]);+ #if stbir__coder_min_num >= 2+ decode[1] = stbir__half_to_float(input[stbir__decode_order1]);+ #endif+ #if stbir__coder_min_num >= 3+ decode[2] = stbir__half_to_float(input[stbir__decode_order2]);+ #endif+ decode += stbir__coder_min_num;+ input += stbir__coder_min_num;+ }+ #endif+}++static void STBIR__CODER_NAME( stbir__encode_half_float_linear )( void * outputp, int width_times_channels, float const * encode )+{+ stbir__FP16 STBIR_SIMD_STREAMOUT_PTR( * ) output = (stbir__FP16*) outputp;+ stbir__FP16 * end_output = ( (stbir__FP16*) output ) + width_times_channels;++ #ifdef STBIR_SIMD+ if ( width_times_channels >= 8 )+ {+ 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);+ #ifdef stbir__decode_swizzle+ #ifdef STBIR_SIMD8+ {+ stbir__simdf8 of;+ stbir__simdf8_load( of, encode );+ stbir__encode_simdf8_unflip( of );+ stbir__float_to_half_SIMD( output, (float*)&of );+ }+ #else+ {+ stbir__simdf of[2];+ stbir__simdf_load( of[0], encode );+ stbir__simdf_load( of[1], encode+4 );+ stbir__encode_simdf4_unflip( of[0] );+ stbir__encode_simdf4_unflip( of[1] );+ stbir__float_to_half_SIMD( output, (float*)of );+ }+ #endif+ #else+ stbir__float_to_half_SIMD( output, encode );+ #endif+ encode += 8;+ output += 8;+ if ( output <= end_output )+ continue;+ if ( output == ( end_output + 8 ) )+ break;+ output = end_output; // backup and do last couple+ encode = end_encode_m8;+ }+ return;+ }+ #endif++ // 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);+ output[0-4] = stbir__float_to_half(encode[stbir__encode_order0]);+ output[1-4] = stbir__float_to_half(encode[stbir__encode_order1]);+ output[2-4] = stbir__float_to_half(encode[stbir__encode_order2]);+ output[3-4] = stbir__float_to_half(encode[stbir__encode_order3]);+ output += 4;+ encode += 4;+ }+ output -= 4;+ #endif++ // do the remnants+ #if stbir__coder_min_num < 4+ STBIR_NO_UNROLL_LOOP_START+ while( output < end_output )+ {+ STBIR_NO_UNROLL(output);+ output[0] = stbir__float_to_half(encode[stbir__encode_order0]);+ #if stbir__coder_min_num >= 2+ output[1] = stbir__float_to_half(encode[stbir__encode_order1]);+ #endif+ #if stbir__coder_min_num >= 3+ output[2] = stbir__float_to_half(encode[stbir__encode_order2]);+ #endif+ output += stbir__coder_min_num;+ encode += stbir__coder_min_num;+ }+ #endif+}++static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int width_times_channels, void const * inputp )+{+ #ifdef stbir__decode_swizzle+ float STBIR_STREAMOUT_PTR( * ) decode = decodep;+ float * decode_end = (float*) decode + width_times_channels;+ float const * input = (float const *)inputp;++ #ifdef STBIR_SIMD+ if ( width_times_channels >= 16 )+ {+ 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);+ #ifdef stbir__decode_swizzle+ #ifdef STBIR_SIMD8+ {+ stbir__simdf8 of0,of1;+ stbir__simdf8_load( of0, input );+ stbir__simdf8_load( of1, input+8 );+ stbir__decode_simdf8_flip( of0 );+ stbir__decode_simdf8_flip( of1 );+ stbir__simdf8_store( decode, of0 );+ stbir__simdf8_store( decode+8, of1 );+ }+ #else+ {+ stbir__simdf of0,of1,of2,of3;+ stbir__simdf_load( of0, input );+ stbir__simdf_load( of1, input+4 );+ stbir__simdf_load( of2, input+8 );+ stbir__simdf_load( of3, input+12 );+ stbir__decode_simdf4_flip( of0 );+ stbir__decode_simdf4_flip( of1 );+ stbir__decode_simdf4_flip( of2 );+ stbir__decode_simdf4_flip( of3 );+ stbir__simdf_store( decode, of0 );+ stbir__simdf_store( decode+4, of1 );+ stbir__simdf_store( decode+8, of2 );+ stbir__simdf_store( decode+12, of3 );+ }+ #endif+ #endif+ decode += 16;+ input += 16;+ if ( decode <= decode_end )+ continue;+ if ( decode == ( decode_end + 16 ) )+ break;+ decode = decode_end; // backup and do last couple+ input = end_input_m16;+ }+ return;+ }+ #endif++ // 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);+ decode[0-4] = input[stbir__decode_order0];+ decode[1-4] = input[stbir__decode_order1];+ decode[2-4] = input[stbir__decode_order2];+ decode[3-4] = input[stbir__decode_order3];+ decode += 4;+ input += 4;+ }+ decode -= 4;+ #endif++ // do the remnants+ #if stbir__coder_min_num < 4+ STBIR_NO_UNROLL_LOOP_START+ while( decode < decode_end )+ {+ STBIR_NO_UNROLL(decode);+ decode[0] = input[stbir__decode_order0];+ #if stbir__coder_min_num >= 2+ decode[1] = input[stbir__decode_order1];+ #endif+ #if stbir__coder_min_num >= 3+ decode[2] = input[stbir__decode_order2];+ #endif+ decode += stbir__coder_min_num;+ input += stbir__coder_min_num;+ }+ #endif++ #else++ if ( (void*)decodep != inputp )+ STBIR_MEMCPY( decodep, inputp, width_times_channels * sizeof( float ) );++ #endif+}++static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int width_times_channels, float const * encode )+{+ #if !defined( STBIR_FLOAT_HIGH_CLAMP ) && !defined(STBIR_FLOAT_LO_CLAMP) && !defined(stbir__decode_swizzle)++ if ( (void*)outputp != (void*) encode )+ STBIR_MEMCPY( outputp, encode, width_times_channels * sizeof( float ) );++ #else++ float STBIR_SIMD_STREAMOUT_PTR( * ) output = (float*) outputp;+ float * end_output = ( (float*) output ) + width_times_channels;++ #ifdef STBIR_FLOAT_HIGH_CLAMP+ #define stbir_scalar_hi_clamp( v ) if ( v > STBIR_FLOAT_HIGH_CLAMP ) v = STBIR_FLOAT_HIGH_CLAMP;+ #else+ #define stbir_scalar_hi_clamp( v )+ #endif+ #ifdef STBIR_FLOAT_LOW_CLAMP+ #define stbir_scalar_lo_clamp( v ) if ( v < STBIR_FLOAT_LOW_CLAMP ) v = STBIR_FLOAT_LOW_CLAMP;+ #else+ #define stbir_scalar_lo_clamp( v )+ #endif++ #ifdef STBIR_SIMD++ #ifdef STBIR_FLOAT_HIGH_CLAMP+ const stbir__simdfX high_clamp = stbir__simdf_frepX(STBIR_FLOAT_HIGH_CLAMP);+ #endif+ #ifdef STBIR_FLOAT_LOW_CLAMP+ const stbir__simdfX low_clamp = stbir__simdf_frepX(STBIR_FLOAT_LOW_CLAMP);+ #endif++ if ( width_times_channels >= ( stbir__simdfX_float_count * 2 ) )+ {+ 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;+ STBIR_SIMD_NO_UNROLL(encode);+ stbir__simdfX_load( e0, encode );+ stbir__simdfX_load( e1, encode+stbir__simdfX_float_count );+#ifdef STBIR_FLOAT_HIGH_CLAMP+ stbir__simdfX_min( e0, e0, high_clamp );+ stbir__simdfX_min( e1, e1, high_clamp );+#endif+#ifdef STBIR_FLOAT_LOW_CLAMP+ stbir__simdfX_max( e0, e0, low_clamp );+ stbir__simdfX_max( e1, e1, low_clamp );+#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 )+ continue;+ if ( output == ( end_output + ( stbir__simdfX_float_count * 2 ) ) )+ break;+ output = end_output; // backup and do last couple+ encode = end_encode_m8;+ }+ return;+ }++ // 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;+ STBIR_NO_UNROLL(encode);+ stbir__simdf_load( e0, encode );+#ifdef STBIR_FLOAT_HIGH_CLAMP+ stbir__simdf_min( e0, e0, high_clamp );+#endif+#ifdef STBIR_FLOAT_LOW_CLAMP+ stbir__simdf_max( e0, e0, low_clamp );+#endif+ stbir__encode_simdf4_unflip( e0 );+ stbir__simdf_store( output-4, e0 );+ output += 4;+ encode += 4;+ }+ output -= 4;+ #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 e;+ STBIR_SIMD_NO_UNROLL(encode);+ e = encode[ stbir__encode_order0 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[0-4] = e;+ e = encode[ stbir__encode_order1 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[1-4] = e;+ e = encode[ stbir__encode_order2 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[2-4] = e;+ e = encode[ stbir__encode_order3 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[3-4] = e;+ output += 4;+ encode += 4;+ }+ output -= 4;++ #endif++ #endif++ // do the remnants+ #if stbir__coder_min_num < 4+ STBIR_NO_UNROLL_LOOP_START+ while( output < end_output )+ {+ float e;+ STBIR_NO_UNROLL(encode);+ e = encode[ stbir__encode_order0 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[0] = e;+ #if stbir__coder_min_num >= 2+ e = encode[ stbir__encode_order1 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[1] = e;+ #endif+ #if stbir__coder_min_num >= 3+ e = encode[ stbir__encode_order2 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[2] = e;+ #endif+ output += stbir__coder_min_num;+ encode += stbir__coder_min_num;+ }+ #endif++ #endif+}++#undef stbir__decode_suffix+#undef stbir__decode_simdf8_flip+#undef stbir__decode_simdf4_flip+#undef stbir__decode_order0+#undef stbir__decode_order1+#undef stbir__decode_order2+#undef stbir__decode_order3+#undef stbir__encode_order0+#undef stbir__encode_order1+#undef stbir__encode_order2+#undef stbir__encode_order3+#undef stbir__encode_simdf8_unflip+#undef stbir__encode_simdf4_unflip+#undef stbir__encode_simdfX_unflip+#undef STBIR__CODER_NAME+#undef stbir__coder_min_num+#undef stbir__decode_swizzle+#undef stbir_scalar_hi_clamp+#undef stbir_scalar_lo_clamp+#undef STB_IMAGE_RESIZE_DO_CODERS++#elif defined( STB_IMAGE_RESIZE_DO_VERTICALS)++#ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE+#define STBIR_chans( start, end ) STBIR_strs_join14(start,STBIR__vertical_channels,end,_cont)+#else+#define STBIR_chans( start, end ) STBIR_strs_join1(start,STBIR__vertical_channels,end)+#endif++#if STBIR__vertical_channels >= 1+#define stbIF0( code ) code+#else+#define stbIF0( code )+#endif+#if STBIR__vertical_channels >= 2+#define stbIF1( code ) code+#else+#define stbIF1( code )+#endif+#if STBIR__vertical_channels >= 3+#define stbIF2( code ) code+#else+#define stbIF2( code )+#endif+#if STBIR__vertical_channels >= 4+#define stbIF3( code ) code+#else+#define stbIF3( code )+#endif+#if STBIR__vertical_channels >= 5+#define stbIF4( code ) code+#else+#define stbIF4( code )+#endif+#if STBIR__vertical_channels >= 6+#define stbIF5( code ) code+#else+#define stbIF5( code )+#endif+#if STBIR__vertical_channels >= 7+#define stbIF6( code ) code+#else+#define stbIF6( code )+#endif+#if STBIR__vertical_channels >= 8+#define stbIF7( code ) code+#else+#define stbIF7( code )+#endif++static void STBIR_chans( stbir__vertical_scatter_with_,_coeffs)( float ** outputs, float const * vertical_coefficients, float const * input, float const * input_end )+{+ stbIF0( float STBIR_SIMD_STREAMOUT_PTR( * ) output0 = outputs[0]; float c0s = vertical_coefficients[0]; )+ stbIF1( float STBIR_SIMD_STREAMOUT_PTR( * ) output1 = outputs[1]; float c1s = vertical_coefficients[1]; )+ stbIF2( float STBIR_SIMD_STREAMOUT_PTR( * ) output2 = outputs[2]; float c2s = vertical_coefficients[2]; )+ stbIF3( float STBIR_SIMD_STREAMOUT_PTR( * ) output3 = outputs[3]; float c3s = vertical_coefficients[3]; )+ stbIF4( float STBIR_SIMD_STREAMOUT_PTR( * ) output4 = outputs[4]; float c4s = vertical_coefficients[4]; )+ stbIF5( float STBIR_SIMD_STREAMOUT_PTR( * ) output5 = outputs[5]; float c5s = vertical_coefficients[5]; )+ stbIF6( float STBIR_SIMD_STREAMOUT_PTR( * ) output6 = outputs[6]; float c6s = vertical_coefficients[6]; )+ stbIF7( float STBIR_SIMD_STREAMOUT_PTR( * ) output7 = outputs[7]; float c7s = vertical_coefficients[7]; )++ #ifdef STBIR_SIMD+ {+ stbIF0(stbir__simdfX c0 = stbir__simdf_frepX( c0s ); )+ stbIF1(stbir__simdfX c1 = stbir__simdf_frepX( c1s ); )+ stbIF2(stbir__simdfX c2 = stbir__simdf_frepX( c2s ); )+ stbIF3(stbir__simdfX c3 = stbir__simdf_frepX( c3s ); )+ stbIF4(stbir__simdfX c4 = stbir__simdf_frepX( c4s ); )+ stbIF5(stbir__simdfX c5 = stbir__simdf_frepX( c5s ); )+ stbIF6(stbir__simdfX c6 = stbir__simdf_frepX( c6s ); )+ stbIF7(stbir__simdfX c7 = stbir__simdf_frepX( c7s ); )+ 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);++ stbir__simdfX_load( r0, input ); stbir__simdfX_load( r1, input+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input+(3*stbir__simdfX_float_count) );++ #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_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_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_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_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_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_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_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_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 );+ 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 );+ 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 );+ 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 );+ 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 );+ 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 );+ 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 );+ 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 );+ 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); )+ }+ STBIR_SIMD_NO_UNROLL_LOOP_START+ while ( ( (char*)input_end - (char*) input ) >= 16 )+ {+ stbir__simdf o0, r0;+ STBIR_SIMD_NO_UNROLL(output0);++ stbir__simdf_load( r0, input );++ #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE+ stbIF0( stbir__simdf_load( o0, output0 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c0 ) ); stbir__simdf_store( output0, o0 ); )+ stbIF1( stbir__simdf_load( o0, output1 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c1 ) ); stbir__simdf_store( output1, o0 ); )+ stbIF2( stbir__simdf_load( o0, output2 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c2 ) ); stbir__simdf_store( output2, o0 ); )+ stbIF3( stbir__simdf_load( o0, output3 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c3 ) ); stbir__simdf_store( output3, o0 ); )+ stbIF4( stbir__simdf_load( o0, output4 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c4 ) ); stbir__simdf_store( output4, o0 ); )+ stbIF5( stbir__simdf_load( o0, output5 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c5 ) ); stbir__simdf_store( output5, o0 ); )+ stbIF6( stbir__simdf_load( o0, output6 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c6 ) ); stbir__simdf_store( output6, o0 ); )+ stbIF7( stbir__simdf_load( o0, output7 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c7 ) ); stbir__simdf_store( output7, o0 ); )+ #else+ stbIF0( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c0 ) ); stbir__simdf_store( output0, o0 ); )+ stbIF1( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c1 ) ); stbir__simdf_store( output1, o0 ); )+ stbIF2( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c2 ) ); stbir__simdf_store( output2, o0 ); )+ stbIF3( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c3 ) ); stbir__simdf_store( output3, o0 ); )+ stbIF4( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c4 ) ); stbir__simdf_store( output4, o0 ); )+ stbIF5( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c5 ) ); stbir__simdf_store( output5, o0 ); )+ 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+ STBIR_NO_UNROLL_LOOP_START+ while ( ( (char*)input_end - (char*) input ) >= 16 )+ {+ float r0, r1, r2, r3;+ STBIR_NO_UNROLL(input);++ r0 = input[0], r1 = input[1], r2 = input[2], r3 = input[3];++ #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE+ stbIF0( output0[0] += ( r0 * c0s ); output0[1] += ( r1 * c0s ); output0[2] += ( r2 * c0s ); output0[3] += ( r3 * c0s ); )+ stbIF1( output1[0] += ( r0 * c1s ); output1[1] += ( r1 * c1s ); output1[2] += ( r2 * c1s ); output1[3] += ( r3 * c1s ); )+ stbIF2( output2[0] += ( r0 * c2s ); output2[1] += ( r1 * c2s ); output2[2] += ( r2 * c2s ); output2[3] += ( r3 * c2s ); )+ stbIF3( output3[0] += ( r0 * c3s ); output3[1] += ( r1 * c3s ); output3[2] += ( r2 * c3s ); output3[3] += ( r3 * c3s ); )+ stbIF4( output4[0] += ( r0 * c4s ); output4[1] += ( r1 * c4s ); output4[2] += ( r2 * c4s ); output4[3] += ( r3 * c4s ); )+ stbIF5( output5[0] += ( r0 * c5s ); output5[1] += ( r1 * c5s ); output5[2] += ( r2 * c5s ); output5[3] += ( r3 * c5s ); )+ stbIF6( output6[0] += ( r0 * c6s ); output6[1] += ( r1 * c6s ); output6[2] += ( r2 * c6s ); output6[3] += ( r3 * c6s ); )+ stbIF7( output7[0] += ( r0 * c7s ); output7[1] += ( r1 * c7s ); output7[2] += ( r2 * c7s ); output7[3] += ( r3 * c7s ); )+ #else+ stbIF0( output0[0] = ( r0 * c0s ); output0[1] = ( r1 * c0s ); output0[2] = ( r2 * c0s ); output0[3] = ( r3 * c0s ); )+ stbIF1( output1[0] = ( r0 * c1s ); output1[1] = ( r1 * c1s ); output1[2] = ( r2 * c1s ); output1[3] = ( r3 * c1s ); )+ stbIF2( output2[0] = ( r0 * c2s ); output2[1] = ( r1 * c2s ); output2[2] = ( r2 * c2s ); output2[3] = ( r3 * c2s ); )+ stbIF3( output3[0] = ( r0 * c3s ); output3[1] = ( r1 * c3s ); output3[2] = ( r2 * c3s ); output3[3] = ( r3 * c3s ); )+ stbIF4( output4[0] = ( r0 * c4s ); output4[1] = ( r1 * c4s ); output4[2] = ( r2 * c4s ); output4[3] = ( r3 * c4s ); )+ stbIF5( output5[0] = ( r0 * c5s ); output5[1] = ( r1 * c5s ); output5[2] = ( r2 * c5s ); output5[3] = ( r3 * c5s ); )+ stbIF6( output6[0] = ( r0 * c6s ); output6[1] = ( r1 * c6s ); output6[2] = ( r2 * c6s ); output6[3] = ( r3 * c6s ); )+ stbIF7( output7[0] = ( r0 * c7s ); output7[1] = ( r1 * c7s ); output7[2] = ( r2 * c7s ); output7[3] = ( r3 * c7s ); )+ #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; )+ }+ #endif+ STBIR_NO_UNROLL_LOOP_START+ while ( input < input_end )+ {+ float r = input[0];+ STBIR_NO_UNROLL(output0);++ #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE+ stbIF0( output0[0] += ( r * c0s ); )+ stbIF1( output1[0] += ( r * c1s ); )+ stbIF2( output2[0] += ( r * c2s ); )+ stbIF3( output3[0] += ( r * c3s ); )+ stbIF4( output4[0] += ( r * c4s ); )+ stbIF5( output5[0] += ( r * c5s ); )+ stbIF6( output6[0] += ( r * c6s ); )+ stbIF7( output7[0] += ( r * c7s ); )+ #else+ stbIF0( output0[0] = ( r * c0s ); )+ stbIF1( output1[0] = ( r * c1s ); )+ stbIF2( output2[0] = ( r * c2s ); )+ stbIF3( output3[0] = ( r * c3s ); )+ stbIF4( output4[0] = ( r * c4s ); )+ stbIF5( output5[0] = ( r * c5s ); )+ stbIF6( output6[0] = ( r * c6s ); )+ stbIF7( output7[0] = ( r * c7s ); )+ #endif++ ++input;+ stbIF0( ++output0; ) stbIF1( ++output1; ) stbIF2( ++output2; ) stbIF3( ++output3; ) stbIF4( ++output4; ) stbIF5( ++output5; ) stbIF6( ++output6; ) stbIF7( ++output7; )+ }+}++static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, float const * vertical_coefficients, float const ** inputs, float const * input0_end )+{+ float STBIR_SIMD_STREAMOUT_PTR( * ) output = outputp;++ stbIF0( float const * input0 = inputs[0]; float c0s = vertical_coefficients[0]; )+ stbIF1( float const * input1 = inputs[1]; float c1s = vertical_coefficients[1]; )+ stbIF2( float const * input2 = inputs[2]; float c2s = vertical_coefficients[2]; )+ stbIF3( float const * input3 = inputs[3]; float c3s = vertical_coefficients[3]; )+ stbIF4( float const * input4 = inputs[4]; float c4s = vertical_coefficients[4]; )+ stbIF5( float const * input5 = inputs[5]; float c5s = vertical_coefficients[5]; )+ stbIF6( float const * input6 = inputs[6]; float c6s = vertical_coefficients[6]; )+ stbIF7( float const * input7 = inputs[7]; float c7s = vertical_coefficients[7]; )++#if ( STBIR__vertical_channels == 1 ) && !defined(STB_IMAGE_RESIZE_VERTICAL_CONTINUE)+ // check single channel one weight+ if ( ( c0s >= (1.0f-0.000001f) ) && ( c0s <= (1.0f+0.000001f) ) )+ {+ STBIR_MEMCPY( output, input0, (char*)input0_end - (char*)input0 );+ return;+ }+#endif++ #ifdef STBIR_SIMD+ {+ stbIF0(stbir__simdfX c0 = stbir__simdf_frepX( c0s ); )+ stbIF1(stbir__simdfX c1 = stbir__simdf_frepX( c1s ); )+ stbIF2(stbir__simdfX c2 = stbir__simdf_frepX( c2s ); )+ stbIF3(stbir__simdfX c3 = stbir__simdf_frepX( c3s ); )+ stbIF4(stbir__simdfX c4 = stbir__simdf_frepX( c4s ); )+ stbIF5(stbir__simdfX c5 = stbir__simdf_frepX( c5s ); )+ stbIF6(stbir__simdfX c6 = stbir__simdf_frepX( c6s ); )+ stbIF7(stbir__simdfX c7 = stbir__simdf_frepX( c7s ); )++ 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) ); )+ 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) ); )+ stbIF4( stbir__prefetch( input4 + (16*stbir__simdfX_float_count) ); )+ stbIF5( stbir__prefetch( input5 + (16*stbir__simdfX_float_count) ); )+ stbIF6( stbir__prefetch( input6 + (16*stbir__simdfX_float_count) ); )+ stbIF7( stbir__prefetch( input7 + (16*stbir__simdfX_float_count) ); )++ #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE+ stbIF0( stbir__simdfX_load( o0, output ); stbir__simdfX_load( o1, output+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output+(3*stbir__simdfX_float_count) );+ stbir__simdfX_load( r0, input0 ); stbir__simdfX_load( r1, input0+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input0+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input0+(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 ); )+ #else+ stbIF0( stbir__simdfX_load( r0, input0 ); stbir__simdfX_load( r1, input0+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input0+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input0+(3*stbir__simdfX_float_count) );+ stbir__simdfX_mult( o0, r0, c0 ); stbir__simdfX_mult( o1, r1, c0 ); stbir__simdfX_mult( o2, r2, c0 ); stbir__simdfX_mult( o3, r3, c0 ); )+ #endif++ stbIF1( stbir__simdfX_load( r0, input1 ); stbir__simdfX_load( r1, input1+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input1+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input1+(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 ); )+ stbIF2( stbir__simdfX_load( r0, input2 ); stbir__simdfX_load( r1, input2+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input2+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input2+(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 ); )+ stbIF3( stbir__simdfX_load( r0, input3 ); stbir__simdfX_load( r1, input3+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input3+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input3+(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 ); )+ stbIF4( stbir__simdfX_load( r0, input4 ); stbir__simdfX_load( r1, input4+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input4+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input4+(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 ); )+ stbIF5( stbir__simdfX_load( r0, input5 ); stbir__simdfX_load( r1, input5+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input5+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input5+(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 ); )+ stbIF6( stbir__simdfX_load( r0, input6 ); stbir__simdfX_load( r1, input6+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input6+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input6+(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 ); )+ stbIF7( stbir__simdfX_load( r0, input7 ); stbir__simdfX_load( r1, input7+stbir__simdfX_float_count ); stbir__simdfX_load( r2, input7+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( r3, input7+(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_store( output, o0 ); stbir__simdfX_store( output+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output+(3*stbir__simdfX_float_count), o3 );+ output += (4*stbir__simdfX_float_count);+ 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); )+ }++ STBIR_SIMD_NO_UNROLL_LOOP_START+ while ( ( (char*)input0_end - (char*) input0 ) >= 16 )+ {+ stbir__simdf o0, r0;+ STBIR_SIMD_NO_UNROLL(output);++ #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE+ stbIF0( stbir__simdf_load( o0, output ); stbir__simdf_load( r0, input0 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c0 ) ); )+ #else+ stbIF0( stbir__simdf_load( r0, input0 ); stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c0 ) ); )+ #endif+ stbIF1( stbir__simdf_load( r0, input1 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c1 ) ); )+ stbIF2( stbir__simdf_load( r0, input2 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c2 ) ); )+ stbIF3( stbir__simdf_load( r0, input3 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c3 ) ); )+ stbIF4( stbir__simdf_load( r0, input4 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c4 ) ); )+ stbIF5( stbir__simdf_load( r0, input5 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c5 ) ); )+ stbIF6( stbir__simdf_load( r0, input6 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c6 ) ); )+ stbIF7( stbir__simdf_load( r0, input7 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c7 ) ); )++ stbir__simdf_store( output, o0 );+ output += 4;+ stbIF0( input0 += 4; ) stbIF1( input1 += 4; ) stbIF2( input2 += 4; ) stbIF3( input3 += 4; ) stbIF4( input4 += 4; ) stbIF5( input5 += 4; ) stbIF6( input6 += 4; ) stbIF7( input7 += 4; )+ }+ }+ #else+ STBIR_NO_UNROLL_LOOP_START+ while ( ( (char*)input0_end - (char*) input0 ) >= 16 )+ {+ float o0, o1, o2, o3;+ STBIR_NO_UNROLL(output);+ #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE+ stbIF0( o0 = output[0] + input0[0] * c0s; o1 = output[1] + input0[1] * c0s; o2 = output[2] + input0[2] * c0s; o3 = output[3] + input0[3] * c0s; )+ #else+ stbIF0( o0 = input0[0] * c0s; o1 = input0[1] * c0s; o2 = input0[2] * c0s; o3 = input0[3] * c0s; )+ #endif+ stbIF1( o0 += input1[0] * c1s; o1 += input1[1] * c1s; o2 += input1[2] * c1s; o3 += input1[3] * c1s; )+ stbIF2( o0 += input2[0] * c2s; o1 += input2[1] * c2s; o2 += input2[2] * c2s; o3 += input2[3] * c2s; )+ stbIF3( o0 += input3[0] * c3s; o1 += input3[1] * c3s; o2 += input3[2] * c3s; o3 += input3[3] * c3s; )+ stbIF4( o0 += input4[0] * c4s; o1 += input4[1] * c4s; o2 += input4[2] * c4s; o3 += input4[3] * c4s; )+ stbIF5( o0 += input5[0] * c5s; o1 += input5[1] * c5s; o2 += input5[2] * c5s; o3 += input5[3] * c5s; )+ stbIF6( o0 += input6[0] * c6s; o1 += input6[1] * c6s; o2 += input6[2] * c6s; o3 += input6[3] * c6s; )+ stbIF7( o0 += input7[0] * c7s; o1 += input7[1] * c7s; o2 += input7[2] * c7s; o3 += input7[3] * c7s; )+ output[0] = o0; output[1] = o1; output[2] = o2; output[3] = o3;+ output += 4;+ 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+ STBIR_NO_UNROLL_LOOP_START+ while ( input0 < input0_end )+ {+ float o0;+ STBIR_NO_UNROLL(output);+ #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE+ stbIF0( o0 = output[0] + input0[0] * c0s; )+ #else+ stbIF0( o0 = input0[0] * c0s; )+ #endif+ stbIF1( o0 += input1[0] * c1s; )+ stbIF2( o0 += input2[0] * c2s; )+ stbIF3( o0 += input3[0] * c3s; )+ stbIF4( o0 += input4[0] * c4s; )+ stbIF5( o0 += input5[0] * c5s; )+ stbIF6( o0 += input6[0] * c6s; )+ stbIF7( o0 += input7[0] * c7s; )+ output[0] = o0;+ ++output;+ stbIF0( ++input0; ) stbIF1( ++input1; ) stbIF2( ++input2; ) stbIF3( ++input3; ) stbIF4( ++input4; ) stbIF5( ++input5; ) stbIF6( ++input6; ) stbIF7( ++input7; )+ }+}++#undef stbIF0+#undef stbIF1+#undef stbIF2+#undef stbIF3+#undef stbIF4+#undef stbIF5+#undef stbIF6+#undef stbIF7+#undef STB_IMAGE_RESIZE_DO_VERTICALS+#undef STBIR__vertical_channels+#undef STB_IMAGE_RESIZE_DO_HORIZONTALS+#undef STBIR_strs_join24+#undef STBIR_strs_join14+#undef STBIR_chans+#ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE+#undef STB_IMAGE_RESIZE_VERTICAL_CONTINUE+#endif++#else // !STB_IMAGE_RESIZE_DO_VERTICALS++#define STBIR_chans( start, end ) STBIR_strs_join1(start,STBIR__horizontal_channels,end)++#ifndef stbir__2_coeff_only+#define stbir__2_coeff_only() \+ stbir__1_coeff_only(); \+ 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);+#endif++#ifndef stbir__3_coeff_only+#define stbir__3_coeff_only() \+ stbir__2_coeff_only(); \+ 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);+#endif++#ifndef stbir__3_coeff_setup+#define stbir__3_coeff_setup()+#endif++#ifndef stbir__4_coeff_start+#define stbir__4_coeff_start() \+ stbir__2_coeff_only(); \+ 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);+#endif++#ifndef stbir__store_output_tiny+#define stbir__store_output_tiny stbir__store_output+#endif++static void STBIR_chans( stbir__horizontal_gather_,_channels_with_1_coeff)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )+{+ 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 * hc = horizontal_coefficients;+ stbir__1_coeff_only();+ stbir__store_output_tiny();+ } while ( output < output_end );+}++static void STBIR_chans( stbir__horizontal_gather_,_channels_with_2_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )+{+ 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 * hc = horizontal_coefficients;+ stbir__2_coeff_only();+ stbir__store_output_tiny();+ } while ( output < output_end );+}++static void STBIR_chans( stbir__horizontal_gather_,_channels_with_3_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )+{+ 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 * hc = horizontal_coefficients;+ stbir__3_coeff_only();+ stbir__store_output_tiny();+ } while ( output < output_end );+}++static void STBIR_chans( stbir__horizontal_gather_,_channels_with_4_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )+{+ 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 * hc = horizontal_coefficients;+ stbir__4_coeff_start();+ stbir__store_output();+ } while ( output < output_end );+}++static void STBIR_chans( stbir__horizontal_gather_,_channels_with_5_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )+{+ 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 * hc = horizontal_coefficients;+ stbir__4_coeff_start();+ stbir__1_coeff_remnant(4);+ stbir__store_output();+ } while ( output < output_end );+}++static void STBIR_chans( stbir__horizontal_gather_,_channels_with_6_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )+{+ 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 * hc = horizontal_coefficients;+ stbir__4_coeff_start();+ stbir__2_coeff_remnant(4);+ stbir__store_output();+ } while ( output < output_end );+}++static void STBIR_chans( stbir__horizontal_gather_,_channels_with_7_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )+{+ 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 * hc = horizontal_coefficients;++ stbir__4_coeff_start();+ stbir__3_coeff_remnant(4);+ stbir__store_output();+ } while ( output < output_end );+}++static void STBIR_chans( stbir__horizontal_gather_,_channels_with_8_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )+{+ 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 * hc = horizontal_coefficients;+ stbir__4_coeff_start();+ stbir__4_coeff_continue_from_4(4);+ stbir__store_output();+ } while ( output < output_end );+}++static void STBIR_chans( stbir__horizontal_gather_,_channels_with_9_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )+{+ 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 * hc = horizontal_coefficients;+ stbir__4_coeff_start();+ stbir__4_coeff_continue_from_4(4);+ stbir__1_coeff_remnant(8);+ stbir__store_output();+ } while ( output < output_end );+}++static void STBIR_chans( stbir__horizontal_gather_,_channels_with_10_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )+{+ 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 * hc = horizontal_coefficients;+ stbir__4_coeff_start();+ stbir__4_coeff_continue_from_4(4);+ stbir__2_coeff_remnant(8);+ stbir__store_output();+ } while ( output < output_end );+}++static void STBIR_chans( stbir__horizontal_gather_,_channels_with_11_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )+{+ 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 * hc = horizontal_coefficients;+ stbir__4_coeff_start();+ stbir__4_coeff_continue_from_4(4);+ stbir__3_coeff_remnant(8);+ stbir__store_output();+ } while ( output < output_end );+}++static void STBIR_chans( stbir__horizontal_gather_,_channels_with_12_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )+{+ 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 * hc = horizontal_coefficients;+ stbir__4_coeff_start();+ stbir__4_coeff_continue_from_4(4);+ stbir__4_coeff_continue_from_4(8);+ stbir__store_output();+ } while ( output < output_end );+}++static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod0 )( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )+{+ 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 * 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__store_output();+ } while ( output < output_end );+}++static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod1 )( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )+{+ 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 * 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__store_output();+ } while ( output < output_end );+}++static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod2 )( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )+{+ 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 * 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__store_output();+ } while ( output < output_end );+}++static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod3 )( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )+{+ 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 * 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__store_output();+ } while ( output < output_end );+}++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),+};++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_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_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),+};++#undef STBIR__horizontal_channels+#undef STB_IMAGE_RESIZE_DO_HORIZONTALS+#undef stbir__1_coeff_only+#undef stbir__1_coeff_remnant+#undef stbir__2_coeff_only+#undef stbir__2_coeff_remnant+#undef stbir__3_coeff_only+#undef stbir__3_coeff_remnant+#undef stbir__3_coeff_setup+#undef stbir__4_coeff_start+#undef stbir__4_coeff_continue_from_4+#undef stbir__store_output+#undef stbir__store_output_tiny+#undef STBIR_chans++#endif // HORIZONALS++#undef STBIR_strs_join2+#undef STBIR_strs_join1++#endif // STB_IMAGE_RESIZE_DO_HORIZONTALS/VERTICALS/CODERS++/*+------------------------------------------------------------------------------+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+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.+------------------------------------------------------------------------------+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,+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+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 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------ */
raylib/src/platforms/rcore_android.c view
@@ -74,7 +74,7 @@ // Global Variables Definition //---------------------------------------------------------------------------------- extern CoreData CORE; // Global CORE state context-+extern bool isGpuReady; // Flag to note GPU has been initialized successfully static PlatformData platform = { 0 }; // Platform specific data //----------------------------------------------------------------------------------@@ -281,14 +281,15 @@ // Request to end the native activity ANativeActivity_finish(app->activity); - // Android ALooper_pollAll() variables+ // Android ALooper_pollOnce() variables int pollResult = 0; int pollEvents = 0; // Waiting for application events before complete finishing while (!app->destroyRequested) {- while ((pollResult = ALooper_pollAll(0, NULL, &pollEvents, (void **)&platform.source)) >= 0)+ // Poll all events until we reach return value TIMEOUT, meaning no events left to process+ while ((pollResult = ALooper_pollOnce(0, NULL, &pollEvents, (void **)&platform.source)) > ALOOPER_POLL_TIMEOUT) { if (platform.source != NULL) platform.source->process(app, platform.source); }@@ -632,6 +633,13 @@ TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform"); } +// Get physical key name.+const char *GetKeyName(int key)+{+ TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform");+ return "";+}+ // Register all input events void PollInputEvents(void) {@@ -675,27 +683,27 @@ CORE.Input.Keyboard.keyRepeatInFrame[i] = 0; } - // Android ALooper_pollAll() variables+ // Android ALooper_pollOnce() variables int pollResult = 0; int pollEvents = 0; - // Poll Events (registered events)+ // Poll Events (registered events) until we reach TIMEOUT which indicates there are no events left to poll // NOTE: Activity is paused if not enabled (platform.appEnabled)- while ((pollResult = ALooper_pollAll(platform.appEnabled? 0 : -1, NULL, &pollEvents, (void**)&platform.source)) >= 0)+ while ((pollResult = ALooper_pollOnce(platform.appEnabled? 0 : -1, NULL, &pollEvents, (void**)&platform.source)) > ALOOPER_POLL_TIMEOUT) { // Process this event if (platform.source != NULL) platform.source->process(platform.app, platform.source); - // NOTE: Never close window, native activity is controlled by the system!+ // NOTE: Allow closing the window in case a configuration change happened.+ // The android_main function should be allowed to return to its caller in order for the+ // Android OS to relaunch the activity. if (platform.app->destroyRequested != 0) {- //CORE.Window.shouldClose = true;- //ANativeActivity_finish(platform.app->activity);+ CORE.Window.shouldClose = true; } } } - //---------------------------------------------------------------------------------- // Module Internal Functions Definition //----------------------------------------------------------------------------------@@ -760,20 +768,20 @@ TRACELOG(LOG_INFO, "PLATFORM: ANDROID: Initialized successfully"); - // Android ALooper_pollAll() variables+ // Android ALooper_pollOnce() variables int pollResult = 0; int pollEvents = 0; // Wait for window to be initialized (display and context) while (!CORE.Window.ready) {- // Process events loop- while ((pollResult = ALooper_pollAll(0, NULL, &pollEvents, (void**)&platform.source)) >= 0)+ // Process events until we reach TIMEOUT, which indicates no more events queued.+ while ((pollResult = ALooper_pollOnce(0, NULL, &pollEvents, (void**)&platform.source)) > ALOOPER_POLL_TIMEOUT) { // Process this event if (platform.source != NULL) platform.source->process(platform.app, platform.source); - // NOTE: Never close window, native activity is controlled by the system!+ // NOTE: It's highly likely destroyRequested will never be non-zero at the start of the activity lifecycle. //if (platform.app->destroyRequested != 0) CORE.Window.shouldClose = true; } }@@ -804,6 +812,12 @@ eglTerminate(platform.device); platform.device = EGL_NO_DISPLAY; }++ // NOTE: Reset global state in case the activity is being relaunched.+ if (platform.app->destroyRequested != 0) {+ CORE = (CoreData){0};+ platform = (PlatformData){0};+ } } // Initialize display device and framebuffer@@ -974,6 +988,7 @@ // Initialize OpenGL context (states and resources) // NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);+ isGpuReady = true; // Setup default viewport // NOTE: It updated CORE.Window.render.width and CORE.Window.render.height
raylib/src/platforms/rcore_desktop_glfw.c view
@@ -109,6 +109,7 @@ // Window callbacks events static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized+static void WindowPosCallback(GLFWwindow* window, int x, int y); // GLFW3 WindowPos Callback, runs when window is moved static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored static void WindowMaximizeCallback(GLFWwindow* window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus@@ -147,8 +148,8 @@ if (!CORE.Window.fullscreen) { // Store previous window position (in case we exit fullscreen)- glfwGetWindowPos(platform.handle, &CORE.Window.position.x, &CORE.Window.position.y);-+ CORE.Window.previousPosition = CORE.Window.position;+ int monitorCount = 0; int monitorIndex = GetCurrentMonitor(); GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);@@ -179,7 +180,11 @@ CORE.Window.fullscreen = false; CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE; - glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.position.x, CORE.Window.position.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);+ glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.previousPosition.x, CORE.Window.previousPosition.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);++ // we update the window position right away+ CORE.Window.position.x = CORE.Window.previousPosition.x;+ CORE.Window.position.y = CORE.Window.previousPosition.y; } // Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)@@ -190,11 +195,11 @@ // Toggle borderless windowed mode void ToggleBorderlessWindowed(void) {- // Leave fullscreen before attempting to set borderless windowed mode and get screen position from it+ // Leave fullscreen before attempting to set borderless windowed mode bool wasOnFullscreen = false; if (CORE.Window.fullscreen) {- CORE.Window.previousPosition = CORE.Window.position;+ // fullscreen already saves the previous position so it does not need to be set here again ToggleFullscreen(); wasOnFullscreen = true; }@@ -213,7 +218,7 @@ { // Store screen position and size // NOTE: If it was on fullscreen, screen position was already stored, so skip setting it here- if (!wasOnFullscreen) glfwGetWindowPos(platform.handle, &CORE.Window.previousPosition.x, &CORE.Window.previousPosition.y);+ if (!wasOnFullscreen) CORE.Window.previousPosition = CORE.Window.position; CORE.Window.previousScreen = CORE.Window.screen; // Set undecorated and topmost modes and flags@@ -255,6 +260,9 @@ glfwFocusWindow(platform.handle); CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;++ CORE.Window.position.x = CORE.Window.previousPosition.x;+ CORE.Window.position.y = CORE.Window.previousPosition.y; } } else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor");@@ -592,6 +600,9 @@ // Set window position on screen (windowed mode) void SetWindowPosition(int x, int y) {+ // Update CORE.Window.position as well+ CORE.Window.position.x = x;+ CORE.Window.position.y = y; glfwSetWindowPos(platform.handle, x, y); } @@ -614,8 +625,9 @@ { TRACELOG(LOG_INFO, "GLFW: Selected monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor])); - const int screenWidth = CORE.Window.screen.width;- const int screenHeight = CORE.Window.screen.height;+ // Here the render width has to be used again in case high dpi flag is enabled+ const int screenWidth = CORE.Window.render.width;+ const int screenHeight = CORE.Window.render.height; int monitorWorkareaX = 0; int monitorWorkareaY = 0; int monitorWorkareaWidth = 0;@@ -1075,6 +1087,12 @@ } } +// Get physical key name.+const char *GetKeyName(int key)+{+ return glfwGetKeyName(key, glfwGetKeyScancode(key));+}+ // Register all input events void PollInputEvents(void) {@@ -1216,7 +1234,6 @@ glfwSetWindowShouldClose(platform.handle, GLFW_FALSE); } - //---------------------------------------------------------------------------------- // Module Internal Functions Definition //----------------------------------------------------------------------------------@@ -1269,6 +1286,11 @@ //glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); // OpenGL API to use. Alternative: GLFW_OPENGL_ES_API //glfwWindowHint(GLFW_AUX_BUFFERS, 0); // Number of auxiliar buffers + // Disable GlFW auto iconify behaviour+ // Auto Iconify automatically minimizes (iconifies) the window if the window loses focus+ // additionally auto iconify restores the hardware resolution of the monitor if the window that loses focus is a fullscreen window+ glfwWindowHint(GLFW_AUTO_ICONIFY, 0); + // Check window creation flags if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) CORE.Window.fullscreen = true; @@ -1424,7 +1446,7 @@ } } - TRACELOG(LOG_WARNING, "SYSTEM: Closest fullscreen videomode: %i x %i", CORE.Window.display.width, CORE.Window.display.height);+ TRACELOG(LOG_INFO, "SYSTEM: Closest fullscreen videomode: %i x %i", CORE.Window.display.width, CORE.Window.display.height); // NOTE: ISSUE: Closest videomode could not match monitor aspect-ratio, for example, // for a desired screen size of 800x450 (16:9), closest supported videomode is 800x600 (4:3),@@ -1448,11 +1470,6 @@ // No-fullscreen window creation bool requestWindowedFullscreen = (CORE.Window.screen.height == 0) && (CORE.Window.screen.width == 0); - // If we are windowed fullscreen, ensures that window does not minimize when focus is lost.- // This hinting code will not work if the user already specified the correct monitor dimensions;- // at this point we don't know the monitor's dimensions. (Though, how did the user then?)- if (requestWindowedFullscreen) glfwWindowHint(GLFW_AUTO_ICONIFY, 0);- // Default to at least one pixel in size, as creation with a zero dimension is not allowed. int creationWidth = CORE.Window.screen.width != 0 ? CORE.Window.screen.width : 1; int creationHeight = CORE.Window.screen.height != 0 ? CORE.Window.screen.height : 1;@@ -1562,12 +1579,17 @@ int monitorWidth = 0; int monitorHeight = 0; glfwGetMonitorWorkarea(monitor, &monitorX, &monitorY, &monitorWidth, &monitorHeight);-- int posX = monitorX + (monitorWidth - (int)CORE.Window.screen.width)/2;- int posY = monitorY + (monitorHeight - (int)CORE.Window.screen.height)/2;+ + // Here CORE.Window.render.width/height should be used instead of CORE.Window.screen.width/height to center the window correctly when the high dpi flag is enabled.+ int posX = monitorX + (monitorWidth - (int)CORE.Window.render.width)/2;+ int posY = monitorY + (monitorHeight - (int)CORE.Window.render.height)/2; if (posX < monitorX) posX = monitorX; if (posY < monitorY) posY = monitorY; SetWindowPosition(posX, posY);++ // Update CORE.Window.position here so it is correct from the start+ CORE.Window.position.x = posX;+ CORE.Window.position.y = posY; } // Load OpenGL extensions@@ -1579,6 +1601,7 @@ //---------------------------------------------------------------------------- // Set window callback events glfwSetWindowSizeCallback(platform.handle, WindowSizeCallback); // NOTE: Resizing not allowed by default!+ glfwSetWindowPosCallback(platform.handle, WindowPosCallback); glfwSetWindowMaximizeCallback(platform.handle, WindowMaximizeCallback); glfwSetWindowIconifyCallback(platform.handle, WindowIconifyCallback); glfwSetWindowFocusCallback(platform.handle, WindowFocusCallback);@@ -1624,16 +1647,16 @@ char *glfwPlatform = ""; switch (glfwGetPlatform()) {- case GLFW_PLATFORM_WIN32: glfwPlatform = "Win32"; break;- case GLFW_PLATFORM_COCOA: glfwPlatform = "Cocoa"; break;+ case GLFW_PLATFORM_WIN32: glfwPlatform = "Win32"; break;+ case GLFW_PLATFORM_COCOA: glfwPlatform = "Cocoa"; break; case GLFW_PLATFORM_WAYLAND: glfwPlatform = "Wayland"; break;- case GLFW_PLATFORM_X11: glfwPlatform = "X11"; break;- case GLFW_PLATFORM_NULL: glfwPlatform = "Null"; break;+ case GLFW_PLATFORM_X11: glfwPlatform = "X11"; break;+ case GLFW_PLATFORM_NULL: glfwPlatform = "Null"; break;+ default: break; } #endif - TRACELOG(LOG_INFO, "GLFW platform: %s", glfwPlatform);- TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (GLFW): Initialized successfully");+ TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (GLFW - %s): Initialized successfully", glfwPlatform); return 0; }@@ -1675,7 +1698,12 @@ // NOTE: Postprocessing texture is not scaled to new size }-+static void WindowPosCallback(GLFWwindow* window, int x, int y)+{+ // Set current window position+ CORE.Window.position.x = x;+ CORE.Window.position.y = y;+} static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley) { CORE.Window.screenScale = MatrixScale(scalex, scaley, 1.0f);
raylib/src/platforms/rcore_desktop_rgfw.c view
@@ -1,6 +1,6 @@ /********************************************************************************************** * -* rcore_desktop_rgfw template - Functions to manage window, graphics device and inputs +* rcore_desktop_rgfw - Functions to manage window, graphics device and inputs * * PLATFORM: RGFW * - Windows (Win32, Win64) @@ -46,7 +46,7 @@ * **********************************************************************************************/ -#ifdef GRAPHICS_API_OPENGL_ES2 +#if defined(GRAPHICS_API_OPENGL_ES2) #define RGFW_OPENGL_ES2 #endif @@ -69,6 +69,7 @@ #define CloseWindow CloseWindow_win32 #define ShowCursor __imp_ShowCursor #define _APISETSTRING_ + __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar); #endif #if defined(__APPLE__) @@ -76,10 +77,6 @@ #define Size NSSIZE #endif -#if defined(_MSC_VER) -__declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar); -#endif - #include "../external/RGFW.h" #if defined(__WIN32) || defined(__WIN64) @@ -182,7 +179,7 @@ [RGFW_u] = KEY_U, [RGFW_v] = KEY_V, [RGFW_w] = KEY_W, - [RGFW_x] KEY_X, + [RGFW_x] = KEY_X, [RGFW_y] = KEY_Y, [RGFW_z] = KEY_Z, [RGFW_Bracket] = KEY_LEFT_BRACKET, @@ -291,7 +288,6 @@ } if (flags & FLAG_WINDOW_RESIZABLE) { - printf("%i %i\n", platform.window->r.w, platform.window->r.h); RGFW_window_setMaxSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h)); RGFW_window_setMinSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h)); } @@ -483,14 +479,14 @@ // Set title for window void SetWindowTitle(const char *title) { - RGFW_window_setName(platform.window, title); + RGFW_window_setName(platform.window, (char*)title); CORE.Window.title = title; } // Set window position on screen (windowed mode) void SetWindowPosition(int x, int y) { - RGFW_window_move(platform.window, RGFW_VECTOR(x, y)); + RGFW_window_move(platform.window, RGFW_POINT(x, y)); } // Set monitor for the current window @@ -536,10 +532,10 @@ // Get native window handle void *GetWindowHandle(void) { -#ifndef RGFW_WINDOWS - return (void *)platform.window->src.window; +#ifdef RGFW_WEBASM + return (void*)platform.window->src.ctx; #else - return platform.window->src.hwnd; + return (void*)platform.window->src.window; #endif } @@ -643,7 +639,7 @@ { RGFW_monitor monitor = RGFW_window_getMonitor(platform.window); - return (Vector2){((u32)monitor.scaleX)*platform.window->r.w, ((u32) monitor.scaleX)*platform.window->r.h}; + return (Vector2){monitor.scaleX, monitor.scaleX}; } // Set clipboard text content @@ -689,10 +685,9 @@ void DisableCursor(void) { RGFW_disableCursor = true; - - // Set cursor position in the middle - SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); + RGFW_window_mouseHold(platform.window, RGFW_AREA(0, 0)); + HideCursor(); } @@ -745,7 +740,7 @@ // Set mouse position XY void SetMousePosition(int x, int y) { - RGFW_window_moveMouse(platform.window, RGFW_VECTOR(x, y)); + RGFW_window_moveMouse(platform.window, RGFW_POINT(x, y)); CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; } @@ -756,6 +751,13 @@ RGFW_window_setMouseStandard(platform.window, cursor); } +// Get physical key name. +const char *GetKeyName(int key) +{ + TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform"); + return ""; +} + static KeyboardKey ConvertScancodeToKey(u32 keycode); // TODO: Review function to avoid duplicate with RSGL @@ -868,10 +870,9 @@ //----------------------------------------------------------------------------- CORE.Window.resizedLastFrame = false; -#define RGFW_HOLD_MOUSE (1L<<2) - -#if defined(RGFW_X11) //|| defined(RGFW_MACOS) - if (platform.window->src.winArgs & RGFW_HOLD_MOUSE) + CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; + #define RGFW_HOLD_MOUSE (1L<<2) + if (platform.window->_winArgs & RGFW_HOLD_MOUSE) { CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f }; CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f }; @@ -880,11 +881,9 @@ { CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; } -#endif while (RGFW_window_checkEvent(platform.window)) { - if ((platform.window->event.type >= RGFW_jsButtonPressed) && (platform.window->event.type <= RGFW_jsAxisMove)) { if (!CORE.Input.Gamepad.ready[platform.window->event.joystick]) @@ -936,7 +935,7 @@ SetupViewport(platform.window->r.w, platform.window->r.h); CORE.Window.screen.width = platform.window->r.w; CORE.Window.screen.height = platform.window->r.h; - CORE.Window.currentFbo.width = platform.window->r.w;; + CORE.Window.currentFbo.width = platform.window->r.w; CORE.Window.currentFbo.height = platform.window->r.h; CORE.Window.resizedLastFrame = true; } break; @@ -1024,17 +1023,10 @@ } break; case RGFW_mousePosChanged: { - if (platform.window->src.winArgs & RGFW_HOLD_MOUSE) + if (platform.window->_winArgs & RGFW_HOLD_MOUSE) { - CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f }; - - if ((event->point.x - (platform.window->r.w/2))*2) - CORE.Input.Mouse.previousPosition.x = CORE.Input.Mouse.currentPosition.x; - if ((event->point.y - (platform.window->r.h/2))*2) - CORE.Input.Mouse.previousPosition.y = CORE.Input.Mouse.currentPosition.y; - - CORE.Input.Mouse.currentPosition.x = (event->point.x - (platform.window->r.w/2))*2; - CORE.Input.Mouse.currentPosition.y = (event->point.y - (platform.window->r.h/2))*2; + CORE.Input.Mouse.currentPosition.x += (float)event->point.x; + CORE.Input.Mouse.currentPosition.y += (float)event->point.y; } else { @@ -1198,12 +1190,9 @@ } #endif } - - if (RGFW_disableCursor && platform.window->event.inFocus) RGFW_window_mouseHold(platform.window, RGFW_AREA(0, 0)); //----------------------------------------------------------------------------- } - //---------------------------------------------------------------------------------- // Module Internal Functions Definition //---------------------------------------------------------------------------------- @@ -1233,15 +1222,15 @@ // Check selection OpenGL version if (rlGetVersion() == RL_OPENGL_21) { - RGFW_setGLVersion(2, 1); + RGFW_setGLVersion(RGFW_GL_CORE, 2, 1); } else if (rlGetVersion() == RL_OPENGL_33) { - RGFW_setGLVersion(3, 3); + RGFW_setGLVersion(RGFW_GL_CORE, 3, 3); } else if (rlGetVersion() == RL_OPENGL_43) { - RGFW_setGLVersion(4, 1); + RGFW_setGLVersion(RGFW_GL_CORE, 4, 1); } if (CORE.Window.flags & FLAG_MSAA_4X_HINT) @@ -1250,6 +1239,15 @@ } platform.window = RGFW_createWindow(CORE.Window.title, RGFW_RECT(0, 0, CORE.Window.screen.width, CORE.Window.screen.height), flags); + + RGFW_area screenSize = RGFW_getScreenSize(); + CORE.Window.display.width = screenSize.w; + CORE.Window.display.height = screenSize.h; + /* + I think this is needed by Raylib now ? + If so, rcore_destkop_sdl should be updated too + */ + SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); if (CORE.Window.flags & FLAG_VSYNC_HINT) RGFW_window_swapInterval(platform.window, 1);
raylib/src/platforms/rcore_desktop_sdl.c view
@@ -58,6 +58,13 @@ #endif //----------------------------------------------------------------------------------+// Defines and Macros+//----------------------------------------------------------------------------------+#ifndef MAX_CLIPBOARD_BUFFER_LENGTH+ #define MAX_CLIPBOARD_BUFFER_LENGTH 1024 // Size of the clipboard buffer used on GetClipboardText()+#endif++//---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- typedef struct {@@ -852,10 +859,22 @@ } // Get clipboard text content-// NOTE: returned string must be freed with SDL_free() const char *GetClipboardText(void) {- return SDL_GetClipboardText();+ static char buffer[MAX_CLIPBOARD_BUFFER_LENGTH] = { 0 };++ char *clipboard = SDL_GetClipboardText();++ int clipboardSize = snprintf(buffer, sizeof(buffer), "%s", clipboard);+ if (clipboardSize >= MAX_CLIPBOARD_BUFFER_LENGTH)+ {+ char *truncate = buffer + MAX_CLIPBOARD_BUFFER_LENGTH - 4;+ sprintf(truncate, "...");+ }++ SDL_free(clipboard);++ return buffer; } // Show mouse cursor@@ -966,6 +985,12 @@ CORE.Input.Mouse.cursor = cursor; } +// Get physical key name.+const char *GetKeyName(int key)+{+ return SDL_GetKeyName(key);+}+ static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event) { CORE.Input.Touch.pointCount = SDL_GetNumTouchFingers(event.touchId);@@ -1583,8 +1608,8 @@ // Initialize storage system //---------------------------------------------------------------------------- // Define base path for storage- CORE.Storage.basePath = SDL_GetBasePath(); // Alternative: GetWorkingDirectory(); - CHDIR(CORE.Storage.basePath); + CORE.Storage.basePath = SDL_GetBasePath(); // Alternative: GetWorkingDirectory();+ CHDIR(CORE.Storage.basePath); //---------------------------------------------------------------------------- TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL): Initialized successfully");
raylib/src/platforms/rcore_drm.c view
@@ -206,7 +206,7 @@ [BTN_TL] = GAMEPAD_BUTTON_LEFT_TRIGGER_1, [BTN_TL2] = GAMEPAD_BUTTON_LEFT_TRIGGER_2, [BTN_TR] = GAMEPAD_BUTTON_RIGHT_TRIGGER_1,- [BTN_TR2] GAMEPAD_BUTTON_RIGHT_TRIGGER_2,+ [BTN_TR2] = GAMEPAD_BUTTON_RIGHT_TRIGGER_2, [BTN_SELECT] = GAMEPAD_BUTTON_MIDDLE_LEFT, [BTN_MODE] = GAMEPAD_BUTTON_MIDDLE, [BTN_START] = GAMEPAD_BUTTON_MIDDLE_RIGHT,@@ -628,6 +628,13 @@ TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform"); } +// Get physical key name.+const char *GetKeyName(int key)+{+ TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform");+ return "";+}+ // Register all input events void PollInputEvents(void) {@@ -756,8 +763,10 @@ drmModeConnector *con = drmModeGetConnector(platform.fd, res->connectors[i]); TRACELOG(LOG_TRACE, "DISPLAY: Connector modes detected: %i", con->count_modes);-- if ((con->connection == DRM_MODE_CONNECTED) && (con->encoder_id))+ + // In certain cases the status of the conneciton is reported as UKNOWN, but it is still connected.+ // This might be a hardware or software limitation like on Raspberry Pi Zero with composite output.+ if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->encoder_id)) { TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected"); platform.connector = con;@@ -1470,7 +1479,6 @@ TEST_BIT(relBits, REL_Y) && TEST_BIT(keyBits, BTN_MOUSE)) isMouse = true; }- if (TEST_BIT(evBits, EV_KEY)) {
raylib/src/platforms/rcore_template.c view
@@ -384,6 +384,13 @@ TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform"); } +// Get physical key name.+const char *GetKeyName(int key)+{+ TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform");+ return "";+}+ // Register all input events void PollInputEvents(void) {@@ -422,7 +429,6 @@ // TODO: Poll input events for current platform }- //---------------------------------------------------------------------------------- // Module Internal Functions Definition
raylib/src/platforms/rcore_web.c view
@@ -129,7 +129,7 @@ // Emscripten window callback events static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData);-static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData);+// static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData); static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData); // Emscripten input callback events@@ -884,6 +884,13 @@ } } +// Get physical key name.+const char *GetKeyName(int key)+{+ TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform");+ return "";+}+ // Register all input events void PollInputEvents(void) {@@ -928,7 +935,6 @@ // so, if mouse is not moved it returns a (0, 0) position... this behaviour should be reviewed! //for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ 0, 0 }; - // Gamepad support using emscripten API // NOTE: GLFW3 joystick functionality not available in web @@ -974,7 +980,7 @@ default: break; } - if (button != -1) // Check for valid button+ if (button + 1 != 0) // Check for valid button { if (gamepadState.digitalButton[j] == 1) {@@ -1565,12 +1571,12 @@ } // Register window resize event-static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData)-{- // TODO: Implement EmscriptenWindowResizedCallback()?+// static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData)+// {+// // TODO: Implement EmscriptenWindowResizedCallback()? - return 1; // The event was consumed by the callback handler-}+// return 1; // The event was consumed by the callback handler+// } EM_JS(int, GetWindowInnerWidth, (), { return window.innerWidth; }); EM_JS(int, GetWindowInnerHeight, (), { return window.innerHeight; });@@ -1586,11 +1592,11 @@ int width = GetWindowInnerWidth(); int height = GetWindowInnerHeight(); - if (width < CORE.Window.screenMin.width) width = CORE.Window.screenMin.width;- else if (width > CORE.Window.screenMax.width && CORE.Window.screenMax.width > 0) width = CORE.Window.screenMax.width;+ if (width < (int)CORE.Window.screenMin.width) width = CORE.Window.screenMin.width;+ else if (width > (int)CORE.Window.screenMax.width && CORE.Window.screenMax.width > 0) width = CORE.Window.screenMax.width; - if (height < CORE.Window.screenMin.height) height = CORE.Window.screenMin.height;- else if (height > CORE.Window.screenMax.height && CORE.Window.screenMax.height > 0) height = CORE.Window.screenMax.height;+ if (height < (int)CORE.Window.screenMin.height) height = CORE.Window.screenMin.height;+ else if (height > (int)CORE.Window.screenMax.height && CORE.Window.screenMax.height > 0) height = CORE.Window.screenMax.height; emscripten_set_canvas_element_size("#canvas", width, height);
raylib/src/raudio.c view
@@ -1626,7 +1626,9 @@ { music.ctxType = MUSIC_AUDIO_FLAC; music.ctxData = ctxFlac;- music.stream = LoadAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels);+ int sampleSize = ctxFlac->bitsPerSample;+ if (ctxFlac->bitsPerSample == 24) sampleSize = 16; // Forcing conversion to s16 on UpdateMusicStream()+ music.stream = LoadAudioStream(ctxFlac->sampleRate, sampleSize, ctxFlac->channels); music.frameCount = (unsigned int)ctxFlac->totalPCMFrameCount; music.looping = true; // Looping enabled by default musicLoaded = true;
raylib/src/raylib.h view
@@ -1,6 +1,6 @@ /********************************************************************************************** *-* raylib v5.5 - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com)+* raylib v5.5-dev - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com) * * FEATURES: * - NO external dependencies, all required libraries included with raylib@@ -84,7 +84,7 @@ #define RAYLIB_VERSION_MAJOR 5 #define RAYLIB_VERSION_MINOR 5 #define RAYLIB_VERSION_PATCH 0-#define RAYLIB_VERSION "5.5"+#define RAYLIB_VERSION "5.5-dev" // Function specifiers in case library is build/used as a shared library // NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll@@ -352,8 +352,10 @@ // Animation vertex data float *animVertices; // Animated vertex positions (after bones transformations) float *animNormals; // Animated normals (after bones transformations)- unsigned char *boneIds; // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning)- float *boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning)+ unsigned char *boneIds; // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) (shader-location = 6)+ float *boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7)+ Matrix *boneMatrices; // Bones animated transformation matrices+ int boneCount; // Number of bones // OpenGL identifiers unsigned int vaoId; // OpenGL Vertex Array Object id@@ -790,7 +792,10 @@ SHADER_LOC_MAP_CUBEMAP, // Shader location: samplerCube texture: cubemap SHADER_LOC_MAP_IRRADIANCE, // Shader location: samplerCube texture: irradiance SHADER_LOC_MAP_PREFILTER, // Shader location: samplerCube texture: prefilter- SHADER_LOC_MAP_BRDF // Shader location: sampler2d texture: brdf+ SHADER_LOC_MAP_BRDF, // Shader location: sampler2d texture: brdf+ SHADER_LOC_VERTEX_BONEIDS, // Shader location: vertex attribute: boneIds+ SHADER_LOC_VERTEX_BONEWEIGHTS, // Shader location: vertex attribute: boneWeights+ SHADER_LOC_BONE_MATRICES // Shader location: array of matrices uniform: boneMatrices } ShaderLocationIndex; #define SHADER_LOC_MAP_DIFFUSE SHADER_LOC_MAP_ALBEDO@@ -968,8 +973,8 @@ RLAPI bool IsWindowState(unsigned int flag); // Check if one specific window flag is enabled RLAPI void SetWindowState(unsigned int flags); // Set window configuration state using flags (only PLATFORM_DESKTOP) RLAPI void ClearWindowState(unsigned int flags); // Clear window configuration state flags-RLAPI void ToggleFullscreen(void); // Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP)-RLAPI void ToggleBorderlessWindowed(void); // Toggle window state: borderless windowed (only PLATFORM_DESKTOP)+RLAPI void ToggleFullscreen(void); // Toggle window state: fullscreen/windowed [resizes monitor to match window resolution] (only PLATFORM_DESKTOP)+RLAPI void ToggleBorderlessWindowed(void); // Toggle window state: borderless windowed [resizes window to match monitor resolution] (only PLATFORM_DESKTOP) RLAPI void MaximizeWindow(void); // Set window state: maximized, if resizable (only PLATFORM_DESKTOP) RLAPI void MinimizeWindow(void); // Set window state: minimized, if resizable (only PLATFORM_DESKTOP) RLAPI void RestoreWindow(void); // Set window state: not minimized/maximized (only PLATFORM_DESKTOP)@@ -1122,11 +1127,12 @@ RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a given path (uses static string) RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string) RLAPI const char *GetApplicationDirectory(void); // Get the directory of the running application (uses static string)+RLAPI int MakeDirectory(const char *dirPath); // Create directories (including full path requested), returns 0 on success RLAPI bool ChangeDirectory(const char *dir); // Change working directory, return true on success RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths-RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and recursive directory scan+RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result RLAPI void UnloadDirectoryFiles(FilePathList files); // Unload filepaths RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window RLAPI FilePathList LoadDroppedFiles(void); // Load dropped filepaths@@ -1228,8 +1234,8 @@ RLAPI Rectangle GetShapesTextureRectangle(void); // Get texture source rectangle that is used for shapes drawing // Basic shapes drawing functions-RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel-RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel (Vector version)+RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel using geometry [Can be slow, use with care]+RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel using geometry (Vector version) [Can be slow, use with care] RLAPI void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw a line RLAPI void DrawLineV(Vector2 startPos, Vector2 endPos, Color color); // Draw a line (using gl lines) RLAPI void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line (using triangles/quads)@@ -1238,7 +1244,7 @@ RLAPI void DrawCircle(int centerX, int centerY, float radius, Color color); // Draw a color-filled circle RLAPI void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw a piece of a circle RLAPI void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw circle sector outline-RLAPI void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2); // Draw a gradient-filled circle+RLAPI void DrawCircleGradient(int centerX, int centerY, float radius, Color inner, Color outer); // Draw a gradient-filled circle RLAPI void DrawCircleV(Vector2 center, float radius, Color color); // Draw a color-filled circle (Vector version) RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline RLAPI void DrawCircleLinesV(Vector2 center, float radius, Color color); // Draw circle outline (Vector version)@@ -1250,9 +1256,9 @@ RLAPI void DrawRectangleV(Vector2 position, Vector2 size, Color color); // Draw a color-filled rectangle (Vector version) RLAPI void DrawRectangleRec(Rectangle rec, Color color); // Draw a color-filled rectangle RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters-RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2);// Draw a vertical-gradient-filled rectangle-RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color color1, Color color2);// Draw a horizontal-gradient-filled rectangle-RLAPI void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // Draw a gradient-filled rectangle with custom vertex colors+RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color top, Color bottom); // Draw a vertical-gradient-filled rectangle+RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color left, Color right); // Draw a horizontal-gradient-filled rectangle+RLAPI void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color topRight, Color bottomRight); // Draw a gradient-filled rectangle with custom vertex colors RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline RLAPI void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color); // Draw rectangle outline with extended parameters RLAPI void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color); // Draw rectangle with rounded edges@@ -1306,7 +1312,6 @@ // NOTE: These functions do not require GPU access RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM) RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data-RLAPI Image LoadImageSvg(const char *fileNameOrString, int width, int height); // Load image from SVG file data or string with specified size RLAPI Image LoadImageAnim(const char *fileName, int *frames); // Load image sequence from file (frames appended to image.data) RLAPI Image LoadImageAnimFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int *frames); // Load image sequence from memory buffer RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load image from memory buffer, fileType refers to extension: i.e. '.png'@@ -1431,6 +1436,7 @@ RLAPI Color ColorContrast(Color color, float contrast); // Get color with contrast correction, contrast values between -1.0f and 1.0f RLAPI Color ColorAlpha(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f RLAPI Color ColorAlphaBlend(Color dst, Color src, Color tint); // Get src alpha-blended into dst color with tint+RLAPI Color ColorLerp(Color color1, Color color2, float factor); // Get color lerp interpolation between two colors, factor [0.0f..1.0f] RLAPI Color GetColor(unsigned int hexValue); // Get Color structure from hexadecimal value RLAPI Color GetPixelColor(void *srcPtr, int format); // Get Color from a source pixel pointer of certain format RLAPI void SetPixelColor(void *dstPtr, Color color, int format); // Set color formatted into destination pixel pointer@@ -1443,7 +1449,7 @@ // Font loading/unloading functions RLAPI Font GetFontDefault(void); // Get the default Font RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM)-RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set+RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // 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 RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style) RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf' RLAPI bool IsFontReady(Font font); // Check if a font is ready@@ -1545,6 +1551,8 @@ RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set) RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters+RLAPI void DrawModelPoints(Model model, Vector3 position, float scale, Color tint); // Draw a model as points+RLAPI void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model as points with extended parameters RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint); // Draw a billboard texture RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint); // Draw a billboard texture defined by source@@ -1588,6 +1596,7 @@ RLAPI void UnloadModelAnimation(ModelAnimation anim); // Unload animation data RLAPI void UnloadModelAnimations(ModelAnimation *animations, int animCount); // Unload animation array data RLAPI bool IsModelAnimationValid(Model model, ModelAnimation anim); // Check model animation skeleton match+RLAPI void UpdateModelAnimationBoneMatrices(Model model, ModelAnimation anim, int frame); // Update model animation mesh bone matrices (Note GPU skinning does not work on Mac) // Collision detection functions RLAPI bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2); // Check collision between two spheres
raylib/src/rcamera.h view
@@ -162,7 +162,6 @@ #endif // RCAMERA_H - /*********************************************************************************** * * CAMERA IMPLEMENTATION@@ -196,12 +195,12 @@ //---------------------------------------------------------------------------------- // Defines and Macros //-----------------------------------------------------------------------------------#define CAMERA_MOVE_SPEED 0.09f+#define CAMERA_MOVE_SPEED 5.4f // Units per second #define CAMERA_ROTATION_SPEED 0.03f #define CAMERA_PAN_SPEED 0.2f // Camera mouse movement sensitivity-#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f // TODO: it should be independant of framerate+#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f // Camera orbital speed in CAMERA_ORBITAL mode #define CAMERA_ORBITAL_SPEED 0.5f // Radians per second@@ -444,11 +443,17 @@ bool lockView = ((mode == CAMERA_FREE) || (mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL)); bool rotateUp = false; + // Camera speeds based on frame time+ float cameraMoveSpeed = CAMERA_MOVE_SPEED*GetFrameTime();+ float cameraRotationSpeed = CAMERA_ROTATION_SPEED*GetFrameTime();+ float cameraPanSpeed = CAMERA_PAN_SPEED*GetFrameTime();+ float cameraOrbitalSpeed = CAMERA_ORBITAL_SPEED*GetFrameTime();+ if (mode == CAMERA_CUSTOM) {} else if (mode == CAMERA_ORBITAL) { // Orbital can just orbit- Matrix rotation = MatrixRotate(GetCameraUp(camera), CAMERA_ORBITAL_SPEED*GetFrameTime());+ Matrix rotation = MatrixRotate(GetCameraUp(camera), cameraOrbitalSpeed); Vector3 view = Vector3Subtract(camera->position, camera->target); view = Vector3Transform(view, rotation); camera->position = Vector3Add(camera->target, view);@@ -456,22 +461,22 @@ else { // Camera rotation- if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp);- if (IsKeyDown(KEY_UP)) CameraPitch(camera, CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp);- if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -CAMERA_ROTATION_SPEED, rotateAroundTarget);- if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, CAMERA_ROTATION_SPEED, rotateAroundTarget);- if (IsKeyDown(KEY_Q)) CameraRoll(camera, -CAMERA_ROTATION_SPEED);- if (IsKeyDown(KEY_E)) CameraRoll(camera, CAMERA_ROTATION_SPEED);+ if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -cameraRotationSpeed, lockView, rotateAroundTarget, rotateUp);+ if (IsKeyDown(KEY_UP)) CameraPitch(camera, cameraRotationSpeed, lockView, rotateAroundTarget, rotateUp);+ if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -cameraRotationSpeed, rotateAroundTarget);+ if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, cameraRotationSpeed, rotateAroundTarget);+ if (IsKeyDown(KEY_Q)) CameraRoll(camera, -cameraRotationSpeed);+ if (IsKeyDown(KEY_E)) CameraRoll(camera, cameraRotationSpeed); // Camera movement // Camera pan (for CAMERA_FREE) if ((mode == CAMERA_FREE) && (IsMouseButtonDown(MOUSE_BUTTON_MIDDLE))) { const Vector2 mouseDelta = GetMouseDelta();- if (mouseDelta.x > 0.0f) CameraMoveRight(camera, CAMERA_PAN_SPEED, moveInWorldPlane);- if (mouseDelta.x < 0.0f) CameraMoveRight(camera, -CAMERA_PAN_SPEED, moveInWorldPlane);- if (mouseDelta.y > 0.0f) CameraMoveUp(camera, -CAMERA_PAN_SPEED);- if (mouseDelta.y < 0.0f) CameraMoveUp(camera, CAMERA_PAN_SPEED);+ if (mouseDelta.x > 0.0f) CameraMoveRight(camera, cameraPanSpeed, moveInWorldPlane);+ if (mouseDelta.x < 0.0f) CameraMoveRight(camera, -cameraPanSpeed, moveInWorldPlane);+ if (mouseDelta.y > 0.0f) CameraMoveUp(camera, -cameraPanSpeed);+ if (mouseDelta.y < 0.0f) CameraMoveUp(camera, cameraPanSpeed); } else {@@ -481,10 +486,10 @@ } // Keyboard support- if (IsKeyDown(KEY_W)) CameraMoveForward(camera, CAMERA_MOVE_SPEED, moveInWorldPlane);- if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane);- if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane);- if (IsKeyDown(KEY_D)) CameraMoveRight(camera, CAMERA_MOVE_SPEED, moveInWorldPlane);+ if (IsKeyDown(KEY_W)) CameraMoveForward(camera, cameraMoveSpeed, moveInWorldPlane);+ if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -cameraMoveSpeed, moveInWorldPlane);+ if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -cameraMoveSpeed, moveInWorldPlane);+ if (IsKeyDown(KEY_D)) CameraMoveRight(camera, cameraMoveSpeed, moveInWorldPlane); // Gamepad movement if (IsGamepadAvailable(0))@@ -493,16 +498,16 @@ CameraYaw(camera, -(GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_X)*2)*CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget); CameraPitch(camera, -(GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_Y)*2)*CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp); - if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_Y) <= -0.25f) CameraMoveForward(camera, CAMERA_MOVE_SPEED, moveInWorldPlane);- if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_X) <= -0.25f) CameraMoveRight(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane);- if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_Y) >= 0.25f) CameraMoveForward(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane);- if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_X) >= 0.25f) CameraMoveRight(camera, CAMERA_MOVE_SPEED, moveInWorldPlane);+ if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_Y) <= -0.25f) CameraMoveForward(camera, cameraMoveSpeed, moveInWorldPlane);+ if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_X) <= -0.25f) CameraMoveRight(camera, -cameraMoveSpeed, moveInWorldPlane);+ if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_Y) >= 0.25f) CameraMoveForward(camera, -cameraMoveSpeed, moveInWorldPlane);+ if (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_X) >= 0.25f) CameraMoveRight(camera, cameraMoveSpeed, moveInWorldPlane); } if (mode == CAMERA_FREE) {- if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, CAMERA_MOVE_SPEED);- if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -CAMERA_MOVE_SPEED);+ if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, cameraMoveSpeed);+ if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -cameraMoveSpeed); } }
raylib/src/rcore.c view
@@ -165,6 +165,10 @@ unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); #elif defined(__linux__) #include <unistd.h>+#elif defined(__FreeBSD__)+ #include <sys/types.h>+ #include <sys/sysctl.h>+ #include <unistd.h> #elif defined(__APPLE__) #include <sys/syslimits.h> #include <mach-o/dyld.h>@@ -187,14 +191,16 @@ #endif #if defined(_WIN32)- #include <direct.h> // Required for: _getch(), _chdir()+ #include <io.h> // Required for: _access() [Used in FileExists()]+ #include <direct.h> // Required for: _getch(), _chdir(), _mkdir() #define GETCWD _getcwd // NOTE: MSDN recommends not to use getcwd(), chdir() #define CHDIR _chdir- #include <io.h> // Required for: _access() [Used in FileExists()]+ #define MKDIR(dir) _mkdir(dir) #else- #include <unistd.h> // Required for: getch(), chdir() (POSIX), access()+ #include <unistd.h> // Required for: getch(), chdir(), mkdir(), access() #define GETCWD getcwd #define CHDIR chdir+ #define MKDIR(dir) mkdir(dir, 0777) #endif //----------------------------------------------------------------------------------@@ -247,6 +253,10 @@ #define MAX_AUTOMATION_EVENTS 16384 // Maximum number of automation events to record #endif +#ifndef DIRECTORY_FILTER_TAG+ #define DIRECTORY_FILTER_TAG "DIR" // Name tag used to request directory inclusion on directory scan+#endif // NOTE: Used in ScanDirectoryFiles(), ScanDirectoryFilesRecursively() and LoadDirectoryFilesEx()+ // Flags operation macros #define FLAG_SET(n, f) ((n) |= (f)) #define FLAG_CLEAR(n, f) ((n) &= ~(f))@@ -360,16 +370,21 @@ //---------------------------------------------------------------------------------- RLAPI const char *raylib_version = RAYLIB_VERSION; // raylib version exported symbol, required for some bindings -CoreData CORE = { 0 }; // Global CORE state context+CoreData CORE = { 0 }; // Global CORE state context +// Flag to note GPU acceleration is available,+// referenced from other modules to support GPU data loading+// NOTE: Useful to allow Texture, RenderTexture, Font.texture, Mesh.vaoId/vboId, Shader loading+bool isGpuReady = false;+ #if defined(SUPPORT_SCREEN_CAPTURE)-static int screenshotCounter = 0; // Screenshots counter+static int screenshotCounter = 0; // Screenshots counter #endif #if defined(SUPPORT_GIF_RECORDING)-unsigned int gifFrameCounter = 0; // GIF frames counter-bool gifRecording = false; // GIF recording state-MsfGifState gifState = { 0 }; // MSGIF context state+static unsigned int gifFrameCounter = 0; // GIF frames counter+static bool gifRecording = false; // GIF recording state+static MsfGifState gifState = { 0 }; // MSGIF context state #endif #if defined(SUPPORT_AUTOMATION_EVENTS)@@ -563,7 +578,6 @@ //void DisableCursor(void) // Initialize window and OpenGL context-// NOTE: data parameter could be used to pass any kind of required data to the initialization void InitWindow(int width, int height, const char *title) { TRACELOG(LOG_INFO, "Initializing raylib %s", RAYLIB_VERSION);@@ -637,28 +651,31 @@ // Initialize rlgl default data (buffers and shaders) // NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);+ isGpuReady = true; // Flag to note GPU has been initialized successfully // Setup default viewport SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height); -#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)- // Load default font- // WARNING: External function: Module required: rtext- LoadFontDefault();- #if defined(SUPPORT_MODULE_RSHAPES)- // Set font white rectangle for shapes drawing, so shapes and text can be batched together- // WARNING: rshapes module is required, if not available, default internal white rectangle is used- Rectangle rec = GetFontDefault().recs[95];- if (CORE.Window.flags & FLAG_MSAA_4X_HINT)- {- // NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering- SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 });- }- else- {- // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding- SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 });- }+#if defined(SUPPORT_MODULE_RTEXT)+ #if defined(SUPPORT_DEFAULT_FONT)+ // Load default font+ // WARNING: External function: Module required: rtext+ LoadFontDefault();+ #if defined(SUPPORT_MODULE_RSHAPES)+ // Set font white rectangle for shapes drawing, so shapes and text can be batched together+ // WARNING: rshapes module is required, if not available, default internal white rectangle is used+ Rectangle rec = GetFontDefault().recs[95];+ if (CORE.Window.flags & FLAG_MSAA_4X_HINT)+ {+ // NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering+ SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 });+ }+ else+ {+ // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding+ SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 });+ }+ #endif #endif #else #if defined(SUPPORT_MODULE_RSHAPES)@@ -668,21 +685,14 @@ SetShapesTexture(texture, (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f }); // WARNING: Module required: rshapes #endif #endif-#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)- if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)- {- // Set default font texture filter for HighDPI (blurry)- // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps- rlTextureParameters(GetFontDefault().texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR);- rlTextureParameters(GetFontDefault().texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);- }-#endif CORE.Time.frameCounter = 0; CORE.Window.shouldClose = false; // Initialize random seed SetRandomSeed((unsigned int)time(NULL));+ + TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", GetWorkingDirectory()); } // Close window and unload OpenGL context@@ -1294,6 +1304,8 @@ // vertex color location = 3 // vertex tangent location = 4 // vertex texcoord2 location = 5+ // vertex boneIds location = 6+ // vertex boneWeights location = 7 // NOTE: If any location is not found, loc point becomes -1 @@ -1309,6 +1321,8 @@ shader.locs[SHADER_LOC_VERTEX_NORMAL] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL); shader.locs[SHADER_LOC_VERTEX_TANGENT] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT); shader.locs[SHADER_LOC_VERTEX_COLOR] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR);+ shader.locs[SHADER_LOC_VERTEX_BONEIDS] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS);+ shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS); // Get handles to GLSL uniform locations (vertex shader) shader.locs[SHADER_LOC_MATRIX_MVP] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_MVP);@@ -1316,6 +1330,7 @@ shader.locs[SHADER_LOC_MATRIX_PROJECTION] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION); shader.locs[SHADER_LOC_MATRIX_MODEL] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL); shader.locs[SHADER_LOC_MATRIX_NORMAL] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL);+ shader.locs[SHADER_LOC_BONE_MATRICES] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES); // Get handles to GLSL uniform locations (fragment shader) shader.locs[SHADER_LOC_COLOR_DIFFUSE] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR);@@ -2160,6 +2175,28 @@ appDir[0] = '.'; appDir[1] = '/'; }+#elif defined(__FreeBSD__)+ size_t size = sizeof(appDir);+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};++ if (sysctl(mib, 4, appDir, &size, NULL, 0) == 0)+ {+ int len = strlen(appDir);+ for (int i = len; i >= 0; --i)+ {+ if (appDir[i] == '/')+ {+ appDir[i + 1] = '\0';+ break;+ }+ }+ }+ else+ {+ appDir[0] = '.';+ appDir[1] = '/';+ }+ #endif return appDir;@@ -2231,6 +2268,40 @@ RL_FREE(files.paths); } +// Create directories (including full path requested), returns 0 on success+int MakeDirectory(const char *dirPath)+{+ if ((dirPath == NULL) || (dirPath[0] == '\0')) return 1; // Path is not valid+ if (DirectoryExists(dirPath)) return 0; // Path already exists (is valid)++ // Copy path string to avoid modifying original+ int len = (int)strlen(dirPath) + 1;+ char *pathcpy = (char *)RL_CALLOC(len, 1);+ memcpy(pathcpy, dirPath, len);++ // Iterate over pathcpy, create each subdirectory as needed+ for (int i = 0; (i < len) && (pathcpy[i] != '\0'); i++)+ {+ if (pathcpy[i] == ':') i++;+ else+ {+ if ((pathcpy[i] == '\\') || (pathcpy[i] == '/'))+ {+ pathcpy[i] = '\0';+ if (!DirectoryExists(pathcpy)) MKDIR(pathcpy);+ pathcpy[i] = '/';+ }+ }+ }++ // Create final directory+ if (!DirectoryExists(pathcpy)) MKDIR(pathcpy);++ RL_FREE(pathcpy);++ return 0;+}+ // Change working directory, returns true on success bool ChangeDirectory(const char *dir) {@@ -2713,8 +2784,8 @@ } break; case INPUT_MOUSE_WHEEL_MOTION: // param[0]: x delta, param[1]: y delta {- CORE.Input.Mouse.currentWheelMove.x = (float)event.params[0]; break;- CORE.Input.Mouse.currentWheelMove.y = (float)event.params[1]; break;+ CORE.Input.Mouse.currentWheelMove.x = (float)event.params[0];+ CORE.Input.Mouse.currentWheelMove.y = (float)event.params[1]; } break; case INPUT_TOUCH_UP: CORE.Input.Touch.currentTouchState[event.params[0]] = false; break; // param[0]: id case INPUT_TOUCH_DOWN: CORE.Input.Touch.currentTouchState[event.params[0]] = true; break; // param[0]: id@@ -2751,6 +2822,8 @@ case ACTION_SETTARGETFPS: SetTargetFPS(event.params[0]); break; default: break; }++ TRACELOG(LOG_INFO, "AUTOMATION PLAY: Frame: %i | Event type: %i | Event parameters: %i, %i, %i", event.frame, event.type, event.params[0], event.params[1], event.params[2]); } #endif }@@ -2958,11 +3031,15 @@ // Get axis movement vector for a gamepad float GetGamepadAxisMovement(int gamepad, int axis) {- float value = 0;+ float value = (axis == GAMEPAD_AXIS_LEFT_TRIGGER || axis == GAMEPAD_AXIS_RIGHT_TRIGGER)? -1.0f : 0.0f; - if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXIS) &&- (fabsf(CORE.Input.Gamepad.axisState[gamepad][axis]) > 0.1f)) value = CORE.Input.Gamepad.axisState[gamepad][axis]; // 0.1f = GAMEPAD_AXIS_MINIMUM_DRIFT/DELTA+ if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXIS)) {+ float movement = value < 0.0f ? CORE.Input.Gamepad.axisState[gamepad][axis] : fabsf(CORE.Input.Gamepad.axisState[gamepad][axis]); + // 0.1f = GAMEPAD_AXIS_MINIMUM_DRIFT/DELTA+ if (movement > value + 0.1f) value = CORE.Input.Gamepad.axisState[gamepad][axis];+ }+ return value; } @@ -3306,11 +3383,22 @@ if (filter != NULL) {- if (IsFileExtension(path, filter))+ if (IsPathFile(path)) {- strcpy(files->paths[files->count], path);- files->count++;+ if (IsFileExtension(path, filter))+ {+ strcpy(files->paths[files->count], path);+ files->count++;+ } }+ else+ {+ if (TextFindIndex(filter, DIRECTORY_FILTER_TAG) >= 0)+ {+ strcpy(files->paths[files->count], path);+ files->count++;+ }+ } } else {@@ -3369,7 +3457,22 @@ break; } }- else ScanDirectoryFilesRecursively(path, files, filter);+ else + {+ if ((filter != NULL) && (TextFindIndex(filter, DIRECTORY_FILTER_TAG) >= 0))+ {+ strcpy(files->paths[files->count], path);+ files->count++;+ }+ + if (files->count >= files->capacity)+ {+ TRACELOG(LOG_WARNING, "FILEIO: Maximum filepath scan capacity reached (%i files)", files->capacity);+ break;+ }++ ScanDirectoryFilesRecursively(path, files, filter);+ } } } @@ -3482,7 +3585,7 @@ currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter; currentEventList->events[currentEventList->count].type = INPUT_MOUSE_WHEEL_MOTION; currentEventList->events[currentEventList->count].params[0] = (int)CORE.Input.Mouse.currentWheelMove.x;- currentEventList->events[currentEventList->count].params[1] = (int)CORE.Input.Mouse.currentWheelMove.y;;+ currentEventList->events[currentEventList->count].params[1] = (int)CORE.Input.Mouse.currentWheelMove.y; currentEventList->events[currentEventList->count].params[2] = 0; TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_MOUSE_WHEEL_MOTION | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);@@ -3605,7 +3708,8 @@ for (int axis = 0; axis < MAX_GAMEPAD_AXIS; axis++) { // Event type: INPUT_GAMEPAD_AXIS_MOTION- if (CORE.Input.Gamepad.axisState[gamepad][axis] > 0.1f)+ float defaultMovement = (axis == GAMEPAD_AXIS_LEFT_TRIGGER || axis == GAMEPAD_AXIS_RIGHT_TRIGGER)? -1.0f : 0.0f;+ if (GetGamepadAxisMovement(gamepad, axis) != defaultMovement) { currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter; currentEventList->events[currentEventList->count].type = INPUT_GAMEPAD_AXIS_MOTION;
raylib/src/rlgl.h view
@@ -68,12 +68,15 @@ * #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR * #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT * #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2+* #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS "vertexBoneIds" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS+* #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS * #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix * #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix * #define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix * #define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL "matModel" // model matrix * #define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView))) * #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color)+* #define RL_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES "boneMatrices" // bone matrices * #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0) * #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1) * #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2)@@ -324,24 +327,36 @@ // Default shader vertex attribute locations #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION- #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0+ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD- #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1+ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL- #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2+ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR- #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3+ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT-#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4+#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2- #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5+ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5 #endif+#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES+ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6+#endif +#ifdef RL_SUPPORT_MESH_GPU_SKINNING+#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS+ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 7+#endif+#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS+ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8+#endif+#endif+ //---------------------------------------------------------------------------------- // Types and Structures Definition //----------------------------------------------------------------------------------@@ -527,6 +542,10 @@ RL_SHADER_UNIFORM_IVEC2, // Shader uniform type: ivec2 (2 int) RL_SHADER_UNIFORM_IVEC3, // Shader uniform type: ivec3 (3 int) RL_SHADER_UNIFORM_IVEC4, // Shader uniform type: ivec4 (4 int)+ RL_SHADER_UNIFORM_UINT, // Shader uniform type: unsigned int+ RL_SHADER_UNIFORM_UIVEC2, // Shader uniform type: uivec2 (2 unsigned int)+ RL_SHADER_UNIFORM_UIVEC3, // Shader uniform type: uivec3 (3 unsigned int)+ RL_SHADER_UNIFORM_UIVEC4, // Shader uniform type: uivec4 (4 unsigned int) RL_SHADER_UNIFORM_SAMPLER2D // Shader uniform type: sampler2d } rlShaderUniformDataType; @@ -665,7 +684,7 @@ RLAPI void rlScissor(int x, int y, int width, int height); // Scissor test RLAPI void rlEnableWireMode(void); // Enable wire mode RLAPI void rlEnablePointMode(void); // Enable point mode-RLAPI void rlDisableWireMode(void); // Disable wire mode ( and point ) maybe rename+RLAPI void rlDisableWireMode(void); // Disable wire (and point) mode RLAPI void rlSetLineWidth(float width); // Set the line drawing width RLAPI float rlGetLineWidth(void); // Get the line drawing width RLAPI void rlEnableSmoothLines(void); // Enable line aliasing@@ -755,6 +774,7 @@ RLAPI int rlGetLocationAttrib(unsigned int shaderId, const char *attribName); // Get shader location attribute RLAPI void rlSetUniform(int locIndex, const void *value, int uniformType, int count); // Set shader value uniform RLAPI void rlSetUniformMatrix(int locIndex, Matrix mat); // Set shader value matrix+RLAPI void rlSetUniformMatrices(int locIndex, const Matrix *mat, int count); // Set shader value matrices RLAPI void rlSetUniformSampler(int locIndex, unsigned int textureId); // Set shader value sampler RLAPI void rlSetShader(unsigned int id, int *locs); // Set shader currently active (id and locations) @@ -973,6 +993,12 @@ #ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 #endif+#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS+ #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS "vertexBoneIds" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS+#endif+#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS+ #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS+#endif #ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_MVP #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix@@ -992,6 +1018,9 @@ #ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color) #endif+#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES+ #define RL_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES "boneMatrices" // bone matrices+#endif #ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0) #endif@@ -1948,6 +1977,7 @@ #endif } +// Enable point mode void rlEnablePointMode(void) { #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)@@ -1956,6 +1986,7 @@ glEnable(GL_PROGRAM_POINT_SIZE); #endif }+ // Disable wire mode void rlDisableWireMode(void) {@@ -3994,18 +4025,18 @@ unsigned int fragmentShaderId = 0; // Compile vertex shader (if provided)+ // NOTE: If not vertex shader is provided, use default one if (vsCode != NULL) vertexShaderId = rlCompileShader(vsCode, GL_VERTEX_SHADER);- // In case no vertex shader was provided or compilation failed, we use default vertex shader- if (vertexShaderId == 0) vertexShaderId = RLGL.State.defaultVShaderId;+ else vertexShaderId = RLGL.State.defaultVShaderId; // Compile fragment shader (if provided)+ // NOTE: If not vertex shader is provided, use default one if (fsCode != NULL) fragmentShaderId = rlCompileShader(fsCode, GL_FRAGMENT_SHADER);- // In case no fragment shader was provided or compilation failed, we use default fragment shader- if (fragmentShaderId == 0) fragmentShaderId = RLGL.State.defaultFShaderId;+ else fragmentShaderId = RLGL.State.defaultFShaderId; // In case vertex and fragment shader are the default ones, no need to recompile, we can just assign the default shader program id if ((vertexShaderId == RLGL.State.defaultVShaderId) && (fragmentShaderId == RLGL.State.defaultFShaderId)) id = RLGL.State.defaultShaderId;- else+ else if ((vertexShaderId > 0) && (fragmentShaderId > 0)) { // One of or both shader are new, we need to compile a new shader program id = rlLoadShaderProgram(vertexShaderId, fragmentShaderId);@@ -4083,6 +4114,8 @@ //case GL_GEOMETRY_SHADER: #if defined(GRAPHICS_API_OPENGL_43) case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile compute shader code", shader); break;+ #elif defined(GRAPHICS_API_OPENGL_33)+ case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43", shader); break; #endif default: break; }@@ -4098,6 +4131,8 @@ TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Compile error: %s", shader, log); RL_FREE(log); }++ shader = 0; } else {@@ -4108,6 +4143,8 @@ //case GL_GEOMETRY_SHADER: #if defined(GRAPHICS_API_OPENGL_43) case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader compiled successfully", shader); break;+ #elif defined(GRAPHICS_API_OPENGL_33)+ case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43", shader); break; #endif default: break; }@@ -4137,6 +4174,11 @@ glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT); glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2); +#ifdef RL_SUPPORT_MESH_GPU_SKINNING+ glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS);+ glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS);+#endif+ // NOTE: If some attrib name is no found on the shader, it locations becomes -1 glLinkProgram(program);@@ -4228,8 +4270,16 @@ case RL_SHADER_UNIFORM_IVEC2: glUniform2iv(locIndex, count, (int *)value); break; case RL_SHADER_UNIFORM_IVEC3: glUniform3iv(locIndex, count, (int *)value); break; case RL_SHADER_UNIFORM_IVEC4: glUniform4iv(locIndex, count, (int *)value); break;+ #if !defined(GRAPHICS_API_OPENGL_ES2)+ case RL_SHADER_UNIFORM_UINT: glUniform1uiv(locIndex, count, (unsigned int *)value); break;+ case RL_SHADER_UNIFORM_UIVEC2: glUniform2uiv(locIndex, count, (unsigned int *)value); break;+ case RL_SHADER_UNIFORM_UIVEC3: glUniform3uiv(locIndex, count, (unsigned int *)value); break;+ case RL_SHADER_UNIFORM_UIVEC4: glUniform4uiv(locIndex, count, (unsigned int *)value); break;+ #endif case RL_SHADER_UNIFORM_SAMPLER2D: glUniform1iv(locIndex, count, (int *)value); break; default: TRACELOG(RL_LOG_WARNING, "SHADER: Failed to set uniform value, data type not recognized");++ // TODO: Support glUniform1uiv(), glUniform2uiv(), glUniform3uiv(), glUniform4uiv() } #endif }@@ -4263,6 +4313,14 @@ #endif } +// Set shader value uniform matrix+void rlSetUniformMatrices(int locIndex, const Matrix *matrices, int count)+{+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)+ glUniformMatrix4fv(locIndex, count, true, (const float*)matrices);+#endif+}+ // Set shader value uniform sampler void rlSetUniformSampler(int locIndex, unsigned int textureId) {@@ -4348,6 +4406,8 @@ TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader program loaded successfully", program); }+#else+ TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43"); #endif return program;@@ -4372,6 +4432,8 @@ glBufferData(GL_SHADER_STORAGE_BUFFER, size, data, usageHint? usageHint : RL_STREAM_COPY); if (data == NULL) glClearBufferData(GL_SHADER_STORAGE_BUFFER, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, NULL); // Clear buffer data to 0 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);+#else+ TRACELOG(RL_LOG_WARNING, "SSBO: SSBO not enabled. Define GRAPHICS_API_OPENGL_43"); #endif return ssbo;@@ -4382,7 +4444,10 @@ { #if defined(GRAPHICS_API_OPENGL_43) glDeleteBuffers(1, &ssboId);+#else+ TRACELOG(RL_LOG_WARNING, "SSBO: SSBO not enabled. Define GRAPHICS_API_OPENGL_43"); #endif+ } // Update SSBO buffer data@@ -4397,14 +4462,14 @@ // Get SSBO buffer size unsigned int rlGetShaderBufferSize(unsigned int id) {- long long size = 0;- #if defined(GRAPHICS_API_OPENGL_43)+ GLint64 size = 0; glBindBuffer(GL_SHADER_STORAGE_BUFFER, id); glGetBufferParameteri64v(GL_SHADER_STORAGE_BUFFER, GL_BUFFER_SIZE, &size);-#endif- return (size > 0)? (unsigned int)size : 0;+#else+ return 0;+#endif } // Read SSBO buffer data (GPU->CPU)@@ -4442,6 +4507,8 @@ rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); glBindImageTexture(index, id, 0, 0, 0, readonly? GL_READ_ONLY : GL_READ_WRITE, glInternalFormat);+#else+ TRACELOG(RL_LOG_WARNING, "TEXTURE: Image texture binding not enabled. Define GRAPHICS_API_OPENGL_43"); #endif } @@ -4756,7 +4823,16 @@ "out vec2 fragTexCoord; \n" "out vec4 fragColor; \n" #endif-#if defined(GRAPHICS_API_OPENGL_ES2)++#if defined(GRAPHICS_API_OPENGL_ES3)+ "#version 300 es \n"+ "precision mediump float; \n" // Precision required for OpenGL ES3 (WebGL 2) (on some browsers)+ "in vec3 vertexPosition; \n"+ "in vec2 vertexTexCoord; \n"+ "in vec4 vertexColor; \n"+ "out vec2 fragTexCoord; \n"+ "out vec4 fragColor; \n"+#elif defined(GRAPHICS_API_OPENGL_ES2) "#version 100 \n" "precision mediump float; \n" // Precision required for OpenGL ES2 (WebGL) (on some browsers) "attribute vec3 vertexPosition; \n"@@ -4765,6 +4841,7 @@ "varying vec2 fragTexCoord; \n" "varying vec4 fragColor; \n" #endif+ "uniform mat4 mvp; \n" "void main() \n" "{ \n"@@ -4799,7 +4876,21 @@ " finalColor = texelColor*colDiffuse*fragColor; \n" "} \n"; #endif-#if defined(GRAPHICS_API_OPENGL_ES2)++#if defined(GRAPHICS_API_OPENGL_ES3)+ "#version 300 es \n"+ "precision mediump float; \n" // Precision required for OpenGL ES3 (WebGL 2)+ "in vec2 fragTexCoord; \n"+ "in vec4 fragColor; \n"+ "out vec4 finalColor; \n"+ "uniform sampler2D texture0; \n"+ "uniform vec4 colDiffuse; \n"+ "void main() \n"+ "{ \n"+ " vec4 texelColor = texture(texture0, fragTexCoord); \n"+ " finalColor = texelColor*colDiffuse*fragColor; \n"+ "} \n";+#elif defined(GRAPHICS_API_OPENGL_ES2) "#version 100 \n" "precision mediump float; \n" // Precision required for OpenGL ES2 (WebGL) "varying vec2 fragTexCoord; \n"@@ -4969,7 +5060,8 @@ default: break; } - dataSize = width*height*bpp/8; // Total data size in bytes+ double bytesPerPixel = (double)bpp/8.0;+ dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes // Most compressed formats works on 4x4 blocks, // if texture is smaller, minimum dataSize is 8 or 16
raylib/src/rmodels.c view
@@ -130,7 +130,7 @@ #define MAX_MATERIAL_MAPS 12 // Maximum number of maps supported #endif #ifndef MAX_MESH_VERTEX_BUFFERS- #define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh+ #define MAX_MESH_VERTEX_BUFFERS 9 // Maximum vertex buffers (VBO) per mesh #endif //----------------------------------------------------------------------------------@@ -702,7 +702,6 @@ rlPopMatrix(); } - // Draw a wired cylinder with base at startPos and top at endPos // NOTE: It could be also used for pyramid and cone void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color)@@ -1246,14 +1245,19 @@ mesh->vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VERTEX_BUFFERS, sizeof(unsigned int)); mesh->vaoId = 0; // Vertex Array Object- mesh->vboId[0] = 0; // Vertex buffer: positions- mesh->vboId[1] = 0; // Vertex buffer: texcoords- mesh->vboId[2] = 0; // Vertex buffer: normals- mesh->vboId[3] = 0; // Vertex buffer: colors- mesh->vboId[4] = 0; // Vertex buffer: tangents- mesh->vboId[5] = 0; // Vertex buffer: texcoords2- mesh->vboId[6] = 0; // Vertex buffer: indices+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = 0; // Vertex buffer: positions+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = 0; // Vertex buffer: texcoords+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = 0; // Vertex buffer: normals+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = 0; // Vertex buffer: colors+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = 0; // Vertex buffer: tangents+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = 0; // Vertex buffer: texcoords2+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = 0; // Vertex buffer: indices +#ifdef RL_SUPPORT_MESH_GPU_SKINNING+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = 0; // Vertex buffer: boneIds+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = 0; // Vertex buffer: boneWeights+#endif+ #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) mesh->vaoId = rlLoadVertexArray(); rlEnableVertexArray(mesh->vaoId);@@ -1262,12 +1266,12 @@ // Enable vertex attributes: position (shader-location = 0) void *vertices = (mesh->animVertices != NULL)? mesh->animVertices : mesh->vertices;- mesh->vboId[0] = rlLoadVertexBuffer(vertices, mesh->vertexCount*3*sizeof(float), dynamic);+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = rlLoadVertexBuffer(vertices, mesh->vertexCount*3*sizeof(float), dynamic); rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, 3, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION); // Enable vertex attributes: texcoords (shader-location = 1)- mesh->vboId[1] = rlLoadVertexBuffer(mesh->texcoords, mesh->vertexCount*2*sizeof(float), dynamic);+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = rlLoadVertexBuffer(mesh->texcoords, mesh->vertexCount*2*sizeof(float), dynamic); rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, 2, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD); @@ -1278,7 +1282,7 @@ { // Enable vertex attributes: normals (shader-location = 2) void *normals = (mesh->animNormals != NULL)? mesh->animNormals : mesh->normals;- mesh->vboId[2] = rlLoadVertexBuffer(normals, mesh->vertexCount*3*sizeof(float), dynamic);+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = rlLoadVertexBuffer(normals, mesh->vertexCount*3*sizeof(float), dynamic); rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, 3, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL); }@@ -1294,7 +1298,7 @@ if (mesh->colors != NULL) { // Enable vertex attribute: color (shader-location = 3)- mesh->vboId[3] = rlLoadVertexBuffer(mesh->colors, mesh->vertexCount*4*sizeof(unsigned char), dynamic);+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = rlLoadVertexBuffer(mesh->colors, mesh->vertexCount*4*sizeof(unsigned char), dynamic); rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, 4, RL_UNSIGNED_BYTE, 1, 0, 0); rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR); }@@ -1310,7 +1314,7 @@ if (mesh->tangents != NULL) { // Enable vertex attribute: tangent (shader-location = 4)- mesh->vboId[4] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), dynamic);+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), dynamic); rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, 4, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT); }@@ -1326,7 +1330,7 @@ if (mesh->texcoords2 != NULL) { // Enable vertex attribute: texcoord2 (shader-location = 5)- mesh->vboId[5] = rlLoadVertexBuffer(mesh->texcoords2, mesh->vertexCount*2*sizeof(float), dynamic);+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = rlLoadVertexBuffer(mesh->texcoords2, mesh->vertexCount*2*sizeof(float), dynamic); rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, 2, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2); }@@ -1339,9 +1343,43 @@ rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2); } +#ifdef RL_SUPPORT_MESH_GPU_SKINNING+ if (mesh->boneIds != NULL)+ {+ // Enable vertex attribute: boneIds (shader-location = 6)+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = rlLoadVertexBuffer(mesh->boneIds, mesh->vertexCount*4*sizeof(unsigned char), dynamic);+ rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, 4, RL_UNSIGNED_BYTE, 0, 0, 0);+ rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS);+ }+ else+ {+ // Default vertex attribute: boneIds+ // WARNING: Default value provided to shader if location available+ float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f };+ rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, value, SHADER_ATTRIB_VEC4, 4);+ rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS);+ }+ + if (mesh->boneWeights != NULL)+ {+ // Enable vertex attribute: boneWeights (shader-location = 7)+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = rlLoadVertexBuffer(mesh->boneWeights, mesh->vertexCount*4*sizeof(float), dynamic);+ rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, 4, RL_FLOAT, 0, 0, 0);+ rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS);+ }+ else+ {+ // Default vertex attribute: boneWeights+ // WARNING: Default value provided to shader if location available+ float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f };+ rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, value, SHADER_ATTRIB_VEC4, 2);+ rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS);+ }+#endif+ if (mesh->indices != NULL) {- mesh->vboId[6] = rlLoadVertexBufferElement(mesh->indices, mesh->triangleCount*3*sizeof(unsigned short), dynamic);+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = rlLoadVertexBufferElement(mesh->indices, mesh->triangleCount*3*sizeof(unsigned short), dynamic); } if (mesh->vaoId > 0) TRACELOG(LOG_INFO, "VAO: [ID %i] Mesh uploaded successfully to VRAM (GPU)", mesh->vaoId);@@ -1451,6 +1489,14 @@ // Upload model normal matrix (if locations available) if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel)));++#ifdef RL_SUPPORT_MESH_GPU_SKINNING+ // Upload Bone Transforms + if (material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1 && mesh.boneMatrices)+ {+ rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount);+ }+#endif //----------------------------------------------------- // Bind active texture maps (if available)@@ -1478,19 +1524,19 @@ if (!rlEnableVertexArray(mesh.vaoId)) { // Bind mesh VBO data: vertex position (shader-location = 0)- rlEnableVertexBuffer(mesh.vboId[0]);+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]); // Bind mesh VBO data: vertex texcoords (shader-location = 1)- rlEnableVertexBuffer(mesh.vboId[1]);+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]); if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1) { // Bind mesh VBO data: vertex normals (shader-location = 2)- rlEnableVertexBuffer(mesh.vboId[2]);+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL]); }@@ -1498,9 +1544,9 @@ // Bind mesh VBO data: vertex colors (shader-location = 3, if available) if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1) {- if (mesh.vboId[3] != 0)+ if (mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] != 0) {- rlEnableVertexBuffer(mesh.vboId[3]);+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR], 4, RL_UNSIGNED_BYTE, 1, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]); }@@ -1517,7 +1563,7 @@ // Bind mesh VBO data: vertex tangents (shader-location = 4, if available) if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1) {- rlEnableVertexBuffer(mesh.vboId[4]);+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT], 4, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT]); }@@ -1525,12 +1571,30 @@ // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available) if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1) {- rlEnableVertexBuffer(mesh.vboId[5]);+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]); } - if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]);+#ifdef RL_SUPPORT_MESH_GPU_SKINNING+ // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available)+ if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1)+ {+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS]);+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS], 4, RL_UNSIGNED_BYTE, 0, 0, 0);+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS]);+ }+ + // Bind mesh VBO data: vertex bone weights (shader-location = 7, if available)+ if (material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] != -1)+ {+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS]);+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0);+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]);+ }+#endif++ if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]); } int eyeCount = 1;@@ -1671,6 +1735,15 @@ // Upload model normal matrix (if locations available) if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel)));+ +#ifdef RL_SUPPORT_MESH_GPU_SKINNING+ // Upload Bone Transforms + if (material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1 && mesh.boneMatrices)+ {+ rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount);+ }+#endif+ //----------------------------------------------------- // Bind active texture maps (if available)@@ -1696,19 +1769,19 @@ if (!rlEnableVertexArray(mesh.vaoId)) { // Bind mesh VBO data: vertex position (shader-location = 0)- rlEnableVertexBuffer(mesh.vboId[0]);+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]); // Bind mesh VBO data: vertex texcoords (shader-location = 1)- rlEnableVertexBuffer(mesh.vboId[1]);+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]); if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1) { // Bind mesh VBO data: vertex normals (shader-location = 2)- rlEnableVertexBuffer(mesh.vboId[2]);+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL]); }@@ -1716,9 +1789,9 @@ // Bind mesh VBO data: vertex colors (shader-location = 3, if available) if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1) {- if (mesh.vboId[3] != 0)+ if (mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] != 0) {- rlEnableVertexBuffer(mesh.vboId[3]);+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR], 4, RL_UNSIGNED_BYTE, 1, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]); }@@ -1735,7 +1808,7 @@ // Bind mesh VBO data: vertex tangents (shader-location = 4, if available) if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1) {- rlEnableVertexBuffer(mesh.vboId[4]);+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT], 4, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT]); }@@ -1743,12 +1816,30 @@ // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available) if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1) {- rlEnableVertexBuffer(mesh.vboId[5]);+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]); } - if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]);+#ifdef RL_SUPPORT_MESH_GPU_SKINNING+ // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available)+ if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1)+ {+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS]);+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS], 4, RL_UNSIGNED_BYTE, 0, 0, 0);+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS]);+ }+ + // Bind mesh VBO data: vertex bone weights (shader-location = 7, if available)+ if (material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] != -1)+ {+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS]);+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0);+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]);+ }+#endif++ if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]); } int eyeCount = 1;@@ -1825,6 +1916,7 @@ RL_FREE(mesh.animNormals); RL_FREE(mesh.boneWeights); RL_FREE(mesh.boneIds);+ RL_FREE(mesh.boneMatrices); } // Export mesh data to file@@ -2004,7 +2096,6 @@ return success; } - #if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL) // Process obj materials static void ProcessMaterialsOBJ(Material *materials, tinyobj_material_t *mats, int materialCount)@@ -2016,6 +2107,8 @@ // NOTE: Uses default shader, which only supports MATERIAL_MAP_DIFFUSE materials[m] = LoadMaterialDefault(); + if (mats == NULL) continue;+ // Get default texture, in case no texture is defined // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8 materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };@@ -2253,6 +2346,50 @@ } } +void UpdateModelAnimationBoneMatrices(Model model, ModelAnimation anim, int frame)+{+ if ((anim.frameCount > 0) && (anim.bones != NULL) && (anim.framePoses != NULL))+ {+ if (frame >= anim.frameCount) frame = frame%anim.frameCount; + + for (int i = 0; i < model.meshCount; i++)+ {+ if (model.meshes[i].boneMatrices)+ {+ assert(model.meshes[i].boneCount == anim.boneCount);+ + for (int boneId = 0; boneId < model.meshes[i].boneCount; boneId++)+ {+ Vector3 inTranslation = model.bindPose[boneId].translation;+ Quaternion inRotation = model.bindPose[boneId].rotation;+ Vector3 inScale = model.bindPose[boneId].scale;+ + Vector3 outTranslation = anim.framePoses[frame][boneId].translation;+ Quaternion outRotation = anim.framePoses[frame][boneId].rotation;+ Vector3 outScale = anim.framePoses[frame][boneId].scale;++ Vector3 invTranslation = Vector3RotateByQuaternion(Vector3Negate(inTranslation), QuaternionInvert(inRotation));+ Quaternion invRotation = QuaternionInvert(inRotation);+ Vector3 invScale = Vector3Divide((Vector3){ 1.0f, 1.0f, 1.0f }, inScale);++ Vector3 boneTranslation = Vector3Add(+ Vector3RotateByQuaternion(Vector3Multiply(outScale, invTranslation),+ outRotation), outTranslation); + Quaternion boneRotation = QuaternionMultiply(outRotation, invRotation);+ Vector3 boneScale = Vector3Multiply(outScale, invScale);+ + Matrix boneMatrix = MatrixMultiply(MatrixMultiply(+ QuaternionToMatrix(boneRotation),+ MatrixTranslate(boneTranslation.x, boneTranslation.y, boneTranslation.z)),+ MatrixScale(boneScale.x, boneScale.y, boneScale.z));+ + model.meshes[i].boneMatrices[boneId] = boneMatrix;+ }+ }+ }+ }+}+ // Unload animation array data void UnloadModelAnimations(ModelAnimation *animations, int animCount) {@@ -3631,6 +3768,30 @@ rlDisableWireMode(); } +// Draw a model points+void DrawModelPoints(Model model, Vector3 position, float scale, Color tint)+{+ rlEnablePointMode();+ rlDisableBackfaceCulling();++ DrawModel(model, position, scale, tint);++ rlEnableBackfaceCulling();+ rlDisableWireMode();+}++// Draw a model points+void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)+{+ rlEnablePointMode();+ rlDisableBackfaceCulling();++ DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint);++ rlEnableBackfaceCulling();+ rlDisableWireMode();+}+ // Draw a billboard void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint) {@@ -4049,126 +4210,238 @@ // - the mesh is automatically triangulated by tinyobj static Model LoadOBJ(const char *fileName) {+ tinyobj_attrib_t objAttributes = { 0 };+ tinyobj_shape_t* objShapes = NULL;+ unsigned int objShapeCount = 0;++ tinyobj_material_t* objMaterials = NULL;+ unsigned int objMaterialCount = 0;+ Model model = { 0 };+ model.transform = MatrixIdentity(); - tinyobj_attrib_t attrib = { 0 };- tinyobj_shape_t *meshes = NULL;- unsigned int meshCount = 0;+ char* fileText = LoadFileText(fileName); - tinyobj_material_t *materials = NULL;- unsigned int materialCount = 0;+ if (fileText == NULL)+ {+ TRACELOG(LOG_ERROR, "MODEL Unable to read obj file %s", fileName);+ return model;+ } - char *fileText = LoadFileText(fileName);+ char currentDir[1024] = { 0 };+ strcpy(currentDir, GetWorkingDirectory()); // Save current working directory+ const char* workingDir = GetDirectoryPath(fileName); // Switch to OBJ directory for material path correctness+ if (CHDIR(workingDir) != 0)+ {+ TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", workingDir);+ } - if (fileText != NULL)+ unsigned int dataSize = (unsigned int)strlen(fileText);++ unsigned int flags = TINYOBJ_FLAG_TRIANGULATE;+ int ret = tinyobj_parse_obj(&objAttributes, &objShapes, &objShapeCount, &objMaterials, &objMaterialCount, fileText, dataSize, flags);++ if (ret != TINYOBJ_SUCCESS) {- unsigned int dataSize = (unsigned int)strlen(fileText);+ TRACELOG(LOG_ERROR, "MODEL Unable to read obj data %s", fileName);+ return model;+ } - char currentDir[1024] = { 0 };- strcpy(currentDir, GetWorkingDirectory()); // Save current working directory- const char *workingDir = GetDirectoryPath(fileName); // Switch to OBJ directory for material path correctness- if (CHDIR(workingDir) != 0)+ UnloadFileText(fileText);++ unsigned int faceVertIndex = 0;+ unsigned int nextShape = 1;+ int lastMaterial = -1;+ unsigned int meshIndex = 0;++ // count meshes+ unsigned int nextShapeEnd = objAttributes.num_face_num_verts;++ // see how many verts till the next shape++ if (objShapeCount > 1) nextShapeEnd = objShapes[nextShape].face_offset;++ // walk all the faces+ for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++)+ {+ if (faceVertIndex >= nextShapeEnd) {- TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", workingDir);+ // try to find the last vert in the next shape+ nextShape++;+ if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset;+ else nextShapeEnd = objAttributes.num_face_num_verts; // this is actually the total number of face verts in the file, not faces+ meshIndex++; }+ else if (lastMaterial != -1 && objAttributes.material_ids[faceId] != lastMaterial)+ {+ meshIndex++;// if this is a new material, we need to allocate a new mesh+ } - unsigned int flags = TINYOBJ_FLAG_TRIANGULATE;- int ret = tinyobj_parse_obj(&attrib, &meshes, &meshCount, &materials, &materialCount, fileText, dataSize, flags);+ lastMaterial = objAttributes.material_ids[faceId];+ faceVertIndex += objAttributes.face_num_verts[faceId];+ } - if (ret != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load OBJ data", fileName);- else TRACELOG(LOG_INFO, "MODEL: [%s] OBJ data loaded successfully: %i meshes/%i materials", fileName, meshCount, materialCount);+ // allocate the base meshes and materials+ model.meshCount = meshIndex + 1;+ model.meshes = (Mesh*)MemAlloc(sizeof(Mesh) * model.meshCount); - // WARNING: We are not splitting meshes by materials (previous implementation)- // Depending on the provided OBJ that was not the best option and it just crashed- // so, implementation was simplified to prioritize parsed meshes- model.meshCount = meshCount;+ if (objMaterialCount > 0)+ {+ model.materialCount = objMaterialCount;+ model.materials = (Material*)MemAlloc(sizeof(Material) * objMaterialCount);+ }+ else // we must allocate at least one material+ {+ model.materialCount = 1;+ model.materials = (Material*)MemAlloc(sizeof(Material) * 1);+ } - // Set number of materials available- // NOTE: There could be more materials available than meshes but it will be resolved at- // model.meshMaterial, just assigning the right material to corresponding mesh- model.materialCount = materialCount;- if (model.materialCount == 0)+ model.meshMaterial = (int*)MemAlloc(sizeof(int) * model.meshCount);++ // see how many verts are in each mesh+ unsigned int* localMeshVertexCounts = (unsigned int*)MemAlloc(sizeof(unsigned int) * model.meshCount);++ faceVertIndex = 0;+ nextShapeEnd = objAttributes.num_face_num_verts;+ lastMaterial = -1;+ meshIndex = 0;+ unsigned int localMeshVertexCount = 0;++ nextShape = 1;+ if (objShapeCount > 1)+ nextShapeEnd = objShapes[nextShape].face_offset;++ // walk all the faces+ for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++)+ {+ bool newMesh = false; // do we need a new mesh?+ if (faceVertIndex >= nextShapeEnd) {- model.materialCount = 1;- TRACELOG(LOG_INFO, "MODEL: No materials provided, setting one default material for all meshes");+ // try to find the last vert in the next shape+ nextShape++;+ if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset;+ else nextShapeEnd = objAttributes.num_face_num_verts; // this is actually the total number of face verts in the file, not faces++ newMesh = true; }+ else if (lastMaterial != -1 && objAttributes.material_ids[faceId] != lastMaterial)+ {+ newMesh = true;+ } - // Init model meshes and materials- model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));- model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); // Material index assigned to each mesh- model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));+ lastMaterial = objAttributes.material_ids[faceId]; - // Process each provided mesh- for (int i = 0; i < model.meshCount; i++)+ if (newMesh) {- // WARNING: We need to calculate the mesh triangles manually using meshes[i].face_offset- // because in case of triangulated quads, meshes[i].length actually report quads,- // despite the triangulation that is efectively considered on attrib.num_faces- unsigned int tris = 0;- if (i == model.meshCount - 1) tris = attrib.num_faces - meshes[i].face_offset;- else tris = meshes[i + 1].face_offset;+ localMeshVertexCounts[meshIndex] = localMeshVertexCount; - model.meshes[i].vertexCount = tris*3;- model.meshes[i].triangleCount = tris; // Face count (triangulated)- model.meshes[i].vertices = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));- model.meshes[i].texcoords = (float *)RL_CALLOC(model.meshes[i].vertexCount*2, sizeof(float));- model.meshes[i].normals = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));- model.meshMaterial[i] = 0; // By default, assign material 0 to each mesh+ localMeshVertexCount = 0;+ meshIndex++;+ } - // Process all mesh faces- for (unsigned int face = 0, f = meshes[i].face_offset, v = 0, vt = 0, vn = 0; face < tris; face++, f++, v += 3, vt += 3, vn += 3)- {- // Get indices for the face- tinyobj_vertex_index_t idx0 = attrib.faces[f*3 + 0];- tinyobj_vertex_index_t idx1 = attrib.faces[f*3 + 1];- tinyobj_vertex_index_t idx2 = attrib.faces[f*3 + 2];+ faceVertIndex += objAttributes.face_num_verts[faceId];+ localMeshVertexCount += objAttributes.face_num_verts[faceId];+ }+ localMeshVertexCounts[meshIndex] = localMeshVertexCount; - // Fill vertices buffer (float) using vertex index of the face- for (int n = 0; n < 3; n++) { model.meshes[i].vertices[v*3 + n] = attrib.vertices[idx0.v_idx*3 + n]; }- for (int n = 0; n < 3; n++) { model.meshes[i].vertices[(v + 1)*3 + n] = attrib.vertices[idx1.v_idx*3 + n]; }- for (int n = 0; n < 3; n++) { model.meshes[i].vertices[(v + 2)*3 + n] = attrib.vertices[idx2.v_idx*3 + n]; }+ for (int i = 0; i < model.meshCount; i++)+ {+ // allocate the buffers for each mesh+ unsigned int vertexCount = localMeshVertexCounts[i]; - if (attrib.num_texcoords > 0)- {- // Fill texcoords buffer (float) using vertex index of the face- // NOTE: Y-coordinate must be flipped upside-down- model.meshes[i].texcoords[vt*2 + 0] = attrib.texcoords[idx0.vt_idx*2 + 0];- model.meshes[i].texcoords[vt*2 + 1] = 1.0f - attrib.texcoords[idx0.vt_idx*2 + 1];+ model.meshes[i].vertexCount = vertexCount;+ model.meshes[i].triangleCount = vertexCount / 3; - model.meshes[i].texcoords[(vt + 1)*2 + 0] = attrib.texcoords[idx1.vt_idx*2 + 0];- model.meshes[i].texcoords[(vt + 1)*2 + 1] = 1.0f - attrib.texcoords[idx1.vt_idx*2 + 1];+ model.meshes[i].vertices = (float*)MemAlloc(sizeof(float) * vertexCount * 3);+ model.meshes[i].normals = (float*)MemAlloc(sizeof(float) * vertexCount * 3);+ model.meshes[i].texcoords = (float*)MemAlloc(sizeof(float) * vertexCount * 2);+ model.meshes[i].colors = (unsigned char*)MemAlloc(sizeof(unsigned char) * vertexCount * 4);+ } - model.meshes[i].texcoords[(vt + 2)*2 + 0] = attrib.texcoords[idx2.vt_idx*2 + 0];- model.meshes[i].texcoords[(vt + 2)*2 + 1] = 1.0f - attrib.texcoords[idx2.vt_idx*2 + 1];- }+ MemFree(localMeshVertexCounts);+ localMeshVertexCounts = NULL; - if (attrib.num_normals > 0)- {- // Fill normals buffer (float) using vertex index of the face- for (int n = 0; n < 3; n++) { model.meshes[i].normals[vn*3 + n] = attrib.normals[idx0.vn_idx*3 + n]; }- for (int n = 0; n < 3; n++) { model.meshes[i].normals[(vn + 1)*3 + n] = attrib.normals[idx1.vn_idx*3 + n]; }- for (int n = 0; n < 3; n++) { model.meshes[i].normals[(vn + 2)*3 + n] = attrib.normals[idx2.vn_idx*3 + n]; }- }- }+ // fill meshes+ faceVertIndex = 0;++ nextShapeEnd = objAttributes.num_face_num_verts;++ // see how many verts till the next shape+ nextShape = 1;+ if (objShapeCount > 1) nextShapeEnd = objShapes[nextShape].face_offset;+ lastMaterial = -1;+ meshIndex = 0;+ localMeshVertexCount = 0;++ // walk all the faces+ for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++)+ {+ bool newMesh = false; // do we need a new mesh?+ if (faceVertIndex >= nextShapeEnd)+ {+ // try to find the last vert in the next shape+ nextShape++;+ if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset;+ else nextShapeEnd = objAttributes.num_face_num_verts; // this is actually the total number of face verts in the file, not faces+ newMesh = true; }+ // if this is a new material, we need to allocate a new mesh+ if (lastMaterial != -1 && objAttributes.material_ids[faceId] != lastMaterial) newMesh = true;+ lastMaterial = objAttributes.material_ids[faceId]; - // Init model materials- if (materialCount > 0) ProcessMaterialsOBJ(model.materials, materials, materialCount);- else model.materials[0] = LoadMaterialDefault(); // Set default material for the mesh+ if (newMesh)+ {+ localMeshVertexCount = 0;+ meshIndex++;+ } - tinyobj_attrib_free(&attrib);- tinyobj_shapes_free(meshes, model.meshCount);- tinyobj_materials_free(materials, materialCount);+ int matId = 0;+ if (lastMaterial >= 0 && lastMaterial < (int)objMaterialCount)+ matId = lastMaterial; - UnloadFileText(fileText);+ model.meshMaterial[meshIndex] = matId; - // Restore current working directory- if (CHDIR(currentDir) != 0)+ for (int f = 0; f < objAttributes.face_num_verts[faceId]; f++) {- TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", currentDir);+ int vertIndex = objAttributes.faces[faceVertIndex].v_idx;+ int normalIndex = objAttributes.faces[faceVertIndex].vn_idx;+ int texcordIndex = objAttributes.faces[faceVertIndex].vt_idx;++ for (int i = 0; i < 3; i++)+ model.meshes[meshIndex].vertices[localMeshVertexCount * 3 + i] = objAttributes.vertices[vertIndex * 3 + i];++ for (int i = 0; i < 3; i++)+ model.meshes[meshIndex].normals[localMeshVertexCount * 3 + i] = objAttributes.normals[normalIndex * 3 + i];++ for (int i = 0; i < 2; i++)+ model.meshes[meshIndex].texcoords[localMeshVertexCount * 2 + i] = objAttributes.texcoords[texcordIndex * 2 + i];++ model.meshes[meshIndex].texcoords[localMeshVertexCount * 2 + 1] = 1.0f - model.meshes[meshIndex].texcoords[localMeshVertexCount * 2 + 1];++ for (int i = 0; i < 4; i++)+ model.meshes[meshIndex].colors[localMeshVertexCount * 4 + i] = 255;++ faceVertIndex++;+ localMeshVertexCount++; } } + if (objMaterialCount > 0) ProcessMaterialsOBJ(model.materials, objMaterials, objMaterialCount);+ else model.materials[0] = LoadMaterialDefault(); // Set default material for the mesh++ tinyobj_attrib_free(&objAttributes);+ tinyobj_shapes_free(objShapes, objShapeCount);+ tinyobj_materials_free(objMaterials, objMaterialCount);++ for (int i = 0; i < model.meshCount; i++)+ UploadMesh(model.meshes + i, true);++ // Restore current working directory+ if (CHDIR(currentDir) != 0)+ {+ TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", currentDir);+ }+ return model; } #endif@@ -4533,6 +4806,17 @@ } BuildPoseFromParentJoints(model.bones, model.boneCount, model.bindPose);+ + for (int i = 0; i < model.meshCount; i++)+ {+ model.meshes[i].boneCount = model.boneCount;+ model.meshes[i].boneMatrices = RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));+ + for (int j = 0; j < model.meshes[i].boneCount; j++)+ {+ model.meshes[i].boneMatrices[j] = MatrixIdentity();+ }+ } UnloadFileData(fileData); @@ -4942,17 +5226,19 @@ ***********************************************************************************************/ // Macro to simplify attributes loading code- #define LOAD_ATTRIBUTE(accesor, numComp, dataType, dstPtr) \+ #define LOAD_ATTRIBUTE(accesor, numComp, srcType, dstPtr) LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, srcType) ++ #define LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, dstType) \ { \ int n = 0; \- dataType *buffer = (dataType *)accesor->buffer_view->buffer->data + accesor->buffer_view->offset/sizeof(dataType) + accesor->offset/sizeof(dataType); \+ srcType *buffer = (srcType *)accesor->buffer_view->buffer->data + accesor->buffer_view->offset/sizeof(srcType) + accesor->offset/sizeof(srcType); \ for (unsigned int k = 0; k < accesor->count; k++) \ {\ for (int l = 0; l < numComp; l++) \ {\- dstPtr[numComp*k + l] = buffer[n + l];\+ dstPtr[numComp*k + l] = (dstType)buffer[n + l];\ }\- n += (int)(accesor->stride/sizeof(dataType));\+ n += (int)(accesor->stride/sizeof(srcType));\ }\ } @@ -5393,8 +5679,6 @@ else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName); } else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName);-- } // NOTE: Attributes related to animations are processed separately@@ -5415,23 +5699,25 @@ // Load unsigned short data type into mesh.indices LOAD_ATTRIBUTE(attribute, 1, unsigned short, model.meshes[meshIndex].indices) }+ else if (attribute->component_type == cgltf_component_type_r_8u)+ {+ // Init raylib mesh indices to copy glTF attribute data+ model.meshes[meshIndex].indices = RL_MALLOC(attribute->count * sizeof(unsigned short));+ LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned char, model.meshes[meshIndex].indices, unsigned short)++ } else if (attribute->component_type == cgltf_component_type_r_32u) { // Init raylib mesh indices to copy glTF attribute data model.meshes[meshIndex].indices = RL_MALLOC(attribute->count*sizeof(unsigned short));-- // Load data into a temp buffer to be converted to raylib data type- unsigned int *temp = RL_MALLOC(attribute->count*sizeof(unsigned int));- LOAD_ATTRIBUTE(attribute, 1, unsigned int, temp);-- // Convert data to raylib indices data type (unsigned short)- for (unsigned int d = 0; d < attribute->count; d++) model.meshes[meshIndex].indices[d] = (unsigned short)temp[d];+ LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned int, model.meshes[meshIndex].indices, unsigned short); TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data converted from u32 to u16, possible loss of data", fileName);-- RL_FREE(temp); }- else TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data format not supported, use u16", fileName);+ else + {+ TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data format not supported, use u16", fileName);+ } } else model.meshes[meshIndex].triangleCount = model.meshes[meshIndex].vertexCount/3; // Unindexed mesh @@ -5463,7 +5749,7 @@ // - Only supports linear interpolation (default method in Blender when checked "Always Sample Animations" when exporting a GLTF file) // - Only supports translation/rotation/scale animation channel.path, weights not considered (i.e. morph targets) //----------------------------------------------------------------------------------------------------- if (data->skins_count == 1)+ if (data->skins_count > 0) { cgltf_skin skin = data->skins[0]; model.bones = LoadBoneInfoGLTF(skin, &model.boneCount);@@ -5483,9 +5769,9 @@ MatrixDecompose(worldMatrix, &(model.bindPose[i].translation), &(model.bindPose[i].rotation), &(model.bindPose[i].scale)); } }- else if (data->skins_count > 1)+ if (data->skins_count > 1) {- TRACELOG(LOG_ERROR, "MODEL: [%s] can only load one skin (armature) per model, but gltf skins_count == %i", fileName, data->skins_count);+ TRACELOG(LOG_WARNING, "MODEL: [%s] can only load one skin (armature) per model, but gltf skins_count == %i", fileName, data->skins_count); } meshIndex = 0;@@ -5616,6 +5902,15 @@ { memcpy(model.meshes[meshIndex].animNormals, model.meshes[meshIndex].normals, model.meshes[meshIndex].vertexCount*3*sizeof(float)); }+ + // Bone Transform Matrices+ model.meshes[meshIndex].boneCount = model.boneCount;+ model.meshes[meshIndex].boneMatrices = RL_CALLOC(model.meshes[meshIndex].boneCount, sizeof(Matrix));+ + for (int j = 0; j < model.meshes[meshIndex].boneCount; j++)+ {+ model.meshes[meshIndex].boneMatrices[j] = MatrixIdentity();+ } meshIndex++; // Move to next mesh }@@ -5741,11 +6036,11 @@ cgltf_accessor_read_float(output, 3*keyframe+1, tmp, 4); Vector4 v1 = {tmp[0], tmp[1], tmp[2], tmp[3]}; cgltf_accessor_read_float(output, 3*keyframe+2, tmp, 4);- Vector4 outTangent1 = {tmp[0], tmp[1], tmp[2]};+ Vector4 outTangent1 = {tmp[0], tmp[1], tmp[2], 0.0f}; cgltf_accessor_read_float(output, 3*(keyframe+1)+1, tmp, 4); Vector4 v2 = {tmp[0], tmp[1], tmp[2], tmp[3]}; cgltf_accessor_read_float(output, 3*(keyframe+1), tmp, 4);- Vector4 inTangent2 = {tmp[0], tmp[1], tmp[2]};+ Vector4 inTangent2 = {tmp[0], tmp[1], tmp[2], 0.0f}; Vector4 *r = data; v1 = QuaternionNormalize(v1);@@ -5797,7 +6092,7 @@ if (result == cgltf_result_success) {- if (data->skins_count == 1)+ if (data->skins_count > 0) { cgltf_skin skin = data->skins[0]; *animCount = (int)data->animations_count;@@ -5932,7 +6227,11 @@ RL_FREE(boneChannels); } }- else TRACELOG(LOG_ERROR, "MODEL: [%s] expected exactly one skin to load animation data from, but found %i", fileName, data->skins_count);+ + if (data->skins_count > 1)+ {+ TRACELOG(LOG_WARNING, "MODEL: [%s] expected exactly one skin to load animation data from, but found %i", fileName, data->skins_count);+ } cgltf_free(data); }@@ -6384,6 +6683,13 @@ { memcpy(model.meshes[i].animVertices, model.meshes[i].vertices, model.meshes[i].vertexCount*3*sizeof(float)); memcpy(model.meshes[i].animNormals, model.meshes[i].normals, model.meshes[i].vertexCount*3*sizeof(float));+ + model.meshes[i].boneCount = model.boneCount;+ model.meshes[i].boneMatrices = RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));+ for (j = 0; j < model.meshes[i].boneCount; j++)+ {+ model.meshes[i].boneMatrices[j] = MatrixIdentity();+ } } }
raylib/src/rshapes.c view
@@ -79,8 +79,8 @@ //---------------------------------------------------------------------------------- // Global Variables Definition //-----------------------------------------------------------------------------------Texture2D texShapes = { 1, 1, 1, 1, 7 }; // Texture used on shapes drawing (white pixel loaded by rlgl)-Rectangle texShapesRec = { 0.0f, 0.0f, 1.0f, 1.0f }; // Texture source rectangle used on shapes drawing+static Texture2D texShapes = { 1, 1, 1, 1, 7 }; // Texture used on shapes drawing (white pixel loaded by rlgl)+static Rectangle texShapesRec = { 0.0f, 0.0f, 1.0f, 1.0f }; // Texture source rectangle used on shapes drawing //---------------------------------------------------------------------------------- // Module specific Functions Declaration@@ -430,17 +430,16 @@ } // Draw a gradient-filled circle-// NOTE: Gradient goes from center (color1) to border (color2)-void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2)+void DrawCircleGradient(int centerX, int centerY, float radius, Color inner, Color outer) { rlBegin(RL_TRIANGLES); for (int i = 0; i < 360; i += 10) {- rlColor4ub(color1.r, color1.g, color1.b, color1.a);+ rlColor4ub(inner.r, inner.g, inner.b, inner.a); rlVertex2f((float)centerX, (float)centerY);- rlColor4ub(color2.r, color2.g, color2.b, color2.a);+ rlColor4ub(outer.r, outer.g, outer.b, outer.a); rlVertex2f((float)centerX + cosf(DEG2RAD*(i + 10))*radius, (float)centerY + sinf(DEG2RAD*(i + 10))*radius);- rlColor4ub(color2.r, color2.g, color2.b, color2.a);+ rlColor4ub(outer.r, outer.g, outer.b, outer.a); rlVertex2f((float)centerX + cosf(DEG2RAD*i)*radius, (float)centerY + sinf(DEG2RAD*i)*radius); } rlEnd();@@ -761,22 +760,19 @@ } // Draw a vertical-gradient-filled rectangle-// NOTE: Gradient goes from bottom (color1) to top (color2)-void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2)+void DrawRectangleGradientV(int posX, int posY, int width, int height, Color top, Color bottom) {- DrawRectangleGradientEx((Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, color1, color2, color2, color1);+ DrawRectangleGradientEx((Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, top, bottom, bottom, top); } // Draw a horizontal-gradient-filled rectangle-// NOTE: Gradient goes from bottom (color1) to top (color2)-void DrawRectangleGradientH(int posX, int posY, int width, int height, Color color1, Color color2)+void DrawRectangleGradientH(int posX, int posY, int width, int height, Color left, Color right) {- DrawRectangleGradientEx((Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, color1, color1, color2, color2);+ DrawRectangleGradientEx((Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, left, left, right, right); } // Draw a gradient-filled rectangle-// NOTE: Colors refer to corners, starting at top-lef corner and counter-clockwise-void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4)+void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color topRight, Color bottomRight) { rlSetTexture(GetShapesTexture().id); Rectangle shapeRect = GetShapesTextureRectangle();@@ -785,19 +781,19 @@ rlNormal3f(0.0f, 0.0f, 1.0f); // NOTE: Default raylib font character 95 is a white square- rlColor4ub(col1.r, col1.g, col1.b, col1.a);+ rlColor4ub(topLeft.r, topLeft.g, topLeft.b, topLeft.a); rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); rlVertex2f(rec.x, rec.y); - rlColor4ub(col2.r, col2.g, col2.b, col2.a);+ rlColor4ub(bottomLeft.r, bottomLeft.g, bottomLeft.b, bottomLeft.a); rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); rlVertex2f(rec.x, rec.y + rec.height); - rlColor4ub(col3.r, col3.g, col3.b, col3.a);+ rlColor4ub(topRight.r, topRight.g, topRight.b, topRight.a); rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); rlVertex2f(rec.x + rec.width, rec.y + rec.height); - rlColor4ub(col4.r, col4.g, col4.b, col4.a);+ rlColor4ub(bottomRight.r, bottomRight.g, bottomRight.b, bottomRight.a); rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); rlVertex2f(rec.x + rec.width, rec.y); rlEnd();
raylib/src/rtext.c view
@@ -124,6 +124,7 @@ //---------------------------------------------------------------------------------- // Global variables //----------------------------------------------------------------------------------+extern bool isGpuReady; #if defined(SUPPORT_DEFAULT_FONT) // Default font provided by raylib // NOTE: Default font is loaded on InitWindow() and disposed on CloseWindow() [module: core]@@ -252,15 +253,15 @@ counter++; } - defaultFont.texture = LoadTextureFromImage(imFont);+ if (isGpuReady) defaultFont.texture = LoadTextureFromImage(imFont); // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount //------------------------------------------------------------------------------ // Allocate space for our characters info data // NOTE: This memory must be freed at end! --> Done by CloseWindow()- defaultFont.glyphs = (GlyphInfo *)RL_MALLOC(defaultFont.glyphCount*sizeof(GlyphInfo));- defaultFont.recs = (Rectangle *)RL_MALLOC(defaultFont.glyphCount*sizeof(Rectangle));+ defaultFont.glyphs = (GlyphInfo *)RL_CALLOC(defaultFont.glyphCount, sizeof(GlyphInfo));+ defaultFont.recs = (Rectangle *)RL_CALLOC(defaultFont.glyphCount, sizeof(Rectangle)); int currentLine = 0; int currentPosX = charsDivisor;@@ -308,7 +309,7 @@ extern void UnloadFontDefault(void) { for (int i = 0; i < defaultFont.glyphCount; i++) UnloadImage(defaultFont.glyphs[i].image);- UnloadTexture(defaultFont.texture);+ if (isGpuReady) UnloadTexture(defaultFont.texture); RL_FREE(defaultFont.glyphs); RL_FREE(defaultFont.recs); }@@ -362,11 +363,14 @@ UnloadImage(image); } - if (font.texture.id == 0) TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);- else+ if (isGpuReady) {- SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance)- TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", FONT_TTF_DEFAULT_SIZE, FONT_TTF_DEFAULT_NUMCHARS);+ if (font.texture.id == 0) TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);+ else+ {+ SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance)+ TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", FONT_TTF_DEFAULT_SIZE, FONT_TTF_DEFAULT_NUMCHARS);+ } } return font;@@ -487,7 +491,7 @@ }; // Set font with all data parsed from image- font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture+ if (isGpuReady) font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture font.glyphCount = index; font.glyphPadding = 0; @@ -556,7 +560,7 @@ font.glyphPadding = FONT_TTF_DEFAULT_CHARS_PADDING; Image atlas = GenImageFontAtlas(font.glyphs, &font.recs, font.glyphCount, font.baseSize, font.glyphPadding, 0);- font.texture = LoadTextureFromImage(atlas);+ if (isGpuReady) font.texture = LoadTextureFromImage(atlas); // Update glyphs[i].image to use alpha, required to be used on ImageDrawText() for (int i = 0; i < font.glyphCount; i++)@@ -580,7 +584,7 @@ // Check if a font is ready bool IsFontReady(Font font) {- return ((font.texture.id > 0) && // Validate OpenGL id fot font texture atlas+ return ((font.texture.id > 0) && // Validate OpenGL id for font texture atlas (font.baseSize > 0) && // Validate font size (font.glyphCount > 0) && // Validate font contains some glyph (font.recs != NULL) && // Validate font recs defining glyphs on texture atlas@@ -673,6 +677,8 @@ { stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL); chars[i].advanceX = (int)((float)chars[i].advanceX*scaleFactor);+ + if (chh > fontSize) TRACELOG(LOG_WARNING, "FONT: Character [0x%08x] size is bigger than expected font size", ch); // Load characters images chars[i].image.width = chw;@@ -946,7 +952,7 @@ if (font.texture.id != GetFontDefault().texture.id) { UnloadFontData(font.glyphs, font.glyphCount);- UnloadTexture(font.texture);+ if (isGpuReady) UnloadTexture(font.texture); RL_FREE(font.recs); TRACELOGD("FONT: Unloaded font data from RAM and VRAM");@@ -1066,7 +1072,7 @@ byteCount += sprintf(txtData + byteCount, " Image imFont = { fontImageData_%s, %i, %i, 1, %i };\n\n", styleName, image.width, image.height, image.format); #endif byteCount += sprintf(txtData + byteCount, " // Load texture from image\n");- byteCount += sprintf(txtData + byteCount, " font.texture = LoadTextureFromImage(imFont);\n");+ byteCount += sprintf(txtData + byteCount, " if (isGpuReady) font.texture = LoadTextureFromImage(imFont);\n"); #if defined(SUPPORT_COMPRESSED_FONT_ATLAS) byteCount += sprintf(txtData + byteCount, " UnloadImage(imFont); // Uncompressed data can be unloaded from memory\n\n"); #endif@@ -1277,7 +1283,7 @@ { Vector2 textSize = { 0 }; - if ((font.texture.id == 0) || (text == NULL)) return textSize; // Security check+ if ((isGpuReady && (font.texture.id == 0)) || (text == NULL)) return textSize; // Security check int size = TextLength(text); // Get size in bytes of text int tempByteCounter = 0; // Used to count longer text line num chars@@ -1467,8 +1473,7 @@ 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+ if (text[i++] == '.') { float divisor = 10.0f; for (; ((text[i] >= '0') && (text[i] <= '9')); i++)@@ -1478,7 +1483,7 @@ } } - return value;+ return value*sign; } #if defined(SUPPORT_TEXT_MANIPULATION)@@ -2258,7 +2263,7 @@ RL_FREE(imFonts); - font.texture = LoadTextureFromImage(fullFont);+ if (isGpuReady) font.texture = LoadTextureFromImage(fullFont); // Fill font characters info data font.baseSize = fontSize;@@ -2300,7 +2305,7 @@ UnloadImage(fullFont); UnloadFileText(fileText); - if (font.texture.id == 0)+ if (isGpuReady && (font.texture.id == 0)) { UnloadFont(font); font = GetFontDefault();
raylib/src/rtextures.c view
@@ -225,14 +225,6 @@ #pragma GCC diagnostic pop #endif -#if defined(SUPPORT_FILEFORMAT_SVG)- #define NANOSVG_IMPLEMENTATION // Expands implementation- #include "external/nanosvg.h"-- #define NANOSVGRAST_IMPLEMENTATION- #include "external/nanosvgrast.h"-#endif- //---------------------------------------------------------------------------------- // Defines and Macros //----------------------------------------------------------------------------------@@ -335,84 +327,6 @@ return image; } -// Load an image from a SVG file or string with custom size-Image LoadImageSvg(const char *fileNameOrString, int width, int height)-{- Image image = { 0 };--#if defined(SUPPORT_FILEFORMAT_SVG)- bool isSvgStringValid = false;-- // Validate fileName or string- if (fileNameOrString != NULL)- {- int dataSize = 0;- unsigned char *fileData = NULL;-- if (FileExists(fileNameOrString))- {- fileData = LoadFileData(fileNameOrString, &dataSize);- isSvgStringValid = true;- }- else- {- // Validate fileData as valid SVG string data- //<svg xmlns="http://www.w3.org/2000/svg" width="2500" height="2484" viewBox="0 0 192.756 191.488">- if ((fileNameOrString != NULL) &&- (fileNameOrString[0] == '<') &&- (fileNameOrString[1] == 's') &&- (fileNameOrString[2] == 'v') &&- (fileNameOrString[3] == 'g'))- {- fileData = (unsigned char *)fileNameOrString;- isSvgStringValid = true;- }- }-- if (isSvgStringValid)- {- struct NSVGimage *svgImage = nsvgParse(fileData, "px", 96.0f);-- unsigned char *img = RL_MALLOC(width*height*4);-- // Calculate scales for both the width and the height- const float scaleWidth = width/svgImage->width;- const float scaleHeight = height/svgImage->height;-- // Set the largest of the 2 scales to be the scale to use- const float scale = (scaleHeight > scaleWidth)? scaleWidth : scaleHeight;-- int offsetX = 0;- int offsetY = 0;-- if (scaleHeight > scaleWidth) offsetY = (height - svgImage->height*scale)/2;- else offsetX = (width - svgImage->width*scale)/2;-- // Rasterize- struct NSVGrasterizer *rast = nsvgCreateRasterizer();- nsvgRasterize(rast, svgImage, (int)offsetX, (int)offsetY, scale, img, width, height, width*4);-- // Populate image struct with all data- image.data = img;- image.width = width;- image.height = height;- image.mipmaps = 1;- image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;-- // Free used memory- nsvgDelete(svgImage);- nsvgDeleteRasterizer(rast);- }-- if (isSvgStringValid && (fileData != fileNameOrString)) UnloadFileData(fileData);- }-#else- TRACELOG(LOG_WARNING, "SVG image support not enabled, image can not be loaded");-#endif-- return image;-}- // Load animated image data // - Image.data buffer includes all frames: [image#0][image#1][image#2][...] // - Number of frames is returned through 'frames' parameter@@ -503,7 +417,16 @@ Image image = { 0 }; // Security check for input data- if ((fileType == NULL) || (fileData == NULL) || (dataSize == 0)) return image;+ if ((fileData == NULL) || (dataSize == 0))+ {+ TRACELOG(LOG_WARNING, "IMAGE: Invalid file data");+ return image;+ }+ if (fileType == NULL)+ {+ TRACELOG(LOG_WARNING, "IMAGE: Missing file extension");+ return image;+ } if ((false) #if defined(SUPPORT_FILEFORMAT_PNG)@@ -591,36 +514,6 @@ } } #endif-#if defined(SUPPORT_FILEFORMAT_SVG)- else if ((strcmp(fileType, ".svg") == 0) || (strcmp(fileType, ".SVG") == 0))- {- // Validate fileData as valid SVG string data- //<svg xmlns="http://www.w3.org/2000/svg" width="2500" height="2484" viewBox="0 0 192.756 191.488">- if ((fileData != NULL) &&- (fileData[0] == '<') &&- (fileData[1] == 's') &&- (fileData[2] == 'v') &&- (fileData[3] == 'g'))- {- struct NSVGimage *svgImage = nsvgParse(fileData, "px", 96.0f);- unsigned char *img = RL_MALLOC(svgImage->width*svgImage->height*4);-- // Rasterize- struct NSVGrasterizer *rast = nsvgCreateRasterizer();- nsvgRasterize(rast, svgImage, 0, 0, 1.0f, img, svgImage->width, svgImage->height, svgImage->width*4);-- // Populate image struct with all data- image.data = img;- image.width = svgImage->width;- image.height = svgImage->height;- image.mipmaps = 1;- image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;-- nsvgDelete(svgImage);- nsvgDeleteRasterizer(rast);- }- }-#endif #if defined(SUPPORT_FILEFORMAT_DDS) else if ((strcmp(fileType, ".dds") == 0) || (strcmp(fileType, ".DDS") == 0)) {@@ -1103,6 +996,7 @@ { Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color)); + float aspectRatio = (float)width / (float)height; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++)@@ -1110,6 +1004,10 @@ float nx = (float)(x + offsetX)*(scale/(float)width); float ny = (float)(y + offsetY)*(scale/(float)height); + // Apply aspect ratio compensation to wider side+ if (width > height) nx *= aspectRatio;+ else ny /= aspectRatio;+ // Basic perlin noise implementation (not used) //float p = (stb_perlin_noise3(nx, ny, 0.0f, 0, 0, 0); @@ -1213,6 +1111,7 @@ { Image image = { 0 }; +#if defined(SUPPORT_MODULE_RTEXT) int textLength = TextLength(text); int imageViewSize = width*height; @@ -1223,6 +1122,10 @@ image.mipmaps = 1; memcpy(image.data, text, (textLength > imageViewSize)? imageViewSize : textLength);+#else+ TRACELOG(LOG_WARNING, "IMAGE: GenImageText() requires module: rtext");+ image = GenImageColor(width, height, BLACK); // Generating placeholder black image rectangle+#endif return image; }@@ -4546,6 +4449,9 @@ if (source.width < 0) { flipX = true; source.width *= -1; } if (source.height < 0) source.y -= source.height;+ + if (dest.width < 0) dest.width *= -1;+ if (dest.height < 0) dest.height *= -1; Vector2 topLeft = { 0 }; Vector2 topRight = { 0 };@@ -5164,6 +5070,22 @@ return out; } +// Get color lerp interpolation between two colors, factor [0.0f..1.0f]+Color ColorLerp(Color color1, Color color2, float factor) +{ + Color color = { 0 };+ + if (factor < 0.0f) factor = 0.0f;+ else if (factor > 1.0f) factor = 1.0f;++ color.r = (unsigned char)((1.0f - factor)*color1.r + factor*color2.r);+ color.g = (unsigned char)((1.0f - factor)*color1.g + factor*color2.g);+ color.b = (unsigned char)((1.0f - factor)*color1.b + factor*color2.b);+ color.a = (unsigned char)((1.0f - factor)*color1.a + factor*color2.a);++ return color;+}+ // Get a Color struct from hexadecimal value Color GetColor(unsigned int hexValue) {@@ -5389,7 +5311,8 @@ default: break; } - dataSize = width*height*bpp/8; // Total data size in bytes+ double bytesPerPixel = (double)bpp/8.0;+ dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes // Most compressed formats works on 4x4 blocks, // if texture is smaller, minimum dataSize is 8 or 16
raylib/src/utils.c view
@@ -76,7 +76,6 @@ void SetLoadFileTextCallback(LoadFileTextCallback callback) { loadFileText = callback; } // Set custom file text loader void SetSaveFileTextCallback(SaveFileTextCallback callback) { saveFileText = callback; } // Set custom file text saver - #if defined(PLATFORM_ANDROID) static AAssetManager *assetManager = NULL; // Android assets manager pointer static const char *internalDataPath = NULL; // Android internal data path
src/Raylib/Core.hs view
@@ -112,6 +112,7 @@ traceLog, setTraceLogLevel, openURL,+ setTraceLogCallback, setLoadFileDataCallback, setSaveFileDataCallback, setLoadFileTextCallback,@@ -132,6 +133,7 @@ getPrevDirectoryPath, getWorkingDirectory, getApplicationDirectory,+ makeDirectory, changeDirectory, isPathFile, isFileNameValid,@@ -333,6 +335,7 @@ c'getPrevDirectoryPath, c'getWorkingDirectory, c'getApplicationDirectory,+ c'makeDirectory, c'changeDirectory, c'isPathFile, c'isFileNameValid,@@ -482,209 +485,211 @@ VrDeviceInfo, VrStereoConfig, unpackShaderUniformData,- unpackShaderUniformDataV,+ unpackShaderUniformDataV, C'TraceLogCallback, TraceLogCallback, ) import GHC.IO (unsafePerformIO) $( genNative- [ ("c'initWindow", "InitWindow_", "rl_bindings.h", [t|CInt -> CInt -> CString -> IO ()|], False),- ("c'windowShouldClose", "WindowShouldClose_", "rl_bindings.h", [t|IO CBool|], False),- ("c'closeWindow", "CloseWindow_", "rl_bindings.h", [t|IO ()|], False),- ("c'isWindowReady", "IsWindowReady_", "rl_bindings.h", [t|IO CBool|], False),- ("c'isWindowFullscreen", "IsWindowFullscreen_", "rl_bindings.h", [t|IO CBool|], False),- ("c'isWindowHidden", "IsWindowHidden_", "rl_bindings.h", [t|IO CBool|], False),- ("c'isWindowMinimized", "IsWindowMinimized_", "rl_bindings.h", [t|IO CBool|], False),- ("c'isWindowMaximized", "IsWindowMaximized_", "rl_bindings.h", [t|IO CBool|], False),- ("c'isWindowFocused", "IsWindowFocused_", "rl_bindings.h", [t|IO CBool|], False),- ("c'isWindowResized", "IsWindowResized_", "rl_bindings.h", [t|IO CBool|], False),- ("c'isWindowState", "IsWindowState_", "rl_bindings.h", [t|CUInt -> IO CBool|], False),- ("c'setWindowState", "SetWindowState_", "rl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'clearWindowState", "ClearWindowState_", "rl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'toggleFullscreen", "ToggleFullscreen_", "rl_bindings.h", [t|IO ()|], False),- ("c'toggleBorderlessWindowed", "ToggleBorderlessWindowed_", "rl_bindings.h", [t|IO ()|], False),- ("c'maximizeWindow", "MaximizeWindow_", "rl_bindings.h", [t|IO ()|], False),- ("c'minimizeWindow", "MinimizeWindow_", "rl_bindings.h", [t|IO ()|], False),- ("c'restoreWindow", "RestoreWindow_", "rl_bindings.h", [t|IO ()|], False),- ("c'setWindowIcon", "SetWindowIcon_", "rl_bindings.h", [t|Ptr Image -> IO ()|], False),- ("c'setWindowIcons", "SetWindowIcons_", "rl_bindings.h", [t|Ptr Image -> CInt -> IO ()|], False),- ("c'setWindowTitle", "SetWindowTitle_", "rl_bindings.h", [t|CString -> IO ()|], False),- ("c'setWindowPosition", "SetWindowPosition_", "rl_bindings.h", [t|CInt -> CInt -> IO ()|], False),- ("c'setWindowMonitor", "SetWindowMonitor_", "rl_bindings.h", [t|CInt -> IO ()|], False),- ("c'setWindowMinSize", "SetWindowMinSize_", "rl_bindings.h", [t|CInt -> CInt -> IO ()|], False),- ("c'setWindowMaxSize", "SetWindowMaxSize_", "rl_bindings.h", [t|CInt -> CInt -> IO ()|], False),- ("c'setWindowSize", "SetWindowSize_", "rl_bindings.h", [t|CInt -> CInt -> IO ()|], False),- ("c'setWindowOpacity", "SetWindowOpacity_", "rl_bindings.h", [t|CFloat -> IO ()|], False),- ("c'setWindowFocused", "SetWindowFocused_", "rl_bindings.h", [t|IO ()|], False),- ("c'getWindowHandle", "GetWindowHandle_", "rl_bindings.h", [t|IO (Ptr ())|], False),- ("c'getScreenWidth", "GetScreenWidth_", "rl_bindings.h", [t|IO CInt|], False),- ("c'getScreenHeight", "GetScreenHeight_", "rl_bindings.h", [t|IO CInt|], False),- ("c'getRenderWidth", "GetRenderWidth_", "rl_bindings.h", [t|IO CInt|], False),- ("c'getRenderHeight", "GetRenderHeight_", "rl_bindings.h", [t|IO CInt|], False),- ("c'getMonitorCount", "GetMonitorCount_", "rl_bindings.h", [t|IO CInt|], False),- ("c'getCurrentMonitor", "GetCurrentMonitor_", "rl_bindings.h", [t|IO CInt|], False),- ("c'getMonitorPosition", "GetMonitorPosition_", "rl_bindings.h", [t|CInt -> IO (Ptr Vector2)|], False),- ("c'getMonitorWidth", "GetMonitorWidth_", "rl_bindings.h", [t|CInt -> IO CInt|], False),- ("c'getMonitorHeight", "GetMonitorHeight_", "rl_bindings.h", [t|CInt -> IO CInt|], False),- ("c'getMonitorPhysicalWidth", "GetMonitorPhysicalWidth_", "rl_bindings.h", [t|CInt -> IO CInt|], False),- ("c'getMonitorPhysicalHeight", "GetMonitorPhysicalHeight_", "rl_bindings.h", [t|CInt -> IO CInt|], False),- ("c'getMonitorRefreshRate", "GetMonitorRefreshRate_", "rl_bindings.h", [t|CInt -> IO CInt|], False),- ("c'getWindowPosition", "GetWindowPosition_", "rl_bindings.h", [t|IO (Ptr Vector2)|], False),- ("c'getWindowScaleDPI", "GetWindowScaleDPI_", "rl_bindings.h", [t|IO (Ptr Vector2)|], False),- ("c'getMonitorName", "GetMonitorName_", "rl_bindings.h", [t|CInt -> IO CString|], False),- ("c'setClipboardText", "SetClipboardText_", "rl_bindings.h", [t|CString -> IO ()|], False),- ("c'getClipboardText", "GetClipboardText_", "rl_bindings.h", [t|IO CString|], False),- ("c'enableEventWaiting", "EnableEventWaiting_", "rl_bindings.h", [t|IO ()|], False),- ("c'disableEventWaiting", "DisableEventWaiting_", "rl_bindings.h", [t|IO ()|], False),- ("c'swapScreenBuffer", "SwapScreenBuffer_", "rl_bindings.h", [t|IO ()|], False),- ("c'pollInputEvents", "PollInputEvents_", "rl_bindings.h", [t|IO ()|], False),- ("c'waitTime", "WaitTime_", "rl_bindings.h", [t|CDouble -> IO ()|], False),- ("c'showCursor", "ShowCursor_", "rl_bindings.h", [t|IO ()|], False),- ("c'hideCursor", "HideCursor_", "rl_bindings.h", [t|IO ()|], False),- ("c'isCursorHidden", "IsCursorHidden_", "rl_bindings.h", [t|IO CBool|], False),- ("c'enableCursor", "EnableCursor_", "rl_bindings.h", [t|IO ()|], False),- ("c'disableCursor", "DisableCursor_", "rl_bindings.h", [t|IO ()|], False),- ("c'isCursorOnScreen", "IsCursorOnScreen_", "rl_bindings.h", [t|IO CBool|], False),- ("c'clearBackground", "ClearBackground_", "rl_bindings.h", [t|Ptr Color -> IO ()|], False),- ("c'beginDrawing", "BeginDrawing_", "rl_bindings.h", [t|IO ()|], False),- ("c'endDrawing", "EndDrawing_", "rl_bindings.h", [t|IO ()|], False),- ("c'beginMode2D", "BeginMode2D_", "rl_bindings.h", [t|Ptr Camera2D -> IO ()|], False),- ("c'endMode2D", "EndMode2D_", "rl_bindings.h", [t|IO ()|], False),- ("c'beginMode3D", "BeginMode3D_", "rl_bindings.h", [t|Ptr Camera3D -> IO ()|], False),- ("c'endMode3D", "EndMode3D_", "rl_bindings.h", [t|IO ()|], False),- ("c'beginTextureMode", "BeginTextureMode_", "rl_bindings.h", [t|Ptr RenderTexture -> IO ()|], False),- ("c'endTextureMode", "EndTextureMode_", "rl_bindings.h", [t|IO ()|], False),- ("c'beginShaderMode", "BeginShaderMode_", "rl_bindings.h", [t|Ptr Shader -> IO ()|], False),- ("c'endShaderMode", "EndShaderMode_", "rl_bindings.h", [t|IO ()|], False),- ("c'beginBlendMode", "BeginBlendMode_", "rl_bindings.h", [t|CInt -> IO ()|], False),- ("c'endBlendMode", "EndBlendMode_", "rl_bindings.h", [t|IO ()|], False),- ("c'beginScissorMode", "BeginScissorMode_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> IO ()|], False),- ("c'endScissorMode", "EndScissorMode_", "rl_bindings.h", [t|IO ()|], False),- ("c'beginVrStereoMode", "BeginVrStereoMode_", "rl_bindings.h", [t|Ptr VrStereoConfig -> IO ()|], False),- ("c'endVrStereoMode", "EndVrStereoMode_", "rl_bindings.h", [t|IO ()|], False),- ("c'loadVrStereoConfig", "LoadVrStereoConfig_", "rl_bindings.h", [t|Ptr VrDeviceInfo -> IO (Ptr VrStereoConfig)|], False),- ("c'unloadVrStereoConfig", "UnloadVrStereoConfig_", "rl_bindings.h", [t|Ptr VrStereoConfig -> IO ()|], False),- ("c'loadShader", "LoadShader_", "rl_bindings.h", [t|CString -> CString -> IO (Ptr Shader)|], False),- ("c'loadShaderFromMemory", "LoadShaderFromMemory_", "rl_bindings.h", [t|CString -> CString -> IO (Ptr Shader)|], False),- ("c'isShaderReady", "IsShaderReady_", "rl_bindings.h", [t|Ptr Shader -> IO CBool|], False),- ("c'getShaderLocation", "GetShaderLocation_", "rl_bindings.h", [t|Ptr Shader -> CString -> IO CInt|], False),- ("c'getShaderLocationAttrib", "GetShaderLocationAttrib_", "rl_bindings.h", [t|Ptr Shader -> CString -> IO CInt|], False),- ("c'setShaderValue", "SetShaderValue_", "rl_bindings.h", [t|Ptr Shader -> CInt -> Ptr () -> CInt -> IO ()|], False),- ("c'setShaderValueV", "SetShaderValueV_", "rl_bindings.h", [t|Ptr Shader -> CInt -> Ptr () -> CInt -> CInt -> IO ()|], False),- ("c'setShaderValueMatrix", "SetShaderValueMatrix_", "rl_bindings.h", [t|Ptr Shader -> CInt -> Ptr Matrix -> IO ()|], False),- ("c'setShaderValueTexture", "SetShaderValueTexture_", "rl_bindings.h", [t|Ptr Shader -> CInt -> Ptr Texture -> IO ()|], False),- ("c'unloadShader", "UnloadShader_", "rl_bindings.h", [t|Ptr Shader -> IO ()|], False),- ("c'getScreenToWorldRay", "GetScreenToWorldRay_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Camera3D -> IO (Ptr Ray)|], False),- ("c'getScreenToWorldRayEx", "GetScreenToWorldRayEx_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Camera3D -> CFloat -> CFloat -> IO (Ptr Ray)|], False),- ("c'getCameraMatrix", "GetCameraMatrix_", "rl_bindings.h", [t|Ptr Camera3D -> IO (Ptr Matrix)|], False),- ("c'getCameraMatrix2D", "GetCameraMatrix2D_", "rl_bindings.h", [t|Ptr Camera2D -> IO (Ptr Matrix)|], False),- ("c'getWorldToScreen", "GetWorldToScreen_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Camera3D -> IO (Ptr Vector2)|], False),- ("c'getScreenToWorld2D", "GetScreenToWorld2D_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Camera2D -> IO (Ptr Vector2)|], False),- ("c'getWorldToScreenEx", "GetWorldToScreenEx_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Camera3D -> CInt -> CInt -> IO (Ptr Vector2)|], False),- ("c'getWorldToScreen2D", "GetWorldToScreen2D_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Camera2D -> IO (Ptr Vector2)|], False),- ("c'setTargetFPS", "SetTargetFPS_", "rl_bindings.h", [t|CInt -> IO ()|], False),- ("c'getFPS", "GetFPS_", "rl_bindings.h", [t|IO CInt|], False),- ("c'getFrameTime", "GetFrameTime_", "rl_bindings.h", [t|IO CFloat|], False),- ("c'getTime", "GetTime_", "rl_bindings.h", [t|IO CDouble|], False),- ("c'setRandomSeed", "SetRandomSeed_", "rl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'getRandomValue", "GetRandomValue_", "rl_bindings.h", [t|CInt -> CInt -> IO CInt|], False),- ("c'loadRandomSequence", "LoadRandomSequence_", "rl_bindings.h", [t|CUInt -> CInt -> CInt -> IO (Ptr CInt)|], False),- ("c'takeScreenshot", "TakeScreenshot_", "rl_bindings.h", [t|CString -> IO ()|], False),- ("c'setConfigFlags", "SetConfigFlags_", "rl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'traceLog", "TraceLog_", "rl_bindings.h", [t|CInt -> CString -> IO ()|], False), -- Uses varags, can't implement complete functionality- ("c'setTraceLogLevel", "SetTraceLogLevel_", "rl_bindings.h", [t|CInt -> IO ()|], False),- ("c'memAlloc", "MemAlloc_", "rl_bindings.h", [t|CInt -> IO (Ptr ())|], False),- ("c'memRealloc", "MemRealloc_", "rl_bindings.h", [t|Ptr () -> CInt -> IO (Ptr ())|], False),- ("c'memFree", "MemFree_", "rl_bindings.h", [t|Ptr () -> IO ()|], False),- ("c'openURL", "OpenURL_", "rl_bindings.h", [t|CString -> IO ()|], False),- ("c'setLoadFileDataCallback", "SetLoadFileDataCallback_", "rl_bindings.h", [t|C'LoadFileDataCallback -> IO ()|], False),- ("c'setSaveFileDataCallback", "SetSaveFileDataCallback_", "rl_bindings.h", [t|C'SaveFileDataCallback -> IO ()|], False),- ("c'setLoadFileTextCallback", "SetLoadFileTextCallback_", "rl_bindings.h", [t|C'LoadFileTextCallback -> IO ()|], False),- ("c'setSaveFileTextCallback", "SetSaveFileTextCallback_", "rl_bindings.h", [t|C'SaveFileTextCallback -> IO ()|], False),- ("c'loadFileData", "LoadFileData_", "rl_bindings.h", [t|CString -> Ptr CInt -> IO (Ptr CUChar)|], True),- ("c'unloadFileData", "UnloadFileData_", "rl_bindings.h", [t|Ptr CUChar -> IO ()|], False),- ("c'saveFileData", "SaveFileData_", "rl_bindings.h", [t|CString -> Ptr () -> CInt -> IO CBool|], True),- ("c'exportDataAsCode", "ExportDataAsCode_", "rl_bindings.h", [t|Ptr CUChar -> CInt -> CString -> IO CBool|], False),- ("c'loadFileText", "LoadFileText_", "rl_bindings.h", [t|CString -> IO CString|], True),- ("c'unloadFileText", "UnloadFileText_", "rl_bindings.h", [t|CString -> IO ()|], False),- ("c'saveFileText", "SaveFileText_", "rl_bindings.h", [t|CString -> CString -> IO CBool|], True),- ("c'fileExists", "FileExists_", "rl_bindings.h", [t|CString -> IO CBool|], False),- ("c'directoryExists", "DirectoryExists_", "rl_bindings.h", [t|CString -> IO CBool|], False),- ("c'isFileExtension", "IsFileExtension_", "rl_bindings.h", [t|CString -> CString -> IO CBool|], False),- ("c'getFileLength", "GetFileLength_", "rl_bindings.h", [t|CString -> IO CBool|], False),- ("c'getFileExtension", "GetFileExtension_", "rl_bindings.h", [t|CString -> IO CString|], False),- ("c'getFileName", "GetFileName_", "rl_bindings.h", [t|CString -> IO CString|], False),- ("c'getFileNameWithoutExt", "GetFileNameWithoutExt_", "rl_bindings.h", [t|CString -> IO CString|], False),- ("c'getDirectoryPath", "GetDirectoryPath_", "rl_bindings.h", [t|CString -> IO CString|], False),- ("c'getPrevDirectoryPath", "GetPrevDirectoryPath_", "rl_bindings.h", [t|CString -> IO CString|], False),- ("c'getWorkingDirectory", "GetWorkingDirectory_", "rl_bindings.h", [t|IO CString|], False),- ("c'getApplicationDirectory", "GetApplicationDirectory_", "rl_bindings.h", [t|IO CString|], False),- ("c'changeDirectory", "ChangeDirectory_", "rl_bindings.h", [t|CString -> IO CBool|], False),- ("c'isPathFile", "IsPathFile_", "rl_bindings.h", [t|CString -> IO CBool|], False),- ("c'isFileNameValid", "IsFileNameValid_", "rl_bindings.h", [t|CString -> IO CBool|], False),- ("c'loadDirectoryFiles", "LoadDirectoryFiles_", "rl_bindings.h", [t|CString -> IO (Ptr FilePathList)|], False),- ("c'loadDirectoryFilesEx", "LoadDirectoryFilesEx_", "rl_bindings.h", [t|CString -> CString -> CInt -> IO (Ptr FilePathList)|], False),- ("c'unloadDirectoryFiles", "UnloadDirectoryFiles_", "rl_bindings.h", [t|Ptr FilePathList -> IO ()|], False),- ("c'isFileDropped", "IsFileDropped_", "rl_bindings.h", [t|IO CBool|], False),- ("c'loadDroppedFiles", "LoadDroppedFiles_", "rl_bindings.h", [t|IO (Ptr FilePathList)|], False),- ("c'unloadDroppedFiles", "UnloadDroppedFiles_", "rl_bindings.h", [t|Ptr FilePathList -> IO ()|], False),- ("c'getFileModTime", "GetFileModTime_", "rl_bindings.h", [t|CString -> IO CLong|], False),- ("c'compressData", "CompressData_", "rl_bindings.h", [t|Ptr CUChar -> CInt -> Ptr CInt -> IO (Ptr CUChar)|], False),- ("c'decompressData", "DecompressData_", "rl_bindings.h", [t|Ptr CUChar -> CInt -> Ptr CInt -> IO (Ptr CUChar)|], False),- ("c'encodeDataBase64", "EncodeDataBase64_", "rl_bindings.h", [t|Ptr CUChar -> CInt -> Ptr CInt -> IO CString|], False),- ("c'decodeDataBase64", "DecodeDataBase64_", "rl_bindings.h", [t|Ptr CUChar -> Ptr CInt -> IO (Ptr CUChar)|], False),- ("c'loadAutomationEventList", "LoadAutomationEventList_", "rl_bindings.h", [t|CString -> IO (Ptr AutomationEventList)|], False),- ("c'exportAutomationEventList", "ExportAutomationEventList_", "rl_bindings.h", [t|Ptr AutomationEventList -> CString -> IO CBool|], False),- ("c'setAutomationEventList", "SetAutomationEventList_", "rl_bindings.h", [t|Ptr AutomationEventList -> IO ()|], False),- ("c'setAutomationEventBaseFrame", "SetAutomationEventBaseFrame_", "rl_bindings.h", [t|CInt -> IO ()|], False),- ("c'startAutomationEventRecording", "StartAutomationEventRecording_", "rl_bindings.h", [t|IO ()|], False),- ("c'stopAutomationEventRecording", "StopAutomationEventRecording_", "rl_bindings.h", [t|IO ()|], False),- ("c'playAutomationEvent", "PlayAutomationEvent", "rl_bindings.h", [t|Ptr AutomationEvent -> IO ()|], False),- ("c'isKeyPressed", "IsKeyPressed_", "rl_bindings.h", [t|CInt -> IO CBool|], False),- ("c'isKeyPressedRepeat", "IsKeyPressedRepeat_", "rl_bindings.h", [t|CInt -> IO CBool|], False),- ("c'isKeyDown", "IsKeyDown_", "rl_bindings.h", [t|CInt -> IO CBool|], False),- ("c'isKeyReleased", "IsKeyReleased_", "rl_bindings.h", [t|CInt -> IO CBool|], False),- ("c'isKeyUp", "IsKeyUp_", "rl_bindings.h", [t|CInt -> IO CBool|], False),- ("c'setExitKey", "SetExitKey_", "rl_bindings.h", [t|CInt -> IO ()|], False),- ("c'getKeyPressed", "GetKeyPressed_", "rl_bindings.h", [t|IO CInt|], False),- ("c'getCharPressed", "GetCharPressed_", "rl_bindings.h", [t|IO CInt|], False),- ("c'isGamepadAvailable", "IsGamepadAvailable_", "rl_bindings.h", [t|CInt -> IO CBool|], False),- ("c'getGamepadName", "GetGamepadName_", "rl_bindings.h", [t|CInt -> IO CString|], False),- ("c'isGamepadButtonPressed", "IsGamepadButtonPressed_", "rl_bindings.h", [t|CInt -> CInt -> IO CBool|], False),- ("c'isGamepadButtonDown", "IsGamepadButtonDown_", "rl_bindings.h", [t|CInt -> CInt -> IO CBool|], False),- ("c'isGamepadButtonReleased", "IsGamepadButtonReleased_", "rl_bindings.h", [t|CInt -> CInt -> IO CBool|], False),- ("c'isGamepadButtonUp", "IsGamepadButtonUp_", "rl_bindings.h", [t|CInt -> CInt -> IO CBool|], False),- ("c'getGamepadButtonPressed", "GetGamepadButtonPressed_", "rl_bindings.h", [t|IO CInt|], False),- ("c'getGamepadAxisCount", "GetGamepadAxisCount_", "rl_bindings.h", [t|CInt -> IO CInt|], False),- ("c'getGamepadAxisMovement", "GetGamepadAxisMovement_", "rl_bindings.h", [t|CInt -> CInt -> IO CFloat|], False),- ("c'setGamepadMappings", "SetGamepadMappings_", "rl_bindings.h", [t|CString -> IO CInt|], False),- ("c'setGamepadVibration", "SetGamepadVibration_", "rl_bindings.h", [t|CInt -> CFloat -> CFloat -> IO ()|], False),- ("c'isMouseButtonPressed", "IsMouseButtonPressed_", "rl_bindings.h", [t|CInt -> IO CBool|], False),- ("c'isMouseButtonDown", "IsMouseButtonDown_", "rl_bindings.h", [t|CInt -> IO CBool|], False),- ("c'isMouseButtonReleased", "IsMouseButtonReleased_", "rl_bindings.h", [t|CInt -> IO CBool|], False),- ("c'isMouseButtonUp", "IsMouseButtonUp_", "rl_bindings.h", [t|CInt -> IO CBool|], False),- ("c'getMouseX", "GetMouseX_", "rl_bindings.h", [t|IO CInt|], False),- ("c'getMouseY", "GetMouseY_", "rl_bindings.h", [t|IO CInt|], False),- ("c'getMousePosition", "GetMousePosition_", "rl_bindings.h", [t|IO (Ptr Vector2)|], False),- ("c'getMouseDelta", "GetMouseDelta_", "rl_bindings.h", [t|IO (Ptr Vector2)|], False),- ("c'setMousePosition", "SetMousePosition_", "rl_bindings.h", [t|CInt -> CInt -> IO ()|], False),- ("c'setMouseOffset", "SetMouseOffset_", "rl_bindings.h", [t|CInt -> CInt -> IO ()|], False),- ("c'setMouseScale", "SetMouseScale_", "rl_bindings.h", [t|CFloat -> CFloat -> IO ()|], False),- ("c'getMouseWheelMove", "GetMouseWheelMove_", "rl_bindings.h", [t|IO CFloat|], False),- ("c'getMouseWheelMoveV", "GetMouseWheelMoveV_", "rl_bindings.h", [t|IO (Ptr Vector2)|], False),- ("c'setMouseCursor", "SetMouseCursor_", "rl_bindings.h", [t|CInt -> IO ()|], False),- ("c'getTouchX", "GetTouchX_", "rl_bindings.h", [t|IO CInt|], False),- ("c'getTouchY", "GetTouchY_", "rl_bindings.h", [t|IO CInt|], False),- ("c'getTouchPosition", "GetTouchPosition_", "rl_bindings.h", [t|CInt -> IO (Ptr Vector2)|], False),- ("c'getTouchPointId", "GetTouchPointId_", "rl_bindings.h", [t|CInt -> IO CInt|], False),- ("c'getTouchPointCount", "GetTouchPointCount_", "rl_bindings.h", [t|IO CInt|], False),- ("c'setGesturesEnabled", "SetGesturesEnabled_", "rl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'isGestureDetected", "IsGestureDetected_", "rl_bindings.h", [t|CUInt -> IO CBool|], False),- ("c'getGestureDetected", "GetGestureDetected_", "rl_bindings.h", [t|IO CInt|], False),- ("c'getGestureHoldDuration", "GetGestureHoldDuration_", "rl_bindings.h", [t|IO CFloat|], False),- ("c'getGestureDragVector", "GetGestureDragVector_", "rl_bindings.h", [t|IO (Ptr Vector2)|], False),- ("c'getGestureDragAngle", "GetGestureDragAngle_", "rl_bindings.h", [t|IO CFloat|], False),- ("c'getGesturePinchVector", "GetGesturePinchVector_", "rl_bindings.h", [t|IO (Ptr Vector2)|], False),- ("c'getGesturePinchAngle", "GetGesturePinchAngle_", "rl_bindings.h", [t|IO CFloat|], False)+ [ ("c'initWindow", "InitWindow_", "rl_bindings.h", [t|CInt -> CInt -> CString -> IO ()|]),+ ("c'windowShouldClose", "WindowShouldClose_", "rl_bindings.h", [t|IO CBool|]),+ ("c'closeWindow", "CloseWindow_", "rl_bindings.h", [t|IO ()|]),+ ("c'isWindowReady", "IsWindowReady_", "rl_bindings.h", [t|IO CBool|]),+ ("c'isWindowFullscreen", "IsWindowFullscreen_", "rl_bindings.h", [t|IO CBool|]),+ ("c'isWindowHidden", "IsWindowHidden_", "rl_bindings.h", [t|IO CBool|]),+ ("c'isWindowMinimized", "IsWindowMinimized_", "rl_bindings.h", [t|IO CBool|]),+ ("c'isWindowMaximized", "IsWindowMaximized_", "rl_bindings.h", [t|IO CBool|]),+ ("c'isWindowFocused", "IsWindowFocused_", "rl_bindings.h", [t|IO CBool|]),+ ("c'isWindowResized", "IsWindowResized_", "rl_bindings.h", [t|IO CBool|]),+ ("c'isWindowState", "IsWindowState_", "rl_bindings.h", [t|CUInt -> IO CBool|]),+ ("c'setWindowState", "SetWindowState_", "rl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'clearWindowState", "ClearWindowState_", "rl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'toggleFullscreen", "ToggleFullscreen_", "rl_bindings.h", [t|IO ()|]),+ ("c'toggleBorderlessWindowed", "ToggleBorderlessWindowed_", "rl_bindings.h", [t|IO ()|]),+ ("c'maximizeWindow", "MaximizeWindow_", "rl_bindings.h", [t|IO ()|]),+ ("c'minimizeWindow", "MinimizeWindow_", "rl_bindings.h", [t|IO ()|]),+ ("c'restoreWindow", "RestoreWindow_", "rl_bindings.h", [t|IO ()|]),+ ("c'setWindowIcon", "SetWindowIcon_", "rl_bindings.h", [t|Ptr Image -> IO ()|]),+ ("c'setWindowIcons", "SetWindowIcons_", "rl_bindings.h", [t|Ptr Image -> CInt -> IO ()|]),+ ("c'setWindowTitle", "SetWindowTitle_", "rl_bindings.h", [t|CString -> IO ()|]),+ ("c'setWindowPosition", "SetWindowPosition_", "rl_bindings.h", [t|CInt -> CInt -> IO ()|]),+ ("c'setWindowMonitor", "SetWindowMonitor_", "rl_bindings.h", [t|CInt -> IO ()|]),+ ("c'setWindowMinSize", "SetWindowMinSize_", "rl_bindings.h", [t|CInt -> CInt -> IO ()|]),+ ("c'setWindowMaxSize", "SetWindowMaxSize_", "rl_bindings.h", [t|CInt -> CInt -> IO ()|]),+ ("c'setWindowSize", "SetWindowSize_", "rl_bindings.h", [t|CInt -> CInt -> IO ()|]),+ ("c'setWindowOpacity", "SetWindowOpacity_", "rl_bindings.h", [t|CFloat -> IO ()|]),+ ("c'setWindowFocused", "SetWindowFocused_", "rl_bindings.h", [t|IO ()|]),+ ("c'getWindowHandle", "GetWindowHandle_", "rl_bindings.h", [t|IO (Ptr ())|]),+ ("c'getScreenWidth", "GetScreenWidth_", "rl_bindings.h", [t|IO CInt|]),+ ("c'getScreenHeight", "GetScreenHeight_", "rl_bindings.h", [t|IO CInt|]),+ ("c'getRenderWidth", "GetRenderWidth_", "rl_bindings.h", [t|IO CInt|]),+ ("c'getRenderHeight", "GetRenderHeight_", "rl_bindings.h", [t|IO CInt|]),+ ("c'getMonitorCount", "GetMonitorCount_", "rl_bindings.h", [t|IO CInt|]),+ ("c'getCurrentMonitor", "GetCurrentMonitor_", "rl_bindings.h", [t|IO CInt|]),+ ("c'getMonitorPosition", "GetMonitorPosition_", "rl_bindings.h", [t|CInt -> IO (Ptr Vector2)|]),+ ("c'getMonitorWidth", "GetMonitorWidth_", "rl_bindings.h", [t|CInt -> IO CInt|]),+ ("c'getMonitorHeight", "GetMonitorHeight_", "rl_bindings.h", [t|CInt -> IO CInt|]),+ ("c'getMonitorPhysicalWidth", "GetMonitorPhysicalWidth_", "rl_bindings.h", [t|CInt -> IO CInt|]),+ ("c'getMonitorPhysicalHeight", "GetMonitorPhysicalHeight_", "rl_bindings.h", [t|CInt -> IO CInt|]),+ ("c'getMonitorRefreshRate", "GetMonitorRefreshRate_", "rl_bindings.h", [t|CInt -> IO CInt|]),+ ("c'getWindowPosition", "GetWindowPosition_", "rl_bindings.h", [t|IO (Ptr Vector2)|]),+ ("c'getWindowScaleDPI", "GetWindowScaleDPI_", "rl_bindings.h", [t|IO (Ptr Vector2)|]),+ ("c'getMonitorName", "GetMonitorName_", "rl_bindings.h", [t|CInt -> IO CString|]),+ ("c'setClipboardText", "SetClipboardText_", "rl_bindings.h", [t|CString -> IO ()|]),+ ("c'getClipboardText", "GetClipboardText_", "rl_bindings.h", [t|IO CString|]),+ ("c'enableEventWaiting", "EnableEventWaiting_", "rl_bindings.h", [t|IO ()|]),+ ("c'disableEventWaiting", "DisableEventWaiting_", "rl_bindings.h", [t|IO ()|]),+ ("c'swapScreenBuffer", "SwapScreenBuffer_", "rl_bindings.h", [t|IO ()|]),+ ("c'pollInputEvents", "PollInputEvents_", "rl_bindings.h", [t|IO ()|]),+ ("c'waitTime", "WaitTime_", "rl_bindings.h", [t|CDouble -> IO ()|]),+ ("c'showCursor", "ShowCursor_", "rl_bindings.h", [t|IO ()|]),+ ("c'hideCursor", "HideCursor_", "rl_bindings.h", [t|IO ()|]),+ ("c'isCursorHidden", "IsCursorHidden_", "rl_bindings.h", [t|IO CBool|]),+ ("c'enableCursor", "EnableCursor_", "rl_bindings.h", [t|IO ()|]),+ ("c'disableCursor", "DisableCursor_", "rl_bindings.h", [t|IO ()|]),+ ("c'isCursorOnScreen", "IsCursorOnScreen_", "rl_bindings.h", [t|IO CBool|]),+ ("c'clearBackground", "ClearBackground_", "rl_bindings.h", [t|Ptr Color -> IO ()|]),+ ("c'beginDrawing", "BeginDrawing_", "rl_bindings.h", [t|IO ()|]),+ ("c'endDrawing", "EndDrawing_", "rl_bindings.h", [t|IO ()|]),+ ("c'beginMode2D", "BeginMode2D_", "rl_bindings.h", [t|Ptr Camera2D -> IO ()|]),+ ("c'endMode2D", "EndMode2D_", "rl_bindings.h", [t|IO ()|]),+ ("c'beginMode3D", "BeginMode3D_", "rl_bindings.h", [t|Ptr Camera3D -> IO ()|]),+ ("c'endMode3D", "EndMode3D_", "rl_bindings.h", [t|IO ()|]),+ ("c'beginTextureMode", "BeginTextureMode_", "rl_bindings.h", [t|Ptr RenderTexture -> IO ()|]),+ ("c'endTextureMode", "EndTextureMode_", "rl_bindings.h", [t|IO ()|]),+ ("c'beginShaderMode", "BeginShaderMode_", "rl_bindings.h", [t|Ptr Shader -> IO ()|]),+ ("c'endShaderMode", "EndShaderMode_", "rl_bindings.h", [t|IO ()|]),+ ("c'beginBlendMode", "BeginBlendMode_", "rl_bindings.h", [t|CInt -> IO ()|]),+ ("c'endBlendMode", "EndBlendMode_", "rl_bindings.h", [t|IO ()|]),+ ("c'beginScissorMode", "BeginScissorMode_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> IO ()|]),+ ("c'endScissorMode", "EndScissorMode_", "rl_bindings.h", [t|IO ()|]),+ ("c'beginVrStereoMode", "BeginVrStereoMode_", "rl_bindings.h", [t|Ptr VrStereoConfig -> IO ()|]),+ ("c'endVrStereoMode", "EndVrStereoMode_", "rl_bindings.h", [t|IO ()|]),+ ("c'loadVrStereoConfig", "LoadVrStereoConfig_", "rl_bindings.h", [t|Ptr VrDeviceInfo -> IO (Ptr VrStereoConfig)|]),+ ("c'unloadVrStereoConfig", "UnloadVrStereoConfig_", "rl_bindings.h", [t|Ptr VrStereoConfig -> IO ()|]),+ ("c'loadShader", "LoadShader_", "rl_bindings.h", [t|CString -> CString -> IO (Ptr Shader)|]),+ ("c'loadShaderFromMemory", "LoadShaderFromMemory_", "rl_bindings.h", [t|CString -> CString -> IO (Ptr Shader)|]),+ ("c'isShaderReady", "IsShaderReady_", "rl_bindings.h", [t|Ptr Shader -> IO CBool|]),+ ("c'getShaderLocation", "GetShaderLocation_", "rl_bindings.h", [t|Ptr Shader -> CString -> IO CInt|]),+ ("c'getShaderLocationAttrib", "GetShaderLocationAttrib_", "rl_bindings.h", [t|Ptr Shader -> CString -> IO CInt|]),+ ("c'setShaderValue", "SetShaderValue_", "rl_bindings.h", [t|Ptr Shader -> CInt -> Ptr () -> CInt -> IO ()|]),+ ("c'setShaderValueV", "SetShaderValueV_", "rl_bindings.h", [t|Ptr Shader -> CInt -> Ptr () -> CInt -> CInt -> IO ()|]),+ ("c'setShaderValueMatrix", "SetShaderValueMatrix_", "rl_bindings.h", [t|Ptr Shader -> CInt -> Ptr Matrix -> IO ()|]),+ ("c'setShaderValueTexture", "SetShaderValueTexture_", "rl_bindings.h", [t|Ptr Shader -> CInt -> Ptr Texture -> IO ()|]),+ ("c'unloadShader", "UnloadShader_", "rl_bindings.h", [t|Ptr Shader -> IO ()|]),+ ("c'getScreenToWorldRay", "GetScreenToWorldRay_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Camera3D -> IO (Ptr Ray)|]),+ ("c'getScreenToWorldRayEx", "GetScreenToWorldRayEx_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Camera3D -> CFloat -> CFloat -> IO (Ptr Ray)|]),+ ("c'getCameraMatrix", "GetCameraMatrix_", "rl_bindings.h", [t|Ptr Camera3D -> IO (Ptr Matrix)|]),+ ("c'getCameraMatrix2D", "GetCameraMatrix2D_", "rl_bindings.h", [t|Ptr Camera2D -> IO (Ptr Matrix)|]),+ ("c'getWorldToScreen", "GetWorldToScreen_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Camera3D -> IO (Ptr Vector2)|]),+ ("c'getScreenToWorld2D", "GetScreenToWorld2D_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Camera2D -> IO (Ptr Vector2)|]),+ ("c'getWorldToScreenEx", "GetWorldToScreenEx_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Camera3D -> CInt -> CInt -> IO (Ptr Vector2)|]),+ ("c'getWorldToScreen2D", "GetWorldToScreen2D_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Camera2D -> IO (Ptr Vector2)|]),+ ("c'setTargetFPS", "SetTargetFPS_", "rl_bindings.h", [t|CInt -> IO ()|]),+ ("c'getFPS", "GetFPS_", "rl_bindings.h", [t|IO CInt|]),+ ("c'getFrameTime", "GetFrameTime_", "rl_bindings.h", [t|IO CFloat|]),+ ("c'getTime", "GetTime_", "rl_bindings.h", [t|IO CDouble|]),+ ("c'setRandomSeed", "SetRandomSeed_", "rl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'getRandomValue", "GetRandomValue_", "rl_bindings.h", [t|CInt -> CInt -> IO CInt|]),+ ("c'loadRandomSequence", "LoadRandomSequence_", "rl_bindings.h", [t|CUInt -> CInt -> CInt -> IO (Ptr CInt)|]),+ ("c'takeScreenshot", "TakeScreenshot_", "rl_bindings.h", [t|CString -> IO ()|]),+ ("c'setConfigFlags", "SetConfigFlags_", "rl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'traceLog", "TraceLog_", "rl_bindings.h", [t|CInt -> CString -> IO ()|]), -- Uses varags, can't implement complete functionality+ ("c'setTraceLogLevel", "SetTraceLogLevel_", "rl_bindings.h", [t|CInt -> IO ()|]),+ ("c'memAlloc", "MemAlloc_", "rl_bindings.h", [t|CInt -> IO (Ptr ())|]),+ ("c'memRealloc", "MemRealloc_", "rl_bindings.h", [t|Ptr () -> CInt -> IO (Ptr ())|]),+ ("c'memFree", "MemFree_", "rl_bindings.h", [t|Ptr () -> IO ()|]),+ ("c'openURL", "OpenURL_", "rl_bindings.h", [t|CString -> IO ()|]),+ ("c'setTraceLogCallback", "SetTraceLogCallback_", "rl_bindings.h", [t|C'TraceLogCallback -> IO ()|]),+ ("c'setLoadFileDataCallback", "SetLoadFileDataCallback_", "rl_bindings.h", [t|C'LoadFileDataCallback -> IO ()|]),+ ("c'setSaveFileDataCallback", "SetSaveFileDataCallback_", "rl_bindings.h", [t|C'SaveFileDataCallback -> IO ()|]),+ ("c'setLoadFileTextCallback", "SetLoadFileTextCallback_", "rl_bindings.h", [t|C'LoadFileTextCallback -> IO ()|]),+ ("c'setSaveFileTextCallback", "SetSaveFileTextCallback_", "rl_bindings.h", [t|C'SaveFileTextCallback -> IO ()|]),+ ("c'loadFileData", "LoadFileData_", "rl_bindings.h", [t|CString -> Ptr CInt -> IO (Ptr CUChar)|]),+ ("c'unloadFileData", "UnloadFileData_", "rl_bindings.h", [t|Ptr CUChar -> IO ()|]),+ ("c'saveFileData", "SaveFileData_", "rl_bindings.h", [t|CString -> Ptr () -> CInt -> IO CBool|]),+ ("c'exportDataAsCode", "ExportDataAsCode_", "rl_bindings.h", [t|Ptr CUChar -> CInt -> CString -> IO CBool|]),+ ("c'loadFileText", "LoadFileText_", "rl_bindings.h", [t|CString -> IO CString|]),+ ("c'unloadFileText", "UnloadFileText_", "rl_bindings.h", [t|CString -> IO ()|]),+ ("c'saveFileText", "SaveFileText_", "rl_bindings.h", [t|CString -> CString -> IO CBool|]),+ ("c'fileExists", "FileExists_", "rl_bindings.h", [t|CString -> IO CBool|]),+ ("c'directoryExists", "DirectoryExists_", "rl_bindings.h", [t|CString -> IO CBool|]),+ ("c'isFileExtension", "IsFileExtension_", "rl_bindings.h", [t|CString -> CString -> IO CBool|]),+ ("c'getFileLength", "GetFileLength_", "rl_bindings.h", [t|CString -> IO CBool|]),+ ("c'getFileExtension", "GetFileExtension_", "rl_bindings.h", [t|CString -> IO CString|]),+ ("c'getFileName", "GetFileName_", "rl_bindings.h", [t|CString -> IO CString|]),+ ("c'getFileNameWithoutExt", "GetFileNameWithoutExt_", "rl_bindings.h", [t|CString -> IO CString|]),+ ("c'getDirectoryPath", "GetDirectoryPath_", "rl_bindings.h", [t|CString -> IO CString|]),+ ("c'getPrevDirectoryPath", "GetPrevDirectoryPath_", "rl_bindings.h", [t|CString -> IO CString|]),+ ("c'getWorkingDirectory", "GetWorkingDirectory_", "rl_bindings.h", [t|IO CString|]),+ ("c'getApplicationDirectory", "GetApplicationDirectory_", "rl_bindings.h", [t|IO CString|]),+ ("c'makeDirectory", "MakeDirectory_", "rl_bindings.h", [t|CString -> IO CInt|]),+ ("c'changeDirectory", "ChangeDirectory_", "rl_bindings.h", [t|CString -> IO CBool|]),+ ("c'isPathFile", "IsPathFile_", "rl_bindings.h", [t|CString -> IO CBool|]),+ ("c'isFileNameValid", "IsFileNameValid_", "rl_bindings.h", [t|CString -> IO CBool|]),+ ("c'loadDirectoryFiles", "LoadDirectoryFiles_", "rl_bindings.h", [t|CString -> IO (Ptr FilePathList)|]),+ ("c'loadDirectoryFilesEx", "LoadDirectoryFilesEx_", "rl_bindings.h", [t|CString -> CString -> CInt -> IO (Ptr FilePathList)|]),+ ("c'unloadDirectoryFiles", "UnloadDirectoryFiles_", "rl_bindings.h", [t|Ptr FilePathList -> IO ()|]),+ ("c'isFileDropped", "IsFileDropped_", "rl_bindings.h", [t|IO CBool|]),+ ("c'loadDroppedFiles", "LoadDroppedFiles_", "rl_bindings.h", [t|IO (Ptr FilePathList)|]),+ ("c'unloadDroppedFiles", "UnloadDroppedFiles_", "rl_bindings.h", [t|Ptr FilePathList -> IO ()|]),+ ("c'getFileModTime", "GetFileModTime_", "rl_bindings.h", [t|CString -> IO CLong|]),+ ("c'compressData", "CompressData_", "rl_bindings.h", [t|Ptr CUChar -> CInt -> Ptr CInt -> IO (Ptr CUChar)|]),+ ("c'decompressData", "DecompressData_", "rl_bindings.h", [t|Ptr CUChar -> CInt -> Ptr CInt -> IO (Ptr CUChar)|]),+ ("c'encodeDataBase64", "EncodeDataBase64_", "rl_bindings.h", [t|Ptr CUChar -> CInt -> Ptr CInt -> IO CString|]),+ ("c'decodeDataBase64", "DecodeDataBase64_", "rl_bindings.h", [t|Ptr CUChar -> Ptr CInt -> IO (Ptr CUChar)|]),+ ("c'loadAutomationEventList", "LoadAutomationEventList_", "rl_bindings.h", [t|CString -> IO (Ptr AutomationEventList)|]),+ ("c'exportAutomationEventList", "ExportAutomationEventList_", "rl_bindings.h", [t|Ptr AutomationEventList -> CString -> IO CBool|]),+ ("c'setAutomationEventList", "SetAutomationEventList_", "rl_bindings.h", [t|Ptr AutomationEventList -> IO ()|]),+ ("c'setAutomationEventBaseFrame", "SetAutomationEventBaseFrame_", "rl_bindings.h", [t|CInt -> IO ()|]),+ ("c'startAutomationEventRecording", "StartAutomationEventRecording_", "rl_bindings.h", [t|IO ()|]),+ ("c'stopAutomationEventRecording", "StopAutomationEventRecording_", "rl_bindings.h", [t|IO ()|]),+ ("c'playAutomationEvent", "PlayAutomationEvent", "rl_bindings.h", [t|Ptr AutomationEvent -> IO ()|]),+ ("c'isKeyPressed", "IsKeyPressed_", "rl_bindings.h", [t|CInt -> IO CBool|]),+ ("c'isKeyPressedRepeat", "IsKeyPressedRepeat_", "rl_bindings.h", [t|CInt -> IO CBool|]),+ ("c'isKeyDown", "IsKeyDown_", "rl_bindings.h", [t|CInt -> IO CBool|]),+ ("c'isKeyReleased", "IsKeyReleased_", "rl_bindings.h", [t|CInt -> IO CBool|]),+ ("c'isKeyUp", "IsKeyUp_", "rl_bindings.h", [t|CInt -> IO CBool|]),+ ("c'setExitKey", "SetExitKey_", "rl_bindings.h", [t|CInt -> IO ()|]),+ ("c'getKeyPressed", "GetKeyPressed_", "rl_bindings.h", [t|IO CInt|]),+ ("c'getCharPressed", "GetCharPressed_", "rl_bindings.h", [t|IO CInt|]),+ ("c'isGamepadAvailable", "IsGamepadAvailable_", "rl_bindings.h", [t|CInt -> IO CBool|]),+ ("c'getGamepadName", "GetGamepadName_", "rl_bindings.h", [t|CInt -> IO CString|]),+ ("c'isGamepadButtonPressed", "IsGamepadButtonPressed_", "rl_bindings.h", [t|CInt -> CInt -> IO CBool|]),+ ("c'isGamepadButtonDown", "IsGamepadButtonDown_", "rl_bindings.h", [t|CInt -> CInt -> IO CBool|]),+ ("c'isGamepadButtonReleased", "IsGamepadButtonReleased_", "rl_bindings.h", [t|CInt -> CInt -> IO CBool|]),+ ("c'isGamepadButtonUp", "IsGamepadButtonUp_", "rl_bindings.h", [t|CInt -> CInt -> IO CBool|]),+ ("c'getGamepadButtonPressed", "GetGamepadButtonPressed_", "rl_bindings.h", [t|IO CInt|]),+ ("c'getGamepadAxisCount", "GetGamepadAxisCount_", "rl_bindings.h", [t|CInt -> IO CInt|]),+ ("c'getGamepadAxisMovement", "GetGamepadAxisMovement_", "rl_bindings.h", [t|CInt -> CInt -> IO CFloat|]),+ ("c'setGamepadMappings", "SetGamepadMappings_", "rl_bindings.h", [t|CString -> IO CInt|]),+ ("c'setGamepadVibration", "SetGamepadVibration_", "rl_bindings.h", [t|CInt -> CFloat -> CFloat -> IO ()|]),+ ("c'isMouseButtonPressed", "IsMouseButtonPressed_", "rl_bindings.h", [t|CInt -> IO CBool|]),+ ("c'isMouseButtonDown", "IsMouseButtonDown_", "rl_bindings.h", [t|CInt -> IO CBool|]),+ ("c'isMouseButtonReleased", "IsMouseButtonReleased_", "rl_bindings.h", [t|CInt -> IO CBool|]),+ ("c'isMouseButtonUp", "IsMouseButtonUp_", "rl_bindings.h", [t|CInt -> IO CBool|]),+ ("c'getMouseX", "GetMouseX_", "rl_bindings.h", [t|IO CInt|]),+ ("c'getMouseY", "GetMouseY_", "rl_bindings.h", [t|IO CInt|]),+ ("c'getMousePosition", "GetMousePosition_", "rl_bindings.h", [t|IO (Ptr Vector2)|]),+ ("c'getMouseDelta", "GetMouseDelta_", "rl_bindings.h", [t|IO (Ptr Vector2)|]),+ ("c'setMousePosition", "SetMousePosition_", "rl_bindings.h", [t|CInt -> CInt -> IO ()|]),+ ("c'setMouseOffset", "SetMouseOffset_", "rl_bindings.h", [t|CInt -> CInt -> IO ()|]),+ ("c'setMouseScale", "SetMouseScale_", "rl_bindings.h", [t|CFloat -> CFloat -> IO ()|]),+ ("c'getMouseWheelMove", "GetMouseWheelMove_", "rl_bindings.h", [t|IO CFloat|]),+ ("c'getMouseWheelMoveV", "GetMouseWheelMoveV_", "rl_bindings.h", [t|IO (Ptr Vector2)|]),+ ("c'setMouseCursor", "SetMouseCursor_", "rl_bindings.h", [t|CInt -> IO ()|]),+ ("c'getTouchX", "GetTouchX_", "rl_bindings.h", [t|IO CInt|]),+ ("c'getTouchY", "GetTouchY_", "rl_bindings.h", [t|IO CInt|]),+ ("c'getTouchPosition", "GetTouchPosition_", "rl_bindings.h", [t|CInt -> IO (Ptr Vector2)|]),+ ("c'getTouchPointId", "GetTouchPointId_", "rl_bindings.h", [t|CInt -> IO CInt|]),+ ("c'getTouchPointCount", "GetTouchPointCount_", "rl_bindings.h", [t|IO CInt|]),+ ("c'setGesturesEnabled", "SetGesturesEnabled_", "rl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'isGestureDetected", "IsGestureDetected_", "rl_bindings.h", [t|CUInt -> IO CBool|]),+ ("c'getGestureDetected", "GetGestureDetected_", "rl_bindings.h", [t|IO CInt|]),+ ("c'getGestureHoldDuration", "GetGestureHoldDuration_", "rl_bindings.h", [t|IO CFloat|]),+ ("c'getGestureDragVector", "GetGestureDragVector_", "rl_bindings.h", [t|IO (Ptr Vector2)|]),+ ("c'getGestureDragAngle", "GetGestureDragAngle_", "rl_bindings.h", [t|IO CFloat|]),+ ("c'getGesturePinchVector", "GetGesturePinchVector_", "rl_bindings.h", [t|IO (Ptr Vector2)|]),+ ("c'getGesturePinchAngle", "GetGesturePinchAngle_", "rl_bindings.h", [t|IO CFloat|]) ] ) @@ -1053,29 +1058,30 @@ openURL :: String -> IO () openURL url = withCString url c'openURL -setLoadFileDataCallback :: LoadFileDataCallback -> IO C'LoadFileDataCallback+setTraceLogCallback :: TraceLogCallback -> IO ()+setTraceLogCallback callback = do+ c <- createTraceLogCallback callback+ c'setTraceLogCallback c++setLoadFileDataCallback :: LoadFileDataCallback -> IO () setLoadFileDataCallback callback = do c <- createLoadFileDataCallback callback c'setLoadFileDataCallback c- return c -setSaveFileDataCallback :: (Storable a) => SaveFileDataCallback a -> IO C'SaveFileDataCallback+setSaveFileDataCallback :: (Storable a) => SaveFileDataCallback a -> IO () setSaveFileDataCallback callback = do c <- createSaveFileDataCallback callback c'setSaveFileDataCallback c- return c -setLoadFileTextCallback :: LoadFileTextCallback -> IO C'LoadFileTextCallback+setLoadFileTextCallback :: LoadFileTextCallback -> IO () setLoadFileTextCallback callback = do c <- createLoadFileTextCallback callback c'setLoadFileTextCallback c- return c -setSaveFileTextCallback :: SaveFileTextCallback -> IO C'SaveFileTextCallback+setSaveFileTextCallback :: SaveFileTextCallback -> IO () setSaveFileTextCallback callback = do c <- createSaveFileTextCallback callback c'setSaveFileTextCallback c- return c loadFileData :: String -> IO [Integer] loadFileData fileName =@@ -1138,6 +1144,9 @@ getApplicationDirectory :: IO String getApplicationDirectory = c'getApplicationDirectory >>= peekCString +makeDirectory :: String -> IO Bool+makeDirectory dirPath = (== 0) <$> withCString dirPath c'makeDirectory+ changeDirectory :: String -> IO Bool changeDirectory dir = toBool <$> withCString dir c'changeDirectory @@ -1401,36 +1410,33 @@ getGesturePinchAngle = realToFrac <$> c'getGesturePinchAngle foreign import ccall unsafe "wrapper"+ mk'traceLogCallback ::+ (CInt -> CString -> IO ()) -> IO C'TraceLogCallback++foreign import ccall unsafe "wrapper" mk'loadFileDataCallback :: (CString -> Ptr CUInt -> IO (Ptr CUChar)) -> IO C'LoadFileDataCallback --- foreign import ccall unsafe "dynamic"--- mK'loadFileDataCallback ::--- C'LoadFileDataCallback -> (CString -> Ptr CUInt -> IO (Ptr CUChar))- foreign import ccall unsafe "wrapper" mk'saveFileDataCallback :: (CString -> Ptr () -> CUInt -> IO CInt) -> IO C'SaveFileDataCallback --- foreign import ccall unsafe "dynamic"--- mK'saveFileDataCallback ::--- C'SaveFileDataCallback -> (CString -> Ptr () -> CUInt -> IO CInt)- foreign import ccall unsafe "wrapper" mk'loadFileTextCallback :: (CString -> IO CString) -> IO C'LoadFileTextCallback --- foreign import ccall unsafe "dynamic"--- mK'loadFileTextCallback ::--- C'LoadFileTextCallback -> (CString -> IO CString)- foreign import ccall unsafe "wrapper" mk'saveFileTextCallback :: (CString -> CString -> IO CInt) -> IO C'SaveFileTextCallback --- foreign import ccall unsafe "dynamic"--- mK'saveFileTextCallback ::--- C'SaveFileTextCallback -> (CString -> CString -> IO CInt)+createTraceLogCallback :: TraceLogCallback -> IO C'TraceLogCallback+createTraceLogCallback callback =+ mk'traceLogCallback+ (\logLevel text ->+ do+ t <- peekCString text+ callback (toEnum (fromIntegral logLevel)) t+ ) createLoadFileDataCallback :: LoadFileDataCallback -> IO C'LoadFileDataCallback createLoadFileDataCallback callback =
src/Raylib/Core/Audio.hs view
@@ -171,72 +171,72 @@ ) $( genNative- [ ("c'initAudioDevice", "InitAudioDevice_", "rl_bindings.h", [t|IO ()|], False),- ("c'closeAudioDevice", "CloseAudioDevice_", "rl_bindings.h", [t|IO ()|], False),- ("c'isAudioDeviceReady", "IsAudioDeviceReady_", "rl_bindings.h", [t|IO CBool|], False),- ("c'setMasterVolume", "SetMasterVolume_", "rl_bindings.h", [t|CFloat -> IO ()|], False),- ("c'getMasterVolume", "GetMasterVolume_", "rl_bindings.h", [t|IO CFloat|], False),- ("c'loadWave", "LoadWave_", "rl_bindings.h", [t|CString -> IO (Ptr Wave)|], False),- ("c'loadWaveFromMemory", "LoadWaveFromMemory_", "rl_bindings.h", [t|CString -> Ptr CUChar -> CInt -> IO (Ptr Wave)|], False),- ("c'loadSound", "LoadSound_", "rl_bindings.h", [t|CString -> IO (Ptr Sound)|], False),- ("c'loadSoundFromWave", "LoadSoundFromWave_", "rl_bindings.h", [t|Ptr Wave -> IO (Ptr Sound)|], False),- ("c'loadSoundAlias", "LoadSoundAlias_", "rl_bindings.h", [t|Ptr Sound -> IO (Ptr Sound)|], False),- ("c'updateSound", "UpdateSound_", "rl_bindings.h", [t|Ptr Sound -> Ptr () -> CInt -> IO ()|], False),- ("c'isWaveReady", "IsWaveReady_", "rl_bindings.h", [t|Ptr Wave -> IO CBool|], False),- ("c'unloadWave", "UnloadWave_", "rl_bindings.h", [t|Ptr Wave -> IO ()|], False),- ("c'isSoundReady", "IsSoundReady_", "rl_bindings.h", [t|Ptr Sound -> IO CBool|], False),- ("c'unloadSound", "UnloadSound_", "rl_bindings.h", [t|Ptr Sound -> IO ()|], False),- ("c'unloadSoundAlias", "UnloadSoundAlias_", "rl_bindings.h", [t|Ptr Sound -> IO ()|], False),- ("c'exportWave", "ExportWave_", "rl_bindings.h", [t|Ptr Wave -> CString -> IO CBool|], False),- ("c'exportWaveAsCode", "ExportWaveAsCode_", "rl_bindings.h", [t|Ptr Wave -> CString -> IO CBool|], False),- ("c'playSound", "PlaySound_", "rl_bindings.h", [t|Ptr Sound -> IO ()|], False),- ("c'stopSound", "StopSound_", "rl_bindings.h", [t|Ptr Sound -> IO ()|], False),- ("c'pauseSound", "PauseSound_", "rl_bindings.h", [t|Ptr Sound -> IO ()|], False),- ("c'resumeSound", "ResumeSound_", "rl_bindings.h", [t|Ptr Sound -> IO ()|], False),- ("c'isSoundPlaying", "IsSoundPlaying_", "rl_bindings.h", [t|Ptr Sound -> IO CBool|], False),- ("c'setSoundVolume", "SetSoundVolume_", "rl_bindings.h", [t|Ptr Sound -> CFloat -> IO ()|], False),- ("c'setSoundPitch", "SetSoundPitch_", "rl_bindings.h", [t|Ptr Sound -> CFloat -> IO ()|], False),- ("c'setSoundPan", "SetSoundPan_", "rl_bindings.h", [t|Ptr Sound -> CFloat -> IO ()|], False),- ("c'waveCopy", "WaveCopy_", "rl_bindings.h", [t|Ptr Wave -> IO (Ptr Wave)|], False),- ("c'waveCrop", "WaveCrop_", "rl_bindings.h", [t|Ptr Wave -> CInt -> CInt -> IO ()|], False),- ("c'waveFormat", "WaveFormat_", "rl_bindings.h", [t|Ptr Wave -> CInt -> CInt -> CInt -> IO ()|], False),- ("c'loadWaveSamples", "LoadWaveSamples_", "rl_bindings.h", [t|Ptr Wave -> IO (Ptr CFloat)|], False),- ("c'unloadWaveSamples", "UnloadWaveSamples_", "rl_bindings.h", [t|Ptr CFloat -> IO ()|], False),- ("c'loadMusicStream", "LoadMusicStream_", "rl_bindings.h", [t|CString -> IO (Ptr Music)|], False),- ("c'loadMusicStreamFromMemory", "LoadMusicStreamFromMemory_", "rl_bindings.h", [t|CString -> Ptr CUChar -> CInt -> IO (Ptr Music)|], False),- ("c'isMusicReady", "IsMusicReady_", "rl_bindings.h", [t|Ptr Music -> IO CBool|], False),- ("c'unloadMusicStream", "UnloadMusicStream_", "rl_bindings.h", [t|Ptr Music -> IO ()|], False),- ("c'playMusicStream", "PlayMusicStream_", "rl_bindings.h", [t|Ptr Music -> IO ()|], False),- ("c'isMusicStreamPlaying", "IsMusicStreamPlaying_", "rl_bindings.h", [t|Ptr Music -> IO CBool|], False),- ("c'updateMusicStream", "UpdateMusicStream_", "rl_bindings.h", [t|Ptr Music -> IO ()|], False),- ("c'stopMusicStream", "StopMusicStream_", "rl_bindings.h", [t|Ptr Music -> IO ()|], False),- ("c'pauseMusicStream", "PauseMusicStream_", "rl_bindings.h", [t|Ptr Music -> IO ()|], False),- ("c'resumeMusicStream", "ResumeMusicStream_", "rl_bindings.h", [t|Ptr Music -> IO ()|], False),- ("c'seekMusicStream", "SeekMusicStream_", "rl_bindings.h", [t|Ptr Music -> CFloat -> IO ()|], False),- ("c'setMusicVolume", "SetMusicVolume_", "rl_bindings.h", [t|Ptr Music -> CFloat -> IO ()|], False),- ("c'setMusicPitch", "SetMusicPitch_", "rl_bindings.h", [t|Ptr Music -> CFloat -> IO ()|], False),- ("c'setMusicPan", "SetMusicPan_", "rl_bindings.h", [t|Ptr Music -> CFloat -> IO ()|], False),- ("c'getMusicTimeLength", "GetMusicTimeLength_", "rl_bindings.h", [t|Ptr Music -> IO CFloat|], False),- ("c'getMusicTimePlayed", "GetMusicTimePlayed_", "rl_bindings.h", [t|Ptr Music -> IO CFloat|], False),- ("c'loadAudioStream", "LoadAudioStream_", "rl_bindings.h", [t|CUInt -> CUInt -> CUInt -> IO (Ptr AudioStream)|], False),- ("c'isAudioStreamReady", "IsAudioStreamReady_", "rl_bindings.h", [t|Ptr AudioStream -> IO CBool|], False),- ("c'unloadAudioStream", "UnloadAudioStream_", "rl_bindings.h", [t|Ptr AudioStream -> IO ()|], False),- ("c'updateAudioStream", "UpdateAudioStream_", "rl_bindings.h", [t|Ptr AudioStream -> Ptr () -> CInt -> IO ()|], False),- ("c'isAudioStreamProcessed", "IsAudioStreamProcessed_", "rl_bindings.h", [t|Ptr AudioStream -> IO CBool|], False),- ("c'playAudioStream", "PlayAudioStream_", "rl_bindings.h", [t|Ptr AudioStream -> IO ()|], False),- ("c'pauseAudioStream", "PauseAudioStream_", "rl_bindings.h", [t|Ptr AudioStream -> IO ()|], False),- ("c'resumeAudioStream", "ResumeAudioStream_", "rl_bindings.h", [t|Ptr AudioStream -> IO ()|], False),- ("c'isAudioStreamPlaying", "IsAudioStreamPlaying_", "rl_bindings.h", [t|Ptr AudioStream -> IO CBool|], False),- ("c'stopAudioStream", "StopAudioStream_", "rl_bindings.h", [t|Ptr AudioStream -> IO ()|], False),- ("c'setAudioStreamVolume", "SetAudioStreamVolume_", "rl_bindings.h", [t|Ptr AudioStream -> CFloat -> IO ()|], False),- ("c'setAudioStreamPitch", "SetAudioStreamPitch_", "rl_bindings.h", [t|Ptr AudioStream -> CFloat -> IO ()|], False),- ("c'setAudioStreamPan", "SetAudioStreamPan_", "rl_bindings.h", [t|Ptr AudioStream -> CFloat -> IO ()|], False),- ("c'setAudioStreamBufferSizeDefault", "SetAudioStreamBufferSizeDefault_", "rl_bindings.h", [t|CInt -> IO ()|], False),- ("c'setAudioStreamCallback", "SetAudioStreamCallback_", "rl_bindings.h", [t|Ptr AudioStream -> C'AudioCallback -> IO ()|], False),- ("c'attachAudioStreamProcessor", "AttachAudioStreamProcessor_", "rl_bindings.h", [t|Ptr AudioStream -> C'AudioCallback -> IO ()|], False),- ("c'detachAudioStreamProcessor", "DetachAudioStreamProcessor_", "rl_bindings.h", [t|Ptr AudioStream -> C'AudioCallback -> IO ()|], False),- ("c'attachAudioMixedProcessor", "AttachAudioMixedProcessor_", "rl_bindings.h", [t|C'AudioCallback -> IO ()|], False),- ("c'detachAudioMixedProcessor", "DetachAudioMixedProcessor_", "rl_bindings.h", [t|C'AudioCallback -> IO ()|], False)+ [ ("c'initAudioDevice", "InitAudioDevice_", "rl_bindings.h", [t|IO ()|]),+ ("c'closeAudioDevice", "CloseAudioDevice_", "rl_bindings.h", [t|IO ()|]),+ ("c'isAudioDeviceReady", "IsAudioDeviceReady_", "rl_bindings.h", [t|IO CBool|]),+ ("c'setMasterVolume", "SetMasterVolume_", "rl_bindings.h", [t|CFloat -> IO ()|]),+ ("c'getMasterVolume", "GetMasterVolume_", "rl_bindings.h", [t|IO CFloat|]),+ ("c'loadWave", "LoadWave_", "rl_bindings.h", [t|CString -> IO (Ptr Wave)|]),+ ("c'loadWaveFromMemory", "LoadWaveFromMemory_", "rl_bindings.h", [t|CString -> Ptr CUChar -> CInt -> IO (Ptr Wave)|]),+ ("c'loadSound", "LoadSound_", "rl_bindings.h", [t|CString -> IO (Ptr Sound)|]),+ ("c'loadSoundFromWave", "LoadSoundFromWave_", "rl_bindings.h", [t|Ptr Wave -> IO (Ptr Sound)|]),+ ("c'loadSoundAlias", "LoadSoundAlias_", "rl_bindings.h", [t|Ptr Sound -> IO (Ptr Sound)|]),+ ("c'updateSound", "UpdateSound_", "rl_bindings.h", [t|Ptr Sound -> Ptr () -> CInt -> IO ()|]),+ ("c'isWaveReady", "IsWaveReady_", "rl_bindings.h", [t|Ptr Wave -> IO CBool|]),+ ("c'unloadWave", "UnloadWave_", "rl_bindings.h", [t|Ptr Wave -> IO ()|]),+ ("c'isSoundReady", "IsSoundReady_", "rl_bindings.h", [t|Ptr Sound -> IO CBool|]),+ ("c'unloadSound", "UnloadSound_", "rl_bindings.h", [t|Ptr Sound -> IO ()|]),+ ("c'unloadSoundAlias", "UnloadSoundAlias_", "rl_bindings.h", [t|Ptr Sound -> IO ()|]),+ ("c'exportWave", "ExportWave_", "rl_bindings.h", [t|Ptr Wave -> CString -> IO CBool|]),+ ("c'exportWaveAsCode", "ExportWaveAsCode_", "rl_bindings.h", [t|Ptr Wave -> CString -> IO CBool|]),+ ("c'playSound", "PlaySound_", "rl_bindings.h", [t|Ptr Sound -> IO ()|]),+ ("c'stopSound", "StopSound_", "rl_bindings.h", [t|Ptr Sound -> IO ()|]),+ ("c'pauseSound", "PauseSound_", "rl_bindings.h", [t|Ptr Sound -> IO ()|]),+ ("c'resumeSound", "ResumeSound_", "rl_bindings.h", [t|Ptr Sound -> IO ()|]),+ ("c'isSoundPlaying", "IsSoundPlaying_", "rl_bindings.h", [t|Ptr Sound -> IO CBool|]),+ ("c'setSoundVolume", "SetSoundVolume_", "rl_bindings.h", [t|Ptr Sound -> CFloat -> IO ()|]),+ ("c'setSoundPitch", "SetSoundPitch_", "rl_bindings.h", [t|Ptr Sound -> CFloat -> IO ()|]),+ ("c'setSoundPan", "SetSoundPan_", "rl_bindings.h", [t|Ptr Sound -> CFloat -> IO ()|]),+ ("c'waveCopy", "WaveCopy_", "rl_bindings.h", [t|Ptr Wave -> IO (Ptr Wave)|]),+ ("c'waveCrop", "WaveCrop_", "rl_bindings.h", [t|Ptr Wave -> CInt -> CInt -> IO ()|]),+ ("c'waveFormat", "WaveFormat_", "rl_bindings.h", [t|Ptr Wave -> CInt -> CInt -> CInt -> IO ()|]),+ ("c'loadWaveSamples", "LoadWaveSamples_", "rl_bindings.h", [t|Ptr Wave -> IO (Ptr CFloat)|]),+ ("c'unloadWaveSamples", "UnloadWaveSamples_", "rl_bindings.h", [t|Ptr CFloat -> IO ()|]),+ ("c'loadMusicStream", "LoadMusicStream_", "rl_bindings.h", [t|CString -> IO (Ptr Music)|]),+ ("c'loadMusicStreamFromMemory", "LoadMusicStreamFromMemory_", "rl_bindings.h", [t|CString -> Ptr CUChar -> CInt -> IO (Ptr Music)|]),+ ("c'isMusicReady", "IsMusicReady_", "rl_bindings.h", [t|Ptr Music -> IO CBool|]),+ ("c'unloadMusicStream", "UnloadMusicStream_", "rl_bindings.h", [t|Ptr Music -> IO ()|]),+ ("c'playMusicStream", "PlayMusicStream_", "rl_bindings.h", [t|Ptr Music -> IO ()|]),+ ("c'isMusicStreamPlaying", "IsMusicStreamPlaying_", "rl_bindings.h", [t|Ptr Music -> IO CBool|]),+ ("c'updateMusicStream", "UpdateMusicStream_", "rl_bindings.h", [t|Ptr Music -> IO ()|]),+ ("c'stopMusicStream", "StopMusicStream_", "rl_bindings.h", [t|Ptr Music -> IO ()|]),+ ("c'pauseMusicStream", "PauseMusicStream_", "rl_bindings.h", [t|Ptr Music -> IO ()|]),+ ("c'resumeMusicStream", "ResumeMusicStream_", "rl_bindings.h", [t|Ptr Music -> IO ()|]),+ ("c'seekMusicStream", "SeekMusicStream_", "rl_bindings.h", [t|Ptr Music -> CFloat -> IO ()|]),+ ("c'setMusicVolume", "SetMusicVolume_", "rl_bindings.h", [t|Ptr Music -> CFloat -> IO ()|]),+ ("c'setMusicPitch", "SetMusicPitch_", "rl_bindings.h", [t|Ptr Music -> CFloat -> IO ()|]),+ ("c'setMusicPan", "SetMusicPan_", "rl_bindings.h", [t|Ptr Music -> CFloat -> IO ()|]),+ ("c'getMusicTimeLength", "GetMusicTimeLength_", "rl_bindings.h", [t|Ptr Music -> IO CFloat|]),+ ("c'getMusicTimePlayed", "GetMusicTimePlayed_", "rl_bindings.h", [t|Ptr Music -> IO CFloat|]),+ ("c'loadAudioStream", "LoadAudioStream_", "rl_bindings.h", [t|CUInt -> CUInt -> CUInt -> IO (Ptr AudioStream)|]),+ ("c'isAudioStreamReady", "IsAudioStreamReady_", "rl_bindings.h", [t|Ptr AudioStream -> IO CBool|]),+ ("c'unloadAudioStream", "UnloadAudioStream_", "rl_bindings.h", [t|Ptr AudioStream -> IO ()|]),+ ("c'updateAudioStream", "UpdateAudioStream_", "rl_bindings.h", [t|Ptr AudioStream -> Ptr () -> CInt -> IO ()|]),+ ("c'isAudioStreamProcessed", "IsAudioStreamProcessed_", "rl_bindings.h", [t|Ptr AudioStream -> IO CBool|]),+ ("c'playAudioStream", "PlayAudioStream_", "rl_bindings.h", [t|Ptr AudioStream -> IO ()|]),+ ("c'pauseAudioStream", "PauseAudioStream_", "rl_bindings.h", [t|Ptr AudioStream -> IO ()|]),+ ("c'resumeAudioStream", "ResumeAudioStream_", "rl_bindings.h", [t|Ptr AudioStream -> IO ()|]),+ ("c'isAudioStreamPlaying", "IsAudioStreamPlaying_", "rl_bindings.h", [t|Ptr AudioStream -> IO CBool|]),+ ("c'stopAudioStream", "StopAudioStream_", "rl_bindings.h", [t|Ptr AudioStream -> IO ()|]),+ ("c'setAudioStreamVolume", "SetAudioStreamVolume_", "rl_bindings.h", [t|Ptr AudioStream -> CFloat -> IO ()|]),+ ("c'setAudioStreamPitch", "SetAudioStreamPitch_", "rl_bindings.h", [t|Ptr AudioStream -> CFloat -> IO ()|]),+ ("c'setAudioStreamPan", "SetAudioStreamPan_", "rl_bindings.h", [t|Ptr AudioStream -> CFloat -> IO ()|]),+ ("c'setAudioStreamBufferSizeDefault", "SetAudioStreamBufferSizeDefault_", "rl_bindings.h", [t|CInt -> IO ()|]),+ ("c'setAudioStreamCallback", "SetAudioStreamCallback_", "rl_bindings.h", [t|Ptr AudioStream -> C'AudioCallback -> IO ()|]),+ ("c'attachAudioStreamProcessor", "AttachAudioStreamProcessor_", "rl_bindings.h", [t|Ptr AudioStream -> C'AudioCallback -> IO ()|]),+ ("c'detachAudioStreamProcessor", "DetachAudioStreamProcessor_", "rl_bindings.h", [t|Ptr AudioStream -> C'AudioCallback -> IO ()|]),+ ("c'attachAudioMixedProcessor", "AttachAudioMixedProcessor_", "rl_bindings.h", [t|C'AudioCallback -> IO ()|]),+ ("c'detachAudioMixedProcessor", "DetachAudioMixedProcessor_", "rl_bindings.h", [t|C'AudioCallback -> IO ()|]) ] )
src/Raylib/Core/Camera.hs view
@@ -20,8 +20,8 @@ import Raylib.Types (Camera3D, CameraMode, Vector3) $( genNative- [ ("c'updateCamera", "UpdateCamera_", "rl_bindings.h", [t|Ptr Camera3D -> CInt -> IO ()|], False),- ("c'updateCameraPro", "UpdateCameraPro_", "rl_bindings.h", [t|Ptr Camera3D -> Ptr Vector3 -> Ptr Vector3 -> CFloat -> IO ()|], False)+ [ ("c'updateCamera", "UpdateCamera_", "rl_bindings.h", [t|Ptr Camera3D -> CInt -> IO ()|]),+ ("c'updateCameraPro", "UpdateCameraPro_", "rl_bindings.h", [t|Ptr Camera3D -> Ptr Vector3 -> Ptr Vector3 -> CFloat -> IO ()|]) ] )
src/Raylib/Core/Models.hs view
@@ -34,6 +34,8 @@ drawModelEx, drawModelWires, drawModelWiresEx,+ drawModelPoints,+ drawModelPointsEx, drawBoundingBox, drawBillboard, drawBillboardRec,@@ -67,6 +69,7 @@ loadModelAnimations, updateModelAnimation, isModelAnimationValid,+ updateModelAnimationBoneMatrices, checkCollisionSpheres, checkCollisionBoxes, checkCollisionBoxSphere,@@ -107,6 +110,8 @@ c'drawModelEx, c'drawModelWires, c'drawModelWiresEx,+ c'drawModelPoints,+ c'drawModelPointsEx, c'drawBoundingBox, c'drawBillboard, c'drawBillboardRec,@@ -142,6 +147,7 @@ c'unloadModelAnimation, c'unloadModelAnimations, c'isModelAnimationValid,+ c'updateModelAnimationBoneMatrices, c'checkCollisionSpheres, c'checkCollisionBoxes, c'checkCollisionBoxSphere,@@ -193,79 +199,82 @@ ) $( genNative- [ ("c'drawLine3D", "DrawLine3D_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Vector3 -> Ptr Color -> IO ()|], False),- ("c'drawPoint3D", "DrawPoint3D_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Color -> IO ()|], False),- ("c'drawCircle3D", "DrawCircle3D_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> Ptr Vector3 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawTriangle3D", "DrawTriangle3D_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Vector3 -> Ptr Vector3 -> Ptr Color -> IO ()|], False),- ("c'drawTriangleStrip3D", "DrawTriangleStrip3D_", "rl_bindings.h", [t|Ptr Vector3 -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawCube", "DrawCube_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> CFloat -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawCubeV", "DrawCubeV_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Vector3 -> Ptr Color -> IO ()|], False),- ("c'drawCubeWires", "DrawCubeWires_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> CFloat -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawCubeWiresV", "DrawCubeWiresV_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Vector3 -> Ptr Color -> IO ()|], False),- ("c'drawSphere", "DrawSphere_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawSphereEx", "DrawSphereEx_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> CInt -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawSphereWires", "DrawSphereWires_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> CInt -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawCylinder", "DrawCylinder_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawCylinderEx", "DrawCylinderEx_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Vector3 -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawCylinderWires", "DrawCylinderWires_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawCylinderWiresEx", "DrawCylinderWiresEx_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Vector3 -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawCapsule", "DrawCapsule_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Vector3 -> CFloat -> CInt -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawCapsuleWires", "DrawCapsuleWires_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Vector3 -> CFloat -> CInt -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawPlane", "DrawPlane_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Vector2 -> Ptr Color -> IO ()|], False),- ("c'drawRay", "DrawRay_", "rl_bindings.h", [t|Ptr Ray -> Ptr Color -> IO ()|], False),- ("c'drawGrid", "DrawGrid_", "rl_bindings.h", [t|CInt -> CFloat -> IO ()|], False),- ("c'loadModel", "LoadModel_", "rl_bindings.h", [t|CString -> IO (Ptr Model)|], False),- ("c'loadModelFromMesh", "LoadModelFromMesh_", "rl_bindings.h", [t|Ptr Mesh -> IO (Ptr Model)|], False),- ("c'isModelReady", "IsModelReady_", "rl_bindings.h", [t|Ptr Model -> IO CBool|], False),- ("c'unloadModel", "UnloadModel_", "rl_bindings.h", [t|Ptr Model -> IO ()|], False),- ("c'getModelBoundingBox", "GetModelBoundingBox_", "rl_bindings.h", [t|Ptr Model -> IO (Ptr BoundingBox)|], False),- ("c'drawModel", "DrawModel_", "rl_bindings.h", [t|Ptr Model -> Ptr Vector3 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawModelEx", "DrawModelEx_", "rl_bindings.h", [t|Ptr Model -> Ptr Vector3 -> Ptr Vector3 -> CFloat -> Ptr Vector3 -> Ptr Color -> IO ()|], False),- ("c'drawModelWires", "DrawModelWires_", "rl_bindings.h", [t|Ptr Model -> Ptr Vector3 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawModelWiresEx", "DrawModelWiresEx_", "rl_bindings.h", [t|Ptr Model -> Ptr Vector3 -> Ptr Vector3 -> CFloat -> Ptr Vector3 -> Ptr Color -> IO ()|], False),- ("c'drawBoundingBox", "DrawBoundingBox_", "rl_bindings.h", [t|Ptr BoundingBox -> Ptr Color -> IO ()|], False),- ("c'drawBillboard", "DrawBillboard_", "rl_bindings.h", [t|Ptr Camera3D -> Ptr Texture -> Ptr Vector3 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawBillboardRec", "DrawBillboardRec_", "rl_bindings.h", [t|Ptr Camera3D -> Ptr Texture -> Ptr Rectangle -> Ptr Vector3 -> Ptr Vector2 -> Ptr Color -> IO ()|], False),- ("c'drawBillboardPro", "DrawBillboardPro_", "rl_bindings.h", [t|Ptr Camera3D -> Ptr Texture -> Ptr Rectangle -> Ptr Vector3 -> Ptr Vector3 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'uploadMesh", "UploadMesh_", "rl_bindings.h", [t|Ptr Mesh -> CInt -> IO ()|], False),- ("c'updateMeshBuffer", "UpdateMeshBuffer_", "rl_bindings.h", [t|Ptr Mesh -> CInt -> Ptr () -> CInt -> CInt -> IO ()|], False),- ("c'unloadMesh", "UnloadMesh_", "rl_bindings.h", [t|Ptr Mesh -> IO ()|], False),- ("c'drawMesh", "DrawMesh_", "rl_bindings.h", [t|Ptr Mesh -> Ptr Material -> Ptr Matrix -> IO ()|], False),- ("c'drawMeshInstanced", "DrawMeshInstanced_", "rl_bindings.h", [t|Ptr Mesh -> Ptr Material -> Ptr Matrix -> CInt -> IO ()|], False),- ("c'exportMesh", "ExportMesh_", "rl_bindings.h", [t|Ptr Mesh -> CString -> IO CBool|], False),- ("c'exportMeshAsCode", "ExportMeshAsCode_", "rl_bindings.h", [t|Ptr Mesh -> CString -> IO CBool|], False),- ("c'getMeshBoundingBox", "GetMeshBoundingBox_", "rl_bindings.h", [t|Ptr Mesh -> IO (Ptr BoundingBox)|], False),- ("c'genMeshTangents", "GenMeshTangents_", "rl_bindings.h", [t|Ptr Mesh -> IO ()|], False),- ("c'genMeshPoly", "GenMeshPoly_", "rl_bindings.h", [t|CInt -> CFloat -> IO (Ptr Mesh)|], False),- ("c'genMeshPlane", "GenMeshPlane_", "rl_bindings.h", [t|CFloat -> CFloat -> CInt -> CInt -> IO (Ptr Mesh)|], False),- ("c'genMeshCube", "GenMeshCube_", "rl_bindings.h", [t|CFloat -> CFloat -> CFloat -> IO (Ptr Mesh)|], False),- ("c'genMeshSphere", "GenMeshSphere_", "rl_bindings.h", [t|CFloat -> CInt -> CInt -> IO (Ptr Mesh)|], False),- ("c'genMeshHemiSphere", "GenMeshHemiSphere_", "rl_bindings.h", [t|CFloat -> CInt -> CInt -> IO (Ptr Mesh)|], False),- ("c'genMeshCylinder", "GenMeshCylinder_", "rl_bindings.h", [t|CFloat -> CFloat -> CInt -> IO (Ptr Mesh)|], False),- ("c'genMeshCone", "GenMeshCone_", "rl_bindings.h", [t|CFloat -> CFloat -> CInt -> IO (Ptr Mesh)|], False),- ("c'genMeshTorus", "GenMeshTorus_", "rl_bindings.h", [t|CFloat -> CFloat -> CInt -> CInt -> IO (Ptr Mesh)|], False),- ("c'genMeshKnot", "GenMeshKnot_", "rl_bindings.h", [t|CFloat -> CFloat -> CInt -> CInt -> IO (Ptr Mesh)|], False),- ("c'genMeshHeightmap", "GenMeshHeightmap_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector3 -> IO (Ptr Mesh)|], False),- ("c'genMeshCubicmap", "GenMeshCubicmap_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector3 -> IO (Ptr Mesh)|], False),- ("c'loadMaterials", "LoadMaterials_", "rl_bindings.h", [t|CString -> Ptr CInt -> IO (Ptr Material)|], False),- ("c'loadMaterialDefault", "LoadMaterialDefault_", "rl_bindings.h", [t|IO (Ptr Material)|], False),- ("c'isMaterialReady", "IsMaterialReady_", "rl_bindings.h", [t|Ptr Material -> IO CBool|], False),- ("c'unloadMaterial", "UnloadMaterial_", "rl_bindings.h", [t|Ptr Material -> IO ()|], False),- ("c'setMaterialTexture", "SetMaterialTexture_", "rl_bindings.h", [t|Ptr Material -> CInt -> Ptr Texture -> IO ()|], False),- ("c'setModelMeshMaterial", "SetModelMeshMaterial_", "rl_bindings.h", [t|Ptr Model -> CInt -> CInt -> IO ()|], False),- ("c'loadModelAnimations", "LoadModelAnimations_", "rl_bindings.h", [t|CString -> Ptr CInt -> IO (Ptr ModelAnimation)|], False),- ("c'updateModelAnimation", "UpdateModelAnimation_", "rl_bindings.h", [t|Ptr Model -> Ptr ModelAnimation -> CInt -> IO ()|], False),- ("c'unloadModelAnimation", "UnloadModelAnimation_", "rl_bindings.h", [t|Ptr ModelAnimation -> IO ()|], False),- ("c'unloadModelAnimations", "UnloadModelAnimations_", "rl_bindings.h", [t|Ptr ModelAnimation -> CInt -> IO ()|], False),- ("c'isModelAnimationValid", "IsModelAnimationValid_", "rl_bindings.h", [t|Ptr Model -> Ptr ModelAnimation -> IO CBool|], False),- ("c'checkCollisionSpheres", "CheckCollisionSpheres_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> Ptr Vector3 -> CFloat -> IO CBool|], False),- ("c'checkCollisionBoxes", "CheckCollisionBoxes_", "rl_bindings.h", [t|Ptr BoundingBox -> Ptr BoundingBox -> IO CBool|], False),- ("c'checkCollisionBoxSphere", "CheckCollisionBoxSphere_", "rl_bindings.h", [t|Ptr BoundingBox -> Ptr Vector3 -> CFloat -> IO CBool|], False),- ("c'getRayCollisionSphere", "GetRayCollisionSphere_", "rl_bindings.h", [t|Ptr Ray -> Ptr Vector3 -> CFloat -> IO (Ptr RayCollision)|], False),- ("c'getRayCollisionBox", "GetRayCollisionBox_", "rl_bindings.h", [t|Ptr Ray -> Ptr BoundingBox -> IO (Ptr RayCollision)|], False),- ("c'getRayCollisionMesh", "GetRayCollisionMesh_", "rl_bindings.h", [t|Ptr Ray -> Ptr Mesh -> Ptr Matrix -> IO (Ptr RayCollision)|], False),- ("c'getRayCollisionTriangle", "GetRayCollisionTriangle_", "rl_bindings.h", [t|Ptr Ray -> Ptr Vector3 -> Ptr Vector3 -> Ptr Vector3 -> IO (Ptr RayCollision)|], False),- ("c'getRayCollisionQuad", "GetRayCollisionQuad_", "rl_bindings.h", [t|Ptr Ray -> Ptr Vector3 -> Ptr Vector3 -> Ptr Vector3 -> Ptr Vector3 -> IO (Ptr RayCollision)|], False)+ [ ("c'drawLine3D", "DrawLine3D_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Vector3 -> Ptr Color -> IO ()|]),+ ("c'drawPoint3D", "DrawPoint3D_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Color -> IO ()|]),+ ("c'drawCircle3D", "DrawCircle3D_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> Ptr Vector3 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawTriangle3D", "DrawTriangle3D_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Vector3 -> Ptr Vector3 -> Ptr Color -> IO ()|]),+ ("c'drawTriangleStrip3D", "DrawTriangleStrip3D_", "rl_bindings.h", [t|Ptr Vector3 -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawCube", "DrawCube_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> CFloat -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawCubeV", "DrawCubeV_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Vector3 -> Ptr Color -> IO ()|]),+ ("c'drawCubeWires", "DrawCubeWires_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> CFloat -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawCubeWiresV", "DrawCubeWiresV_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Vector3 -> Ptr Color -> IO ()|]),+ ("c'drawSphere", "DrawSphere_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawSphereEx", "DrawSphereEx_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> CInt -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawSphereWires", "DrawSphereWires_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> CInt -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawCylinder", "DrawCylinder_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawCylinderEx", "DrawCylinderEx_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Vector3 -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawCylinderWires", "DrawCylinderWires_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawCylinderWiresEx", "DrawCylinderWiresEx_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Vector3 -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawCapsule", "DrawCapsule_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Vector3 -> CFloat -> CInt -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawCapsuleWires", "DrawCapsuleWires_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Vector3 -> CFloat -> CInt -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawPlane", "DrawPlane_", "rl_bindings.h", [t|Ptr Vector3 -> Ptr Vector2 -> Ptr Color -> IO ()|]),+ ("c'drawRay", "DrawRay_", "rl_bindings.h", [t|Ptr Ray -> Ptr Color -> IO ()|]),+ ("c'drawGrid", "DrawGrid_", "rl_bindings.h", [t|CInt -> CFloat -> IO ()|]),+ ("c'loadModel", "LoadModel_", "rl_bindings.h", [t|CString -> IO (Ptr Model)|]),+ ("c'loadModelFromMesh", "LoadModelFromMesh_", "rl_bindings.h", [t|Ptr Mesh -> IO (Ptr Model)|]),+ ("c'isModelReady", "IsModelReady_", "rl_bindings.h", [t|Ptr Model -> IO CBool|]),+ ("c'unloadModel", "UnloadModel_", "rl_bindings.h", [t|Ptr Model -> IO ()|]),+ ("c'getModelBoundingBox", "GetModelBoundingBox_", "rl_bindings.h", [t|Ptr Model -> IO (Ptr BoundingBox)|]),+ ("c'drawModel", "DrawModel_", "rl_bindings.h", [t|Ptr Model -> Ptr Vector3 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawModelEx", "DrawModelEx_", "rl_bindings.h", [t|Ptr Model -> Ptr Vector3 -> Ptr Vector3 -> CFloat -> Ptr Vector3 -> Ptr Color -> IO ()|]),+ ("c'drawModelWires", "DrawModelWires_", "rl_bindings.h", [t|Ptr Model -> Ptr Vector3 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawModelWiresEx", "DrawModelWiresEx_", "rl_bindings.h", [t|Ptr Model -> Ptr Vector3 -> Ptr Vector3 -> CFloat -> Ptr Vector3 -> Ptr Color -> IO ()|]),+ ("c'drawModelPoints", "DrawModelPoints_", "rl_bindings.h", [t|Ptr Model -> Ptr Vector3 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawModelPointsEx", "DrawModelPointsEx_", "rl_bindings.h", [t|Ptr Model -> Ptr Vector3 -> Ptr Vector3 -> CFloat -> Ptr Vector3 -> Ptr Color -> IO ()|]),+ ("c'drawBoundingBox", "DrawBoundingBox_", "rl_bindings.h", [t|Ptr BoundingBox -> Ptr Color -> IO ()|]),+ ("c'drawBillboard", "DrawBillboard_", "rl_bindings.h", [t|Ptr Camera3D -> Ptr Texture -> Ptr Vector3 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawBillboardRec", "DrawBillboardRec_", "rl_bindings.h", [t|Ptr Camera3D -> Ptr Texture -> Ptr Rectangle -> Ptr Vector3 -> Ptr Vector2 -> Ptr Color -> IO ()|]),+ ("c'drawBillboardPro", "DrawBillboardPro_", "rl_bindings.h", [t|Ptr Camera3D -> Ptr Texture -> Ptr Rectangle -> Ptr Vector3 -> Ptr Vector3 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'uploadMesh", "UploadMesh_", "rl_bindings.h", [t|Ptr Mesh -> CInt -> IO ()|]),+ ("c'updateMeshBuffer", "UpdateMeshBuffer_", "rl_bindings.h", [t|Ptr Mesh -> CInt -> Ptr () -> CInt -> CInt -> IO ()|]),+ ("c'unloadMesh", "UnloadMesh_", "rl_bindings.h", [t|Ptr Mesh -> IO ()|]),+ ("c'drawMesh", "DrawMesh_", "rl_bindings.h", [t|Ptr Mesh -> Ptr Material -> Ptr Matrix -> IO ()|]),+ ("c'drawMeshInstanced", "DrawMeshInstanced_", "rl_bindings.h", [t|Ptr Mesh -> Ptr Material -> Ptr Matrix -> CInt -> IO ()|]),+ ("c'exportMesh", "ExportMesh_", "rl_bindings.h", [t|Ptr Mesh -> CString -> IO CBool|]),+ ("c'exportMeshAsCode", "ExportMeshAsCode_", "rl_bindings.h", [t|Ptr Mesh -> CString -> IO CBool|]),+ ("c'getMeshBoundingBox", "GetMeshBoundingBox_", "rl_bindings.h", [t|Ptr Mesh -> IO (Ptr BoundingBox)|]),+ ("c'genMeshTangents", "GenMeshTangents_", "rl_bindings.h", [t|Ptr Mesh -> IO ()|]),+ ("c'genMeshPoly", "GenMeshPoly_", "rl_bindings.h", [t|CInt -> CFloat -> IO (Ptr Mesh)|]),+ ("c'genMeshPlane", "GenMeshPlane_", "rl_bindings.h", [t|CFloat -> CFloat -> CInt -> CInt -> IO (Ptr Mesh)|]),+ ("c'genMeshCube", "GenMeshCube_", "rl_bindings.h", [t|CFloat -> CFloat -> CFloat -> IO (Ptr Mesh)|]),+ ("c'genMeshSphere", "GenMeshSphere_", "rl_bindings.h", [t|CFloat -> CInt -> CInt -> IO (Ptr Mesh)|]),+ ("c'genMeshHemiSphere", "GenMeshHemiSphere_", "rl_bindings.h", [t|CFloat -> CInt -> CInt -> IO (Ptr Mesh)|]),+ ("c'genMeshCylinder", "GenMeshCylinder_", "rl_bindings.h", [t|CFloat -> CFloat -> CInt -> IO (Ptr Mesh)|]),+ ("c'genMeshCone", "GenMeshCone_", "rl_bindings.h", [t|CFloat -> CFloat -> CInt -> IO (Ptr Mesh)|]),+ ("c'genMeshTorus", "GenMeshTorus_", "rl_bindings.h", [t|CFloat -> CFloat -> CInt -> CInt -> IO (Ptr Mesh)|]),+ ("c'genMeshKnot", "GenMeshKnot_", "rl_bindings.h", [t|CFloat -> CFloat -> CInt -> CInt -> IO (Ptr Mesh)|]),+ ("c'genMeshHeightmap", "GenMeshHeightmap_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector3 -> IO (Ptr Mesh)|]),+ ("c'genMeshCubicmap", "GenMeshCubicmap_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector3 -> IO (Ptr Mesh)|]),+ ("c'loadMaterials", "LoadMaterials_", "rl_bindings.h", [t|CString -> Ptr CInt -> IO (Ptr Material)|]),+ ("c'loadMaterialDefault", "LoadMaterialDefault_", "rl_bindings.h", [t|IO (Ptr Material)|]),+ ("c'isMaterialReady", "IsMaterialReady_", "rl_bindings.h", [t|Ptr Material -> IO CBool|]),+ ("c'unloadMaterial", "UnloadMaterial_", "rl_bindings.h", [t|Ptr Material -> IO ()|]),+ ("c'setMaterialTexture", "SetMaterialTexture_", "rl_bindings.h", [t|Ptr Material -> CInt -> Ptr Texture -> IO ()|]),+ ("c'setModelMeshMaterial", "SetModelMeshMaterial_", "rl_bindings.h", [t|Ptr Model -> CInt -> CInt -> IO ()|]),+ ("c'loadModelAnimations", "LoadModelAnimations_", "rl_bindings.h", [t|CString -> Ptr CInt -> IO (Ptr ModelAnimation)|]),+ ("c'updateModelAnimation", "UpdateModelAnimation_", "rl_bindings.h", [t|Ptr Model -> Ptr ModelAnimation -> CInt -> IO ()|]),+ ("c'unloadModelAnimation", "UnloadModelAnimation_", "rl_bindings.h", [t|Ptr ModelAnimation -> IO ()|]),+ ("c'unloadModelAnimations", "UnloadModelAnimations_", "rl_bindings.h", [t|Ptr ModelAnimation -> CInt -> IO ()|]),+ ("c'isModelAnimationValid", "IsModelAnimationValid_", "rl_bindings.h", [t|Ptr Model -> Ptr ModelAnimation -> IO CBool|]),+ ("c'updateModelAnimationBoneMatrices", "UpdateModelAnimationBoneMatrices_", "rl_bindings.h", [t|Ptr Model -> Ptr ModelAnimation -> CInt -> IO ()|]),+ ("c'checkCollisionSpheres", "CheckCollisionSpheres_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> Ptr Vector3 -> CFloat -> IO CBool|]),+ ("c'checkCollisionBoxes", "CheckCollisionBoxes_", "rl_bindings.h", [t|Ptr BoundingBox -> Ptr BoundingBox -> IO CBool|]),+ ("c'checkCollisionBoxSphere", "CheckCollisionBoxSphere_", "rl_bindings.h", [t|Ptr BoundingBox -> Ptr Vector3 -> CFloat -> IO CBool|]),+ ("c'getRayCollisionSphere", "GetRayCollisionSphere_", "rl_bindings.h", [t|Ptr Ray -> Ptr Vector3 -> CFloat -> IO (Ptr RayCollision)|]),+ ("c'getRayCollisionBox", "GetRayCollisionBox_", "rl_bindings.h", [t|Ptr Ray -> Ptr BoundingBox -> IO (Ptr RayCollision)|]),+ ("c'getRayCollisionMesh", "GetRayCollisionMesh_", "rl_bindings.h", [t|Ptr Ray -> Ptr Mesh -> Ptr Matrix -> IO (Ptr RayCollision)|]),+ ("c'getRayCollisionTriangle", "GetRayCollisionTriangle_", "rl_bindings.h", [t|Ptr Ray -> Ptr Vector3 -> Ptr Vector3 -> Ptr Vector3 -> IO (Ptr RayCollision)|]),+ ("c'getRayCollisionQuad", "GetRayCollisionQuad_", "rl_bindings.h", [t|Ptr Ray -> Ptr Vector3 -> Ptr Vector3 -> Ptr Vector3 -> Ptr Vector3 -> IO (Ptr RayCollision)|]) ] ) @@ -369,6 +378,12 @@ drawModelWiresEx :: Model -> Vector3 -> Vector3 -> Float -> Vector3 -> Color -> IO () drawModelWiresEx model position rotationAxis rotationAngle scale tint = withFreeable model (\m -> withFreeable position (\p -> withFreeable rotationAxis (\r -> withFreeable scale (withFreeable tint . c'drawModelWiresEx m p r (realToFrac rotationAngle))))) +drawModelPoints :: Model -> Vector3 -> Float -> Color -> IO ()+drawModelPoints model position scale tint = withFreeable model (\m -> withFreeable position (\p -> withFreeable tint (c'drawModelPoints m p (realToFrac scale))))++drawModelPointsEx :: Model -> Vector3 -> Vector3 -> Float -> Vector3 -> Color -> IO ()+drawModelPointsEx model position rotationAxis rotationAngle scale tint = withFreeable model (\m -> withFreeable position (\p -> withFreeable rotationAxis (\r -> withFreeable scale (withFreeable tint . c'drawModelPointsEx m p r (realToFrac rotationAngle)))))+ drawBoundingBox :: BoundingBox -> Color -> IO () drawBoundingBox box color = withFreeable box (withFreeable color . c'drawBoundingBox) @@ -498,6 +513,9 @@ isModelAnimationValid :: Model -> ModelAnimation -> IO Bool isModelAnimationValid model animation = toBool <$> withFreeable model (withFreeable animation . c'isModelAnimationValid)++updateModelAnimationBoneMatrices :: Model -> ModelAnimation -> Int -> IO ()+updateModelAnimationBoneMatrices model animation frame = withFreeable model (\m -> withFreeable animation (\a -> c'updateModelAnimationBoneMatrices m a (fromIntegral frame))) checkCollisionSpheres :: Vector3 -> Float -> Vector3 -> Float -> Bool checkCollisionSpheres center1 radius1 center2 radius2 = toBool $ unsafePerformIO (withFreeable center1 (\c1 -> withFreeable center2 (\c2 -> c'checkCollisionSpheres c1 (realToFrac radius1) c2 (realToFrac radius2))))
src/Raylib/Core/Shapes.hs view
@@ -154,72 +154,72 @@ import Raylib.Types (Color, Rectangle, Texture, Vector2, pattern Vector2) $( genNative- [ ("c'setShapesTexture", "SetShapesTexture_", "rl_bindings.h", [t|Ptr Texture -> Ptr Rectangle -> IO ()|], False),- ("c'getShapesTexture", "GetShapesTexture_", "rl_bindings.h", [t|IO (Ptr Texture)|], False),- ("c'getShapesTextureRectangle", "GetShapesTextureRectangle_", "rl_bindings.h", [t|IO (Ptr Rectangle)|], False),- ("c'drawPixel", "DrawPixel_", "rl_bindings.h", [t|CInt -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawPixelV", "DrawPixelV_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Color -> IO ()|], False),- ("c'drawLine", "DrawLine_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawLineV", "DrawLineV_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|], False),- ("c'drawLineEx", "DrawLineEx_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawLineStrip", "DrawLineStrip_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawLineBezier", "DrawLineBezier_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawCircle", "DrawCircle_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawCircleSector", "DrawCircleSector_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawCircleSectorLines", "DrawCircleSectorLines_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawCircleGradient", "DrawCircleGradient_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> Ptr Color -> Ptr Color -> IO ()|], False),- ("c'drawCircleV", "DrawCircleV_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawCircleLines", "DrawCircleLines_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawCircleLinesV", "DrawCircleLinesV_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawEllipse", "DrawEllipse_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawEllipseLines", "DrawEllipseLines_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawRing", "DrawRing_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawRingLines", "DrawRingLines_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawRectangle", "DrawRectangle_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawRectangleV", "DrawRectangleV_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|], False),- ("c'drawRectangleRec", "DrawRectangleRec_", "rl_bindings.h", [t|Ptr Rectangle -> Ptr Color -> IO ()|], False),- ("c'drawRectanglePro", "DrawRectanglePro_", "rl_bindings.h", [t|Ptr Rectangle -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawRectangleGradientV", "DrawRectangleGradientV_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> Ptr Color -> Ptr Color -> IO ()|], False),- ("c'drawRectangleGradientH", "DrawRectangleGradientH_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> Ptr Color -> Ptr Color -> IO ()|], False),- ("c'drawRectangleGradientEx", "DrawRectangleGradientEx_", "rl_bindings.h", [t|Ptr Rectangle -> Ptr Color -> Ptr Color -> Ptr Color -> Ptr Color -> IO ()|], False),- ("c'drawRectangleLines", "DrawRectangleLines_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawRectangleLinesEx", "DrawRectangleLinesEx_", "rl_bindings.h", [t|Ptr Rectangle -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawRectangleRounded", "DrawRectangleRounded_", "rl_bindings.h", [t|Ptr Rectangle -> CFloat -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawRectangleRoundedLines", "DrawRectangleRoundedLines_", "rl_bindings.h", [t|Ptr Rectangle -> CFloat -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawRectangleRoundedLinesEx", "DrawRectangleRoundedLinesEx_", "rl_bindings.h", [t|Ptr Rectangle -> CFloat -> CInt -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawTriangle", "DrawTriangle_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|], False),- ("c'drawTriangleLines", "DrawTriangleLines_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|], False),- ("c'drawTriangleFan", "DrawTriangleFan_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawTriangleStrip", "DrawTriangleStrip_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawPoly", "DrawPoly_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> CFloat -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawPolyLines", "DrawPolyLines_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> CFloat -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawPolyLinesEx", "DrawPolyLinesEx_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> CFloat -> CFloat -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawSplineLinear", "DrawSplineLinear_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawSplineBasis", "DrawSplineBasis_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawSplineCatmullRom", "DrawSplineCatmullRom_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawSplineBezierQuadratic", "DrawSplineBezierQuadratic_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawSplineBezierCubic", "DrawSplineBezierCubic_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawSplineSegmentLinear", "DrawSplineSegmentLinear_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawSplineSegmentBasis", "DrawSplineSegmentBasis_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawSplineSegmentCatmullRom", "DrawSplineSegmentCatmullRom_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawSplineSegmentBezierQuadratic", "DrawSplineSegmentBezierQuadratic_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawSplineSegmentBezierCubic", "DrawSplineSegmentBezierCubic_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'getSplinePointLinear", "GetSplinePointLinear_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> CFloat -> IO (Ptr Vector2)|], False),- ("c'getSplinePointBasis", "GetSplinePointBasis_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> IO (Ptr Vector2)|], False),- ("c'getSplinePointCatmullRom", "GetSplinePointCatmullRom_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> IO (Ptr Vector2)|], False),- ("c'getSplinePointBezierQuad", "GetSplinePointBezierQuad_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> IO (Ptr Vector2)|], False),- ("c'getSplinePointBezierCubic", "GetSplinePointBezierCubic_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> IO (Ptr Vector2)|], False),- ("c'checkCollisionRecs", "CheckCollisionRecs_", "rl_bindings.h", [t|Ptr Rectangle -> Ptr Rectangle -> IO CBool|], False),- ("c'checkCollisionCircles", "CheckCollisionCircles_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> Ptr Vector2 -> CFloat -> IO CBool|], False),- ("c'checkCollisionCircleRec", "CheckCollisionCircleRec_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> Ptr Rectangle -> IO CBool|], False),- ("c'checkCollisionPointRec", "CheckCollisionPointRec_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Rectangle -> IO CBool|], False),- ("c'checkCollisionPointCircle", "CheckCollisionPointCircle_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> CFloat -> IO CBool|], False),- ("c'checkCollisionPointTriangle", "CheckCollisionPointTriangle_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> IO CBool|], False),- ("c'checkCollisionPointPoly", "CheckCollisionPointPoly_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> CInt -> IO CBool|], False),- ("c'checkCollisionLines", "CheckCollisionLines_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> IO CBool|], False),- ("c'checkCollisionPointLine", "CheckCollisionPointLine_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CInt -> IO CBool|], False),- ("c'checkCollisionCircleLine", "CheckCollisionCircleLine_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> Ptr Vector2 -> Ptr Vector2 -> IO CBool|], False),- ("c'getCollisionRec", "GetCollisionRec_", "rl_bindings.h", [t|Ptr Rectangle -> Ptr Rectangle -> IO (Ptr Rectangle)|], False)+ [ ("c'setShapesTexture", "SetShapesTexture_", "rl_bindings.h", [t|Ptr Texture -> Ptr Rectangle -> IO ()|]),+ ("c'getShapesTexture", "GetShapesTexture_", "rl_bindings.h", [t|IO (Ptr Texture)|]),+ ("c'getShapesTextureRectangle", "GetShapesTextureRectangle_", "rl_bindings.h", [t|IO (Ptr Rectangle)|]),+ ("c'drawPixel", "DrawPixel_", "rl_bindings.h", [t|CInt -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawPixelV", "DrawPixelV_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Color -> IO ()|]),+ ("c'drawLine", "DrawLine_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawLineV", "DrawLineV_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|]),+ ("c'drawLineEx", "DrawLineEx_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawLineStrip", "DrawLineStrip_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawLineBezier", "DrawLineBezier_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawCircle", "DrawCircle_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawCircleSector", "DrawCircleSector_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawCircleSectorLines", "DrawCircleSectorLines_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawCircleGradient", "DrawCircleGradient_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> Ptr Color -> Ptr Color -> IO ()|]),+ ("c'drawCircleV", "DrawCircleV_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawCircleLines", "DrawCircleLines_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawCircleLinesV", "DrawCircleLinesV_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawEllipse", "DrawEllipse_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawEllipseLines", "DrawEllipseLines_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawRing", "DrawRing_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawRingLines", "DrawRingLines_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawRectangle", "DrawRectangle_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawRectangleV", "DrawRectangleV_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|]),+ ("c'drawRectangleRec", "DrawRectangleRec_", "rl_bindings.h", [t|Ptr Rectangle -> Ptr Color -> IO ()|]),+ ("c'drawRectanglePro", "DrawRectanglePro_", "rl_bindings.h", [t|Ptr Rectangle -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawRectangleGradientV", "DrawRectangleGradientV_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> Ptr Color -> Ptr Color -> IO ()|]),+ ("c'drawRectangleGradientH", "DrawRectangleGradientH_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> Ptr Color -> Ptr Color -> IO ()|]),+ ("c'drawRectangleGradientEx", "DrawRectangleGradientEx_", "rl_bindings.h", [t|Ptr Rectangle -> Ptr Color -> Ptr Color -> Ptr Color -> Ptr Color -> IO ()|]),+ ("c'drawRectangleLines", "DrawRectangleLines_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawRectangleLinesEx", "DrawRectangleLinesEx_", "rl_bindings.h", [t|Ptr Rectangle -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawRectangleRounded", "DrawRectangleRounded_", "rl_bindings.h", [t|Ptr Rectangle -> CFloat -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawRectangleRoundedLines", "DrawRectangleRoundedLines_", "rl_bindings.h", [t|Ptr Rectangle -> CFloat -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawRectangleRoundedLinesEx", "DrawRectangleRoundedLinesEx_", "rl_bindings.h", [t|Ptr Rectangle -> CFloat -> CInt -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawTriangle", "DrawTriangle_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|]),+ ("c'drawTriangleLines", "DrawTriangleLines_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|]),+ ("c'drawTriangleFan", "DrawTriangleFan_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawTriangleStrip", "DrawTriangleStrip_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawPoly", "DrawPoly_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> CFloat -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawPolyLines", "DrawPolyLines_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> CFloat -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawPolyLinesEx", "DrawPolyLinesEx_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> CFloat -> CFloat -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawSplineLinear", "DrawSplineLinear_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawSplineBasis", "DrawSplineBasis_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawSplineCatmullRom", "DrawSplineCatmullRom_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawSplineBezierQuadratic", "DrawSplineBezierQuadratic_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawSplineBezierCubic", "DrawSplineBezierCubic_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawSplineSegmentLinear", "DrawSplineSegmentLinear_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawSplineSegmentBasis", "DrawSplineSegmentBasis_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawSplineSegmentCatmullRom", "DrawSplineSegmentCatmullRom_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawSplineSegmentBezierQuadratic", "DrawSplineSegmentBezierQuadratic_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawSplineSegmentBezierCubic", "DrawSplineSegmentBezierCubic_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'getSplinePointLinear", "GetSplinePointLinear_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> CFloat -> IO (Ptr Vector2)|]),+ ("c'getSplinePointBasis", "GetSplinePointBasis_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> IO (Ptr Vector2)|]),+ ("c'getSplinePointCatmullRom", "GetSplinePointCatmullRom_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> IO (Ptr Vector2)|]),+ ("c'getSplinePointBezierQuad", "GetSplinePointBezierQuad_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> IO (Ptr Vector2)|]),+ ("c'getSplinePointBezierCubic", "GetSplinePointBezierCubic_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> IO (Ptr Vector2)|]),+ ("c'checkCollisionRecs", "CheckCollisionRecs_", "rl_bindings.h", [t|Ptr Rectangle -> Ptr Rectangle -> IO CBool|]),+ ("c'checkCollisionCircles", "CheckCollisionCircles_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> Ptr Vector2 -> CFloat -> IO CBool|]),+ ("c'checkCollisionCircleRec", "CheckCollisionCircleRec_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> Ptr Rectangle -> IO CBool|]),+ ("c'checkCollisionPointRec", "CheckCollisionPointRec_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Rectangle -> IO CBool|]),+ ("c'checkCollisionPointCircle", "CheckCollisionPointCircle_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> CFloat -> IO CBool|]),+ ("c'checkCollisionPointTriangle", "CheckCollisionPointTriangle_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> IO CBool|]),+ ("c'checkCollisionPointPoly", "CheckCollisionPointPoly_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> CInt -> IO CBool|]),+ ("c'checkCollisionLines", "CheckCollisionLines_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> IO CBool|]),+ ("c'checkCollisionPointLine", "CheckCollisionPointLine_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CInt -> IO CBool|]),+ ("c'checkCollisionCircleLine", "CheckCollisionCircleLine_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> Ptr Vector2 -> Ptr Vector2 -> IO CBool|]),+ ("c'getCollisionRec", "GetCollisionRec_", "rl_bindings.h", [t|Ptr Rectangle -> Ptr Rectangle -> IO (Ptr Rectangle)|]) ] ) @@ -282,8 +282,8 @@ ) drawCircleGradient :: Int -> Int -> Float -> Color -> Color -> IO ()-drawCircleGradient centerX centerY radius color1 color2 =- withFreeable color1 (withFreeable color2 . c'drawCircleGradient (fromIntegral centerX) (fromIntegral centerY) (realToFrac radius))+drawCircleGradient centerX centerY radius inner outer =+ withFreeable inner (withFreeable outer . c'drawCircleGradient (fromIntegral centerX) (fromIntegral centerY) (realToFrac radius)) drawCircleV :: Vector2 -> Float -> Color -> IO () drawCircleV center radius color =@@ -354,10 +354,10 @@ withFreeable color (\c -> withFreeable rect (\r -> withFreeable origin (\o -> c'drawRectanglePro r o (realToFrac rotation) c))) drawRectangleGradientV :: Int -> Int -> Int -> Int -> Color -> Color -> IO ()-drawRectangleGradientV posX posY width height color1 color2 =+drawRectangleGradientV posX posY width height top bottom = withFreeable- color1- ( withFreeable color2+ top+ ( withFreeable bottom . c'drawRectangleGradientV (fromIntegral posX) (fromIntegral posY)@@ -366,10 +366,10 @@ ) drawRectangleGradientH :: Int -> Int -> Int -> Int -> Color -> Color -> IO ()-drawRectangleGradientH posX posY width height color1 color2 =+drawRectangleGradientH posX posY width height left right = withFreeable- color1- ( withFreeable color2+ left+ ( withFreeable right . c'drawRectangleGradientH (fromIntegral posX) (fromIntegral posY)@@ -378,17 +378,17 @@ ) drawRectangleGradientEx :: Rectangle -> Color -> Color -> Color -> Color -> IO ()-drawRectangleGradientEx rect col1 col2 col3 col4 =+drawRectangleGradientEx rect topLeft bottomLeft topRight bottomRight = withFreeable rect ( \r -> withFreeable- col1+ topLeft ( \c1 -> withFreeable- col2+ bottomLeft ( \c2 ->- withFreeable col3 (withFreeable col4 . c'drawRectangleGradientEx r c1 c2)+ withFreeable topRight (withFreeable bottomRight . c'drawRectangleGradientEx r c1 c2) ) ) )
src/Raylib/Core/Text.hs view
@@ -98,35 +98,35 @@ ) $( genNative- [ ("c'getFontDefault", "GetFontDefault_", "rl_bindings.h", [t|IO (Ptr Font)|], False),- ("c'loadFont", "LoadFont_", "rl_bindings.h", [t|CString -> IO (Ptr Font)|], False),- ("c'loadFontEx", "LoadFontEx_", "rl_bindings.h", [t|CString -> CInt -> Ptr CInt -> CInt -> IO (Ptr Font)|], False),- ("c'loadFontFromImage", "LoadFontFromImage_", "rl_bindings.h", [t|Ptr Image -> Ptr Color -> CInt -> IO (Ptr Font)|], False),- ("c'loadFontFromMemory", "LoadFontFromMemory_", "rl_bindings.h", [t|CString -> Ptr CUChar -> CInt -> CInt -> Ptr CInt -> CInt -> IO (Ptr Font)|], False),- ("c'loadFontData", "LoadFontData_", "rl_bindings.h", [t|Ptr CUChar -> CInt -> CInt -> Ptr CInt -> CInt -> CInt -> IO (Ptr GlyphInfo)|], False),- ("c'genImageFontAtlas", "GenImageFontAtlas_", "rl_bindings.h", [t|Ptr GlyphInfo -> Ptr (Ptr Rectangle) -> CInt -> CInt -> CInt -> CInt -> IO (Ptr Image)|], False),- ("c'unloadFontData", "UnloadFontData_", "rl_bindings.h", [t|Ptr GlyphInfo -> CInt -> IO ()|], False),- ("c'isFontReady", "IsFontReady_", "rl_bindings.h", [t|Ptr Font -> IO CBool|], False),- ("c'unloadFont", "UnloadFont_", "rl_bindings.h", [t|Ptr Font -> IO ()|], False),- ("c'exportFontAsCode", "ExportFontAsCode_", "rl_bindings.h", [t|Ptr Font -> CString -> IO CBool|], False),- ("c'drawFPS", "DrawFPS_", "rl_bindings.h", [t|CInt -> CInt -> IO ()|], False),- ("c'drawText", "DrawText_", "rl_bindings.h", [t|CString -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawTextEx", "DrawTextEx_", "rl_bindings.h", [t|Ptr Font -> CString -> Ptr Vector2 -> CFloat -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawTextPro", "DrawTextPro_", "rl_bindings.h", [t|Ptr Font -> CString -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> CFloat -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawTextCodepoint", "DrawTextCodepoint_", "rl_bindings.h", [t|Ptr Font -> CInt -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawTextCodepoints", "DrawTextCodepoints_", "rl_bindings.h", [t|Ptr Font -> Ptr CInt -> CInt -> Ptr Vector2 -> CFloat -> CFloat -> Ptr Color -> IO ()|], False),- ("c'setTextLineSpacing", "SetTextLineSpacing_", "rl_bindings.h", [t|CInt -> IO ()|], False),- ("c'measureText", "MeasureText_", "rl_bindings.h", [t|CString -> CInt -> IO CInt|], False),- ("c'measureTextEx", "MeasureTextEx_", "rl_bindings.h", [t|Ptr Font -> CString -> CFloat -> CFloat -> IO (Ptr Vector2)|], False),- ("c'getGlyphIndex", "GetGlyphIndex_", "rl_bindings.h", [t|Ptr Font -> CInt -> IO CInt|], False),- ("c'getGlyphInfo", "GetGlyphInfo_", "rl_bindings.h", [t|Ptr Font -> CInt -> IO (Ptr GlyphInfo)|], False),- ("c'getGlyphAtlasRec", "GetGlyphAtlasRec_", "rl_bindings.h", [t|Ptr Font -> CInt -> IO (Ptr Rectangle)|], False),- ("c'loadUTF8", "LoadUTF8_", "rl_bindings.h", [t|Ptr CInt -> CInt -> IO CString|], False),- ("c'loadCodepoints", "LoadCodepoints_", "rl_bindings.h", [t|CString -> Ptr CInt -> IO (Ptr CInt)|], False),- ("c'getCodepointCount", "GetCodepointCount_", "rl_bindings.h", [t|CString -> IO CInt|], False),- ("c'getCodepointNext", "GetCodepointNext_", "rl_bindings.h", [t|CString -> Ptr CInt -> IO CInt|], False),- ("c'getCodepointPrevious", "GetCodepointPrevious_", "rl_bindings.h", [t|CString -> Ptr CInt -> IO CInt|], False),- ("c'codepointToUTF8", "CodepointToUTF8_", "rl_bindings.h", [t|CInt -> Ptr CInt -> IO CString|], False)+ [ ("c'getFontDefault", "GetFontDefault_", "rl_bindings.h", [t|IO (Ptr Font)|]),+ ("c'loadFont", "LoadFont_", "rl_bindings.h", [t|CString -> IO (Ptr Font)|]),+ ("c'loadFontEx", "LoadFontEx_", "rl_bindings.h", [t|CString -> CInt -> Ptr CInt -> CInt -> IO (Ptr Font)|]),+ ("c'loadFontFromImage", "LoadFontFromImage_", "rl_bindings.h", [t|Ptr Image -> Ptr Color -> CInt -> IO (Ptr Font)|]),+ ("c'loadFontFromMemory", "LoadFontFromMemory_", "rl_bindings.h", [t|CString -> Ptr CUChar -> CInt -> CInt -> Ptr CInt -> CInt -> IO (Ptr Font)|]),+ ("c'loadFontData", "LoadFontData_", "rl_bindings.h", [t|Ptr CUChar -> CInt -> CInt -> Ptr CInt -> CInt -> CInt -> IO (Ptr GlyphInfo)|]),+ ("c'genImageFontAtlas", "GenImageFontAtlas_", "rl_bindings.h", [t|Ptr GlyphInfo -> Ptr (Ptr Rectangle) -> CInt -> CInt -> CInt -> CInt -> IO (Ptr Image)|]),+ ("c'unloadFontData", "UnloadFontData_", "rl_bindings.h", [t|Ptr GlyphInfo -> CInt -> IO ()|]),+ ("c'isFontReady", "IsFontReady_", "rl_bindings.h", [t|Ptr Font -> IO CBool|]),+ ("c'unloadFont", "UnloadFont_", "rl_bindings.h", [t|Ptr Font -> IO ()|]),+ ("c'exportFontAsCode", "ExportFontAsCode_", "rl_bindings.h", [t|Ptr Font -> CString -> IO CBool|]),+ ("c'drawFPS", "DrawFPS_", "rl_bindings.h", [t|CInt -> CInt -> IO ()|]),+ ("c'drawText", "DrawText_", "rl_bindings.h", [t|CString -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawTextEx", "DrawTextEx_", "rl_bindings.h", [t|Ptr Font -> CString -> Ptr Vector2 -> CFloat -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawTextPro", "DrawTextPro_", "rl_bindings.h", [t|Ptr Font -> CString -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> CFloat -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawTextCodepoint", "DrawTextCodepoint_", "rl_bindings.h", [t|Ptr Font -> CInt -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawTextCodepoints", "DrawTextCodepoints_", "rl_bindings.h", [t|Ptr Font -> Ptr CInt -> CInt -> Ptr Vector2 -> CFloat -> CFloat -> Ptr Color -> IO ()|]),+ ("c'setTextLineSpacing", "SetTextLineSpacing_", "rl_bindings.h", [t|CInt -> IO ()|]),+ ("c'measureText", "MeasureText_", "rl_bindings.h", [t|CString -> CInt -> IO CInt|]),+ ("c'measureTextEx", "MeasureTextEx_", "rl_bindings.h", [t|Ptr Font -> CString -> CFloat -> CFloat -> IO (Ptr Vector2)|]),+ ("c'getGlyphIndex", "GetGlyphIndex_", "rl_bindings.h", [t|Ptr Font -> CInt -> IO CInt|]),+ ("c'getGlyphInfo", "GetGlyphInfo_", "rl_bindings.h", [t|Ptr Font -> CInt -> IO (Ptr GlyphInfo)|]),+ ("c'getGlyphAtlasRec", "GetGlyphAtlasRec_", "rl_bindings.h", [t|Ptr Font -> CInt -> IO (Ptr Rectangle)|]),+ ("c'loadUTF8", "LoadUTF8_", "rl_bindings.h", [t|Ptr CInt -> CInt -> IO CString|]),+ ("c'loadCodepoints", "LoadCodepoints_", "rl_bindings.h", [t|CString -> Ptr CInt -> IO (Ptr CInt)|]),+ ("c'getCodepointCount", "GetCodepointCount_", "rl_bindings.h", [t|CString -> IO CInt|]),+ ("c'getCodepointNext", "GetCodepointNext_", "rl_bindings.h", [t|CString -> Ptr CInt -> IO CInt|]),+ ("c'getCodepointPrevious", "GetCodepointPrevious_", "rl_bindings.h", [t|CString -> Ptr CInt -> IO CInt|]),+ ("c'codepointToUTF8", "CodepointToUTF8_", "rl_bindings.h", [t|CInt -> Ptr CInt -> IO CString|]) ] )
src/Raylib/Core/Textures.hs view
@@ -5,7 +5,6 @@ ( -- * High level loadImage, loadImageRaw,- loadImageSvg, loadImageAnim, loadImageAnimFromMemory, loadImageFromMemory,@@ -108,6 +107,7 @@ colorContrast, colorAlpha, colorAlphaBlend,+ colorLerp, getColor, getPixelColor, setPixelColor,@@ -116,7 +116,6 @@ -- * Native c'loadImage, c'loadImageRaw,- c'loadImageSvg, c'loadImageAnim, c'loadImageAnimFromMemory, c'loadImageFromMemory,@@ -221,6 +220,7 @@ c'colorContrast, c'colorAlpha, c'colorAlphaBlend,+ c'colorLerp, c'getColor, c'getPixelColor, c'setPixelColor,@@ -272,116 +272,116 @@ ) $( genNative- [ ("c'loadImage", "LoadImage_", "rl_bindings.h", [t|CString -> IO (Ptr Image)|], False),- ("c'loadImageRaw", "LoadImageRaw_", "rl_bindings.h", [t|CString -> CInt -> CInt -> CInt -> CInt -> IO (Ptr Image)|], False),- ("c'loadImageSvg", "LoadImageSvg_", "rl_bindings.h", [t|CString -> CInt -> CInt -> IO (Ptr Image)|], False),- ("c'loadImageAnim", "LoadImageAnim_", "rl_bindings.h", [t|CString -> Ptr CInt -> IO (Ptr Image)|], False),- ("c'loadImageAnimFromMemory", "LoadImageAnimFromMemory_", "rl_bindings.h", [t|CString -> Ptr CUChar -> CInt -> Ptr CInt -> IO (Ptr Image)|], False),- ("c'loadImageFromMemory", "LoadImageFromMemory_", "rl_bindings.h", [t|CString -> Ptr CUChar -> CInt -> IO (Ptr Image)|], False),- ("c'loadImageFromTexture", "LoadImageFromTexture_", "rl_bindings.h", [t|Ptr Texture -> IO (Ptr Image)|], False),- ("c'loadImageFromScreen", "LoadImageFromScreen_", "rl_bindings.h", [t|IO (Ptr Image)|], False),- ("c'isImageReady", "IsImageReady_", "rl_bindings.h", [t|Ptr Image -> IO CBool|], False),- ("c'unloadImage", "UnloadImage_", "rl_bindings.h", [t|Ptr Image -> IO ()|], False),- ("c'exportImage", "ExportImage_", "rl_bindings.h", [t|Ptr Image -> CString -> IO CBool|], False),- ("c'exportImageToMemory", "ExportImageToMemory_", "rl_bindings.h", [t|Ptr Image -> CString -> Ptr CInt -> IO (Ptr CUChar)|], False),- ("c'exportImageAsCode", "ExportImageAsCode_", "rl_bindings.h", [t|Ptr Image -> CString -> IO CBool|], False),- ("c'genImageColor", "GenImageColor_", "rl_bindings.h", [t|CInt -> CInt -> Ptr Color -> IO (Ptr Image)|], False),- ("c'genImageGradientLinear", "GenImageGradientLinear_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> Ptr Color -> Ptr Color -> IO (Ptr Image)|], False),- ("c'genImageGradientRadial", "GenImageGradientRadial_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> Ptr Color -> Ptr Color -> IO (Ptr Image)|], False),- ("c'genImageGradientSquare", "GenImageGradientSquare_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> Ptr Color -> Ptr Color -> IO (Ptr Image)|], False),- ("c'genImageChecked", "GenImageChecked_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> Ptr Color -> Ptr Color -> IO (Ptr Image)|], False),- ("c'genImageWhiteNoise", "GenImageWhiteNoise_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> IO (Ptr Image)|], False),- ("c'genImagePerlinNoise", "GenImagePerlinNoise_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> CFloat -> IO (Ptr Image)|], False),- ("c'genImageCellular", "GenImageCellular_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> IO (Ptr Image)|], False),- ("c'genImageText", "GenImageText_", "rl_bindings.h", [t|CInt -> CInt -> CString -> IO (Ptr Image)|], False),- ("c'imageCopy", "ImageCopy_", "rl_bindings.h", [t|Ptr Image -> IO (Ptr Image)|], False),- ("c'imageFromImage", "ImageFromImage_", "rl_bindings.h", [t|Ptr Image -> Ptr Rectangle -> IO (Ptr Image)|], False),- ("c'imageFromChannel", "ImageFromChannel_", "rl_bindings.h", [t|Ptr Image -> CInt -> IO (Ptr Image)|], False),- ("c'imageText", "ImageText_", "rl_bindings.h", [t|CString -> CInt -> Ptr Color -> IO (Ptr Image)|], False),- ("c'imageTextEx", "ImageTextEx_", "rl_bindings.h", [t|Ptr Font -> CString -> CFloat -> CFloat -> Ptr Color -> IO (Ptr Image)|], False),- ("c'imageFormat", "ImageFormat_", "rl_bindings.h", [t|Ptr Image -> CInt -> IO ()|], False),- ("c'imageToPOT", "ImageToPOT_", "rl_bindings.h", [t|Ptr Image -> Ptr Color -> IO ()|], False),- ("c'imageCrop", "ImageCrop_", "rl_bindings.h", [t|Ptr Image -> Ptr Rectangle -> IO ()|], False),- ("c'imageAlphaCrop", "ImageAlphaCrop_", "rl_bindings.h", [t|Ptr Image -> CFloat -> IO ()|], False),- ("c'imageAlphaClear", "ImageAlphaClear_", "rl_bindings.h", [t|Ptr Image -> Ptr Color -> CFloat -> IO ()|], False),- ("c'imageAlphaMask", "ImageAlphaMask_", "rl_bindings.h", [t|Ptr Image -> Ptr Image -> IO ()|], False),- ("c'imageAlphaPremultiply", "ImageAlphaPremultiply_", "rl_bindings.h", [t|Ptr Image -> IO ()|], False),- ("c'imageBlurGaussian", "ImageBlurGaussian_", "rl_bindings.h", [t|Ptr Image -> CInt -> IO ()|], False),- ("c'imageKernelConvolution", "ImageKernelConvolution_", "rl_bindings.h", [t|Ptr Image -> Ptr CFloat -> CInt -> IO ()|], False),- ("c'imageResize", "ImageResize_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> IO ()|], False),- ("c'imageResizeNN", "ImageResizeNN_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> IO ()|], False),- ("c'imageResizeCanvas", "ImageResizeCanvas_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|], False),- ("c'imageMipmaps", "ImageMipmaps_", "rl_bindings.h", [t|Ptr Image -> IO ()|], False),- ("c'imageDither", "ImageDither_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> CInt -> CInt -> IO ()|], False),- ("c'imageFlipVertical", "ImageFlipVertical_", "rl_bindings.h", [t|Ptr Image -> IO ()|], False),- ("c'imageFlipHorizontal", "ImageFlipHorizontal_", "rl_bindings.h", [t|Ptr Image -> IO ()|], False),- ("c'imageRotate", "ImageRotate_", "rl_bindings.h", [t|Ptr Image -> CInt -> IO ()|], False),- ("c'imageRotateCW", "ImageRotateCW_", "rl_bindings.h", [t|Ptr Image -> IO ()|], False),- ("c'imageRotateCCW", "ImageRotateCCW_", "rl_bindings.h", [t|Ptr Image -> IO ()|], False),- ("c'imageColorTint", "ImageColorTint_", "rl_bindings.h", [t|Ptr Image -> Ptr Color -> IO ()|], False),- ("c'imageColorInvert", "ImageColorInvert_", "rl_bindings.h", [t|Ptr Image -> IO ()|], False),- ("c'imageColorGrayscale", "ImageColorGrayscale_", "rl_bindings.h", [t|Ptr Image -> IO ()|], False),- ("c'imageColorContrast", "ImageColorContrast_", "rl_bindings.h", [t|Ptr Image -> CFloat -> IO ()|], False),- ("c'imageColorBrightness", "ImageColorBrightness_", "rl_bindings.h", [t|Ptr Image -> CInt -> IO ()|], False),- ("c'imageColorReplace", "ImageColorReplace_", "rl_bindings.h", [t|Ptr Image -> Ptr Color -> Ptr Color -> IO ()|], False),- ("c'loadImageColors", "LoadImageColors_", "rl_bindings.h", [t|Ptr Image -> IO (Ptr Color)|], False),- ("c'loadImagePalette", "LoadImagePalette_", "rl_bindings.h", [t|Ptr Image -> CInt -> Ptr CInt -> IO (Ptr Color)|], False),- ("c'getImageAlphaBorder", "GetImageAlphaBorder_", "rl_bindings.h", [t|Ptr Image -> CFloat -> IO (Ptr Rectangle)|], False),- ("c'getImageColor", "GetImageColor_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> IO (Ptr Color)|], False),- ("c'imageClearBackground", "ImageClearBackground_", "rl_bindings.h", [t|Ptr Image -> Ptr Color -> IO ()|], False),- ("c'imageDrawPixel", "ImageDrawPixel_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> Ptr Color -> IO ()|], False),- ("c'imageDrawPixelV", "ImageDrawPixelV_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Color -> IO ()|], False),- ("c'imageDrawLine", "ImageDrawLine_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|], False),- ("c'imageDrawLineV", "ImageDrawLineV_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|], False),- ("c'imageDrawCircle", "ImageDrawCircle_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|], False),- ("c'imageDrawCircleV", "ImageDrawCircleV_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> CInt -> Ptr Color -> IO ()|], False),- ("c'imageDrawCircleLines", "ImageDrawCircleLines_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|], False),- ("c'imageDrawCircleLinesV", "ImageDrawCircleLinesV_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> CInt -> Ptr Color -> IO ()|], False),- ("c'imageDrawRectangle", "ImageDrawRectangle_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|], False),- ("c'imageDrawRectangleV", "ImageDrawRectangleV_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|], False),- ("c'imageDrawRectangleRec", "ImageDrawRectangleRec_", "rl_bindings.h", [t|Ptr Image -> Ptr Rectangle -> Ptr Color -> IO ()|], False),- ("c'imageDrawRectangleLines", "ImageDrawRectangleLines_", "rl_bindings.h", [t|Ptr Image -> Ptr Rectangle -> CInt -> Ptr Color -> IO ()|], False),- ("c'imageDrawTriangle", "ImageDrawTriangle_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|], False),- ("c'imageDrawTriangleEx", "ImageDrawTriangleEx_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> Ptr Color -> Ptr Color -> IO ()|], False),- ("c'imageDrawTriangleLines", "ImageDrawTriangleLines_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|], False),- ("c'imageDrawTriangleFan", "ImageDrawTriangleFan_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> CInt -> Ptr Color -> IO ()|], False),- ("c'imageDrawTriangleStrip", "ImageDrawTriangleStrip_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> CInt -> Ptr Color -> IO ()|], False),- ("c'imageDraw", "ImageDraw_", "rl_bindings.h", [t|Ptr Image -> Ptr Image -> Ptr Rectangle -> Ptr Rectangle -> Ptr Color -> IO ()|], False),- ("c'imageDrawText", "ImageDrawText_", "rl_bindings.h", [t|Ptr Image -> CString -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|], False),- ("c'imageDrawTextEx", "ImageDrawTextEx_", "rl_bindings.h", [t|Ptr Image -> Ptr Font -> CString -> Ptr Vector2 -> CFloat -> CFloat -> Ptr Color -> IO ()|], False),- ("c'loadTexture", "LoadTexture_", "rl_bindings.h", [t|CString -> IO (Ptr Texture)|], False),- ("c'loadTextureFromImage", "LoadTextureFromImage_", "rl_bindings.h", [t|Ptr Image -> IO (Ptr Texture)|], False),- ("c'loadTextureCubemap", "LoadTextureCubemap_", "rl_bindings.h", [t|Ptr Image -> CInt -> IO (Ptr Texture)|], False),- ("c'loadRenderTexture", "LoadRenderTexture_", "rl_bindings.h", [t|CInt -> CInt -> IO (Ptr RenderTexture)|], False),- ("c'isTextureReady", "IsTextureReady_", "rl_bindings.h", [t|Ptr Texture -> IO CBool|], False),- ("c'unloadTexture", "UnloadTexture_", "rl_bindings.h", [t|Ptr Texture -> IO ()|], False),- ("c'isRenderTextureReady", "IsRenderTextureReady_", "rl_bindings.h", [t|Ptr RenderTexture -> IO CBool|], False),- ("c'unloadRenderTexture", "UnloadRenderTexture_", "rl_bindings.h", [t|Ptr RenderTexture -> IO ()|], False),- ("c'updateTexture", "UpdateTexture_", "rl_bindings.h", [t|Ptr Texture -> Ptr () -> IO ()|], False),- ("c'updateTextureRec", "UpdateTextureRec_", "rl_bindings.h", [t|Ptr Texture -> Ptr Rectangle -> Ptr () -> IO ()|], False),- ("c'genTextureMipmaps", "GenTextureMipmaps_", "rl_bindings.h", [t|Ptr Texture -> IO ()|], False),- ("c'setTextureFilter", "SetTextureFilter_", "rl_bindings.h", [t|Ptr Texture -> CInt -> IO ()|], False),- ("c'setTextureWrap", "SetTextureWrap_", "rl_bindings.h", [t|Ptr Texture -> CInt -> IO ()|], False),- ("c'drawTexture", "DrawTexture_", "rl_bindings.h", [t|Ptr Texture -> CInt -> CInt -> Ptr Color -> IO ()|], False),- ("c'drawTextureV", "DrawTextureV_", "rl_bindings.h", [t|Ptr Texture -> Ptr Vector2 -> Ptr Color -> IO ()|], False),- ("c'drawTextureEx", "DrawTextureEx_", "rl_bindings.h", [t|Ptr Texture -> Ptr Vector2 -> CFloat -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawTextureRec", "DrawTextureRec_", "rl_bindings.h", [t|Ptr Texture -> Ptr Rectangle -> Ptr Vector2 -> Ptr Color -> IO ()|], False),- ("c'drawTexturePro", "DrawTexturePro_", "rl_bindings.h", [t|Ptr Texture -> Ptr Rectangle -> Ptr Rectangle -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'drawTextureNPatch", "DrawTextureNPatch_", "rl_bindings.h", [t|Ptr Texture -> Ptr NPatchInfo -> Ptr Rectangle -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|], False),- ("c'fade", "Fade_", "rl_bindings.h", [t|Ptr Color -> CFloat -> IO (Ptr Color)|], False),- ("c'colorToInt", "ColorToInt_", "rl_bindings.h", [t|Ptr Color -> IO CInt|], False),- ("c'colorNormalize", "ColorNormalize_", "rl_bindings.h", [t|Ptr Color -> IO (Ptr Vector4)|], False),- ("c'colorFromNormalized", "ColorFromNormalized_", "rl_bindings.h", [t|Ptr Vector4 -> IO (Ptr Color)|], False),- ("c'colorToHSV", "ColorToHSV_", "rl_bindings.h", [t|Ptr Color -> IO (Ptr Vector3)|], False),- ("c'colorFromHSV", "ColorFromHSV_", "rl_bindings.h", [t|CFloat -> CFloat -> CFloat -> IO (Ptr Color)|], False),- ("c'colorTint", "ColorTint_", "rl_bindings.h", [t|Ptr Color -> Ptr Color -> IO (Ptr Color)|], False),- ("c'colorBrightness", "ColorBrightness_", "rl_bindings.h", [t|Ptr Color -> CFloat -> IO (Ptr Color)|], False),- ("c'colorContrast", "ColorContrast_", "rl_bindings.h", [t|Ptr Color -> CFloat -> IO (Ptr Color)|], False),- ("c'colorAlpha", "ColorAlpha_", "rl_bindings.h", [t|Ptr Color -> CFloat -> IO (Ptr Color)|], False),- ("c'colorAlphaBlend", "ColorAlphaBlend_", "rl_bindings.h", [t|Ptr Color -> Ptr Color -> Ptr Color -> IO (Ptr Color)|], False),- ("c'getColor", "GetColor_", "rl_bindings.h", [t|CUInt -> IO (Ptr Color)|], False),- ("c'getPixelColor", "GetPixelColor_", "rl_bindings.h", [t|Ptr () -> CInt -> IO (Ptr Color)|], False),- ("c'setPixelColor", "SetPixelColor_", "rl_bindings.h", [t|Ptr () -> Ptr Color -> CInt -> IO ()|], False)+ [ ("c'loadImage", "LoadImage_", "rl_bindings.h", [t|CString -> IO (Ptr Image)|]),+ ("c'loadImageRaw", "LoadImageRaw_", "rl_bindings.h", [t|CString -> CInt -> CInt -> CInt -> CInt -> IO (Ptr Image)|]),+ ("c'loadImageAnim", "LoadImageAnim_", "rl_bindings.h", [t|CString -> Ptr CInt -> IO (Ptr Image)|]),+ ("c'loadImageAnimFromMemory", "LoadImageAnimFromMemory_", "rl_bindings.h", [t|CString -> Ptr CUChar -> CInt -> Ptr CInt -> IO (Ptr Image)|]),+ ("c'loadImageFromMemory", "LoadImageFromMemory_", "rl_bindings.h", [t|CString -> Ptr CUChar -> CInt -> IO (Ptr Image)|]),+ ("c'loadImageFromTexture", "LoadImageFromTexture_", "rl_bindings.h", [t|Ptr Texture -> IO (Ptr Image)|]),+ ("c'loadImageFromScreen", "LoadImageFromScreen_", "rl_bindings.h", [t|IO (Ptr Image)|]),+ ("c'isImageReady", "IsImageReady_", "rl_bindings.h", [t|Ptr Image -> IO CBool|]),+ ("c'unloadImage", "UnloadImage_", "rl_bindings.h", [t|Ptr Image -> IO ()|]),+ ("c'exportImage", "ExportImage_", "rl_bindings.h", [t|Ptr Image -> CString -> IO CBool|]),+ ("c'exportImageToMemory", "ExportImageToMemory_", "rl_bindings.h", [t|Ptr Image -> CString -> Ptr CInt -> IO (Ptr CUChar)|]),+ ("c'exportImageAsCode", "ExportImageAsCode_", "rl_bindings.h", [t|Ptr Image -> CString -> IO CBool|]),+ ("c'genImageColor", "GenImageColor_", "rl_bindings.h", [t|CInt -> CInt -> Ptr Color -> IO (Ptr Image)|]),+ ("c'genImageGradientLinear", "GenImageGradientLinear_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> Ptr Color -> Ptr Color -> IO (Ptr Image)|]),+ ("c'genImageGradientRadial", "GenImageGradientRadial_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> Ptr Color -> Ptr Color -> IO (Ptr Image)|]),+ ("c'genImageGradientSquare", "GenImageGradientSquare_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> Ptr Color -> Ptr Color -> IO (Ptr Image)|]),+ ("c'genImageChecked", "GenImageChecked_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> Ptr Color -> Ptr Color -> IO (Ptr Image)|]),+ ("c'genImageWhiteNoise", "GenImageWhiteNoise_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> IO (Ptr Image)|]),+ ("c'genImagePerlinNoise", "GenImagePerlinNoise_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> CFloat -> IO (Ptr Image)|]),+ ("c'genImageCellular", "GenImageCellular_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> IO (Ptr Image)|]),+ ("c'genImageText", "GenImageText_", "rl_bindings.h", [t|CInt -> CInt -> CString -> IO (Ptr Image)|]),+ ("c'imageCopy", "ImageCopy_", "rl_bindings.h", [t|Ptr Image -> IO (Ptr Image)|]),+ ("c'imageFromImage", "ImageFromImage_", "rl_bindings.h", [t|Ptr Image -> Ptr Rectangle -> IO (Ptr Image)|]),+ ("c'imageFromChannel", "ImageFromChannel_", "rl_bindings.h", [t|Ptr Image -> CInt -> IO (Ptr Image)|]),+ ("c'imageText", "ImageText_", "rl_bindings.h", [t|CString -> CInt -> Ptr Color -> IO (Ptr Image)|]),+ ("c'imageTextEx", "ImageTextEx_", "rl_bindings.h", [t|Ptr Font -> CString -> CFloat -> CFloat -> Ptr Color -> IO (Ptr Image)|]),+ ("c'imageFormat", "ImageFormat_", "rl_bindings.h", [t|Ptr Image -> CInt -> IO ()|]),+ ("c'imageToPOT", "ImageToPOT_", "rl_bindings.h", [t|Ptr Image -> Ptr Color -> IO ()|]),+ ("c'imageCrop", "ImageCrop_", "rl_bindings.h", [t|Ptr Image -> Ptr Rectangle -> IO ()|]),+ ("c'imageAlphaCrop", "ImageAlphaCrop_", "rl_bindings.h", [t|Ptr Image -> CFloat -> IO ()|]),+ ("c'imageAlphaClear", "ImageAlphaClear_", "rl_bindings.h", [t|Ptr Image -> Ptr Color -> CFloat -> IO ()|]),+ ("c'imageAlphaMask", "ImageAlphaMask_", "rl_bindings.h", [t|Ptr Image -> Ptr Image -> IO ()|]),+ ("c'imageAlphaPremultiply", "ImageAlphaPremultiply_", "rl_bindings.h", [t|Ptr Image -> IO ()|]),+ ("c'imageBlurGaussian", "ImageBlurGaussian_", "rl_bindings.h", [t|Ptr Image -> CInt -> IO ()|]),+ ("c'imageKernelConvolution", "ImageKernelConvolution_", "rl_bindings.h", [t|Ptr Image -> Ptr CFloat -> CInt -> IO ()|]),+ ("c'imageResize", "ImageResize_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> IO ()|]),+ ("c'imageResizeNN", "ImageResizeNN_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> IO ()|]),+ ("c'imageResizeCanvas", "ImageResizeCanvas_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),+ ("c'imageMipmaps", "ImageMipmaps_", "rl_bindings.h", [t|Ptr Image -> IO ()|]),+ ("c'imageDither", "ImageDither_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> CInt -> CInt -> IO ()|]),+ ("c'imageFlipVertical", "ImageFlipVertical_", "rl_bindings.h", [t|Ptr Image -> IO ()|]),+ ("c'imageFlipHorizontal", "ImageFlipHorizontal_", "rl_bindings.h", [t|Ptr Image -> IO ()|]),+ ("c'imageRotate", "ImageRotate_", "rl_bindings.h", [t|Ptr Image -> CInt -> IO ()|]),+ ("c'imageRotateCW", "ImageRotateCW_", "rl_bindings.h", [t|Ptr Image -> IO ()|]),+ ("c'imageRotateCCW", "ImageRotateCCW_", "rl_bindings.h", [t|Ptr Image -> IO ()|]),+ ("c'imageColorTint", "ImageColorTint_", "rl_bindings.h", [t|Ptr Image -> Ptr Color -> IO ()|]),+ ("c'imageColorInvert", "ImageColorInvert_", "rl_bindings.h", [t|Ptr Image -> IO ()|]),+ ("c'imageColorGrayscale", "ImageColorGrayscale_", "rl_bindings.h", [t|Ptr Image -> IO ()|]),+ ("c'imageColorContrast", "ImageColorContrast_", "rl_bindings.h", [t|Ptr Image -> CFloat -> IO ()|]),+ ("c'imageColorBrightness", "ImageColorBrightness_", "rl_bindings.h", [t|Ptr Image -> CInt -> IO ()|]),+ ("c'imageColorReplace", "ImageColorReplace_", "rl_bindings.h", [t|Ptr Image -> Ptr Color -> Ptr Color -> IO ()|]),+ ("c'loadImageColors", "LoadImageColors_", "rl_bindings.h", [t|Ptr Image -> IO (Ptr Color)|]),+ ("c'loadImagePalette", "LoadImagePalette_", "rl_bindings.h", [t|Ptr Image -> CInt -> Ptr CInt -> IO (Ptr Color)|]),+ ("c'getImageAlphaBorder", "GetImageAlphaBorder_", "rl_bindings.h", [t|Ptr Image -> CFloat -> IO (Ptr Rectangle)|]),+ ("c'getImageColor", "GetImageColor_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> IO (Ptr Color)|]),+ ("c'imageClearBackground", "ImageClearBackground_", "rl_bindings.h", [t|Ptr Image -> Ptr Color -> IO ()|]),+ ("c'imageDrawPixel", "ImageDrawPixel_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> Ptr Color -> IO ()|]),+ ("c'imageDrawPixelV", "ImageDrawPixelV_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Color -> IO ()|]),+ ("c'imageDrawLine", "ImageDrawLine_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),+ ("c'imageDrawLineV", "ImageDrawLineV_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|]),+ ("c'imageDrawCircle", "ImageDrawCircle_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),+ ("c'imageDrawCircleV", "ImageDrawCircleV_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> CInt -> Ptr Color -> IO ()|]),+ ("c'imageDrawCircleLines", "ImageDrawCircleLines_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),+ ("c'imageDrawCircleLinesV", "ImageDrawCircleLinesV_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> CInt -> Ptr Color -> IO ()|]),+ ("c'imageDrawRectangle", "ImageDrawRectangle_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),+ ("c'imageDrawRectangleV", "ImageDrawRectangleV_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|]),+ ("c'imageDrawRectangleRec", "ImageDrawRectangleRec_", "rl_bindings.h", [t|Ptr Image -> Ptr Rectangle -> Ptr Color -> IO ()|]),+ ("c'imageDrawRectangleLines", "ImageDrawRectangleLines_", "rl_bindings.h", [t|Ptr Image -> Ptr Rectangle -> CInt -> Ptr Color -> IO ()|]),+ ("c'imageDrawTriangle", "ImageDrawTriangle_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|]),+ ("c'imageDrawTriangleEx", "ImageDrawTriangleEx_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> Ptr Color -> Ptr Color -> IO ()|]),+ ("c'imageDrawTriangleLines", "ImageDrawTriangleLines_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|]),+ ("c'imageDrawTriangleFan", "ImageDrawTriangleFan_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> CInt -> Ptr Color -> IO ()|]),+ ("c'imageDrawTriangleStrip", "ImageDrawTriangleStrip_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> CInt -> Ptr Color -> IO ()|]),+ ("c'imageDraw", "ImageDraw_", "rl_bindings.h", [t|Ptr Image -> Ptr Image -> Ptr Rectangle -> Ptr Rectangle -> Ptr Color -> IO ()|]),+ ("c'imageDrawText", "ImageDrawText_", "rl_bindings.h", [t|Ptr Image -> CString -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),+ ("c'imageDrawTextEx", "ImageDrawTextEx_", "rl_bindings.h", [t|Ptr Image -> Ptr Font -> CString -> Ptr Vector2 -> CFloat -> CFloat -> Ptr Color -> IO ()|]),+ ("c'loadTexture", "LoadTexture_", "rl_bindings.h", [t|CString -> IO (Ptr Texture)|]),+ ("c'loadTextureFromImage", "LoadTextureFromImage_", "rl_bindings.h", [t|Ptr Image -> IO (Ptr Texture)|]),+ ("c'loadTextureCubemap", "LoadTextureCubemap_", "rl_bindings.h", [t|Ptr Image -> CInt -> IO (Ptr Texture)|]),+ ("c'loadRenderTexture", "LoadRenderTexture_", "rl_bindings.h", [t|CInt -> CInt -> IO (Ptr RenderTexture)|]),+ ("c'isTextureReady", "IsTextureReady_", "rl_bindings.h", [t|Ptr Texture -> IO CBool|]),+ ("c'unloadTexture", "UnloadTexture_", "rl_bindings.h", [t|Ptr Texture -> IO ()|]),+ ("c'isRenderTextureReady", "IsRenderTextureReady_", "rl_bindings.h", [t|Ptr RenderTexture -> IO CBool|]),+ ("c'unloadRenderTexture", "UnloadRenderTexture_", "rl_bindings.h", [t|Ptr RenderTexture -> IO ()|]),+ ("c'updateTexture", "UpdateTexture_", "rl_bindings.h", [t|Ptr Texture -> Ptr () -> IO ()|]),+ ("c'updateTextureRec", "UpdateTextureRec_", "rl_bindings.h", [t|Ptr Texture -> Ptr Rectangle -> Ptr () -> IO ()|]),+ ("c'genTextureMipmaps", "GenTextureMipmaps_", "rl_bindings.h", [t|Ptr Texture -> IO ()|]),+ ("c'setTextureFilter", "SetTextureFilter_", "rl_bindings.h", [t|Ptr Texture -> CInt -> IO ()|]),+ ("c'setTextureWrap", "SetTextureWrap_", "rl_bindings.h", [t|Ptr Texture -> CInt -> IO ()|]),+ ("c'drawTexture", "DrawTexture_", "rl_bindings.h", [t|Ptr Texture -> CInt -> CInt -> Ptr Color -> IO ()|]),+ ("c'drawTextureV", "DrawTextureV_", "rl_bindings.h", [t|Ptr Texture -> Ptr Vector2 -> Ptr Color -> IO ()|]),+ ("c'drawTextureEx", "DrawTextureEx_", "rl_bindings.h", [t|Ptr Texture -> Ptr Vector2 -> CFloat -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawTextureRec", "DrawTextureRec_", "rl_bindings.h", [t|Ptr Texture -> Ptr Rectangle -> Ptr Vector2 -> Ptr Color -> IO ()|]),+ ("c'drawTexturePro", "DrawTexturePro_", "rl_bindings.h", [t|Ptr Texture -> Ptr Rectangle -> Ptr Rectangle -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'drawTextureNPatch", "DrawTextureNPatch_", "rl_bindings.h", [t|Ptr Texture -> Ptr NPatchInfo -> Ptr Rectangle -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),+ ("c'fade", "Fade_", "rl_bindings.h", [t|Ptr Color -> CFloat -> IO (Ptr Color)|]),+ ("c'colorToInt", "ColorToInt_", "rl_bindings.h", [t|Ptr Color -> IO CInt|]),+ ("c'colorNormalize", "ColorNormalize_", "rl_bindings.h", [t|Ptr Color -> IO (Ptr Vector4)|]),+ ("c'colorFromNormalized", "ColorFromNormalized_", "rl_bindings.h", [t|Ptr Vector4 -> IO (Ptr Color)|]),+ ("c'colorToHSV", "ColorToHSV_", "rl_bindings.h", [t|Ptr Color -> IO (Ptr Vector3)|]),+ ("c'colorFromHSV", "ColorFromHSV_", "rl_bindings.h", [t|CFloat -> CFloat -> CFloat -> IO (Ptr Color)|]),+ ("c'colorTint", "ColorTint_", "rl_bindings.h", [t|Ptr Color -> Ptr Color -> IO (Ptr Color)|]),+ ("c'colorBrightness", "ColorBrightness_", "rl_bindings.h", [t|Ptr Color -> CFloat -> IO (Ptr Color)|]),+ ("c'colorContrast", "ColorContrast_", "rl_bindings.h", [t|Ptr Color -> CFloat -> IO (Ptr Color)|]),+ ("c'colorAlpha", "ColorAlpha_", "rl_bindings.h", [t|Ptr Color -> CFloat -> IO (Ptr Color)|]),+ ("c'colorAlphaBlend", "ColorAlphaBlend_", "rl_bindings.h", [t|Ptr Color -> Ptr Color -> Ptr Color -> IO (Ptr Color)|]),+ ("c'colorLerp", "ColorLerp_", "rl_bindings.h", [t|Ptr Color -> Ptr Color -> CFloat -> IO (Ptr Color)|]),+ ("c'getColor", "GetColor_", "rl_bindings.h", [t|CUInt -> IO (Ptr Color)|]),+ ("c'getPixelColor", "GetPixelColor_", "rl_bindings.h", [t|Ptr () -> CInt -> IO (Ptr Color)|]),+ ("c'setPixelColor", "SetPixelColor_", "rl_bindings.h", [t|Ptr () -> Ptr Color -> CInt -> IO ()|]) ] ) @@ -392,9 +392,6 @@ loadImageRaw fileName width height format headerSize = withCString fileName (\str -> c'loadImageRaw str (fromIntegral width) (fromIntegral height) (fromIntegral $ fromEnum format) (fromIntegral headerSize)) >>= pop -loadImageSvg :: String -> Int -> Int -> IO Image-loadImageSvg fileNameOrString width height = withCString fileNameOrString (\s -> c'loadImageSvg s (fromIntegral width) (fromIntegral height)) >>= pop- -- | Returns the animation and the number of frames in a tuple loadImageAnim :: String -> IO (Image, Int) loadImageAnim fileName =@@ -775,6 +772,9 @@ colorAlphaBlend :: Color -> Color -> Color -> Color colorAlphaBlend dst src tint = unsafePerformIO $ withFreeable dst (\d -> withFreeable src (withFreeable tint . c'colorAlphaBlend d)) >>= pop++colorLerp :: Color -> Color -> Float -> Color+colorLerp color1 color2 factor = unsafePerformIO $ withFreeable color1 (\c1 -> withFreeable color2 (\c2 -> c'colorLerp c1 c2 (realToFrac factor))) >>= pop getColor :: Integer -> Color getColor hexValue = unsafePerformIO $ c'getColor (fromIntegral hexValue) >>= pop
src/Raylib/Internal.hs view
@@ -150,16 +150,16 @@ } $( genNative- [ ("c'rlGetShaderIdDefault", "rlGetShaderIdDefault_", "rlgl_bindings.h", [t|IO CUInt|], False),- ("c'rlUnloadShaderProgram", "rlUnloadShaderProgram_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlUnloadTexture", "rlUnloadTexture_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlUnloadFramebuffer", "rlUnloadFramebuffer_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlUnloadVertexArray", "rlUnloadVertexArray_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlUnloadVertexBuffer", "rlUnloadVertexBuffer_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'unloadMusicStreamData", "UnloadMusicStreamData", "rl_internal.h", [t|CInt -> Ptr () -> IO ()|], False),- ("c'unloadAudioBuffer", "UnloadAudioBuffer_", "rl_internal.h", [t|Ptr () -> IO ()|], False),- ("c'unloadAudioBufferAlias", "UnloadAudioBufferAlias", "rl_internal.h", [t|Ptr () -> IO ()|], False),- ("c'getPixelDataSize", "GetPixelDataSize_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> IO CInt|], False)+ [ ("c'rlGetShaderIdDefault", "rlGetShaderIdDefault_", "rlgl_bindings.h", [t|IO CUInt|]),+ ("c'rlUnloadShaderProgram", "rlUnloadShaderProgram_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlUnloadTexture", "rlUnloadTexture_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlUnloadFramebuffer", "rlUnloadFramebuffer_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlUnloadVertexArray", "rlUnloadVertexArray_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlUnloadVertexBuffer", "rlUnloadVertexBuffer_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'unloadMusicStreamData", "UnloadMusicStreamData", "rl_internal.h", [t|CInt -> Ptr () -> IO ()|]),+ ("c'unloadAudioBuffer", "UnloadAudioBuffer_", "rl_internal.h", [t|Ptr () -> IO ()|]),+ ("c'unloadAudioBufferAlias", "UnloadAudioBufferAlias", "rl_internal.h", [t|Ptr () -> IO ()|]),+ ("c'getPixelDataSize", "GetPixelDataSize_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> IO CInt|]) ] )
src/Raylib/Internal/TH.hs view
@@ -38,7 +38,7 @@ TypeQ, mkName, nameBase,- reify, Foreign (ImportF), Callconv (CCall), Safety (Safe, Unsafe),+ reify, Foreign (ImportF), Callconv (CCall), Safety (Safe), ) #endif@@ -60,16 +60,16 @@ -- means @foreign import@ statements. On web platforms, this means -- `callRaylibFunction` calls. genNative ::- -- | (@hsName@, @cName@, @cFile@, @funType@, @isSafe@)- [(String, String, String, TypeQ, Bool)] ->+ -- | (@hsName@, @cName@, @cFile@, @funType@)+ [(String, String, String, TypeQ)] -> DecsQ genNative funs = do- funs' <- mapM (\(a, b, c, d, e) -> (a,b,c,,e) <$> d) funs+ funs' <- mapM (\(a, b, c, d) -> (a,b,c,) <$> d) funs return (genNative' funs') where genNative' [] = [] #ifdef WEB_FFI- genNative' ((hsName, cName, _, funType, _) : xs) =+ genNative' ((hsName, cName, _, funType) : xs) = [ -- hsName :: funType SigD name funType, -- hsName = callRaylibFunction "_cName"@@ -80,7 +80,7 @@ where name = mkName hsName #else- genNative' ((hsName, cName, cFile, funType, isSafe) : xs) =+ genNative' ((hsName, cName, cFile, funType) : xs) = -- foreign import ccall safe/unsafe "cFile cName" hsName :: funType- ForeignD (ImportF CCall (if isSafe then Safe else Unsafe) (cFile ++ " " ++ cName) (mkName hsName) funType) : genNative' xs+ ForeignD (ImportF CCall Safe (cFile ++ " " ++ cName) (mkName hsName) funType) : genNative' xs #endif
src/Raylib/Types/Core.hs view
@@ -106,10 +106,12 @@ p'automationEventList'events, -- * Callbacks+ TraceLogCallback, LoadFileDataCallback, SaveFileDataCallback, LoadFileTextCallback, SaveFileTextCallback,+ C'TraceLogCallback, C'LoadFileDataCallback, C'SaveFileDataCallback, C'LoadFileTextCallback,@@ -1153,6 +1155,8 @@ -- core callbacks --------------------- --------------------------------------- +type TraceLogCallback = TraceLogLevel -> String -> IO ()+ type LoadFileDataCallback = String -> IO [Integer] type SaveFileDataCallback a = String -> Ptr a -> Integer -> IO Bool@@ -1160,6 +1164,8 @@ type LoadFileTextCallback = String -> IO String type SaveFileTextCallback = String -> String -> IO Bool++type C'TraceLogCallback = FunPtr (CInt -> CString -> IO ()) type C'LoadFileDataCallback = FunPtr (CString -> Ptr CUInt -> IO (Ptr CUChar))
src/Raylib/Types/Core/Models.hs view
@@ -5,6 +5,7 @@ module Raylib.Types.Core.Models ( -- * Enumerations MaterialMapIndex (..),+ DefaultShaderAttributeLocation (..), ShaderLocationIndex (..), ShaderUniformDataType (..), ShaderUniformData (..),@@ -134,6 +135,18 @@ | MaterialMapBrdf deriving (Eq, Show, Enum) +data DefaultShaderAttributeLocation+ = DefaultShaderAttribLocationPosition+ | DefaultShaderAttribLocationTexcoord+ | DefaultShaderAttribLocationNormal+ | DefaultShaderAttribLocationColor+ | DefaultShaderAttribLocationTangent+ | DefaultShaderAttribLocationTexcoord2+ | DefaultShaderAttribLocationIndices+ | DefaultShaderAttribLocationBoneIds+ | DefaultShaderAttribLocationBoneWeights+ deriving (Eq, Show, Enum)+ data ShaderLocationIndex = ShaderLocVertexPosition | ShaderLocVertexTexcoord01@@ -161,6 +174,9 @@ | ShaderLocMapIrradiance | ShaderLocMapPrefilter | ShaderLocMapBrdf+ | ShaderLocVertexBoneIds+ | ShaderLocVertexBoneWeights+ | ShaderLocBoneMatrices deriving (Eq, Show, Enum) data ShaderUniformDataType@@ -325,13 +341,16 @@ mesh'animNormals :: Maybe [Vector3], mesh'boneIds :: Maybe [Word8], mesh'boneWeights :: Maybe [Float],+ mesh'boneMatrices :: Maybe [Matrix],+ mesh'boneCount :: Int, mesh'vaoId :: Integer,+ -- | Use `toEnum` on `DefaultShaderAttributeLocation` for indices mesh'vboId :: Maybe [Integer] } deriving (Eq, Show) instance Storable Mesh where- sizeOf _ = 112+ sizeOf _ = 120 alignment _ = 8 peek _p = do vertexCount <- fromIntegral <$> peek (p'mesh'vertexCount _p)@@ -345,12 +364,14 @@ indices <- (map fromIntegral <$>) <$> (peekMaybeArray vertexCount =<< peek (p'mesh'indices _p)) animVertices <- peekMaybeArray vertexCount =<< peek (p'mesh'animVertices _p) animNormals <- peekMaybeArray vertexCount =<< peek (p'mesh'animNormals _p)- boneIds <- (map fromIntegral <$>) <$> (peekMaybeArray (vertexCount * 4) =<< peek (p'mesh'boneIds _p))- boneWeights <- (map realToFrac <$>) <$> (peekMaybeArray (vertexCount * 4) =<< peek (p'mesh'boneWeights _p))+ boneCount <- fromIntegral <$> peek (p'mesh'boneCount _p)+ boneIds <- (map fromIntegral <$>) <$> (peekMaybeArray boneCount =<< peek (p'mesh'boneIds _p))+ boneWeights <- (map realToFrac <$>) <$> (peekMaybeArray boneCount =<< peek (p'mesh'boneWeights _p))+ boneMatrices <- peekMaybeArray boneCount =<< peek (p'mesh'boneMatrices _p) vaoId <- fromIntegral <$> peek (p'mesh'vaoId _p)- vboId <- (map fromIntegral <$>) <$> (peekMaybeArray 7 =<< peek (p'mesh'vboId _p))- return $ Mesh vertexCount triangleCount vertices texcoords texcoords2 normals tangents colors indices animVertices animNormals boneIds boneWeights vaoId vboId- poke _p (Mesh vertexCount triangleCount vertices texcoords texcoords2 normals tangents colors indices animVertices animNormals boneIds boneWeights vaoId vboId) = do+ vboId <- (map fromIntegral <$>) <$> (peekMaybeArray 9 =<< peek (p'mesh'vboId _p))+ return $ Mesh vertexCount triangleCount vertices texcoords texcoords2 normals tangents colors indices animVertices animNormals boneIds boneWeights boneMatrices boneCount vaoId vboId+ poke _p (Mesh vertexCount triangleCount vertices texcoords texcoords2 normals tangents colors indices animVertices animNormals boneIds boneWeights boneMatrices boneCount vaoId vboId) = do poke (p'mesh'vertexCount _p) (fromIntegral vertexCount) poke (p'mesh'triangleCount _p) (fromIntegral triangleCount) poke (p'mesh'vertices _p) =<< newArray vertices@@ -364,6 +385,8 @@ poke (p'mesh'animNormals _p) =<< newMaybeArray animNormals poke (p'mesh'boneIds _p) =<< newMaybeArray (map fromIntegral <$> boneIds) poke (p'mesh'boneWeights _p) =<< newMaybeArray (map realToFrac <$> boneWeights)+ poke (p'mesh'boneMatrices _p) =<< newMaybeArray boneMatrices+ poke (p'mesh'boneCount _p) (fromIntegral boneCount) poke (p'mesh'vaoId _p) (fromIntegral vaoId) poke (p'mesh'vboId _p) =<< newMaybeArray (map fromIntegral <$> vboId) return ()@@ -420,20 +443,27 @@ p'mesh'animNormals :: Ptr Mesh -> Ptr (Ptr Vector3) p'mesh'animNormals = (`plusPtr` 72) --- maybe array (mesh'vertexCount * 4)+-- maybe array (mesh'boneCount) p'mesh'boneIds :: Ptr Mesh -> Ptr (Ptr CUChar) p'mesh'boneIds = (`plusPtr` 80) --- maybe array (mesh'vertexCount * 4)+-- maybe array (mesh'boneCount) p'mesh'boneWeights :: Ptr Mesh -> Ptr (Ptr CFloat) p'mesh'boneWeights = (`plusPtr` 88) +-- maybe array (mesh'boneCount)+p'mesh'boneMatrices :: Ptr Mesh -> Ptr (Ptr Matrix)+p'mesh'boneMatrices = (`plusPtr` 96)++p'mesh'boneCount :: Ptr Mesh -> Ptr CInt+p'mesh'boneCount = (`plusPtr` 104)+ p'mesh'vaoId :: Ptr Mesh -> Ptr CUInt-p'mesh'vaoId = (`plusPtr` 96)+p'mesh'vaoId = (`plusPtr` 108) --- maybe array (7)+-- maybe array (9) p'mesh'vboId :: Ptr Mesh -> Ptr (Ptr CUInt)-p'mesh'vboId = (`plusPtr` 104)+p'mesh'vboId = (`plusPtr` 112) instance Freeable Mesh where rlFreeDependents _ ptr = do
src/Raylib/Types/Util/GUI.hs view
@@ -511,6 +511,8 @@ DropdownItemsSpacing | -- | DropdownBox arrow hidden DropdownArrowHidden+ | -- | DropdownBox roll up flag (default rolls down)+ DropdownRollUp deriving (Eq, Show) instance Enum GuiDropdownBoxProperty where@@ -518,10 +520,12 @@ ArrowPadding -> 16 DropdownItemsSpacing -> 17 DropdownArrowHidden -> 18+ DropdownRollUp -> 19 toEnum x = case x of 16 -> ArrowPadding 17 -> DropdownItemsSpacing 18 -> DropdownArrowHidden+ 19 -> DropdownRollUp n -> error $ "(GuiDropdownBoxProperty.toEnum) Invalid value: " ++ show n instance Storable GuiDropdownBoxProperty where@@ -880,7 +884,7 @@ | IconLayers2 | IconMLayers | IconMaps- | Icon228+ | IconHot | Icon229 | Icon230 | Icon231@@ -1140,7 +1144,7 @@ IconLayers2 -> 225 IconMLayers -> 226 IconMaps -> 227- Icon228 -> 228+ IconHot -> 228 Icon229 -> 229 Icon230 -> 230 Icon231 -> 231@@ -1397,7 +1401,7 @@ 225 -> IconLayers2 226 -> IconMLayers 227 -> IconMaps- 228 -> Icon228+ 228 -> IconHot 229 -> Icon229 230 -> Icon230 231 -> Icon231
src/Raylib/Types/Util/RLGL.hs view
@@ -384,6 +384,14 @@ RLShaderUniformIVec3 | -- | Shader uniform type: ivec4 (4 int) RLShaderUniformIVec4+ | -- | Shader uniform type: unsigned int+ RLShaderUniformUInt+ | -- | Shader uniform type: uivec2 (2 unsigned int)+ RLShaderUniformUIVec2+ | -- | Shader uniform type: uivec3 (3 unsigned int)+ RLShaderUniformUIVec3+ | -- | Shader uniform type: uivec4 (4 unsigned int)+ RLShaderUniformUIVec4 | -- | Shader uniform type: sampler2d RLShaderUniformSampler2D deriving (Eq, Show, Enum)
src/Raylib/Util/GUI.hs view
@@ -236,63 +236,63 @@ import Raylib.Internal.TH (genNative) import Raylib.Types (Color (Color), Font, GuiControl (Default), GuiControlProperty (..), GuiDefaultProperty (..), GuiIconName, GuiState, GuiTextAlignment, GuiTextAlignmentVertical, GuiTextWrapMode, Rectangle (Rectangle), Vector2, pattern Vector2, Vector3, pattern Vector3) $( genNative- [ ("c'guiEnable", "GuiEnable_", "rgui_bindings.h", [t|IO ()|], False),- ("c'guiDisable", "GuiDisable_", "rgui_bindings.h", [t|IO ()|], False),- ("c'guiLock", "GuiLock_", "rgui_bindings.h", [t|IO ()|], False),- ("c'guiUnlock", "GuiUnlock_", "rgui_bindings.h", [t|IO ()|], False),- ("c'guiIsLocked", "GuiIsLocked_", "rgui_bindings.h", [t|IO CBool|], False),- ("c'guiSetAlpha", "GuiSetAlpha_", "rgui_bindings.h", [t|CFloat -> IO ()|], False),- ("c'guiSetState", "GuiSetState_", "rgui_bindings.h", [t|CInt -> IO ()|], False),- ("c'guiGetState", "GuiGetState_", "rgui_bindings.h", [t|IO CInt|], False),- ("c'guiSetFont", "GuiSetFont_", "rgui_bindings.h", [t|Ptr Font -> IO ()|], False),- ("c'guiGetFont", "GuiGetFont_", "rgui_bindings.h", [t|IO (Ptr Font)|], False),- ("c'guiSetStyle", "GuiSetStyle_", "rgui_bindings.h", [t|CInt -> CInt -> CInt -> IO ()|], False),- ("c'guiGetStyle", "GuiGetStyle_", "rgui_bindings.h", [t|CInt -> CInt -> IO CInt|], False),- ("c'guiLoadStyle", "GuiLoadStyle_", "rgui_bindings.h", [t|CString -> IO ()|], False),- ("c'guiLoadStyleDefault", "GuiLoadStyleDefault_", "rgui_bindings.h", [t|IO ()|], False),- ("c'guiEnableTooltip", "GuiEnableTooltip_", "rgui_bindings.h", [t|IO ()|], False),- ("c'guiDisableTooltip", "GuiDisableTooltip_", "rgui_bindings.h", [t|IO ()|], False),- ("c'guiSetTooltip", "GuiSetTooltip_", "rgui_bindings.h", [t|CString -> IO ()|], False),- ("c'guiIconText", "GuiIconText_", "rgui_bindings.h", [t|CInt -> CString -> IO CString|], False),- ("c'guiSetIconScale", "GuiSetIconScale_", "rgui_bindings.h", [t|CInt -> IO ()|], False),- ("c'guiGetIcons", "GuiGetIcons_", "rgui_bindings.h", [t|IO (Ptr CUInt)|], False),- ("c'guiLoadIcons", "GuiLoadIcons_", "rgui_bindings.h", [t|CString -> CBool -> IO (Ptr CString)|], False),- ("c'guiDrawIcon", "GuiDrawIcon_", "rgui_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|], False),- ("c'guiWindowBox", "GuiWindowBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|], False),- ("c'guiGroupBox", "GuiGroupBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|], False),- ("c'guiLine", "GuiLine_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|], False),- ("c'guiPanel", "GuiPanel_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|], False),- ("c'guiTabBar", "GuiTabBar_", "rgui_bindings.h", [t|Ptr Rectangle -> Ptr CString -> CInt -> Ptr CInt -> IO CInt|], False),- ("c'guiScrollPanel", "GuiScrollPanel_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr Rectangle -> Ptr Vector2 -> Ptr Rectangle -> IO CInt|], False),- ("c'guiLabel", "GuiLabel_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|], False),- ("c'guiButton", "GuiButton_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|], False),- ("c'guiLabelButton", "GuiLabelButton_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|], False),- ("c'guiToggle", "GuiToggle_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CBool -> IO CInt|], False),- ("c'guiToggleGroup", "GuiToggleGroup_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CInt -> IO CInt|], False),- ("c'guiToggleSlider", "GuiToggleSlider_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CInt -> IO CInt|], False),- ("c'guiCheckBox", "GuiCheckBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CBool -> IO CInt|], False),- ("c'guiComboBox", "GuiComboBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CInt -> IO CInt|], False),- ("c'guiDropdownBox", "GuiDropdownBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CInt -> CBool -> IO CInt|], False),- ("c'guiSpinner", "GuiSpinner_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CInt -> CInt -> CInt -> CBool -> IO CInt|], False),- ("c'guiValueBox", "GuiValueBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CInt -> CInt -> CInt -> CBool -> IO CInt|], False),- ("c'guiValueBoxFloat", "GuiValueBoxFloat_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CString -> Ptr CFloat -> CBool -> IO CInt|], False),- ("c'guiTextBox", "GuiTextBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CInt -> CBool -> IO CInt|], False),- ("c'guiSlider", "GuiSlider_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CString -> Ptr CFloat -> CFloat -> CFloat -> IO CInt|], False),- ("c'guiSliderBar", "GuiSliderBar_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CString -> Ptr CFloat -> CFloat -> CFloat -> IO CInt|], False),- ("c'guiProgressBar", "GuiProgressBar_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CString -> Ptr CFloat -> CFloat -> CFloat -> IO CInt|], False),- ("c'guiStatusBar", "GuiStatusBar_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|], False),- ("c'guiDummyRec", "GuiDummyRec_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|], False),- ("c'guiGrid", "GuiGrid_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CFloat -> CInt -> Ptr Vector2 -> IO CInt|], False),- ("c'guiListView", "GuiListView_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CInt -> Ptr CInt -> IO CInt|], False),- ("c'guiListViewEx", "GuiListViewEx_", "rgui_bindings.h", [t|Ptr Rectangle -> Ptr CString -> CInt -> Ptr CInt -> Ptr CInt -> Ptr CInt -> IO CInt|], False),- ("c'guiMessageBox", "GuiMessageBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CString -> CString -> IO CInt|], False),- ("c'guiTextInputBox", "GuiTextInputBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CString -> CString -> CString -> CInt -> Ptr CBool -> IO CInt|], False),- ("c'guiColorPicker", "GuiColorPicker_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr Color -> IO CInt|], False),- ("c'guiColorPanel", "GuiColorPanel_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr Color -> IO CInt|], False),- ("c'guiColorBarAlpha", "GuiColorBarAlpha_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CFloat -> IO CInt|], False),- ("c'guiColorBarHue", "GuiColorBarHue_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CFloat -> IO CInt|], False),- ("c'guiColorPickerHSV", "GuiColorPickerHSV_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr Vector3 -> IO CInt|], False),- ("c'guiColorPanelHSV", "GuiColorPanelHSV_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr Vector3 -> IO CInt|], False)+ [ ("c'guiEnable", "GuiEnable_", "rgui_bindings.h", [t|IO ()|]),+ ("c'guiDisable", "GuiDisable_", "rgui_bindings.h", [t|IO ()|]),+ ("c'guiLock", "GuiLock_", "rgui_bindings.h", [t|IO ()|]),+ ("c'guiUnlock", "GuiUnlock_", "rgui_bindings.h", [t|IO ()|]),+ ("c'guiIsLocked", "GuiIsLocked_", "rgui_bindings.h", [t|IO CBool|]),+ ("c'guiSetAlpha", "GuiSetAlpha_", "rgui_bindings.h", [t|CFloat -> IO ()|]),+ ("c'guiSetState", "GuiSetState_", "rgui_bindings.h", [t|CInt -> IO ()|]),+ ("c'guiGetState", "GuiGetState_", "rgui_bindings.h", [t|IO CInt|]),+ ("c'guiSetFont", "GuiSetFont_", "rgui_bindings.h", [t|Ptr Font -> IO ()|]),+ ("c'guiGetFont", "GuiGetFont_", "rgui_bindings.h", [t|IO (Ptr Font)|]),+ ("c'guiSetStyle", "GuiSetStyle_", "rgui_bindings.h", [t|CInt -> CInt -> CInt -> IO ()|]),+ ("c'guiGetStyle", "GuiGetStyle_", "rgui_bindings.h", [t|CInt -> CInt -> IO CInt|]),+ ("c'guiLoadStyle", "GuiLoadStyle_", "rgui_bindings.h", [t|CString -> IO ()|]),+ ("c'guiLoadStyleDefault", "GuiLoadStyleDefault_", "rgui_bindings.h", [t|IO ()|]),+ ("c'guiEnableTooltip", "GuiEnableTooltip_", "rgui_bindings.h", [t|IO ()|]),+ ("c'guiDisableTooltip", "GuiDisableTooltip_", "rgui_bindings.h", [t|IO ()|]),+ ("c'guiSetTooltip", "GuiSetTooltip_", "rgui_bindings.h", [t|CString -> IO ()|]),+ ("c'guiIconText", "GuiIconText_", "rgui_bindings.h", [t|CInt -> CString -> IO CString|]),+ ("c'guiSetIconScale", "GuiSetIconScale_", "rgui_bindings.h", [t|CInt -> IO ()|]),+ ("c'guiGetIcons", "GuiGetIcons_", "rgui_bindings.h", [t|IO (Ptr CUInt)|]),+ ("c'guiLoadIcons", "GuiLoadIcons_", "rgui_bindings.h", [t|CString -> CBool -> IO (Ptr CString)|]),+ ("c'guiDrawIcon", "GuiDrawIcon_", "rgui_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),+ ("c'guiWindowBox", "GuiWindowBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|]),+ ("c'guiGroupBox", "GuiGroupBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|]),+ ("c'guiLine", "GuiLine_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|]),+ ("c'guiPanel", "GuiPanel_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|]),+ ("c'guiTabBar", "GuiTabBar_", "rgui_bindings.h", [t|Ptr Rectangle -> Ptr CString -> CInt -> Ptr CInt -> IO CInt|]),+ ("c'guiScrollPanel", "GuiScrollPanel_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr Rectangle -> Ptr Vector2 -> Ptr Rectangle -> IO CInt|]),+ ("c'guiLabel", "GuiLabel_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|]),+ ("c'guiButton", "GuiButton_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|]),+ ("c'guiLabelButton", "GuiLabelButton_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|]),+ ("c'guiToggle", "GuiToggle_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CBool -> IO CInt|]),+ ("c'guiToggleGroup", "GuiToggleGroup_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CInt -> IO CInt|]),+ ("c'guiToggleSlider", "GuiToggleSlider_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CInt -> IO CInt|]),+ ("c'guiCheckBox", "GuiCheckBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CBool -> IO CInt|]),+ ("c'guiComboBox", "GuiComboBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CInt -> IO CInt|]),+ ("c'guiDropdownBox", "GuiDropdownBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CInt -> CBool -> IO CInt|]),+ ("c'guiSpinner", "GuiSpinner_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CInt -> CInt -> CInt -> CBool -> IO CInt|]),+ ("c'guiValueBox", "GuiValueBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CInt -> CInt -> CInt -> CBool -> IO CInt|]),+ ("c'guiValueBoxFloat", "GuiValueBoxFloat_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CString -> Ptr CFloat -> CBool -> IO CInt|]),+ ("c'guiTextBox", "GuiTextBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CInt -> CBool -> IO CInt|]),+ ("c'guiSlider", "GuiSlider_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CString -> Ptr CFloat -> CFloat -> CFloat -> IO CInt|]),+ ("c'guiSliderBar", "GuiSliderBar_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CString -> Ptr CFloat -> CFloat -> CFloat -> IO CInt|]),+ ("c'guiProgressBar", "GuiProgressBar_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CString -> Ptr CFloat -> CFloat -> CFloat -> IO CInt|]),+ ("c'guiStatusBar", "GuiStatusBar_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|]),+ ("c'guiDummyRec", "GuiDummyRec_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|]),+ ("c'guiGrid", "GuiGrid_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CFloat -> CInt -> Ptr Vector2 -> IO CInt|]),+ ("c'guiListView", "GuiListView_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CInt -> Ptr CInt -> IO CInt|]),+ ("c'guiListViewEx", "GuiListViewEx_", "rgui_bindings.h", [t|Ptr Rectangle -> Ptr CString -> CInt -> Ptr CInt -> Ptr CInt -> Ptr CInt -> IO CInt|]),+ ("c'guiMessageBox", "GuiMessageBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CString -> CString -> IO CInt|]),+ ("c'guiTextInputBox", "GuiTextInputBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CString -> CString -> CString -> CInt -> Ptr CBool -> IO CInt|]),+ ("c'guiColorPicker", "GuiColorPicker_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr Color -> IO CInt|]),+ ("c'guiColorPanel", "GuiColorPanel_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr Color -> IO CInt|]),+ ("c'guiColorBarAlpha", "GuiColorBarAlpha_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CFloat -> IO CInt|]),+ ("c'guiColorBarHue", "GuiColorBarHue_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CFloat -> IO CInt|]),+ ("c'guiColorPickerHSV", "GuiColorPickerHSV_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr Vector3 -> IO CInt|]),+ ("c'guiColorPanelHSV", "GuiColorPanelHSV_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr Vector3 -> IO CInt|]) ] )
src/Raylib/Util/GUI/Styles.hs view
@@ -22,18 +22,18 @@ import Raylib.Internal.TH (genNative) $( genNative- [ ("c'guiLoadStyleAmber", "GuiLoadStyleAmber_", "rgui_bindings.h", [t|IO ()|], False),- ("c'guiLoadStyleAshes", "GuiLoadStyleAshes_", "rgui_bindings.h", [t|IO ()|], False),- ("c'guiLoadStyleBluish", "GuiLoadStyleBluish_", "rgui_bindings.h", [t|IO ()|], False),- ("c'guiLoadStyleCandy", "GuiLoadStyleCandy_", "rgui_bindings.h", [t|IO ()|], False),- ("c'guiLoadStyleCherry", "GuiLoadStyleCherry_", "rgui_bindings.h", [t|IO ()|], False),- ("c'guiLoadStyleCyber", "GuiLoadStyleCyber_", "rgui_bindings.h", [t|IO ()|], False),- ("c'guiLoadStyleDark", "GuiLoadStyleDark_", "rgui_bindings.h", [t|IO ()|], False),- ("c'guiLoadStyleEnefete", "GuiLoadStyleEnefete_", "rgui_bindings.h", [t|IO ()|], False),- ("c'guiLoadStyleJungle", "GuiLoadStyleJungle_", "rgui_bindings.h", [t|IO ()|], False),- ("c'guiLoadStyleLavanda", "GuiLoadStyleLavanda_", "rgui_bindings.h", [t|IO ()|], False),- ("c'guiLoadStyleSunny", "GuiLoadStyleSunny_", "rgui_bindings.h", [t|IO ()|], False),- ("c'guiLoadStyleTerminal", "GuiLoadStyleTerminal_", "rgui_bindings.h", [t|IO ()|], False)+ [ ("c'guiLoadStyleAmber", "GuiLoadStyleAmber_", "rgui_bindings.h", [t|IO ()|]),+ ("c'guiLoadStyleAshes", "GuiLoadStyleAshes_", "rgui_bindings.h", [t|IO ()|]),+ ("c'guiLoadStyleBluish", "GuiLoadStyleBluish_", "rgui_bindings.h", [t|IO ()|]),+ ("c'guiLoadStyleCandy", "GuiLoadStyleCandy_", "rgui_bindings.h", [t|IO ()|]),+ ("c'guiLoadStyleCherry", "GuiLoadStyleCherry_", "rgui_bindings.h", [t|IO ()|]),+ ("c'guiLoadStyleCyber", "GuiLoadStyleCyber_", "rgui_bindings.h", [t|IO ()|]),+ ("c'guiLoadStyleDark", "GuiLoadStyleDark_", "rgui_bindings.h", [t|IO ()|]),+ ("c'guiLoadStyleEnefete", "GuiLoadStyleEnefete_", "rgui_bindings.h", [t|IO ()|]),+ ("c'guiLoadStyleJungle", "GuiLoadStyleJungle_", "rgui_bindings.h", [t|IO ()|]),+ ("c'guiLoadStyleLavanda", "GuiLoadStyleLavanda_", "rgui_bindings.h", [t|IO ()|]),+ ("c'guiLoadStyleSunny", "GuiLoadStyleSunny_", "rgui_bindings.h", [t|IO ()|]),+ ("c'guiLoadStyleTerminal", "GuiLoadStyleTerminal_", "rgui_bindings.h", [t|IO ()|]) ] )
src/Raylib/Util/RLGL.hs view
@@ -169,6 +169,7 @@ rlGetLocationAttrib, rlSetUniform, rlSetUniformMatrix,+ rlSetUniformMatrices, rlSetUniformSampler, rlSetShader, @@ -300,6 +301,7 @@ c'rlGetLocationAttrib, c'rlSetUniform, c'rlSetUniformMatrix,+ c'rlSetUniformMatrices, c'rlSetUniformSampler, c'rlSetShader, c'rlLoadComputeShaderProgram,@@ -412,160 +414,161 @@ ) $( genNative- [ ("c'rlMatrixMode", "rlMatrixMode_", "rlgl_bindings.h", [t|CInt -> IO ()|], False),- ("c'rlTranslatef", "rlTranslatef_", "rlgl_bindings.h", [t|CFloat -> CFloat -> CFloat -> IO ()|], False),- ("c'rlRotatef", "rlRotatef_", "rlgl_bindings.h", [t|CFloat -> CFloat -> CFloat -> CFloat -> IO ()|], False),- ("c'rlScalef", "rlScalef_", "rlgl_bindings.h", [t|CFloat -> CFloat -> CFloat -> IO ()|], False),- ("c'rlMultMatrixf", "rlMultMatrixf_", "rlgl_bindings.h", [t|Ptr CFloat -> IO ()|], False),- ("c'rlFrustum", "rlFrustum_", "rlgl_bindings.h", [t|CDouble -> CDouble -> CDouble -> CDouble -> CDouble -> CDouble -> IO ()|], False),- ("c'rlOrtho", "rlOrtho_", "rlgl_bindings.h", [t|CDouble -> CDouble -> CDouble -> CDouble -> CDouble -> CDouble -> IO ()|], False),- ("c'rlViewport", "rlViewport_", "rlgl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> IO ()|], False),- ("c'rlSetClipPlanes", "rlSetClipPlanes_", "rlgl_bindings.h", [t|CDouble -> CDouble -> IO ()|], False),- ("c'rlGetCullDistanceNear", "rlGetCullDistanceNear", "rlgl_bindings.h", [t|IO CDouble|], False),- ("c'rlGetCullDistanceFar", "rlGetCullDistanceFar", "rlgl_bindings.h", [t|IO CDouble|], False),- ("c'rlBegin", "rlBegin_", "rlgl_bindings.h", [t|CInt -> IO ()|], False),- ("c'rlVertex2i", "rlVertex2i_", "rlgl_bindings.h", [t|CInt -> CInt -> IO ()|], False),- ("c'rlVertex2f", "rlVertex2f_", "rlgl_bindings.h", [t|CFloat -> CFloat -> IO ()|], False),- ("c'rlVertex3f", "rlVertex3f_", "rlgl_bindings.h", [t|CFloat -> CFloat -> CFloat -> IO ()|], False),- ("c'rlTexCoord2f", "rlTexCoord2f_", "rlgl_bindings.h", [t|CFloat -> CFloat -> IO ()|], False),- ("c'rlNormal3f", "rlNormal3f_", "rlgl_bindings.h", [t|CFloat -> CFloat -> CFloat -> IO ()|], False),- ("c'rlColor4ub", "rlColor4ub_", "rlgl_bindings.h", [t|CUChar -> CUChar -> CUChar -> CUChar -> IO ()|], False),- ("c'rlColor3f", "rlColor3f_", "rlgl_bindings.h", [t|CFloat -> CFloat -> CFloat -> IO ()|], False),- ("c'rlColor4f", "rlColor4f_", "rlgl_bindings.h", [t|CFloat -> CFloat -> CFloat -> CFloat -> IO ()|], False),- ("c'rlEnableVertexArray", "rlEnableVertexArray_", "rlgl_bindings.h", [t|CUInt -> IO CBool|], False),- ("c'rlEnableVertexBuffer", "rlEnableVertexBuffer_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlEnableVertexBufferElement", "rlEnableVertexBufferElement_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlEnableVertexAttribute", "rlEnableVertexAttribute_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlDisableVertexAttribute", "rlDisableVertexAttribute_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlActiveTextureSlot", "rlActiveTextureSlot_", "rlgl_bindings.h", [t|CInt -> IO ()|], False),- ("c'rlEnableTexture", "rlEnableTexture_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlEnableTextureCubemap", "rlEnableTextureCubemap_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlTextureParameters", "rlTextureParameters_", "rlgl_bindings.h", [t|CUInt -> CInt -> CInt -> IO ()|], False),- ("c'rlCubemapParameters", "rlCubemapParameters_", "rlgl_bindings.h", [t|CUInt -> CInt -> CInt -> IO ()|], False),- ("c'rlEnableShader", "rlEnableShader_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlEnableFramebuffer", "rlEnableFramebuffer_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlActiveDrawBuffers", "rlActiveDrawBuffers_", "rlgl_bindings.h", [t|CInt -> IO ()|], False),- ("c'rlBlitFramebuffer", "rlBlitFramebuffer_", "rlgl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> CInt -> CInt -> CInt -> CInt -> CInt -> IO ()|], False),- ("c'rlBindFramebuffer", "rlBindFramebuffer_", "rlgl_bindings.h", [t|CUInt -> CUInt -> IO ()|], False),- ("c'rlColorMask", "rlColorMask_", "rlgl_bindings.h", [t|CBool -> CBool -> CBool -> CBool -> IO ()|], False),- ("c'rlSetCullFace", "rlSetCullFace_", "rlgl_bindings.h", [t|CInt -> IO ()|], False),- ("c'rlScissor", "rlScissor_", "rlgl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> IO ()|], False),- ("c'rlSetLineWidth", "rlSetLineWidth_", "rlgl_bindings.h", [t|CFloat -> IO ()|], False),- ("c'rlGetLineWidth", "rlGetLineWidth_", "rlgl_bindings.h", [t|IO CFloat|], False),- ("c'rlIsStereoRenderEnabled", "rlIsStereoRenderEnabled_", "rlgl_bindings.h", [t|IO CBool|], False),- ("c'rlClearColor", "rlClearColor_", "rlgl_bindings.h", [t|CUChar -> CUChar -> CUChar -> CUChar -> IO ()|], False),- ("c'rlSetBlendMode", "rlSetBlendMode_", "rlgl_bindings.h", [t|CInt -> IO ()|], False),- ("c'rlSetBlendFactors", "rlSetBlendFactors_", "rlgl_bindings.h", [t|CInt -> CInt -> CInt -> IO ()|], False),- ("c'rlSetBlendFactorsSeparate", "rlSetBlendFactorsSeparate_", "rlgl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> CInt -> CInt -> IO ()|], False),- ("c'rlglInit", "rlglInit_", "rlgl_bindings.h", [t|CInt -> CInt -> IO ()|], False),- ("c'rlLoadExtensions", "rlLoadExtensions_", "rlgl_bindings.h", [t|Ptr () -> IO ()|], False),- ("c'rlGetVersion", "rlGetVersion_", "rlgl_bindings.h", [t|IO CInt|], False),- ("c'rlSetFramebufferWidth", "rlSetFramebufferWidth_", "rlgl_bindings.h", [t|CInt -> IO ()|], False),- ("c'rlGetFramebufferWidth", "rlGetFramebufferWidth_", "rlgl_bindings.h", [t|IO CInt|], False),- ("c'rlSetFramebufferHeight", "rlSetFramebufferHeight_", "rlgl_bindings.h", [t|CInt -> IO ()|], False),- ("c'rlGetFramebufferHeight", "rlGetFramebufferHeight_", "rlgl_bindings.h", [t|IO CInt|], False),- ("c'rlGetTextureIdDefault", "rlGetTextureIdDefault_", "rlgl_bindings.h", [t|IO CUInt|], False),- ("c'rlGetShaderIdDefault", "rlGetShaderIdDefault_", "rlgl_bindings.h", [t|IO CUInt|], False),- ("c'rlGetShaderLocsDefault", "rlGetShaderLocsDefault_", "rlgl_bindings.h", [t|IO (Ptr CInt)|], False),- ("c'rlLoadRenderBatch", "rlLoadRenderBatch_", "rlgl_bindings.h", [t|CInt -> CInt -> IO (Ptr RLRenderBatch)|], False),- ("c'rlUnloadRenderBatch", "rlUnloadRenderBatch_", "rlgl_bindings.h", [t|Ptr RLRenderBatch -> IO ()|], False),- ("c'rlDrawRenderBatch", "rlDrawRenderBatch_", "rlgl_bindings.h", [t|Ptr RLRenderBatch -> IO ()|], False),- ("c'rlSetRenderBatchActive", "rlSetRenderBatchActive_", "rlgl_bindings.h", [t|Ptr RLRenderBatch -> IO ()|], False),- ("c'rlCheckRenderBatchLimit", "rlCheckRenderBatchLimit_", "rlgl_bindings.h", [t|CInt -> IO CBool|], False),- ("c'rlSetTexture", "rlSetTexture_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlLoadVertexArray", "rlLoadVertexArray_", "rlgl_bindings.h", [t|IO CUInt|], False),- ("c'rlLoadVertexBuffer", "rlLoadVertexBuffer_", "rlgl_bindings.h", [t|Ptr () -> CInt -> CBool -> IO CUInt|], False),- ("c'rlLoadVertexBufferElement", "rlLoadVertexBufferElement_", "rlgl_bindings.h", [t|Ptr () -> CInt -> CBool -> IO CUInt|], False),- ("c'rlUpdateVertexBuffer", "rlUpdateVertexBuffer_", "rlgl_bindings.h", [t|CUInt -> Ptr () -> CInt -> CInt -> IO ()|], False),- ("c'rlUpdateVertexBufferElements", "rlUpdateVertexBufferElements_", "rlgl_bindings.h", [t|CUInt -> Ptr () -> CInt -> CInt -> IO ()|], False),- ("c'rlUnloadVertexArray", "rlUnloadVertexArray_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlUnloadVertexBuffer", "rlUnloadVertexBuffer_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlSetVertexAttribute", "rlSetVertexAttribute_", "rlgl_bindings.h", [t|CUInt -> CInt -> CInt -> CBool -> CInt -> CInt -> IO ()|], False),- ("c'rlSetVertexAttributeDivisor", "rlSetVertexAttributeDivisor_", "rlgl_bindings.h", [t|CUInt -> CInt -> IO ()|], False),- ("c'rlSetVertexAttributeDefault", "rlSetVertexAttributeDefault_", "rlgl_bindings.h", [t|CInt -> Ptr () -> CInt -> CInt -> IO ()|], False),- ("c'rlDrawVertexArray", "rlDrawVertexArray_", "rlgl_bindings.h", [t|CInt -> CInt -> IO ()|], False),- ("c'rlDrawVertexArrayElements", "rlDrawVertexArrayElements_", "rlgl_bindings.h", [t|CInt -> CInt -> Ptr () -> IO ()|], False),- ("c'rlDrawVertexArrayInstanced", "rlDrawVertexArrayInstanced_", "rlgl_bindings.h", [t|CInt -> CInt -> CInt -> IO ()|], False),- ("c'rlDrawVertexArrayElementsInstanced", "rlDrawVertexArrayElementsInstanced_", "rlgl_bindings.h", [t|CInt -> CInt -> Ptr () -> CInt -> IO ()|], False),- ("c'rlLoadTexture", "rlLoadTexture_", "rlgl_bindings.h", [t|Ptr () -> CInt -> CInt -> CInt -> CInt -> IO CUInt|], False),- ("c'rlLoadTextureDepth", "rlLoadTextureDepth_", "rlgl_bindings.h", [t|CInt -> CInt -> CBool -> IO CUInt|], False),- ("c'rlLoadTextureCubemap", "rlLoadTextureCubemap_", "rlgl_bindings.h", [t|Ptr () -> CInt -> CInt -> IO CUInt|], False),- ("c'rlUpdateTexture", "rlUpdateTexture_", "rlgl_bindings.h", [t|CUInt -> CInt -> CInt -> CInt -> CInt -> CInt -> Ptr () -> IO ()|], False),- ("c'rlGetGlTextureFormats", "rlGetGlTextureFormats_", "rlgl_bindings.h", [t|CInt -> Ptr CUInt -> Ptr CUInt -> Ptr CUInt -> IO ()|], False),- ("c'rlGetPixelFormatName", "rlGetPixelFormatName_", "rlgl_bindings.h", [t|CUInt -> IO CString|], False),- ("c'rlUnloadTexture", "rlUnloadTexture_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlGenTextureMipmaps", "rlGenTextureMipmaps_", "rlgl_bindings.h", [t|CUInt -> CInt -> CInt -> CInt -> Ptr CInt -> IO ()|], False),- ("c'rlReadTexturePixels", "rlReadTexturePixels_", "rlgl_bindings.h", [t|CUInt -> CInt -> CInt -> CInt -> IO (Ptr ())|], False),- ("c'rlReadScreenPixels", "rlReadScreenPixels_", "rlgl_bindings.h", [t|CInt -> CInt -> IO (Ptr CUChar)|], False),- ("c'rlLoadFramebuffer", "rlLoadFramebuffer_", "rlgl_bindings.h", [t|IO CUInt|], False),- ("c'rlFramebufferAttach", "rlFramebufferAttach_", "rlgl_bindings.h", [t|CUInt -> CUInt -> CInt -> CInt -> CInt -> IO ()|], False),- ("c'rlFramebufferComplete", "rlFramebufferComplete_", "rlgl_bindings.h", [t|CUInt -> IO CBool|], False),- ("c'rlUnloadFramebuffer", "rlUnloadFramebuffer_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlLoadShaderCode", "rlLoadShaderCode_", "rlgl_bindings.h", [t|CString -> CString -> IO CUInt|], False),- ("c'rlCompileShader", "rlCompileShader_", "rlgl_bindings.h", [t|CString -> CInt -> IO CUInt|], False),- ("c'rlLoadShaderProgram", "rlLoadShaderProgram_", "rlgl_bindings.h", [t|CUInt -> CUInt -> IO CUInt|], False),- ("c'rlUnloadShaderProgram", "rlUnloadShaderProgram_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlGetLocationUniform", "rlGetLocationUniform_", "rlgl_bindings.h", [t|CUInt -> CString -> IO CInt|], False),- ("c'rlGetLocationAttrib", "rlGetLocationAttrib_", "rlgl_bindings.h", [t|CUInt -> CString -> IO CInt|], False),- ("c'rlSetUniform", "rlSetUniform_", "rlgl_bindings.h", [t|CInt -> Ptr () -> CInt -> CInt -> IO ()|], False),- ("c'rlSetUniformMatrix", "rlSetUniformMatrix_", "rlgl_bindings.h", [t|CInt -> Ptr Matrix -> IO ()|], False),- ("c'rlSetUniformSampler", "rlSetUniformSampler_", "rlgl_bindings.h", [t|CInt -> CUInt -> IO ()|], False),- ("c'rlSetShader", "rlSetShader_", "rlgl_bindings.h", [t|CUInt -> Ptr CInt -> IO ()|], False),- ("c'rlLoadComputeShaderProgram", "rlLoadComputeShaderProgram_", "rlgl_bindings.h", [t|CUInt -> IO CUInt|], False),- ("c'rlComputeShaderDispatch", "rlComputeShaderDispatch_", "rlgl_bindings.h", [t|CUInt -> CUInt -> CUInt -> IO ()|], False),- ("c'rlLoadShaderBuffer", "rlLoadShaderBuffer_", "rlgl_bindings.h", [t|CUInt -> Ptr () -> CInt -> IO CUInt|], False),- ("c'rlUnloadShaderBuffer", "rlUnloadShaderBuffer_", "rlgl_bindings.h", [t|CUInt -> IO ()|], False),- ("c'rlUpdateShaderBuffer", "rlUpdateShaderBuffer_", "rlgl_bindings.h", [t|CUInt -> Ptr () -> CUInt -> CUInt -> IO ()|], False),- ("c'rlBindShaderBuffer", "rlBindShaderBuffer_", "rlgl_bindings.h", [t|CUInt -> CUInt -> IO ()|], False),- ("c'rlReadShaderBuffer", "rlReadShaderBuffer_", "rlgl_bindings.h", [t|CUInt -> Ptr () -> CUInt -> CUInt -> IO ()|], False),- ("c'rlCopyShaderBuffer", "rlCopyShaderBuffer_", "rlgl_bindings.h", [t|CUInt -> CUInt -> CUInt -> CUInt -> CUInt -> IO ()|], False),- ("c'rlGetShaderBufferSize", "rlGetShaderBufferSize_", "rlgl_bindings.h", [t|CUInt -> IO CUInt|], False),- ("c'rlBindImageTexture", "rlBindImageTexture_", "rlgl_bindings.h", [t|CUInt -> CUInt -> CInt -> CBool -> IO ()|], False),- ("c'rlGetMatrixModelview", "rlGetMatrixModelview_", "rlgl_bindings.h", [t|IO (Ptr Matrix)|], False),- ("c'rlGetMatrixProjection", "rlGetMatrixProjection_", "rlgl_bindings.h", [t|IO (Ptr Matrix)|], False),- ("c'rlGetMatrixTransform", "rlGetMatrixTransform_", "rlgl_bindings.h", [t|IO (Ptr Matrix)|], False),- ("c'rlGetMatrixProjectionStereo", "rlGetMatrixProjectionStereo_", "rlgl_bindings.h", [t|CInt -> IO (Ptr Matrix)|], False),- ("c'rlGetMatrixViewOffsetStereo", "rlGetMatrixViewOffsetStereo_", "rlgl_bindings.h", [t|CInt -> IO (Ptr Matrix)|], False),- ("c'rlSetMatrixProjection", "rlSetMatrixProjection_", "rlgl_bindings.h", [t|Ptr Matrix -> IO ()|], False),- ("c'rlSetMatrixModelview", "rlSetMatrixModelview_", "rlgl_bindings.h", [t|Ptr Matrix -> IO ()|], False),- ("c'rlSetMatrixProjectionStereo", "rlSetMatrixProjectionStereo_", "rlgl_bindings.h", [t|Ptr Matrix -> Ptr Matrix -> IO ()|], False),- ("c'rlSetMatrixViewOffsetStereo", "rlSetMatrixViewOffsetStereo_", "rlgl_bindings.h", [t|Ptr Matrix -> Ptr Matrix -> IO ()|], False),- ("c'rlGetPixelDataSize", "rlGetPixelDataSize", "rl_internal.h", [t|CInt -> CInt -> CInt -> IO CInt|], False),- ("c'rlPushMatrix", "rlPushMatrix_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlPopMatrix", "rlPopMatrix_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlLoadIdentity", "rlLoadIdentity_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlEnd", "rlEnd_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlDisableVertexArray", "rlDisableVertexArray_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlDisableVertexBuffer", "rlDisableVertexBuffer_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlDisableVertexBufferElement", "rlDisableVertexBufferElement_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlDisableTexture", "rlDisableTexture_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlDisableTextureCubemap", "rlDisableTextureCubemap_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlDisableShader", "rlDisableShader_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlDisableFramebuffer", "rlDisableFramebuffer_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlGetActiveFramebuffer", "rlGetActiveFramebuffer_", "rlgl_bindings.h", [t|IO CUInt|], False),- ("c'rlEnableColorBlend", "rlEnableColorBlend_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlDisableColorBlend", "rlDisableColorBlend_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlEnableDepthTest", "rlEnableDepthTest_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlDisableDepthTest", "rlDisableDepthTest_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlEnableDepthMask", "rlEnableDepthMask_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlDisableDepthMask", "rlDisableDepthMask_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlEnableBackfaceCulling", "rlEnableBackfaceCulling_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlDisableBackfaceCulling", "rlDisableBackfaceCulling_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlEnableScissorTest", "rlEnableScissorTest_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlDisableScissorTest", "rlDisableScissorTest_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlEnableWireMode", "rlEnableWireMode_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlEnablePointMode", "rlEnablePointMode_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlDisableWireMode", "rlDisableWireMode_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlEnableSmoothLines", "rlEnableSmoothLines_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlDisableSmoothLines", "rlDisableSmoothLines_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlEnableStereoRender", "rlEnableStereoRender_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlDisableStereoRender", "rlDisableStereoRender_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlClearScreenBuffers", "rlClearScreenBuffers_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlCheckErrors", "rlCheckErrors_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlglClose", "rlglClose_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlDrawRenderBatchActive", "rlDrawRenderBatchActive_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlLoadDrawCube", "rlLoadDrawCube_", "rlgl_bindings.h", [t|IO ()|], False),- ("c'rlLoadDrawQuad", "rlLoadDrawQuad_", "rlgl_bindings.h", [t|IO ()|], False)+ [ ("c'rlMatrixMode", "rlMatrixMode_", "rlgl_bindings.h", [t|CInt -> IO ()|]),+ ("c'rlTranslatef", "rlTranslatef_", "rlgl_bindings.h", [t|CFloat -> CFloat -> CFloat -> IO ()|]),+ ("c'rlRotatef", "rlRotatef_", "rlgl_bindings.h", [t|CFloat -> CFloat -> CFloat -> CFloat -> IO ()|]),+ ("c'rlScalef", "rlScalef_", "rlgl_bindings.h", [t|CFloat -> CFloat -> CFloat -> IO ()|]),+ ("c'rlMultMatrixf", "rlMultMatrixf_", "rlgl_bindings.h", [t|Ptr CFloat -> IO ()|]),+ ("c'rlFrustum", "rlFrustum_", "rlgl_bindings.h", [t|CDouble -> CDouble -> CDouble -> CDouble -> CDouble -> CDouble -> IO ()|]),+ ("c'rlOrtho", "rlOrtho_", "rlgl_bindings.h", [t|CDouble -> CDouble -> CDouble -> CDouble -> CDouble -> CDouble -> IO ()|]),+ ("c'rlViewport", "rlViewport_", "rlgl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> IO ()|]),+ ("c'rlSetClipPlanes", "rlSetClipPlanes_", "rlgl_bindings.h", [t|CDouble -> CDouble -> IO ()|]),+ ("c'rlGetCullDistanceNear", "rlGetCullDistanceNear", "rlgl_bindings.h", [t|IO CDouble|]),+ ("c'rlGetCullDistanceFar", "rlGetCullDistanceFar", "rlgl_bindings.h", [t|IO CDouble|]),+ ("c'rlBegin", "rlBegin_", "rlgl_bindings.h", [t|CInt -> IO ()|]),+ ("c'rlVertex2i", "rlVertex2i_", "rlgl_bindings.h", [t|CInt -> CInt -> IO ()|]),+ ("c'rlVertex2f", "rlVertex2f_", "rlgl_bindings.h", [t|CFloat -> CFloat -> IO ()|]),+ ("c'rlVertex3f", "rlVertex3f_", "rlgl_bindings.h", [t|CFloat -> CFloat -> CFloat -> IO ()|]),+ ("c'rlTexCoord2f", "rlTexCoord2f_", "rlgl_bindings.h", [t|CFloat -> CFloat -> IO ()|]),+ ("c'rlNormal3f", "rlNormal3f_", "rlgl_bindings.h", [t|CFloat -> CFloat -> CFloat -> IO ()|]),+ ("c'rlColor4ub", "rlColor4ub_", "rlgl_bindings.h", [t|CUChar -> CUChar -> CUChar -> CUChar -> IO ()|]),+ ("c'rlColor3f", "rlColor3f_", "rlgl_bindings.h", [t|CFloat -> CFloat -> CFloat -> IO ()|]),+ ("c'rlColor4f", "rlColor4f_", "rlgl_bindings.h", [t|CFloat -> CFloat -> CFloat -> CFloat -> IO ()|]),+ ("c'rlEnableVertexArray", "rlEnableVertexArray_", "rlgl_bindings.h", [t|CUInt -> IO CBool|]),+ ("c'rlEnableVertexBuffer", "rlEnableVertexBuffer_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlEnableVertexBufferElement", "rlEnableVertexBufferElement_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlEnableVertexAttribute", "rlEnableVertexAttribute_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlDisableVertexAttribute", "rlDisableVertexAttribute_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlActiveTextureSlot", "rlActiveTextureSlot_", "rlgl_bindings.h", [t|CInt -> IO ()|]),+ ("c'rlEnableTexture", "rlEnableTexture_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlEnableTextureCubemap", "rlEnableTextureCubemap_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlTextureParameters", "rlTextureParameters_", "rlgl_bindings.h", [t|CUInt -> CInt -> CInt -> IO ()|]),+ ("c'rlCubemapParameters", "rlCubemapParameters_", "rlgl_bindings.h", [t|CUInt -> CInt -> CInt -> IO ()|]),+ ("c'rlEnableShader", "rlEnableShader_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlEnableFramebuffer", "rlEnableFramebuffer_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlActiveDrawBuffers", "rlActiveDrawBuffers_", "rlgl_bindings.h", [t|CInt -> IO ()|]),+ ("c'rlBlitFramebuffer", "rlBlitFramebuffer_", "rlgl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> CInt -> CInt -> CInt -> CInt -> CInt -> IO ()|]),+ ("c'rlBindFramebuffer", "rlBindFramebuffer_", "rlgl_bindings.h", [t|CUInt -> CUInt -> IO ()|]),+ ("c'rlColorMask", "rlColorMask_", "rlgl_bindings.h", [t|CBool -> CBool -> CBool -> CBool -> IO ()|]),+ ("c'rlSetCullFace", "rlSetCullFace_", "rlgl_bindings.h", [t|CInt -> IO ()|]),+ ("c'rlScissor", "rlScissor_", "rlgl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> IO ()|]),+ ("c'rlSetLineWidth", "rlSetLineWidth_", "rlgl_bindings.h", [t|CFloat -> IO ()|]),+ ("c'rlGetLineWidth", "rlGetLineWidth_", "rlgl_bindings.h", [t|IO CFloat|]),+ ("c'rlIsStereoRenderEnabled", "rlIsStereoRenderEnabled_", "rlgl_bindings.h", [t|IO CBool|]),+ ("c'rlClearColor", "rlClearColor_", "rlgl_bindings.h", [t|CUChar -> CUChar -> CUChar -> CUChar -> IO ()|]),+ ("c'rlSetBlendMode", "rlSetBlendMode_", "rlgl_bindings.h", [t|CInt -> IO ()|]),+ ("c'rlSetBlendFactors", "rlSetBlendFactors_", "rlgl_bindings.h", [t|CInt -> CInt -> CInt -> IO ()|]),+ ("c'rlSetBlendFactorsSeparate", "rlSetBlendFactorsSeparate_", "rlgl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> CInt -> CInt -> IO ()|]),+ ("c'rlglInit", "rlglInit_", "rlgl_bindings.h", [t|CInt -> CInt -> IO ()|]),+ ("c'rlLoadExtensions", "rlLoadExtensions_", "rlgl_bindings.h", [t|Ptr () -> IO ()|]),+ ("c'rlGetVersion", "rlGetVersion_", "rlgl_bindings.h", [t|IO CInt|]),+ ("c'rlSetFramebufferWidth", "rlSetFramebufferWidth_", "rlgl_bindings.h", [t|CInt -> IO ()|]),+ ("c'rlGetFramebufferWidth", "rlGetFramebufferWidth_", "rlgl_bindings.h", [t|IO CInt|]),+ ("c'rlSetFramebufferHeight", "rlSetFramebufferHeight_", "rlgl_bindings.h", [t|CInt -> IO ()|]),+ ("c'rlGetFramebufferHeight", "rlGetFramebufferHeight_", "rlgl_bindings.h", [t|IO CInt|]),+ ("c'rlGetTextureIdDefault", "rlGetTextureIdDefault_", "rlgl_bindings.h", [t|IO CUInt|]),+ ("c'rlGetShaderIdDefault", "rlGetShaderIdDefault_", "rlgl_bindings.h", [t|IO CUInt|]),+ ("c'rlGetShaderLocsDefault", "rlGetShaderLocsDefault_", "rlgl_bindings.h", [t|IO (Ptr CInt)|]),+ ("c'rlLoadRenderBatch", "rlLoadRenderBatch_", "rlgl_bindings.h", [t|CInt -> CInt -> IO (Ptr RLRenderBatch)|]),+ ("c'rlUnloadRenderBatch", "rlUnloadRenderBatch_", "rlgl_bindings.h", [t|Ptr RLRenderBatch -> IO ()|]),+ ("c'rlDrawRenderBatch", "rlDrawRenderBatch_", "rlgl_bindings.h", [t|Ptr RLRenderBatch -> IO ()|]),+ ("c'rlSetRenderBatchActive", "rlSetRenderBatchActive_", "rlgl_bindings.h", [t|Ptr RLRenderBatch -> IO ()|]),+ ("c'rlCheckRenderBatchLimit", "rlCheckRenderBatchLimit_", "rlgl_bindings.h", [t|CInt -> IO CBool|]),+ ("c'rlSetTexture", "rlSetTexture_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlLoadVertexArray", "rlLoadVertexArray_", "rlgl_bindings.h", [t|IO CUInt|]),+ ("c'rlLoadVertexBuffer", "rlLoadVertexBuffer_", "rlgl_bindings.h", [t|Ptr () -> CInt -> CBool -> IO CUInt|]),+ ("c'rlLoadVertexBufferElement", "rlLoadVertexBufferElement_", "rlgl_bindings.h", [t|Ptr () -> CInt -> CBool -> IO CUInt|]),+ ("c'rlUpdateVertexBuffer", "rlUpdateVertexBuffer_", "rlgl_bindings.h", [t|CUInt -> Ptr () -> CInt -> CInt -> IO ()|]),+ ("c'rlUpdateVertexBufferElements", "rlUpdateVertexBufferElements_", "rlgl_bindings.h", [t|CUInt -> Ptr () -> CInt -> CInt -> IO ()|]),+ ("c'rlUnloadVertexArray", "rlUnloadVertexArray_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlUnloadVertexBuffer", "rlUnloadVertexBuffer_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlSetVertexAttribute", "rlSetVertexAttribute_", "rlgl_bindings.h", [t|CUInt -> CInt -> CInt -> CBool -> CInt -> CInt -> IO ()|]),+ ("c'rlSetVertexAttributeDivisor", "rlSetVertexAttributeDivisor_", "rlgl_bindings.h", [t|CUInt -> CInt -> IO ()|]),+ ("c'rlSetVertexAttributeDefault", "rlSetVertexAttributeDefault_", "rlgl_bindings.h", [t|CInt -> Ptr () -> CInt -> CInt -> IO ()|]),+ ("c'rlDrawVertexArray", "rlDrawVertexArray_", "rlgl_bindings.h", [t|CInt -> CInt -> IO ()|]),+ ("c'rlDrawVertexArrayElements", "rlDrawVertexArrayElements_", "rlgl_bindings.h", [t|CInt -> CInt -> Ptr () -> IO ()|]),+ ("c'rlDrawVertexArrayInstanced", "rlDrawVertexArrayInstanced_", "rlgl_bindings.h", [t|CInt -> CInt -> CInt -> IO ()|]),+ ("c'rlDrawVertexArrayElementsInstanced", "rlDrawVertexArrayElementsInstanced_", "rlgl_bindings.h", [t|CInt -> CInt -> Ptr () -> CInt -> IO ()|]),+ ("c'rlLoadTexture", "rlLoadTexture_", "rlgl_bindings.h", [t|Ptr () -> CInt -> CInt -> CInt -> CInt -> IO CUInt|]),+ ("c'rlLoadTextureDepth", "rlLoadTextureDepth_", "rlgl_bindings.h", [t|CInt -> CInt -> CBool -> IO CUInt|]),+ ("c'rlLoadTextureCubemap", "rlLoadTextureCubemap_", "rlgl_bindings.h", [t|Ptr () -> CInt -> CInt -> IO CUInt|]),+ ("c'rlUpdateTexture", "rlUpdateTexture_", "rlgl_bindings.h", [t|CUInt -> CInt -> CInt -> CInt -> CInt -> CInt -> Ptr () -> IO ()|]),+ ("c'rlGetGlTextureFormats", "rlGetGlTextureFormats_", "rlgl_bindings.h", [t|CInt -> Ptr CUInt -> Ptr CUInt -> Ptr CUInt -> IO ()|]),+ ("c'rlGetPixelFormatName", "rlGetPixelFormatName_", "rlgl_bindings.h", [t|CUInt -> IO CString|]),+ ("c'rlUnloadTexture", "rlUnloadTexture_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlGenTextureMipmaps", "rlGenTextureMipmaps_", "rlgl_bindings.h", [t|CUInt -> CInt -> CInt -> CInt -> Ptr CInt -> IO ()|]),+ ("c'rlReadTexturePixels", "rlReadTexturePixels_", "rlgl_bindings.h", [t|CUInt -> CInt -> CInt -> CInt -> IO (Ptr ())|]),+ ("c'rlReadScreenPixels", "rlReadScreenPixels_", "rlgl_bindings.h", [t|CInt -> CInt -> IO (Ptr CUChar)|]),+ ("c'rlLoadFramebuffer", "rlLoadFramebuffer_", "rlgl_bindings.h", [t|IO CUInt|]),+ ("c'rlFramebufferAttach", "rlFramebufferAttach_", "rlgl_bindings.h", [t|CUInt -> CUInt -> CInt -> CInt -> CInt -> IO ()|]),+ ("c'rlFramebufferComplete", "rlFramebufferComplete_", "rlgl_bindings.h", [t|CUInt -> IO CBool|]),+ ("c'rlUnloadFramebuffer", "rlUnloadFramebuffer_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlLoadShaderCode", "rlLoadShaderCode_", "rlgl_bindings.h", [t|CString -> CString -> IO CUInt|]),+ ("c'rlCompileShader", "rlCompileShader_", "rlgl_bindings.h", [t|CString -> CInt -> IO CUInt|]),+ ("c'rlLoadShaderProgram", "rlLoadShaderProgram_", "rlgl_bindings.h", [t|CUInt -> CUInt -> IO CUInt|]),+ ("c'rlUnloadShaderProgram", "rlUnloadShaderProgram_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlGetLocationUniform", "rlGetLocationUniform_", "rlgl_bindings.h", [t|CUInt -> CString -> IO CInt|]),+ ("c'rlGetLocationAttrib", "rlGetLocationAttrib_", "rlgl_bindings.h", [t|CUInt -> CString -> IO CInt|]),+ ("c'rlSetUniform", "rlSetUniform_", "rlgl_bindings.h", [t|CInt -> Ptr () -> CInt -> CInt -> IO ()|]),+ ("c'rlSetUniformMatrix", "rlSetUniformMatrix_", "rlgl_bindings.h", [t|CInt -> Ptr Matrix -> IO ()|]),+ ("c'rlSetUniformMatrices", "rlSetUniformMatrices_", "rlgl_bindings.h", [t|CInt -> Ptr Matrix -> CInt -> IO ()|]),+ ("c'rlSetUniformSampler", "rlSetUniformSampler_", "rlgl_bindings.h", [t|CInt -> CUInt -> IO ()|]),+ ("c'rlSetShader", "rlSetShader_", "rlgl_bindings.h", [t|CUInt -> Ptr CInt -> IO ()|]),+ ("c'rlLoadComputeShaderProgram", "rlLoadComputeShaderProgram_", "rlgl_bindings.h", [t|CUInt -> IO CUInt|]),+ ("c'rlComputeShaderDispatch", "rlComputeShaderDispatch_", "rlgl_bindings.h", [t|CUInt -> CUInt -> CUInt -> IO ()|]),+ ("c'rlLoadShaderBuffer", "rlLoadShaderBuffer_", "rlgl_bindings.h", [t|CUInt -> Ptr () -> CInt -> IO CUInt|]),+ ("c'rlUnloadShaderBuffer", "rlUnloadShaderBuffer_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),+ ("c'rlUpdateShaderBuffer", "rlUpdateShaderBuffer_", "rlgl_bindings.h", [t|CUInt -> Ptr () -> CUInt -> CUInt -> IO ()|]),+ ("c'rlBindShaderBuffer", "rlBindShaderBuffer_", "rlgl_bindings.h", [t|CUInt -> CUInt -> IO ()|]),+ ("c'rlReadShaderBuffer", "rlReadShaderBuffer_", "rlgl_bindings.h", [t|CUInt -> Ptr () -> CUInt -> CUInt -> IO ()|]),+ ("c'rlCopyShaderBuffer", "rlCopyShaderBuffer_", "rlgl_bindings.h", [t|CUInt -> CUInt -> CUInt -> CUInt -> CUInt -> IO ()|]),+ ("c'rlGetShaderBufferSize", "rlGetShaderBufferSize_", "rlgl_bindings.h", [t|CUInt -> IO CUInt|]),+ ("c'rlBindImageTexture", "rlBindImageTexture_", "rlgl_bindings.h", [t|CUInt -> CUInt -> CInt -> CBool -> IO ()|]),+ ("c'rlGetMatrixModelview", "rlGetMatrixModelview_", "rlgl_bindings.h", [t|IO (Ptr Matrix)|]),+ ("c'rlGetMatrixProjection", "rlGetMatrixProjection_", "rlgl_bindings.h", [t|IO (Ptr Matrix)|]),+ ("c'rlGetMatrixTransform", "rlGetMatrixTransform_", "rlgl_bindings.h", [t|IO (Ptr Matrix)|]),+ ("c'rlGetMatrixProjectionStereo", "rlGetMatrixProjectionStereo_", "rlgl_bindings.h", [t|CInt -> IO (Ptr Matrix)|]),+ ("c'rlGetMatrixViewOffsetStereo", "rlGetMatrixViewOffsetStereo_", "rlgl_bindings.h", [t|CInt -> IO (Ptr Matrix)|]),+ ("c'rlSetMatrixProjection", "rlSetMatrixProjection_", "rlgl_bindings.h", [t|Ptr Matrix -> IO ()|]),+ ("c'rlSetMatrixModelview", "rlSetMatrixModelview_", "rlgl_bindings.h", [t|Ptr Matrix -> IO ()|]),+ ("c'rlSetMatrixProjectionStereo", "rlSetMatrixProjectionStereo_", "rlgl_bindings.h", [t|Ptr Matrix -> Ptr Matrix -> IO ()|]),+ ("c'rlSetMatrixViewOffsetStereo", "rlSetMatrixViewOffsetStereo_", "rlgl_bindings.h", [t|Ptr Matrix -> Ptr Matrix -> IO ()|]),+ ("c'rlGetPixelDataSize", "rlGetPixelDataSize", "rl_internal.h", [t|CInt -> CInt -> CInt -> IO CInt|]),+ ("c'rlPushMatrix", "rlPushMatrix_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlPopMatrix", "rlPopMatrix_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlLoadIdentity", "rlLoadIdentity_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlEnd", "rlEnd_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlDisableVertexArray", "rlDisableVertexArray_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlDisableVertexBuffer", "rlDisableVertexBuffer_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlDisableVertexBufferElement", "rlDisableVertexBufferElement_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlDisableTexture", "rlDisableTexture_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlDisableTextureCubemap", "rlDisableTextureCubemap_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlDisableShader", "rlDisableShader_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlDisableFramebuffer", "rlDisableFramebuffer_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlGetActiveFramebuffer", "rlGetActiveFramebuffer_", "rlgl_bindings.h", [t|IO CUInt|]),+ ("c'rlEnableColorBlend", "rlEnableColorBlend_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlDisableColorBlend", "rlDisableColorBlend_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlEnableDepthTest", "rlEnableDepthTest_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlDisableDepthTest", "rlDisableDepthTest_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlEnableDepthMask", "rlEnableDepthMask_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlDisableDepthMask", "rlDisableDepthMask_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlEnableBackfaceCulling", "rlEnableBackfaceCulling_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlDisableBackfaceCulling", "rlDisableBackfaceCulling_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlEnableScissorTest", "rlEnableScissorTest_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlDisableScissorTest", "rlDisableScissorTest_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlEnableWireMode", "rlEnableWireMode_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlEnablePointMode", "rlEnablePointMode_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlDisableWireMode", "rlDisableWireMode_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlEnableSmoothLines", "rlEnableSmoothLines_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlDisableSmoothLines", "rlDisableSmoothLines_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlEnableStereoRender", "rlEnableStereoRender_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlDisableStereoRender", "rlDisableStereoRender_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlClearScreenBuffers", "rlClearScreenBuffers_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlCheckErrors", "rlCheckErrors_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlglClose", "rlglClose_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlDrawRenderBatchActive", "rlDrawRenderBatchActive_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlLoadDrawCube", "rlLoadDrawCube_", "rlgl_bindings.h", [t|IO ()|]),+ ("c'rlLoadDrawQuad", "rlLoadDrawQuad_", "rlgl_bindings.h", [t|IO ()|]) ] ) @@ -1191,6 +1194,10 @@ -- | Set shader value matrix rlSetUniformMatrix :: Int -> Matrix -> IO () rlSetUniformMatrix locIndex mat = withFreeable mat (c'rlSetUniformMatrix (fromIntegral locIndex))++-- | Set shader value matrices+rlSetUniformMatrices :: Int -> [Matrix] -> IO ()+rlSetUniformMatrices locIndex mats = withFreeableArrayLen mats (\c m -> c'rlSetUniformMatrices (fromIntegral locIndex) m (fromIntegral c)) -- | Set shader value sampler rlSetUniformSampler :: Int -> Integer -> IO ()