Merge branch 'master' into compute-shaders
94
BINDINGS.md
|
|
@ -8,84 +8,101 @@ Some people ported raylib to other languages in form of bindings or wrappers to
|
|||
|:------------------:|:-------------: | :--------:|----------------------------------------------------------------------|
|
||||
| raylib | **3.7** | [C/C++](https://en.wikipedia.org/wiki/C_(programming_language)) | https://github.com/raysan5/raylib |
|
||||
| Raylib-cs | 3.7 | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | https://github.com/ChrisDill/Raylib-cs |
|
||||
| raylib-cppsharp | 2.5 | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | https://github.com/phxvyper/raylib-cppsharp |
|
||||
| raylib-boo | 3.7 | [Boo](http://boo-language.github.io/) | https://github.com/Rabios/raylib-boo |
|
||||
| dray | 3.5 | [D](https://dlang.org/) | https://github.com/xdrie/dray |
|
||||
| raylib-go | 4.0-dev | [Go](https://golang.org/) | https://github.com/gen2brain/raylib-go |
|
||||
| raylib-rs | 3.5 | [Rust](https://www.rust-lang.org/) | https://github.com/deltaphc/raylib-rs |
|
||||
| raylib-lua | 3.7 | [Lua](http://www.lua.org/) | https://github.com/TSnake41/raylib-lua |
|
||||
| raylua | 3.7 | [Lua](http://www.lua.org/) | https://github.com/Rabios/raylua |
|
||||
| nelua-raylib | 3.7 | [nelua](https://nelua.io/) | https://github.com/AKDev21/nelua-raylib |
|
||||
| NimraylibNow! | 3.7 | [Nim](https://nim-lang.org/) | https://github.com/greenfork/nimraylib_now |
|
||||
| raylib-Forever | auto | [Nim](https://nim-lang.org/) | https://github.com/Guevara-chan/Raylib-Forever |
|
||||
| Ray4Laz | 3.7 | [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language)) | https://github.com/GuvaCode/Ray4Laz |
|
||||
| pyraylib | 3.7 | [Python](https://www.python.org/) | https://github.com/Ho011/pyraylib |
|
||||
| raylib-python-cffi | 3.7 | [Python](https://www.python.org/) | https://github.com/electronstudio/raylib-python-cffi |
|
||||
| jaylib | 3.7 | [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) | https://github.com/electronstudio/jaylib/ |
|
||||
| node-raylib | 3.5 | [Node.js](https://nodejs.org/en/) | https://github.com/RobLoach/node-raylib |
|
||||
| raylib-v7 | 3.5 | [JavaScript (v7)](https://en.wikipedia.org/wiki/JavaScript) | https://github.com/Rabios/raylib-v7 |
|
||||
| raylib-php | 3.5 | [PHP](https://en.wikipedia.org/wiki/PHP) | https://github.com/joseph-montanez/raylib-php |
|
||||
| raylib-phpcpp | 3.5 | [PHP](https://en.wikipedia.org/wiki/PHP) | https://github.com/oraoto/raylib-phpcpp |
|
||||
| raylib-factor | 3.5 | [Factor](https://factorcode.org/) | https://github.com/ArnautDaniel/raylib-factor |
|
||||
| gforth-raylib | 3.5 | [Gforth](https://gforth.org/) | https://github.com/ArnautDaniel/gforth-raylib |
|
||||
| hxRaylib | 3.7 | [Haxe](https://haxe.org/) | https://github.com/ForeignSasquatch/hxRaylib |
|
||||
| raylib-wren | 3.7 | [Wren](http://wren.io/) | https://github.com/TSnake41/raylib-wren |
|
||||
| raylib_odin_bindings | 4.0-dev | [Odin](https://odin-lang.org/) | https://github.com/Deathbat2190/raylib_odin_bindings |
|
||||
| raylib.v | 3.7 | [V](https://vlang.io/) | https://github.com/irishgreencitrus/raylib.v |
|
||||
| raylib-ocaml | 3.7 | [OCaml](https://ocaml.org/) | https://github.com/tjammer/raylib-ocaml |
|
||||
| raylib-swift | 3.7 | [Swift](https://swift.org/) | https://github.com/STREGAsGate/Raylib |
|
||||
| hb-raylib | 3.5 | [Harbour](https://harbour.github.io) | https://github.com/MarcosLeonardoMendezGerencir/hb-raylib |
|
||||
| Relib | 3.5 | [ReCT](https://github.com/RedCubeDev-ByteSpace/ReCT) | https://github.com/RedCubeDev-ByteSpace/Relib |
|
||||
| rayex | 3.7 | [elixir](https://elixir-lang.org/) | https://github.com/shiryel/rayex |
|
||||
| kaylib | 3.7 | [Kotlin/native](https://kotlinlang.org) | https://github.com/electronstudio/kaylib |
|
||||
| s48-raylib | 3.7 | [Scheme48](https://s48.org) | https://github.com/rc-05/s48-raylib |
|
||||
|
||||
### Utility Wrapers
|
||||
These are utility wrappers for specific languages, they are not required to use raylib in the language but may adapt the raylib API to be more inline with the language's pardigm.
|
||||
| name | raylib version | language | repo |
|
||||
|:------------------:|:-------------: | :--------:|----------------------------------------------------------------------|
|
||||
| raylib-cpp | 3.7 | [C++](https://en.wikipedia.org/wiki/C%2B%2B) | https://github.com/robloach/raylib-cpp |
|
||||
|
||||
### Older or Unmaintained Language Bindings
|
||||
These are older raylib bindings that are more than 2 versions old or have not been maintained.
|
||||
| name | raylib version | language | repo |
|
||||
|:------------------:|:-------------: | :--------:|----------------------------------------------------------------------|
|
||||
| raylib-cppsharp | 2.5 | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | https://github.com/phxvyper/raylib-cppsharp |
|
||||
| RaylibFS | 2.5 | [F#](https://fsharp.org/) | https://github.com/dallinbeutler/RaylibFS |
|
||||
| raylib_d | 2.5 | [D](https://dlang.org/) | https://github.com/Sepheus/raylib_d |
|
||||
| raylib-d | 3.0 | [D](https://dlang.org/) | https://github.com/onroundit/raylib-d |
|
||||
| bindbc-raylib | 3.0 | [D](https://dlang.org/) | https://github.com/o3o/bindbc-raylib |
|
||||
| dray | 3.5 | [D](https://dlang.org/) | https://github.com/xdrie/dray |
|
||||
| raylib-go | 3.8-dev | [Go](https://golang.org/) | https://github.com/gen2brain/raylib-go |
|
||||
| go-raylib | 3.5 | [Go](https://golang.org/) | https://github.com/chunqian/go-raylib |
|
||||
| raylib-goplus | 2.6-dev | [Go](https://golang.org/) | https://github.com/Lachee/raylib-goplus |
|
||||
| ray-go | 2.6-dev | [Go](https://golang.org/) | https://github.com/hecate-tech/ray-go |
|
||||
| go-raylib | 3.5 | [Go](https://golang.org/) | https://github.com/chunqian/go-raylib |
|
||||
| raylib-rs | 3.5 | [Rust](https://www.rust-lang.org/) | https://github.com/deltaphc/raylib-rs |
|
||||
| raylib-lua | 1.7 | [Lua](http://www.lua.org/) | https://github.com/raysan5/raylib-lua |
|
||||
| raylib-lua-ffi | 2.0 | [Lua](http://www.lua.org/) | https://github.com/raysan5/raylib/issues/693 |
|
||||
| raylib-lua-sol | 2.5 | [Lua](http://www.lua.org/) | https://github.com/RobLoach/raylib-lua-sol |
|
||||
| raylib-lua | 3.7 | [Lua](http://www.lua.org/) | https://github.com/TSnake41/raylib-lua |
|
||||
| raylib-luamore | 3.0 | [Lua](http://www.lua.org/) | https://github.com/HDPLocust/raylib-luamore |
|
||||
| raylua | 3.7 | [Lua](http://www.lua.org/) | https://github.com/Rabios/raylua |
|
||||
| LuaJIT-Raylib | 2.6 | [Lua](http://www.lua.org/) | https://github.com/Bambofy/LuaJIT-Raylib |
|
||||
| raylib-nelua | 3.7 | [nelua](https://nelua.io/) | https://github.com/edubart/nelua-decl/tree/main/libs/raylib |
|
||||
| raylib-lua-sol | 2.5 | [Lua](http://www.lua.org/) | https://github.com/RobLoach/raylib-lua-sol |
|
||||
| raylib-lua-ffi | 2.0 | [Lua](http://www.lua.org/) | https://github.com/raysan5/raylib/issues/693 |
|
||||
| raylib-lua | 1.7 | [Lua](http://www.lua.org/) | https://github.com/raysan5/raylib-lua |
|
||||
| raylib-nelua | 3.0 | [Nelua](https://nelua.io/) | https://github.com/Andre-LA/raylib-nelua |
|
||||
| raylib-Nim | 1.7 | [Nim](https://nim-lang.org/) | https://gitlab.com/define-private-public/raylib-Nim |
|
||||
| raylib-nim | 2.0 | [Nim](https://nim-lang.org/) | https://github.com/Skrylar/raylib-nim |
|
||||
| raylib-Forever | 3.1-dev | [Nim](https://nim-lang.org/) | https://github.com/Guevara-chan/Raylib-Forever |
|
||||
| raylib-Nim | 1.7 | [Nim](https://nim-lang.org/) | https://gitlab.com/define-private-public/raylib-Nim |
|
||||
| nim-raylib | 3.1-dev | [Nim](https://nim-lang.org/) | https://github.com/tomc1998/nim-raylib |
|
||||
| NimraylibNow! | 3.7 | [Nim](https://nim-lang.org/) | https://github.com/greenfork/nimraylib_now |
|
||||
| raylib-haskell | 2.0 | [Haskell](https://www.haskell.org/) | https://github.com/DevJac/raylib-haskell |
|
||||
| raylib-cr | 2.5-dev | [Crystal](https://crystal-lang.org/) | https://github.com/AregevDev/raylib-cr |
|
||||
| cray | 1.8 | [Crystal](https://crystal-lang.org/) | https://gitlab.com/Zatherz/cray |
|
||||
| raylib.cr | 2.0 | [Crystal](https://crystal-lang.org/) | https://github.com/sam0x17/raylib.cr |
|
||||
| raylib-pascal | 2.0 | [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language)) | https://github.com/drezgames/raylib-pascal |
|
||||
| cray | 1.8 | [Crystal](https://crystal-lang.org/) | https://gitlab.com/Zatherz/cray |
|
||||
| raylib-pas | 3.0 | [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language)) | https://github.com/tazdij/raylib-pas |
|
||||
| Ray4Laz | 3.7 | [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language)) | https://github.com/GuvaCode/Ray4Laz |
|
||||
| raylib-pascal | 2.0 | [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language)) | https://github.com/drezgames/raylib-pascal |
|
||||
| Graphics-Raylib | 1.4 | [Perl](https://www.perl.org/) | https://github.com/athreef/Graphics-Raylib |
|
||||
| raylib-ruby-ffi | 2.0 | [Ruby](https://www.ruby-lang.org/en/) | https://github.com/D3nX/raylib-ruby-ffi |
|
||||
| raylib-ruby | 2.6 | [Ruby](https://www.ruby-lang.org/en/) | https://github.com/a0/raylib-ruby |
|
||||
| raylib-ruby-ffi | 2.0 | [Ruby](https://www.ruby-lang.org/en/) | https://github.com/D3nX/raylib-ruby-ffi |
|
||||
| raylib-mruby | 2.5-dev | [mruby](https://github.com/mruby/mruby) | https://github.com/lihaochen910/raylib-mruby |
|
||||
| pyraylib | 3.7 | [Python](https://www.python.org/) | https://github.com/Ho011/pyraylib |
|
||||
| raylib-py | 2.0 | [Python](https://www.python.org/) | https://github.com/overdev/raylib-py |
|
||||
| raylib-python-cffi | 3.7 | [Python](https://www.python.org/) | https://github.com/electronstudio/raylib-python-cffi |
|
||||
| raylib-py-ctbg | 2.6 | [Python](https://www.python.org/) | https://github.com/overdev/raylib-py-ctbg |
|
||||
| jaylib | 3.7 | [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) | https://github.com/electronstudio/jaylib/ |
|
||||
| raylib-py | 2.0 | [Python](https://www.python.org/) | https://github.com/overdev/raylib-py |
|
||||
| raylib-java | 2.0 | [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) | https://github.com/XoanaIO/raylib-java |
|
||||
| raylib-j | 3.5 | [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) | https://github.com/CreedVI/Raylib-J |
|
||||
| clj-raylib | 3.0 | [Clojure](https://clojure.org/) | https://github.com/lsevero/clj-raylib |
|
||||
| node-raylib | 3.5 | [Node.js](https://nodejs.org/en/) | https://github.com/RobLoach/node-raylib |
|
||||
| QuickJS-raylib | 3.0 | [QuickJS](https://bellard.org/quickjs/) | https://github.com/sntg-p/QuickJS-raylib |
|
||||
| raylib-duktape | 2.6 | [JavaScript (Duktape)](https://en.wikipedia.org/wiki/JavaScript) | https://github.com/RobLoach/raylib-duktape |
|
||||
| raylib-v7 | 3.5 | [JavaScript (v7)](https://en.wikipedia.org/wiki/JavaScript) | https://github.com/Rabios/raylib-v7 |
|
||||
| raylib-chaiscript | 2.6 | [ChaiScript](http://chaiscript.com/) | https://github.com/RobLoach/raylib-chaiscript |
|
||||
| raylib-squirrel | 2.5 | [Squirrel](http://www.squirrel-lang.org/) | https://github.com/RobLoach/raylib-squirrel |
|
||||
| racket-raylib-2d | 2.5 | [Racket](https://racket-lang.org/) | https://github.com/arvyy/racket-raylib-2d |
|
||||
| raylib-php | 3.5 | [PHP](https://en.wikipedia.org/wiki/PHP) | https://github.com/joseph-montanez/raylib-php |
|
||||
| raylib-php-ffi | 2.4-dev | [PHP](https://en.wikipedia.org/wiki/PHP) | https://github.com/oraoto/raylib-php-ffi |
|
||||
| raylib-phpcpp | 3.5 | [PHP](https://en.wikipedia.org/wiki/PHP) | https://github.com/oraoto/raylib-phpcpp |
|
||||
| raylib-factor | 3.5 | [Factor](https://factorcode.org/) | https://github.com/ArnautDaniel/raylib-factor |
|
||||
| gforth-raylib | 3.5 | [Gforth](https://gforth.org/) | https://github.com/ArnautDaniel/gforth-raylib |
|
||||
| raylib-haxe | 2.4 | [Haxe](https://haxe.org/) | https://github.com/ibilon/raylib-haxe |
|
||||
| hxRaylib | 3.7 | [Haxe](https://haxe.org/) | https://github.com/ForeignSasquatch/hxRaylib |
|
||||
| ringraylib | 2.6 | [Ring](http://ring-lang.sourceforge.net/) | https://github.com/ringpackages/ringraylib |
|
||||
| cl-raylib | 3.0 | [Common Lisp](https://common-lisp.net/) | https://github.com/longlene/cl-raylib |
|
||||
| raylib-scm | 2.5 | [Chicken Scheme](https://www.call-cc.org/) | https://github.com/yashrk/raylib-scm |
|
||||
| raylib-chibi | 2.5 | [Chibi-Scheme](https://github.com/ashinn/chibi-scheme) | https://github.com/VincentToups/raylib-chibi |
|
||||
| raylib-gambit-scheme | 3.1-dev | [Gambit Scheme](https://github.com/gambit/gambit) | https://github.com/georgjz/raylib-gambit-scheme |
|
||||
| Euraylib | 3.0 | [Euphoria](https://openeuphoria.org/) | https://github.com/gAndy50/Euraylib |
|
||||
| raylib-wren | 3.7 | [Wren](http://wren.io/) | https://github.com/TSnake41/raylib-wren |
|
||||
| raylib-odin | 3.0 | [Odin](https://odin-lang.org/) | https://github.com/kevinw/raylib-odin |
|
||||
| raylib_odin_bindings | 3.8+ | [Odin](https://odin-lang.org/) | https://github.com/Deathbat2190/raylib_odin_bindings |
|
||||
| vraylib | 3.5 | [V](https://vlang.io/) | https://github.com/waotzi/vraylib |
|
||||
| raylib-zig | 3.0 | [Zig](https://ziglang.org/) | https://github.com/Not-Nik/raylib-zig |
|
||||
| raylib-jai | 3.1-dev | [Jai](https://github.com/BSVino/JaiPrimer/blob/master/JaiPrimer.md) | https://github.com/kevinw/raylib-jai |
|
||||
| ray.zig | 2.5 | [Zig](https://ziglang.org/) | https://github.com/BitPuffin/zig-raylib-experiments |
|
||||
| raylib-Ada | 3.0 | [Ada](https://www.adacore.com/about-ada) | https://github.com/mimo/raylib-Ada |
|
||||
| jaylib | 3.0 | [Janet](https://janet-lang.org/) | https://github.com/janet-lang/jaylib |
|
||||
| raykit | ? | [Kit](https://www.kitlang.org/) | https://github.com/Gamerfiend/raykit |
|
||||
| vraylib | 3.5 | [V](https://vlang.io/) | https://github.com/waotzi/vraylib |
|
||||
| raylib.v | 3.7 | [V](https://vlang.io/) | https://github.com/irishgreencitrus/raylib.v |
|
||||
| ray.mod | 3.0 | [BlitzMax](https://blitzmax.org/) | https://github.com/bmx-ng/ray.mod |
|
||||
| raylib-ocaml | 3.7 | [OCaml](https://ocaml.org/) | https://github.com/tjammer/raylib-ocaml |
|
||||
| raylib-mosaic | 3.0 | [Mosaic](https://github.com/sal55/langs/tree/master/Mosaic) | https://github.com/pluckyporcupine/raylib-mosaic |
|
||||
| raylib-xdpw | 2.6 | [XD Pascal](https://github.com/vtereshkov/xdpw) | https://github.com/vtereshkov/raylib-xdpw |
|
||||
| raylib-carp | 3.0 | [Carp](https://github.com/carp-lang/Carp) | https://github.com/pluckyporcupine/raylib-carp |
|
||||
|
|
@ -94,19 +111,10 @@ Some people ported raylib to other languages in form of bindings or wrappers to
|
|||
| raylib-smallBasic | 3.1-dev | [SmallBASIC](https://github.com/smallbasic/SmallBASIC) | https://github.com/smallbasic/smallbasic.plugins/tree/master/raylib |
|
||||
| raylib-ats2 | 3.0 | [ATS2](http://www.ats-lang.org/) | https://github.com/mephistopheles-8/raylib-ats2 |
|
||||
| raylib-beef | 3.0 | [Beef](https://www.beeflang.org/) | https://github.com/M0n7y5/raylib-beef |
|
||||
| raylib-swift | 3.7 | [Swift](https://swift.org/) | https://github.com/STREGAsGate/Raylib |
|
||||
| raylib-never | 3.0 | [Never](https://github.com/never-lang/never) | https://github.com/never-lang/raylib-never |
|
||||
| hb-raylib | 3.5 | [Harbour](https://harbour.github.io) | https://github.com/MarcosLeonardoMendezGerencir/hb-raylib |
|
||||
| Relib | 3.5 | [ReCT](https://github.com/RedCubeDev-ByteSpace/ReCT) | https://github.com/RedCubeDev-ByteSpace/Relib |
|
||||
| rayex | 3.7 | [elixir](https://elixir-lang.org/) | https://github.com/shiryel/rayex |
|
||||
| raylib.cbl | 2.0 | [COBOL](https://en.wikipedia.org/wiki/COBOL) | *[code examples](https://github.com/Martinfx/Cobol/tree/master/OpenCobol/Games/raylib)* |
|
||||
| kaylib | 3.7 | [Kotlin/native](https://kotlinlang.org) | https://github.com/electronstudio/kaylib |
|
||||
|
||||
### Utility Wrapers
|
||||
|
||||
| name | raylib version | language | repo |
|
||||
|:------------------:|:-------------: | :--------:|----------------------------------------------------------------------|
|
||||
| raylib-cpp | 3.7 | [C++](https://en.wikipedia.org/wiki/C%2B%2B) | https://github.com/robloach/raylib-cpp |
|
||||
|
||||
Missing some language or wrapper? Feel free to create a new one! :)
|
||||
|
||||
|
|
|
|||
122
CHANGELOG
|
|
@ -12,7 +12,127 @@ KEY CHANGES:
|
|||
-
|
||||
|
||||
Detailed changes:
|
||||
|
||||
[core] ADDED: Support canvas resizing on web (#1840) by @skylersaleh
|
||||
[core] ADDED: GetMouseDelta() (#1832) by @adricoin2010
|
||||
[core] ADDED: Support additional mouse buttons (#1753) by @lambertwang
|
||||
[core] ADDED: SetRandomSeed() (#1994) by @TommiSinivuo
|
||||
[core] ADDED: GetTouchPointId() #1972
|
||||
[core] RENAMED: SwapBuffers() to SwapScreenBuffer()
|
||||
[core] RENAMED: Wait() to WaitTime()
|
||||
[core] RENAMED: RayHitInfo to RayCollision (#1781)
|
||||
[core] RENAMED: GetRayCollisionGround() to GetRayCollisionQuad() (#1781)
|
||||
[core] REVIEWED: Support mouse wheel on x-axis (#1948)
|
||||
[core] REVIEWED: DisableCursor() on web by registering an empty mouse click event function in emscripten (#1900) by @grenappels
|
||||
[core] REVIEWED: LoadShader() and default locations and descriptions
|
||||
[core] REVIEWED: LoadShaderFromMemory() (#1851) by @Ruminant
|
||||
[core] REVIEWED: WaitTime(), avoid global variables dependency to make the function is self-contained (#1841)
|
||||
[core] REVIEWED: SetWindowSize() to work on web (#1847) by @nikki93
|
||||
[core] REVIEWED: Raspberry RPI/DRM keyboard blocking render loop (#1879) @luizpestana
|
||||
[core] REVIEWED: Android multi-touch (#1869) by @humbe
|
||||
[core] REVIEWED: Implemented GetGamepadName() for emscripten by @nbarkhina
|
||||
[core] REVIEWED: HighDPI support (#1987) by @ArnaudValensi
|
||||
[rlgl] ADDED: rlUpdateVertexBufferElements() (#1915)
|
||||
[rlgl] ADDED: rlActiveDrawBuffers() (#1911)
|
||||
[rlgl] ADDED: rlEnableColorBlend()/rlDisableColorBlend()
|
||||
[rlgl] ADDED: rlGetPixelFormatName()
|
||||
[rlgl] REVIEWED: rlUpdateVertexBuffer (#1914) by @630Studios
|
||||
[rlgl] REVIEWED: rlDrawVertexArrayElements() (#1891)
|
||||
[rlgl] REVIEWED: Wrong normal matrix calculation (#1870)
|
||||
[raymath] ADDED: Vector3Angle()
|
||||
[raymath] REVIEWED: QuaternionFromAxisAngle() (#1892)
|
||||
[raymath] REVIEWED: QuaternionToMatrix() returning transposed result. (#1793) by @object71
|
||||
[shapes] ADDED: RenderPolyLinesEx() (#1758) by @lambertwang
|
||||
[shapes] ADDED: DrawLineBezierCubic() (#2021) by @SAOMDVN
|
||||
[textures] ADDED: GetImageColor() #2024
|
||||
[textures] REMOVED: GenImagePerlinNoise()
|
||||
[textures] RENAMED: GetTextureData() to LoadImageFromTexture()
|
||||
[textures] RENAMED: GetScreenData() to LoadImageFromScreen()
|
||||
[textures] REVIEWED: ExportImage() to use SaveFileData() (#1779)
|
||||
[textures] REVIEWED: LoadImageAnim() #2005
|
||||
[text] ADDED: Security check in case of not valid font
|
||||
[text] ADDED: `GetGlyphInfo()` to get glyph info for a specific codepoint
|
||||
[text] ADDED: `GetGlyphAtlasRec()` to get glyph rectangle within the generated font atlas
|
||||
[text] ADDED: DrawTextPro() with text rotation support, WARNING: DrawTextPro() requires including `rlgl.h`, before it was only dependant on `textures` module.
|
||||
[text] ADDED: UnloadCodepoints() to safely free loaded codepoints
|
||||
[text] REMOVED: DrawTextRec() and DrawTextRecEx(), moved to example, those functions could be very specific depending on user needs so it's better to give the user the full source in case of special requirements instead of allowing a function with +10 input parameters.
|
||||
[text] RENAMED: struct `CharInfo` to `GlyphInfo`, actually that's the correct naming for the data contained. It contains the character glyph metrics and the glyph image; in the past it also contained rectangle within the font atlas but that data has been moved to `Font` struct directly, so, `GlyphInfo` is a more correct name.
|
||||
[text] RENAMED: `CodepointToUtf8()` to `CodepointToUTF8()`, capitalization of UTF-8 is the correct form, it would also require de hyphen but it can be omitted in this case.
|
||||
[text] RENAMED: `TextToUtf8()` to `TextCodepointsToUTF8` for consistency and more detail on the functionality.
|
||||
[text] RENAMED: GetCodepoints() to LoadCodepoints(), now codepoint array data is loaded dynamically instead of reusing a limited static buffer.
|
||||
[text] RENAMED: GetNextCodepoint() to GetCodepoint()
|
||||
[models] ADDED: MagikaVoxel VOX models loading
|
||||
[models] ADDED: GenMeshCone() (#1903)
|
||||
[models] ADDED: GetModelBoundingBox()
|
||||
[models] ADDED: DrawBillboardPro() (#1759) by @nobytesgiven
|
||||
[models] ADDED: DrawCubeTextureRec() (#2001) by @tdgroot
|
||||
[models] ADDED: DrawCylinderEx() and DrawCylinderWiresEx() (#2049) by @Horrowind
|
||||
[models] REMOVED: DrawBillboardEx()
|
||||
[models] RENAMED: MeshBoundingBox() to GetMeshBoundingBox()
|
||||
[models] RENAMED: MeshTangents() to GenMeshTangents()
|
||||
[models] RENAMED: MeshBinormals() to GenMeshBinormals()
|
||||
[models] REVIEWED: GenMeshTangents() (#1877) by @630Studios
|
||||
[models] REVIEWED: CheckCollisionBoxSphere() by @Crydsch
|
||||
[models] REVIEWED: GetRayCollisionQuad() by @Crydsch
|
||||
[models] REVIEWED: LoadGLTF(), fixed missing transformations and nonroot skinning by @MrDiver
|
||||
[models] REVIEWED: Decouple DrawMesh() and DrawMeshInstanced() (#1958)
|
||||
[models] REVIEWED: Support vertex color attribute for GLTF and IQM (#1790) by @object71
|
||||
[models] REVIEWED: DrawBillboardPro() (#1941) by @GithubPrankster
|
||||
[models] REDESIGNED: Major review of glTF loading functionality (#1849) by @object71
|
||||
[audio] ADDED: SeekMusicStream() (#2006) by @GithubPrankster
|
||||
[audio] REMOVED: GetAudioStreamBufferSizeDefault()
|
||||
[audio] RENAMED: InitAudioStream() to LoadAudioStream()
|
||||
[audio] RENAMED: CloseAudioStream() to UnloadAudioStream()
|
||||
[audio] RENAMED: IsMusicPlaying() to IsMusicStreamPlaying()
|
||||
[audio] REVIEWED: ExportWaveAsCode()
|
||||
[audio] REDESIGNED: Use frameCount on audio instead of sampleCount
|
||||
[utils] REVIEWED: exit() on LOG_FATAL instead of LOG_ERROR (#1796)
|
||||
[examples] ADDED: core_custom_frame_control
|
||||
[examples] ADDED: core_basic_screen_manager
|
||||
[examples] ADDED: core_split_screen (#1806) by @JeffM2501
|
||||
[examples] ADDED: core_2d_camera_smooth_pixelperfect (#1771) by @NotManyIdeasDev
|
||||
[examples] ADDED: shaders_texture_outline (#1883) by @GoldenThumbs
|
||||
[examples] ADDED: models_loading_vox (#1940) by @procfxgen
|
||||
[examples] REMOVED: models_material_pbr
|
||||
[examples] REMOVED: models_gltf_animation
|
||||
[examples] REVIEWED: core_3d_picking
|
||||
[examples] REVIEWED: core_input_mouse
|
||||
[examples] REVIEWED: core_vr_simulator, RenderTexture usage
|
||||
[examples] REVIEWED: core_window_letterbox, RenderTexture usage
|
||||
[examples] REVIEWED: shapes_basic_shapes
|
||||
[examples] REVIEWED: shapes_logo_raylib_anim
|
||||
[examples] REVIEWED: textures_to_image
|
||||
[examples] REVIEWED: text_rectangle_bounds
|
||||
[examples] REVIEWED: text_unicode
|
||||
[examples] REVIEWED: text_draw_3d
|
||||
[examples] REVIEWED: models_loading
|
||||
[examples] REVIEWED: models_skybox (#1792) (#1778)
|
||||
[examples] REVIEWED: models_mesh_picking
|
||||
[examples] REVIEWED: models_material_pbr
|
||||
[examples] REVIEWED: models_rlgl_solar_system
|
||||
[examples] REVIEWED: shaders_custom_uniform, RenderTexture usage
|
||||
[examples] REVIEWED: shaders_eratosthenes, RenderTexture usage
|
||||
[examples] REVIEWED: shaders_julia_set, RenderTexture usage
|
||||
[examples] REVIEWED: shaders_postprocessing, RenderTexture usage
|
||||
[examples] REVIEWED: shaders_basic_lighting, simplified (#1865)
|
||||
[examples] REVIEWED: audio_raw_stream.c
|
||||
[examples] REVIEWED: raudio_standalone
|
||||
[examples] REVIEWED: raylib_opengl_interop
|
||||
[examples] REVIEWED: rlgl_standalone.c
|
||||
[examples] REVIEWED: Resources licenses
|
||||
[examples] REVIEWED: models resources reorganization
|
||||
[build] ADDED: Zig build file (#2014) by @TommiSinivuo
|
||||
[build] ADDED: Android VS2019 solution (#2013) by @Kronka
|
||||
[build] REMOVED: VS2017 project, outdated
|
||||
[build] RENAMED: All raylib modules prefixed with 'r' (core -> rcore)
|
||||
[build] RENAMED: SUPPORT_MOUSE_CURSOR_NATIVE to SUPPORT_MOUSE_CURSOR_POINT
|
||||
[build] REVIEWED: examples/examples_template.c
|
||||
[build] REVIEWED: Makefile to latest Emscripten SDK r23
|
||||
[build] REVIEWED: Makefile for latest Android NDK r32 LTS
|
||||
[build] REVIEWED: raylib resource files
|
||||
[build] Moved some extra raylib libraries to /extras/ directory
|
||||
[*] UPDATED: Multiple bindings to latest version
|
||||
[*] UPDATED: All external libraries to latest versions
|
||||
[*] Multiple code improvements and fixes by multiple contributors!
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
Release: raylib 3.7 (26 April 2021)
|
||||
|
|
|
|||
34
SPONSORS.md
|
|
@ -4,18 +4,11 @@
|
|||
|
||||
The following people is currently [**sponsoring raylib**](https://github.com/sponsors/raysan5) with a generous donation to allow improving and growing the project!
|
||||
|
||||
Note that Sponsors donations vary between sponsors, I just decided not to make any distinction while listing them.
|
||||
|
||||
- Eric J. ([@ProfJski](https://github.com/ProfJski))
|
||||
- devdad ([@devdad](https://github.com/devdad))
|
||||
- Zach Geis ([@zacgeis](https://github.com/zacgeis))
|
||||
- minirop ([@minirop](https://github.com/minirop))
|
||||
- Daniel Gómez ([@Koocachookies](https://github.com/Koocachookies))
|
||||
- Sergio ([@anidealgift](https://github.com/anidealgift))
|
||||
- Marc Agüera ([@maguera93](https://github.com/maguera93))
|
||||
- Pau Fernández ([@pauek](https://github.com/pauek))
|
||||
- Snowminx ([@Gamerfiend](https://github.com/Gamerfiend))
|
||||
- NimbusFox ([@NimbusFox](https://github.com/NimbusFox))
|
||||
- Robin Mattheussen ([@romatthe](https://github.com/romatthe))
|
||||
- Grant Haywood ([@cinterloper](https://github.com/cinterloper))
|
||||
- Terry Nguyen ([@terrehbyte](https://github.com/terrehbyte))
|
||||
|
|
@ -25,10 +18,17 @@ Note that Sponsors donations vary between sponsors, I just decided not to make a
|
|||
- cob ([@majorcob](https://github.com/majorcob))
|
||||
- Samuel Batista ([@gamedevsam](https://github.com/gamedevsam))
|
||||
- Merlyn Morgan-Graham ([@kavika13](https://github.com/kavika13))
|
||||
- Toby4213 ([@Toby4213](https://github.com/Toby4213))
|
||||
- linus ([@hochbaum](https://github.com/hochbaum))
|
||||
- Nawarian ([@nawarian](https://github.com/nawarian) - [thephp.website](https://thephp.website/))
|
||||
|
||||
- kenzie ([@sme-ek](https://github.com/sme-ek))
|
||||
- Allan Regush ([@AllanRegush](https://github.com/AllanRegush))
|
||||
- Jeffery Myers ([@JeffM2501](https://github.com/ProfJski))
|
||||
- Ryan Roden-Corrent ([@rcorre](https://github.com/ProfJski))
|
||||
- michaelfiber ([@michaelfiber](https://github.com/ProfJski))
|
||||
- Nikhilesh S ([@nikki93](https://github.com/ProfJski))
|
||||
- kevinabraun ([@kevinabraun](https://github.com/ProfJski))
|
||||
- Matthew Owens ([@MatthewOwens](https://github.com/ProfJski))
|
||||
- Tim Eilers ([@eilerstim](https://github.com/ProfJski))
|
||||
|
||||
### Past raylib GitHub Sponsors
|
||||
|
||||
|
|
@ -49,10 +49,20 @@ The following people has **sponsored raylib** in the past, allowing the project
|
|||
- James Ghawaly ([@jghawaly](https://github.com/jghawaly))
|
||||
- jack ([@Jack-Ji](https://github.com/Jack-Ji))
|
||||
- Guido Offermans ([@jghawaly](https://github.com/GuidoOffermans))
|
||||
- devdad ([@devdad](https://github.com/devdad))
|
||||
- Pau Fernández ([@pauek](https://github.com/pauek))
|
||||
- Sergio ([@anidealgift](https://github.com/anidealgift))
|
||||
- Snowminx ([@Gamerfiend](https://github.com/Gamerfiend))
|
||||
- NimbusFox ([@NimbusFox](https://github.com/NimbusFox))
|
||||
- Shylie ([@Shylie](https://github.com/Shylie))
|
||||
- Livio Dal Maso ([@Humeur](https://github.com/Humeur))
|
||||
- Diego Vaccher ([@denny0754](https://github.com/denny0754))
|
||||
- Ricardo Alcantara ([@ricardoalcantara](https://github.com/ricardoalcantara))
|
||||
- Toby4213 ([@Toby4213](https://github.com/Toby4213))
|
||||
|
||||
### Notes for Current/Past raylib Sponsor
|
||||
|
||||
- **If you are not on the list, feel free to send a PR to add you if desired.**
|
||||
- **If you want your personal webpage listed along your GitHub account, feel free to send a PR to add it.**
|
||||
- **If you prefer not to listed in this list, feel free to send a PR to remove it.**
|
||||
- If you are not on the list, feel free to send a PR to be added (if desired).
|
||||
- If you want your personal webpage or project listed, feel free to send a PR to be added.
|
||||
- If you prefer not to be in this list, feel free to send a PR to be remove.
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,6 @@ if (${PLATFORM} MATCHES "Android")
|
|||
list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/core/core_world_screen.c)
|
||||
|
||||
list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/models/models_mesh_picking.c)
|
||||
list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/models/models_material_pbr.c)
|
||||
list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/models/models_cubicmap.c)
|
||||
list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/models/models_skybox.c)
|
||||
list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/models/models_mesh_picking.c)
|
||||
|
|
|
|||
|
|
@ -462,7 +462,6 @@ MODELS = \
|
|||
models/models_cubicmap \
|
||||
models/models_first_person_maze \
|
||||
models/models_geometric_shapes \
|
||||
models/models_material_pbr \
|
||||
models/models_mesh_generation \
|
||||
models/models_mesh_picking \
|
||||
models/models_loading \
|
||||
|
|
@ -471,8 +470,7 @@ MODELS = \
|
|||
models/models_skybox \
|
||||
models/models_yaw_pitch_roll \
|
||||
models/models_heightmap \
|
||||
models/models_waving_cubes \
|
||||
models/models_magicavoxel_loading
|
||||
models/models_waving_cubes
|
||||
|
||||
SHADERS = \
|
||||
shaders/shaders_model_shader \
|
||||
|
|
|
|||
|
|
@ -1,3 +1,21 @@
|
|||
## Building the Examples
|
||||
|
||||
The examples assume you have already built the `raylib` library in `../src`.
|
||||
|
||||
### With GNU make
|
||||
|
||||
- `make` builds all examples
|
||||
- `make [module]` builds all examples for a particular module (e.g `make core`)
|
||||
|
||||
### With Zig
|
||||
|
||||
The [Zig](https://ziglang.org/) toolchain can compile `C` and `C++` in addition to `Zig`.
|
||||
You may find it easier to use than other toolchains, especially when it comes to cross-compiling.
|
||||
|
||||
- `zig build` to compile all examples
|
||||
- `zig build [module]` to compile all examples for a module (e.g. `zig build core`)
|
||||
- `zig build [example]` to compile _and run_ a particular example (e.g. `zig build core_basic_window`)
|
||||
|
||||
## EXAMPLES LIST
|
||||
|
||||
### category: core
|
||||
|
|
@ -110,7 +128,7 @@ Examples using raylib models functionality, including models loading/generation
|
|||
| 72 | [models_cubicmap](models/models_cubicmap.c) | <img src="models/models_cubicmap.png" alt="models_cubicmap" width="200"> | ray | |
|
||||
| 73 | [models_first_person_maze](models/models_first_person_maze.c) | <img src="models/models_first_person_maze.png" alt="models_first_person_maze" width="200"> | ray | |
|
||||
| 74 | [models_geometric_shapes](models/models_geometric_shapes.c) | <img src="models/models_geometric_shapes.png" alt="models_geometric_shapes" width="200"> | ray | |
|
||||
| 75 | [models_material_pbr](models/models_material_pbr.c) | <img src="models/models_material_pbr.png" alt="models_material_pbr" width="200"> | ray | |
|
||||
| 75 | [...]() | | ray | |
|
||||
| 76 | [models_mesh_generation](models/models_mesh_generation.c) | <img src="models/models_mesh_generation.png" alt="models_mesh_generation" width="200"> | ray | |
|
||||
| 77 | [models_mesh_picking](models/models_mesh_picking.c) | <img src="models/models_mesh_picking.png" alt="models_mesh_picking" width="200"> | [Joel Davis](https://github.com/joeld42) | |
|
||||
| 78 | [models_loading](models/models_loading.c) | <img src="models/models_loading.png" alt="models_loading" width="200"> | ray | |
|
||||
|
|
|
|||
86
examples/build.zig
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
fn add_module(comptime module: []const u8, b: *std.build.Builder, target: std.zig.CrossTarget) !*std.build.Step {
|
||||
// Standard release options allow the person running `zig build` to select
|
||||
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
|
||||
const mode = b.standardReleaseOptions();
|
||||
|
||||
const all = b.step(module, "All " ++ module ++ " examples");
|
||||
const dir = try std.fs.cwd().openDir(
|
||||
module,
|
||||
.{ .iterate = true },
|
||||
);
|
||||
var iter = dir.iterate();
|
||||
while (try iter.next()) |entry| {
|
||||
if (entry.kind != .File) continue;
|
||||
const extension_idx = std.mem.lastIndexOf(u8, entry.name, ".c") orelse continue;
|
||||
const name = entry.name[0..extension_idx];
|
||||
const path = try std.fs.path.join(b.allocator, &.{ module, entry.name });
|
||||
|
||||
// zig's mingw headers do not include pthread.h
|
||||
if (std.mem.eql(u8, "core_loading_thread", name) and target.getOsTag() == .windows) continue;
|
||||
|
||||
const exe = b.addExecutable(name, path);
|
||||
exe.setTarget(target);
|
||||
exe.setBuildMode(mode);
|
||||
exe.linkLibC();
|
||||
exe.addObjectFile(switch (target.getOsTag()) {
|
||||
.windows => "../src/raylib.lib",
|
||||
.linux => "../src/libraylib.a",
|
||||
else => @panic("Unsupported OS"),
|
||||
});
|
||||
|
||||
exe.addIncludeDir("../src");
|
||||
exe.addIncludeDir("../src/external");
|
||||
exe.addIncludeDir("../src/external/glfw/include");
|
||||
|
||||
switch (exe.target.toTarget().os.tag) {
|
||||
.windows => {
|
||||
exe.linkSystemLibrary("winmm");
|
||||
exe.linkSystemLibrary("gdi32");
|
||||
exe.linkSystemLibrary("opengl32");
|
||||
exe.addIncludeDir("external/glfw/deps/mingw");
|
||||
},
|
||||
.linux => {
|
||||
exe.linkSystemLibrary("GL");
|
||||
exe.linkSystemLibrary("rt");
|
||||
exe.linkSystemLibrary("dl");
|
||||
exe.linkSystemLibrary("m");
|
||||
exe.linkSystemLibrary("X11");
|
||||
},
|
||||
else => {
|
||||
@panic("Unsupported OS");
|
||||
},
|
||||
}
|
||||
|
||||
exe.setOutputDir(module);
|
||||
|
||||
var run = exe.run();
|
||||
run.step.dependOn(&b.addInstallArtifact(exe).step);
|
||||
run.cwd = module;
|
||||
b.step(name, name).dependOn(&run.step);
|
||||
all.dependOn(&exe.step);
|
||||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
pub fn build(b: *std.build.Builder) !void {
|
||||
// Standard target options allows the person running `zig build` to choose
|
||||
// what target to build for. Here we do not override the defaults, which
|
||||
// means any target is allowed, and the default is native. Other options
|
||||
// for restricting supported target set are available.
|
||||
const target = b.standardTargetOptions(.{});
|
||||
|
||||
const all = b.getInstallStep();
|
||||
|
||||
all.dependOn(try add_module("audio", b, target));
|
||||
all.dependOn(try add_module("core", b, target));
|
||||
all.dependOn(try add_module("models", b, target));
|
||||
all.dependOn(try add_module("others", b, target));
|
||||
all.dependOn(try add_module("physics", b, target));
|
||||
all.dependOn(try add_module("shaders", b, target));
|
||||
all.dependOn(try add_module("shapes", b, target));
|
||||
all.dependOn(try add_module("text", b, target));
|
||||
all.dependOn(try add_module("textures", b, target));
|
||||
}
|
||||
|
|
@ -39,15 +39,15 @@ int main(void)
|
|||
camera.fovy = 45.0f; // Camera field-of-view Y
|
||||
camera.projection = CAMERA_PERSPECTIVE; // Camera mode type
|
||||
|
||||
Model model = LoadModel("resources/guy/guy.iqm"); // Load the animated model mesh and basic data
|
||||
Texture2D texture = LoadTexture("resources/guy/guytex.png"); // Load model texture and set material
|
||||
Model model = LoadModel("resources/models/iqm/guy.iqm"); // Load the animated model mesh and basic data
|
||||
Texture2D texture = LoadTexture("resources/models/iqm/guytex.png"); // Load model texture and set material
|
||||
SetMaterialTexture(&model.materials[0], MATERIAL_MAP_DIFFUSE, texture); // Set model material map texture
|
||||
|
||||
Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position
|
||||
|
||||
// Load animation data
|
||||
int animsCount = 0;
|
||||
ModelAnimation *anims = LoadModelAnimations("resources/guy/guyanim.iqm", &animsCount);
|
||||
ModelAnimation *anims = LoadModelAnimations("resources/models/iqm/guyanim.iqm", &animsCount);
|
||||
int animFrameCounter = 0;
|
||||
|
||||
SetCameraMode(camera, CAMERA_FREE); // Set free camera mode
|
||||
|
|
|
|||
|
|
@ -1,122 +0,0 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Load 3d gltf model with animations and play them
|
||||
*
|
||||
* This example has been created using raylib 3.5 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
*
|
||||
* Example contributed by Hristo Stamenov (@object71) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2021 Hristo Stamenov (@object71) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************
|
||||
*
|
||||
* To export a model from blender, make sure it is not posed, the vertices need to be in the
|
||||
* same position as they would be in edit mode.
|
||||
* and that the scale of your models is set to 0. Scaling can be done from the export menu.
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
#include "raylib.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - model animation");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera camera = { 0 };
|
||||
camera.position = (Vector3){ 10.0f, 10.0f, 10.0f }; // Camera position
|
||||
camera.target = (Vector3){ 0.0f, 0.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 mode type
|
||||
|
||||
Model model = LoadModel("resources/gltf/rigged_figure.glb"); // Load the animated model mesh and
|
||||
// basic data
|
||||
// Texture2D texture = LoadTexture("resources/guy/guytex.png"); // Load model texture and set material
|
||||
// SetMaterialTexture(&model.materials[0], MAP_DIFFUSE, texture); // Set model material map texture
|
||||
|
||||
Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position
|
||||
|
||||
// Load animation data
|
||||
int animsCount = 0;
|
||||
ModelAnimation *anims = LoadModelAnimations("resources/gltf/rigged_figure.glb", &animsCount);
|
||||
int animFrameCounter = 0;
|
||||
int animationDirection = 1;
|
||||
|
||||
SetCameraMode(camera, CAMERA_FREE); // Set free camera mode
|
||||
|
||||
SetTargetFPS(30); // 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);
|
||||
|
||||
// Play animation when spacebar is held down
|
||||
if (IsKeyDown(KEY_SPACE))
|
||||
{
|
||||
animFrameCounter += animationDirection;
|
||||
|
||||
if (animFrameCounter >= anims[0].frameCount || animFrameCounter <= 0)
|
||||
{
|
||||
animationDirection *= -1;
|
||||
animFrameCounter += animationDirection;
|
||||
}
|
||||
|
||||
UpdateModelAnimation(model, anims[0], animFrameCounter);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(RAYWHITE);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModelEx(model, position, (Vector3){ 1.0f, 0.0f, 0.0f }, -90.0f, (Vector3){ 1.0f, 1.0f, 1.0f }, WHITE);
|
||||
|
||||
for (int i = 0; i < model.boneCount; i++)
|
||||
{
|
||||
DrawSphere(anims[0].framePoses[animFrameCounter][i].translation, 0.01f, RED);
|
||||
}
|
||||
|
||||
DrawGrid(10, 1.0f); // Draw a grid
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("PRESS SPACE to PLAY MODEL ANIMATION", 10, 10, 20, MAROON);
|
||||
DrawText("(cc4) Rigged Figure by @Cesium", screenWidth - 200, screenHeight - 20, 10, GRAY);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
// UnloadTexture(texture); // Unload texture
|
||||
|
||||
// Unload model animations data
|
||||
for (int i = 0; i < animsCount; i++) UnloadModelAnimation(anims[i]);
|
||||
RL_FREE(anims);
|
||||
|
||||
UnloadModel(model); // Unload model
|
||||
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -4,17 +4,19 @@
|
|||
*
|
||||
* raylib supports multiple models file formats:
|
||||
*
|
||||
* - OBJ > Text file, must include vertex position-texcoords-normals information,
|
||||
* if files references some .mtl materials file, it will be loaded (or try to)
|
||||
* - GLTF > Modern text/binary file format, includes lot of information and it could
|
||||
* also reference external files, raylib will try loading mesh and materials data
|
||||
* - IQM > Binary file format including mesh vertex data but also animation data,
|
||||
* - OBJ > Text file format. Must include vertex position-texcoords-normals information,
|
||||
* if files references some .mtl materials file, it will be loaded (or try to).
|
||||
* - GLTF > Text/binary file format. Includes lot of information and it could
|
||||
* also reference external files, raylib will try loading mesh and materials data.
|
||||
* - IQM > Binary file format. Includes mesh vertex data but also animation data,
|
||||
* raylib can load .iqm animations.
|
||||
* - VOX > Binary file format. MagikaVoxel mesh format:
|
||||
* https://github.com/ephtracy/voxel-model/blob/master/MagicaVoxel-file-format-vox.txt
|
||||
*
|
||||
* This example has been created using raylib 2.6 (www.raylib.com)
|
||||
* This example has been created using raylib 4.0 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
*
|
||||
* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2014-2021 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,27 +1,24 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Load 3d gltf model
|
||||
* raylib [models] example - Load models gltf
|
||||
*
|
||||
* This example has been created using raylib 3.5 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
*
|
||||
* NOTE: To export a model from Blender, make sure it is not posed, the vertices need to be
|
||||
* in the same position as they would be in edit mode.
|
||||
* Also make sure the scale parameter of your models is set to 0.0,
|
||||
* scaling can be applied from the export menu.
|
||||
*
|
||||
* Example contributed by Hristo Stamenov (@object71) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2021 Hristo Stamenov (@object71) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************
|
||||
*
|
||||
* To export a model from blender, make sure it is not posed, the vertices need to be in the
|
||||
* same position as they would be in edit mode.
|
||||
* and that the scale of your models is set to 0. Scaling can be done from the export menu.
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
#include "raylib.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX_MODELS 8
|
||||
#define MAX_GLTF_MODELS 8
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
|
@ -40,16 +37,16 @@ int main(void)
|
|||
camera.fovy = 45.0f; // Camera field-of-view Y
|
||||
camera.projection = CAMERA_PERSPECTIVE; // Camera mode type
|
||||
|
||||
Model model[MAX_MODELS] = { 0 };
|
||||
|
||||
model[0] = LoadModel("resources/gltf/raylib_32x32.glb");
|
||||
model[1] = LoadModel("resources/gltf/rigged_figure.glb");
|
||||
model[2] = LoadModel("resources/gltf/GearboxAssy.glb");
|
||||
model[3] = LoadModel("resources/gltf/BoxAnimated.glb");
|
||||
model[4] = LoadModel("resources/gltf/AnimatedTriangle.gltf");
|
||||
model[5] = LoadModel("resources/gltf/AnimatedMorphCube.glb");
|
||||
model[6] = LoadModel("resources/gltf/vertex_colored_object.glb");
|
||||
model[7] = LoadModel("resources/gltf/girl.glb");
|
||||
// Load some models
|
||||
Model model[MAX_GLTF_MODELS] = { 0 };
|
||||
model[0] = LoadModel("resources/models/gltf/raylib_32x32.glb");
|
||||
model[1] = LoadModel("resources/models/gltf/rigged_figure.glb");
|
||||
model[2] = LoadModel("resources/models/gltf/GearboxAssy.glb");
|
||||
model[3] = LoadModel("resources/models/gltf/BoxAnimated.glb");
|
||||
model[4] = LoadModel("resources/models/gltf/AnimatedTriangle.gltf");
|
||||
model[5] = LoadModel("resources/models/gltf/AnimatedMorphCube.glb");
|
||||
model[6] = LoadModel("resources/models/gltf/vertex_colored_object.glb");
|
||||
model[7] = LoadModel("resources/models/gltf/girl.glb");
|
||||
|
||||
int currentModel = 0;
|
||||
|
||||
|
|
@ -65,19 +62,20 @@ int main(void)
|
|||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(&camera);
|
||||
UpdateCamera(&camera); // Update our camera with inputs
|
||||
|
||||
if (IsKeyReleased(KEY_RIGHT))
|
||||
{
|
||||
currentModel++;
|
||||
if (currentModel == MAX_MODELS) currentModel = 0;
|
||||
if (currentModel == MAX_GLTF_MODELS) currentModel = 0;
|
||||
}
|
||||
|
||||
if (IsKeyReleased(KEY_LEFT))
|
||||
{
|
||||
currentModel--;
|
||||
if (currentModel < 0) currentModel = MAX_MODELS - 1;
|
||||
if (currentModel < 0) currentModel = MAX_GLTF_MODELS - 1;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -87,8 +85,7 @@ int main(void)
|
|||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModelEx(model[currentModel], position, (Vector3){ 0.0f, 1.0f, 0.0f }, 180.0f, (Vector3){ 2.0f, 2.0f, 2.0f }, WHITE);
|
||||
|
||||
DrawModel(model[currentModel], position, 1.0f, WHITE);
|
||||
DrawGrid(10, 1.0f); // Draw a grid
|
||||
|
||||
EndMode3D();
|
||||
|
|
@ -99,7 +96,7 @@ int main(void)
|
|||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
for (int i = 0; i < MAX_MODELS; i++) UnloadModel(model[i]); // Unload models
|
||||
for (int i = 0; i < MAX_GLTF_MODELS; i++) UnloadModel(model[i]); // Unload models
|
||||
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
130
examples/models/models_loading_vox.c
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Load models vox (MagicaVoxel)
|
||||
*
|
||||
* This example has been created using raylib 4.0 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
*
|
||||
* Example contributed by Johann Nadalutti (@procfxgen) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2021 Johann Nadalutti (@procfxgen) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
#include "raylib.h"
|
||||
|
||||
#include "raymath.h" // Required for: MatrixTranslate()
|
||||
|
||||
#define MAX_VOX_FILES 3
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
const char *voxFileNames[] = {
|
||||
"resources/models/vox/chr_knight.vox",
|
||||
"resources/models/vox/chr_sword.vox",
|
||||
"resources/models/vox/monu9.vox"
|
||||
};
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - magicavoxel loading");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera camera = { 0 };
|
||||
camera.position = (Vector3){ 10.0f, 10.0f, 10.0f }; // Camera position
|
||||
camera.target = (Vector3){ 0.0f, 0.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 mode type
|
||||
|
||||
// Load MagicaVoxel files
|
||||
Model models[MAX_VOX_FILES] = { 0 };
|
||||
|
||||
for (int i = 0; i < MAX_VOX_FILES; i++)
|
||||
{
|
||||
// Load VOX file and measure time
|
||||
double t0 = GetTime()*1000.0;
|
||||
models[i] = LoadModel(voxFileNames[i]);
|
||||
double t1 = GetTime()*1000.0;
|
||||
|
||||
TraceLog(LOG_WARNING, TextFormat("[%s] File loaded in %.3f ms", voxFileNames[i], t1 - t0));
|
||||
|
||||
// Compute model translation matrix to center model on draw position (0, 0 , 0)
|
||||
BoundingBox bb = GetModelBoundingBox(models[i]);
|
||||
Vector3 center = { 0 };
|
||||
center.x = bb.min.x + (((bb.max.x - bb.min.x)/2));
|
||||
center.z = bb.min.z + (((bb.max.z - bb.min.z)/2));
|
||||
|
||||
Matrix matTranslate = MatrixTranslate(-center.x, 0, -center.z);
|
||||
models[i].transform = matTranslate;
|
||||
}
|
||||
|
||||
int currentModel = 0;
|
||||
|
||||
SetCameraMode(camera, CAMERA_ORBITAL); // Set a orbital camera mode
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(&camera); // Update our camera to orbit
|
||||
|
||||
// Cycle between models on mouse click
|
||||
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) currentModel = (currentModel + 1)%MAX_VOX_FILES;
|
||||
|
||||
// Cycle between models on key pressed
|
||||
if (IsKeyPressed(KEY_RIGHT))
|
||||
{
|
||||
currentModel++;
|
||||
if (currentModel >= MAX_VOX_FILES) currentModel = 0;
|
||||
}
|
||||
else if (IsKeyPressed(KEY_LEFT))
|
||||
{
|
||||
currentModel--;
|
||||
if (currentModel < 0) currentModel = MAX_VOX_FILES - 1;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(RAYWHITE);
|
||||
|
||||
// Draw 3D model
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(models[currentModel], (Vector3){ 0, 0, 0 }, 1.0f, WHITE);
|
||||
DrawGrid(10, 1.0);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Display info
|
||||
DrawRectangle(10, 400, 310, 30, Fade(SKYBLUE, 0.5f));
|
||||
DrawRectangleLines(10, 400, 310, 30, Fade(DARKBLUE, 0.5f));
|
||||
DrawText("MOUSE LEFT BUTTON to CYCLE VOX MODELS", 40, 410, 10, BLUE);
|
||||
DrawText(TextFormat("File: %s", GetFileName(voxFileNames[currentModel])), 10, 10, 20, GRAY);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Unload models data (GPU VRAM)
|
||||
for (int i = 0; i < MAX_VOX_FILES; i++) UnloadModel(models[i]);
|
||||
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - magicavoxel loader and viewer
|
||||
*
|
||||
* This example has been created using raylib 3.8 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
*
|
||||
* Example contributed by Johann Nadalutti
|
||||
*
|
||||
* Copyright (c) 2021 Johann Nadalutti
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
#include "raylib.h"
|
||||
#include "raymath.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// VOX Files to load and view
|
||||
|
||||
#define NUM_VOX_FILES 3
|
||||
|
||||
const char* szVoxFiles[] = {
|
||||
"resources/vox/chr_knight.vox",
|
||||
"resources/vox/chr_sword.vox",
|
||||
"resources/vox/monu9.vox"
|
||||
};
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - magicavoxel loading");
|
||||
|
||||
// Load MagicaVoxel files
|
||||
Model models[NUM_VOX_FILES] = { 0 };
|
||||
|
||||
for (int i = 0; i < NUM_VOX_FILES; i++)
|
||||
{
|
||||
// Load MagicaVoxel File and build model
|
||||
double t0, t1;
|
||||
t0 = GetTime() * 1000.0;
|
||||
|
||||
models[i] = LoadModel(szVoxFiles[i]);
|
||||
|
||||
t1 = GetTime() * 1000.0;
|
||||
TraceLog(LOG_INFO, TextFormat("Vox <%s> loaded in %f ms", GetFileName(szVoxFiles[i]), t1 - t0));
|
||||
|
||||
//Compute model's center matrix
|
||||
BoundingBox bb = GetModelBoundingBox(models[i]);
|
||||
Vector3 center;
|
||||
center.x = bb.min.x + (((bb.max.x - bb.min.x) / 2));
|
||||
center.z = bb.min.z + (((bb.max.z - bb.min.z) / 2));
|
||||
|
||||
Matrix matP = MatrixTranslate(-center.x, 0, -center.z);
|
||||
models[i].transform = matP;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera camera = { { 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 };
|
||||
|
||||
// Model drawing position
|
||||
Vector3 position = { 0.0f, 0.0f, 0.0f };
|
||||
|
||||
int currentModel = 0;
|
||||
|
||||
|
||||
|
||||
SetCameraMode(camera, CAMERA_ORBITAL); // Set a orbital camera mode
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Main game loop
|
||||
//--------------------------------------------------------------------------------------
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(&camera); // Update internal camera and our camera
|
||||
|
||||
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
|
||||
{
|
||||
currentModel = (currentModel + 1) % NUM_VOX_FILES; // Cycle between models
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KEY_RIGHT))
|
||||
{
|
||||
currentModel++;
|
||||
if (currentModel >= NUM_VOX_FILES) currentModel = 0;
|
||||
}
|
||||
else if (IsKeyPressed(KEY_LEFT))
|
||||
{
|
||||
currentModel--;
|
||||
if (currentModel < 0) currentModel = NUM_VOX_FILES - 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(RAYWHITE);
|
||||
|
||||
//Display model
|
||||
BeginMode3D(camera);
|
||||
|
||||
Vector3 rotAxis = { 1,0,0 };
|
||||
Vector3 scale = { 1,1,1 };
|
||||
|
||||
|
||||
DrawModelEx(models[currentModel], position, rotAxis, 0, scale, WHITE);
|
||||
//DrawModelWiresEx(models[currentModel], position, rotAxis, -90.0f, scale, BLACK);
|
||||
|
||||
DrawGrid(10, 1.0);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
//Display debug infos
|
||||
DrawRectangle(30, 400, 310, 30, Fade(SKYBLUE, 0.5f));
|
||||
DrawRectangleLines(30, 400, 310, 30, Fade(DARKBLUE, 0.5f));
|
||||
DrawText("MOUSE LEFT BUTTON to CYCLE VOX MODELS", 40, 410, 10, BLUE);
|
||||
|
||||
DrawText(GetFileName(szVoxFiles[currentModel]), 100, 10, 20, DARKBLUE);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Unload models data (GPU VRAM)
|
||||
for (int i = 0; i < NUM_VOX_FILES; i++) UnloadModel(models[i]);
|
||||
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,543 +0,0 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - PBR material
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 for shaders support and only #version 330
|
||||
* is currently supported. OpenGL ES 2.0 platforms are not supported at the moment.
|
||||
*
|
||||
* This example has been created using raylib 1.8 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
*
|
||||
* Copyright (c) 2017 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
#include "raylib.h"
|
||||
#include "raymath.h"
|
||||
#include "rlgl.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define RLIGHTS_IMPLEMENTATION
|
||||
#include "rlights.h"
|
||||
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
#define GLSL_VERSION 330
|
||||
#else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB
|
||||
#define GLSL_VERSION 100
|
||||
#endif
|
||||
|
||||
#define CUBEMAP_SIZE 1024 // Cubemap texture size
|
||||
#define IRRADIANCE_SIZE 32 // Irradiance texture size
|
||||
#define PREFILTERED_SIZE 256 // Prefiltered HDR environment texture size
|
||||
#define BRDF_SIZE 512 // BRDF LUT texture size
|
||||
#define LIGHT_DISTANCE 1000.0f
|
||||
#define LIGHT_HEIGHT 1.0f
|
||||
|
||||
// PBR texture maps generation
|
||||
static TextureCubemap GenTextureCubemap(Shader shader, Texture2D panorama, int size, int format); // Generate cubemap (6 faces) from equirectangular (panorama) texture
|
||||
static TextureCubemap GenTextureIrradiance(Shader shader, TextureCubemap cubemap, int size); // Generate irradiance cubemap using cubemap texture
|
||||
static TextureCubemap GenTexturePrefilter(Shader shader, TextureCubemap cubemap, int size); // Generate prefilter cubemap using cubemap texture
|
||||
static Texture2D GenTextureBRDF(Shader shader, int size); // Generate a generic BRDF texture
|
||||
|
||||
// PBR material loading
|
||||
static Material LoadMaterialPBR(Color albedo, float metalness, float roughness);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
SetConfigFlags(FLAG_MSAA_4X_HINT); // Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - pbr material");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera camera = { 0 };
|
||||
camera.position = (Vector3){ 4.0f, 4.0f, 4.0f }; // Camera position
|
||||
camera.target = (Vector3){ 0.0f, 0.5f, 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 mode type
|
||||
|
||||
// Load model and PBR material
|
||||
Model model = LoadModel("resources/pbr/trooper.obj");
|
||||
|
||||
// Mesh tangents are generated... and uploaded to GPU
|
||||
// NOTE: New VBO for tangents is generated at default location and also binded to mesh VAO
|
||||
//MeshTangents(&model.meshes[0]);
|
||||
|
||||
model.materials[0] = LoadMaterialPBR((Color){ 255, 255, 255, 255 }, 1.0f, 1.0f);
|
||||
|
||||
// Create lights
|
||||
// NOTE: Lights are added to an internal lights pool automatically
|
||||
CreateLight(LIGHT_POINT, (Vector3){ LIGHT_DISTANCE, LIGHT_HEIGHT, 0.0f }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 255, 0, 0, 255 }, model.materials[0].shader);
|
||||
CreateLight(LIGHT_POINT, (Vector3){ 0.0f, LIGHT_HEIGHT, LIGHT_DISTANCE }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 0, 255, 0, 255 }, model.materials[0].shader);
|
||||
CreateLight(LIGHT_POINT, (Vector3){ -LIGHT_DISTANCE, LIGHT_HEIGHT, 0.0f }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 0, 0, 255, 255 }, model.materials[0].shader);
|
||||
CreateLight(LIGHT_DIRECTIONAL, (Vector3){ 0.0f, LIGHT_HEIGHT*2.0f, -LIGHT_DISTANCE }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 255, 0, 255, 255 }, model.materials[0].shader);
|
||||
|
||||
SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(&camera); // Update camera
|
||||
|
||||
// Send to material PBR shader camera view position
|
||||
float cameraPos[3] = { camera.position.x, camera.position.y, camera.position.z };
|
||||
SetShaderValue(model.materials[0].shader, model.materials[0].shader.locs[SHADER_LOC_VECTOR_VIEW], cameraPos, SHADER_UNIFORM_VEC3);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(RAYWHITE);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, Vector3Zero(), 1.0f, WHITE);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadMaterial(model.materials[0]); // Unload material: shader and textures
|
||||
|
||||
UnloadModel(model); // Unload model
|
||||
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Load PBR material (Supports: ALBEDO, NORMAL, METALNESS, ROUGHNESS, AO, EMMISIVE, HEIGHT maps)
|
||||
// NOTE: PBR shader is loaded inside this function
|
||||
static Material LoadMaterialPBR(Color albedo, float metalness, float roughness)
|
||||
{
|
||||
Material mat = LoadMaterialDefault(); // Initialize material to default
|
||||
|
||||
// Load PBR shader (requires several maps)
|
||||
mat.shader = LoadShader(TextFormat("resources/shaders/glsl%i/pbr.vs", GLSL_VERSION),
|
||||
TextFormat("resources/shaders/glsl%i/pbr.fs", GLSL_VERSION));
|
||||
|
||||
// Get required locations points for PBR material
|
||||
// NOTE: Those location names must be available and used in the shader code
|
||||
mat.shader.locs[SHADER_LOC_MAP_ALBEDO] = GetShaderLocation(mat.shader, "albedo.sampler");
|
||||
mat.shader.locs[SHADER_LOC_MAP_METALNESS] = GetShaderLocation(mat.shader, "metalness.sampler");
|
||||
mat.shader.locs[SHADER_LOC_MAP_NORMAL] = GetShaderLocation(mat.shader, "normals.sampler");
|
||||
mat.shader.locs[SHADER_LOC_MAP_ROUGHNESS] = GetShaderLocation(mat.shader, "roughness.sampler");
|
||||
mat.shader.locs[SHADER_LOC_MAP_OCCLUSION] = GetShaderLocation(mat.shader, "occlusion.sampler");
|
||||
//mat.shader.locs[SHADER_LOC_MAP_EMISSION] = GetShaderLocation(mat.shader, "emission.sampler");
|
||||
//mat.shader.locs[SHADER_LOC_MAP_HEIGHT] = GetShaderLocation(mat.shader, "height.sampler");
|
||||
mat.shader.locs[SHADER_LOC_MAP_IRRADIANCE] = GetShaderLocation(mat.shader, "irradianceMap");
|
||||
mat.shader.locs[SHADER_LOC_MAP_PREFILTER] = GetShaderLocation(mat.shader, "prefilterMap");
|
||||
mat.shader.locs[SHADER_LOC_MAP_BRDF] = GetShaderLocation(mat.shader, "brdfLUT");
|
||||
|
||||
// Set view matrix location
|
||||
mat.shader.locs[SHADER_LOC_MATRIX_MODEL] = GetShaderLocation(mat.shader, "matModel");
|
||||
//mat.shader.locs[SHADER_LOC_MATRIX_VIEW] = GetShaderLocation(mat.shader, "view");
|
||||
mat.shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(mat.shader, "viewPos");
|
||||
|
||||
// Set PBR standard maps
|
||||
mat.maps[MATERIAL_MAP_ALBEDO].texture = LoadTexture("resources/pbr/trooper_albedo.png");
|
||||
mat.maps[MATERIAL_MAP_NORMAL].texture = LoadTexture("resources/pbr/trooper_normals.png");
|
||||
mat.maps[MATERIAL_MAP_METALNESS].texture = LoadTexture("resources/pbr/trooper_metalness.png");
|
||||
mat.maps[MATERIAL_MAP_ROUGHNESS].texture = LoadTexture("resources/pbr/trooper_roughness.png");
|
||||
mat.maps[MATERIAL_MAP_OCCLUSION].texture = LoadTexture("resources/pbr/trooper_ao.png");
|
||||
|
||||
// Set textures filtering for better quality
|
||||
SetTextureFilter(mat.maps[MATERIAL_MAP_ALBEDO].texture, TEXTURE_FILTER_BILINEAR);
|
||||
SetTextureFilter(mat.maps[MATERIAL_MAP_NORMAL].texture, TEXTURE_FILTER_BILINEAR);
|
||||
SetTextureFilter(mat.maps[MATERIAL_MAP_METALNESS].texture, TEXTURE_FILTER_BILINEAR);
|
||||
SetTextureFilter(mat.maps[MATERIAL_MAP_ROUGHNESS].texture, TEXTURE_FILTER_BILINEAR);
|
||||
SetTextureFilter(mat.maps[MATERIAL_MAP_OCCLUSION].texture, TEXTURE_FILTER_BILINEAR);
|
||||
|
||||
// Enable sample usage in shader for assigned textures
|
||||
SetShaderValue(mat.shader, GetShaderLocation(mat.shader, "albedo.useSampler"), (int[1]){ 1 }, SHADER_UNIFORM_INT);
|
||||
SetShaderValue(mat.shader, GetShaderLocation(mat.shader, "normals.useSampler"), (int[1]){ 1 }, SHADER_UNIFORM_INT);
|
||||
SetShaderValue(mat.shader, GetShaderLocation(mat.shader, "metalness.useSampler"), (int[1]){ 1 }, SHADER_UNIFORM_INT);
|
||||
SetShaderValue(mat.shader, GetShaderLocation(mat.shader, "roughness.useSampler"), (int[1]){ 1 }, SHADER_UNIFORM_INT);
|
||||
SetShaderValue(mat.shader, GetShaderLocation(mat.shader, "occlusion.useSampler"), (int[1]){ 1 }, SHADER_UNIFORM_INT);
|
||||
|
||||
int renderModeLoc = GetShaderLocation(mat.shader, "renderMode");
|
||||
SetShaderValue(mat.shader, renderModeLoc, (int[1]){ 0 }, SHADER_UNIFORM_INT);
|
||||
|
||||
// Set up material properties color
|
||||
mat.maps[MATERIAL_MAP_ALBEDO].color = albedo;
|
||||
mat.maps[MATERIAL_MAP_NORMAL].color = (Color){ 128, 128, 255, 255 };
|
||||
mat.maps[MATERIAL_MAP_METALNESS].value = metalness;
|
||||
mat.maps[MATERIAL_MAP_ROUGHNESS].value = roughness;
|
||||
mat.maps[MATERIAL_MAP_OCCLUSION].value = 1.0f;
|
||||
mat.maps[MATERIAL_MAP_EMISSION].value = 0.5f;
|
||||
mat.maps[MATERIAL_MAP_HEIGHT].value = 0.5f;
|
||||
|
||||
// Generate cubemap from panorama texture
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
Texture2D panorama = LoadTexture("resources/dresden_square_2k.hdr");
|
||||
|
||||
// Load equirectangular to cubemap shader
|
||||
Shader shdrCubemap = LoadShader(TextFormat("resources/shaders/glsl%i/pbr.vs", GLSL_VERSION),
|
||||
TextFormat("resources/shaders/glsl%i/pbr.fs", GLSL_VERSION));
|
||||
|
||||
SetShaderValue(shdrCubemap, GetShaderLocation(shdrCubemap, "equirectangularMap"), (int[1]){ 0 }, SHADER_UNIFORM_INT);
|
||||
TextureCubemap cubemap = GenTextureCubemap(shdrCubemap, panorama, CUBEMAP_SIZE, PIXELFORMAT_UNCOMPRESSED_R32G32B32);
|
||||
UnloadTexture(panorama);
|
||||
UnloadShader(shdrCubemap);
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Generate irradiance map from cubemap texture
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// Load irradiance (GI) calculation shader
|
||||
Shader shdrIrradiance = LoadShader(TextFormat("resources/shaders/glsl%i/skybox.vs", GLSL_VERSION),
|
||||
TextFormat("resources/shaders/glsl%i/irradiance.fs", GLSL_VERSION));
|
||||
|
||||
SetShaderValue(shdrIrradiance, GetShaderLocation(shdrIrradiance, "environmentMap"), (int[1]){ 0 }, SHADER_UNIFORM_INT);
|
||||
mat.maps[MATERIAL_MAP_IRRADIANCE].texture = GenTextureIrradiance(shdrIrradiance, cubemap, IRRADIANCE_SIZE);
|
||||
UnloadShader(shdrIrradiance);
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Generate prefilter map from cubemap texture
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// Load reflection prefilter calculation shader
|
||||
Shader shdrPrefilter = LoadShader(TextFormat("resources/shaders/glsl%i/skybox.vs", GLSL_VERSION),
|
||||
TextFormat("resources/shaders/glsl%i/prefilter.fs", GLSL_VERSION));
|
||||
|
||||
SetShaderValue(shdrPrefilter, GetShaderLocation(shdrPrefilter, "environmentMap"), (int[1]){ 0 }, SHADER_UNIFORM_INT);
|
||||
mat.maps[MATERIAL_MAP_PREFILTER].texture = GenTexturePrefilter(shdrPrefilter, cubemap, PREFILTERED_SIZE);
|
||||
UnloadTexture(cubemap);
|
||||
UnloadShader(shdrPrefilter);
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Generate BRDF (bidirectional reflectance distribution function) texture (using shader)
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
Shader shdrBRDF = LoadShader(TextFormat("resources/shaders/glsl%i/brdf.vs", GLSL_VERSION),
|
||||
TextFormat("resources/shaders/glsl%i/brdf.fs", GLSL_VERSION));
|
||||
|
||||
mat.maps[MATERIAL_MAP_BRDF].texture = GenTextureBRDF(shdrBRDF, BRDF_SIZE);
|
||||
UnloadShader(shdrBRDF);
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
// Texture maps generation (PBR)
|
||||
//-------------------------------------------------------------------------------------------
|
||||
// Generate cubemap texture from HDR texture
|
||||
static TextureCubemap GenTextureCubemap(Shader shader, Texture2D panorama, int size, int format)
|
||||
{
|
||||
TextureCubemap cubemap = { 0 };
|
||||
|
||||
rlDisableBackfaceCulling(); // Disable backface culling to render inside the cube
|
||||
|
||||
// STEP 1: Setup framebuffer
|
||||
//------------------------------------------------------------------------------------------
|
||||
unsigned int rbo = rlLoadTextureDepth(size, size, true);
|
||||
cubemap.id = rlLoadTextureCubemap(NULL, size, format);
|
||||
|
||||
unsigned int fbo = rlLoadFramebuffer(size, size);
|
||||
rlFramebufferAttach(fbo, rbo, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER, 0);
|
||||
rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X, 0);
|
||||
|
||||
// Check if framebuffer is complete with attachments (valid)
|
||||
if (rlFramebufferComplete(fbo)) TraceLog(LOG_INFO, "FBO: [ID %i] Framebuffer object created successfully", fbo);
|
||||
//------------------------------------------------------------------------------------------
|
||||
|
||||
// STEP 2: Draw to framebuffer
|
||||
//------------------------------------------------------------------------------------------
|
||||
// NOTE: Shader is used to convert HDR equirectangular environment map to cubemap equivalent (6 faces)
|
||||
rlEnableShader(shader.id);
|
||||
|
||||
// Define projection matrix and send it to shader
|
||||
Matrix matFboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR);
|
||||
rlSetUniformMatrix(shader.locs[SHADER_LOC_MATRIX_PROJECTION], matFboProjection);
|
||||
|
||||
// Define view matrix for every side of the cubemap
|
||||
Matrix fboViews[6] = {
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ -1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }),
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }),
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f })
|
||||
};
|
||||
|
||||
rlViewport(0, 0, size, size); // Set viewport to current fbo dimensions
|
||||
|
||||
// Activate and enable texture for drawing to cubemap faces
|
||||
rlActiveTextureSlot(0);
|
||||
rlEnableTexture(panorama.id);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
// Set the view matrix for the current cube face
|
||||
rlSetUniformMatrix(shader.locs[SHADER_LOC_MATRIX_VIEW], fboViews[i]);
|
||||
|
||||
// Select the current cubemap face attachment for the fbo
|
||||
// WARNING: This function by default enables->attach->disables fbo!!!
|
||||
rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X + i, 0);
|
||||
rlEnableFramebuffer(fbo);
|
||||
|
||||
// Load and draw a cube, it uses the current enabled texture
|
||||
rlClearScreenBuffers();
|
||||
rlLoadDrawCube();
|
||||
|
||||
// ALTERNATIVE: Try to use internal batch system to draw the cube instead of rlLoadDrawCube
|
||||
// for some reason this method does not work, maybe due to cube triangles definition? normals pointing out?
|
||||
// TODO: Investigate this issue...
|
||||
//rlSetTexture(panorama.id); // WARNING: It must be called after enabling current framebuffer if using internal batch system!
|
||||
//rlClearScreenBuffers();
|
||||
//DrawCubeV(Vector3Zero(), Vector3One(), WHITE);
|
||||
//rlDrawRenderBatchActive();
|
||||
}
|
||||
//------------------------------------------------------------------------------------------
|
||||
|
||||
// STEP 3: Unload framebuffer and reset state
|
||||
//------------------------------------------------------------------------------------------
|
||||
rlDisableShader(); // Unbind shader
|
||||
rlDisableTexture(); // Unbind texture
|
||||
rlDisableFramebuffer(); // Unbind framebuffer
|
||||
rlUnloadFramebuffer(fbo); // Unload framebuffer (and automatically attached depth texture/renderbuffer)
|
||||
|
||||
// Reset viewport dimensions to default
|
||||
rlViewport(0, 0, rlGetFramebufferWidth(), rlGetFramebufferHeight());
|
||||
rlEnableBackfaceCulling();
|
||||
//------------------------------------------------------------------------------------------
|
||||
|
||||
cubemap.width = size;
|
||||
cubemap.height = size;
|
||||
cubemap.mipmaps = 1;
|
||||
cubemap.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32;
|
||||
|
||||
return cubemap;
|
||||
}
|
||||
|
||||
// Generate irradiance texture using cubemap data
|
||||
static TextureCubemap GenTextureIrradiance(Shader shader, TextureCubemap cubemap, int size)
|
||||
{
|
||||
TextureCubemap irradiance = { 0 };
|
||||
|
||||
rlDisableBackfaceCulling(); // Disable backface culling to render inside the cube
|
||||
|
||||
// STEP 1: Setup framebuffer
|
||||
//------------------------------------------------------------------------------------------
|
||||
unsigned int rbo = rlLoadTextureDepth(size, size, true);
|
||||
irradiance.id = rlLoadTextureCubemap(NULL, size, PIXELFORMAT_UNCOMPRESSED_R32G32B32);
|
||||
|
||||
unsigned int fbo = rlLoadFramebuffer(size, size);
|
||||
rlFramebufferAttach(fbo, rbo, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER, 0);
|
||||
rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X, 0);
|
||||
//------------------------------------------------------------------------------------------
|
||||
|
||||
// STEP 2: Draw to framebuffer
|
||||
//------------------------------------------------------------------------------------------
|
||||
// NOTE: Shader is used to solve diffuse integral by convolution to create an irradiance cubemap
|
||||
rlEnableShader(shader.id);
|
||||
|
||||
// Define projection matrix and send it to shader
|
||||
Matrix matFboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR);
|
||||
rlSetUniformMatrix(shader.locs[SHADER_LOC_MATRIX_PROJECTION], matFboProjection);
|
||||
|
||||
// Define view matrix for every side of the cubemap
|
||||
Matrix fboViews[6] = {
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ -1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }),
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }),
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f })
|
||||
};
|
||||
|
||||
rlActiveTextureSlot(0);
|
||||
rlEnableTextureCubemap(cubemap.id);
|
||||
|
||||
rlViewport(0, 0, size, size); // Set viewport to current fbo dimensions
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
rlSetUniformMatrix(shader.locs[SHADER_LOC_MATRIX_VIEW], fboViews[i]);
|
||||
rlFramebufferAttach(fbo, irradiance.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X + i, 0);
|
||||
|
||||
rlEnableFramebuffer(fbo);
|
||||
rlClearScreenBuffers();
|
||||
rlLoadDrawCube();
|
||||
}
|
||||
//------------------------------------------------------------------------------------------
|
||||
|
||||
// STEP 3: Unload framebuffer and reset state
|
||||
//------------------------------------------------------------------------------------------
|
||||
rlDisableShader(); // Unbind shader
|
||||
rlDisableTexture(); // Unbind texture
|
||||
rlDisableFramebuffer(); // Unbind framebuffer
|
||||
rlUnloadFramebuffer(fbo); // Unload framebuffer (and automatically attached depth texture/renderbuffer)
|
||||
|
||||
// Reset viewport dimensions to default
|
||||
rlViewport(0, 0, rlGetFramebufferWidth(), rlGetFramebufferHeight());
|
||||
rlEnableBackfaceCulling();
|
||||
//------------------------------------------------------------------------------------------
|
||||
|
||||
irradiance.width = size;
|
||||
irradiance.height = size;
|
||||
irradiance.mipmaps = 1;
|
||||
irradiance.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32;
|
||||
|
||||
return irradiance;
|
||||
}
|
||||
|
||||
// Generate prefilter texture using cubemap data
|
||||
static TextureCubemap GenTexturePrefilter(Shader shader, TextureCubemap cubemap, int size)
|
||||
{
|
||||
TextureCubemap prefilter = { 0 };
|
||||
|
||||
rlDisableBackfaceCulling(); // Disable backface culling to render inside the cube
|
||||
|
||||
// STEP 1: Setup framebuffer
|
||||
//------------------------------------------------------------------------------------------
|
||||
unsigned int rbo = rlLoadTextureDepth(size, size, true);
|
||||
prefilter.id = rlLoadTextureCubemap(NULL, size, PIXELFORMAT_UNCOMPRESSED_R32G32B32);
|
||||
rlTextureParameters(prefilter.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_MIP_LINEAR);
|
||||
|
||||
unsigned int fbo = rlLoadFramebuffer(size, size);
|
||||
rlFramebufferAttach(fbo, rbo, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER, 0);
|
||||
rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X, 0);
|
||||
//------------------------------------------------------------------------------------------
|
||||
|
||||
// Generate mipmaps for the prefiltered HDR texture
|
||||
//glGenerateMipmap(GL_TEXTURE_CUBE_MAP); // TODO!
|
||||
|
||||
// STEP 2: Draw to framebuffer
|
||||
//------------------------------------------------------------------------------------------
|
||||
// NOTE: Shader is used to prefilter HDR and store data into mipmap levels
|
||||
|
||||
// Define projection matrix and send it to shader
|
||||
Matrix fboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR);
|
||||
rlEnableShader(shader.id);
|
||||
rlSetUniformMatrix(shader.locs[SHADER_LOC_MATRIX_PROJECTION], fboProjection);
|
||||
|
||||
// Define view matrix for every side of the cubemap
|
||||
Matrix fboViews[6] = {
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ -1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }),
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }),
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f })
|
||||
};
|
||||
|
||||
rlActiveTextureSlot(0);
|
||||
rlEnableTextureCubemap(cubemap.id);
|
||||
|
||||
// TODO: Locations should be taken out of this function... too shader dependant...
|
||||
int roughnessLoc = rlGetLocationUniform(shader.id, "roughness");
|
||||
|
||||
rlEnableFramebuffer(fbo);
|
||||
|
||||
#define MAX_MIPMAP_LEVELS 5 // Max number of prefilter texture mipmaps
|
||||
|
||||
for (int mip = 0; mip < MAX_MIPMAP_LEVELS; mip++)
|
||||
{
|
||||
// Resize framebuffer according to mip-level size.
|
||||
unsigned int mipWidth = size*(int)powf(0.5f, (float)mip);
|
||||
unsigned int mipHeight = size*(int)powf(0.5f, (float)mip);
|
||||
|
||||
rlViewport(0, 0, mipWidth, mipHeight);
|
||||
|
||||
//glBindRenderbuffer(GL_RENDERBUFFER, rbo);
|
||||
//glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mipWidth, mipHeight);
|
||||
|
||||
float roughness = (float)mip/(float)(MAX_MIPMAP_LEVELS - 1);
|
||||
rlSetUniform(roughnessLoc, &roughness, SHADER_UNIFORM_FLOAT, 1);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
rlSetUniformMatrix(shader.locs[SHADER_LOC_MATRIX_VIEW], fboViews[i]);
|
||||
rlFramebufferAttach(fbo, prefilter.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X + i, mip);
|
||||
|
||||
rlClearScreenBuffers();
|
||||
rlLoadDrawCube();
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------------------
|
||||
|
||||
// STEP 3: Unload framebuffer and reset state
|
||||
//------------------------------------------------------------------------------------------
|
||||
rlDisableShader(); // Unbind shader
|
||||
rlDisableTexture(); // Unbind texture
|
||||
rlDisableFramebuffer(); // Unbind framebuffer
|
||||
rlUnloadFramebuffer(fbo); // Unload framebuffer (and automatically attached depth texture/renderbuffer)
|
||||
|
||||
// Reset viewport dimensions to default
|
||||
rlViewport(0, 0, rlGetFramebufferWidth(), rlGetFramebufferHeight());
|
||||
rlEnableBackfaceCulling();
|
||||
//------------------------------------------------------------------------------------------
|
||||
|
||||
prefilter.width = size;
|
||||
prefilter.height = size;
|
||||
prefilter.mipmaps = MAX_MIPMAP_LEVELS;
|
||||
prefilter.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32;
|
||||
|
||||
return prefilter;
|
||||
}
|
||||
|
||||
// Generate BRDF texture using cubemap data
|
||||
// TODO: Review implementation: https://github.com/HectorMF/BRDFGenerator
|
||||
static Texture2D GenTextureBRDF(Shader shader, int size)
|
||||
{
|
||||
Texture2D brdf = { 0 };
|
||||
|
||||
// STEP 1: Setup framebuffer
|
||||
//------------------------------------------------------------------------------------------
|
||||
unsigned int rbo = rlLoadTextureDepth(size, size, true);
|
||||
brdf.id = rlLoadTexture(NULL, size, size, PIXELFORMAT_UNCOMPRESSED_R32G32B32, 1);
|
||||
|
||||
unsigned int fbo = rlLoadFramebuffer(size, size);
|
||||
rlFramebufferAttach(fbo, rbo, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER, 0);
|
||||
rlFramebufferAttach(fbo, brdf.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_TEXTURE2D, 0);
|
||||
//------------------------------------------------------------------------------------------
|
||||
|
||||
// STEP 2: Draw to framebuffer
|
||||
//------------------------------------------------------------------------------------------
|
||||
// NOTE: Render BRDF LUT into a quad using FBO
|
||||
rlEnableShader(shader.id);
|
||||
|
||||
rlViewport(0, 0, size, size);
|
||||
|
||||
rlEnableFramebuffer(fbo);
|
||||
rlClearScreenBuffers();
|
||||
|
||||
rlLoadDrawQuad();
|
||||
//------------------------------------------------------------------------------------------
|
||||
|
||||
// STEP 3: Unload framebuffer and reset state
|
||||
//------------------------------------------------------------------------------------------
|
||||
rlDisableShader(); // Unbind shader
|
||||
rlDisableTexture(); // Unbind texture
|
||||
rlDisableFramebuffer(); // Unbind framebuffer
|
||||
rlUnloadFramebuffer(fbo); // Unload framebuffer (and automatically attached depth texture/renderbuffer)
|
||||
|
||||
// Reset viewport dimensions to default
|
||||
rlViewport(0, 0, rlGetFramebufferWidth(), rlGetFramebufferHeight());
|
||||
//------------------------------------------------------------------------------------------
|
||||
|
||||
brdf.width = size;
|
||||
brdf.height = size;
|
||||
brdf.mipmaps = 1;
|
||||
brdf.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32;
|
||||
|
||||
return brdf;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 317 KiB |
|
|
@ -35,8 +35,8 @@ int main(void)
|
|||
|
||||
Ray ray = { 0 }; // Picking ray
|
||||
|
||||
Model tower = LoadModel("resources/models/turret.obj"); // Load OBJ model
|
||||
Texture2D texture = LoadTexture("resources/models/turret_diffuse.png"); // Load model texture
|
||||
Model tower = LoadModel("resources/models/obj/turret.obj"); // Load OBJ model
|
||||
Texture2D texture = LoadTexture("resources/models/obj/turret_diffuse.png"); // Load model texture
|
||||
tower.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture; // Set model diffuse texture
|
||||
|
||||
Vector3 towerPos = { 0.0f, 0.0f, 0.0f }; // Set model position
|
||||
|
|
|
|||
|
|
@ -88,7 +88,6 @@ int main(void)
|
|||
rlPushMatrix();
|
||||
rlRotatef(earthOrbitRotation, 0.0f, 1.0f, 0.0f); // Rotation for Earth orbit around Sun
|
||||
rlTranslatef(earthOrbitRadius, 0.0f, 0.0f); // Translation for Earth orbit
|
||||
rlRotatef(-earthOrbitRotation, 0.0f, 1.0f, 0.0f); // Rotation for Earth orbit around Sun inverted
|
||||
|
||||
rlPushMatrix();
|
||||
rlRotatef(earthRotation, 0.25, 1.0, 0.0); // Rotation for Earth itself
|
||||
|
|
@ -99,7 +98,6 @@ int main(void)
|
|||
|
||||
rlRotatef(moonOrbitRotation, 0.0f, 1.0f, 0.0f); // Rotation for Moon orbit around Earth
|
||||
rlTranslatef(moonOrbitRadius, 0.0f, 0.0f); // Translation for Moon orbit
|
||||
rlRotatef(-moonOrbitRotation, 0.0f, 1.0f, 0.0f); // Rotation for Moon orbit around Earth inverted
|
||||
rlRotatef(moonRotation, 0.0f, 1.0f, 0.0f); // Rotation for Moon itself
|
||||
rlScalef(moonRadius, moonRadius, moonRadius); // Scale Moon
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@
|
|||
********************************************************************************************/
|
||||
|
||||
#include "raylib.h"
|
||||
|
||||
#include "rlgl.h"
|
||||
#include "raymath.h"
|
||||
#include "raymath.h" // Required for: MatrixPerspective(), MatrixLookAt()
|
||||
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
#define GLSL_VERSION 330
|
||||
|
|
|
|||
|
|
@ -7,12 +7,13 @@
|
|||
*
|
||||
* Example contributed by Berni (@Berni8k) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2017 Berni (@Berni8k) and Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2017-2021 Berni (@Berni8k) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
#include "raylib.h"
|
||||
#include "raymath.h"
|
||||
|
||||
#include "raymath.h" // Required for: MatrixRotateXYZ()
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
|
@ -33,7 +34,7 @@ int main(void)
|
|||
|
||||
// Model loading
|
||||
// NOTE: Diffuse map loaded automatically
|
||||
Model model = LoadModel("resources/plane/plane.gltf");
|
||||
Model model = LoadModel("resources/models/gltf/plane/plane.gltf");
|
||||
|
||||
float pitch = 0.0f;
|
||||
float roll = 0.0f;
|
||||
|
|
@ -78,7 +79,6 @@ int main(void)
|
|||
model.transform = MatrixRotateXYZ((Vector3){ DEG2RAD*pitch, DEG2RAD*yaw, DEG2RAD*roll });
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
|
|
|||
|
|
@ -1,13 +1,19 @@
|
|||
| resource | author | licence | notes |
|
||||
| :------------------- | :---------: | :------ | :---- |
|
||||
| models/castle.obj,<br> models/castle_diffuse.png | [Alberto Cano](https://www.artstation.com/albertocano) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode) | - |
|
||||
| models/bridge.obj,<br> models/bridge_diffuse.png | [Alberto Cano](https://www.artstation.com/albertocano) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode) | - |
|
||||
| models/house.obj,<br> models/house_diffuse.png | [Alberto Cano](https://www.artstation.com/albertocano) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode) | - |
|
||||
| models/market.obj,<br> models/market_diffuse.png | [Alberto Cano](https://www.artstation.com/albertocano) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode) | - |
|
||||
| models/turret.obj,<br> models/turret_diffuse.png | [Alberto Cano](https://www.artstation.com/albertocano) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode) | - |
|
||||
| models/well.obj,<br> models/well_diffuse.png | [Alberto Cano](https://www.artstation.com/albertocano) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode) | - |
|
||||
| models/cube.obj,<br> models/cube_diffuse.png | [@raysan5](https://github.com/raysan5) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | - |
|
||||
| models/vertex_colored_object.iqm | ❔ | ❔ | - |
|
||||
| models/obj/castle.obj,<br>models/castle_diffuse.png | [Alberto Cano](https://www.artstation.com/albertocano) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode) | - |
|
||||
| models/obj/bridge.obj,<br>models/bridge_diffuse.png | [Alberto Cano](https://www.artstation.com/albertocano) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode) | - |
|
||||
| models/obj/house.obj,<br>models/house_diffuse.png | [Alberto Cano](https://www.artstation.com/albertocano) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode) | - |
|
||||
| models/obj/market.obj,<br>models/market_diffuse.png | [Alberto Cano](https://www.artstation.com/albertocano) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode) | - |
|
||||
| models/obj/turret.obj,<br>models/turret_diffuse.png | [Alberto Cano](https://www.artstation.com/albertocano) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode) | - |
|
||||
| models/obj/well.obj,<br>models/well_diffuse.png | [Alberto Cano](https://www.artstation.com/albertocano) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode) | - |
|
||||
| models/obj/cube.obj,<br>models/cube_diffuse.png | [@raysan5](https://github.com/raysan5) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | - |
|
||||
| models/iqm/guy.iqm,<br>models/iqm/guyanim.iqm,<br>models/iqm/guytex.png,<br>models/iqm/guy.blend | [@culacant](https://github.com/culacant) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | - |
|
||||
| models/iqm/vertex_colored_object.iqm | ❔ | ❔ | - |
|
||||
| models/gltf/plane/plane.gltf,<br>models/gltf/plane/plane.bin,<br>models/gltf/plane/plane_diffuse.png | [GiaHanLam](https://sketchfab.com/GiaHanLam) | [CC-BY](https://creativecommons.org/licenses/by/4.0/) | Used by: [`models_yaw_pitch_roll.c`](https://github.com/raysan5/raylib/blob/master/examples/models/models_yaw_pitch_roll.c)
|
||||
| models/gltf/... | _various_ | Check [LICENSE](https://github.com/raysan5/raylib/blob/master/examples/models/resources/models/gltf/LICENSE) | - |
|
||||
| models/vox/chr_knight.vox | ❔ | ❔ | - |
|
||||
| models/vox/chr_sword.vox | ❔ | ❔ | - |
|
||||
| models/vox/monu9.vox | ❔ | ❔ | - |
|
||||
| billboard.png | [@emegeme](https://github.com/emegeme) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | - |
|
||||
| cubicmap.png | [@raysan5](https://github.com/raysan5) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | - |
|
||||
| cubicmap_atlas.png | [@emegeme](https://github.com/emegeme) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | - |
|
||||
|
|
@ -15,6 +21,3 @@
|
|||
| dresden_square_1k.hdr | [HDRIHaven](https://hdrihaven.com/hdri/?h=dresden_square) | [CC0](https://hdrihaven.com/p/license.php) | - |
|
||||
| dresden_square_2k.hdr | [HDRIHaven](https://hdrihaven.com/hdri/?h=dresden_square) | [CC0](https://hdrihaven.com/p/license.php) | - |
|
||||
| skybox.png | ❔ | ❔ | - |
|
||||
| **guy/...** | [@culacant](https://github.com/culacant) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) |
|
||||
| **plane/...** | [GiaHanLam](https://sketchfab.com/GiaHanLam) | [CC-BY](https://creativecommons.org/licenses/by/4.0/) | Used by: [`models_yaw_pitch_roll.c`](https://github.com/raysan5/raylib/blob/master/examples/models/models_yaw_pitch_roll.c)
|
||||
| **gltf/...** | _various_ | [LICENSE](https://github.com/raysan5/raylib/blob/master/examples/models/resources/gltf/LICENSE) | - |
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 311 KiB |
|
Before Width: | Height: | Size: 434 KiB |
|
|
@ -1,68 +0,0 @@
|
|||
# reference material
|
||||
#mtllib cube.mtl
|
||||
|
||||
# object box
|
||||
|
||||
# vertex (XZY)
|
||||
v 5.5 0 1.5
|
||||
v 8.5 0 1.5
|
||||
v 5.5 0 -1.5
|
||||
v 8.5 0 -1.5
|
||||
v 5.5 3 1.5
|
||||
v 8.5 3 1.5
|
||||
v 5.5 3 -1.5
|
||||
v 8.5 3 -1.5
|
||||
|
||||
# normals (XYZ)
|
||||
vn 0 -1 0
|
||||
vn 0 1 0
|
||||
vn 0 0 1
|
||||
vn 1 0 0
|
||||
vn 0 0 -1
|
||||
vn -1 0 0
|
||||
|
||||
# UVs (XY)
|
||||
vt 0.5 0 0
|
||||
vt 1 0 0
|
||||
vt 1 0.5 0
|
||||
vt 0.5 0.5 0
|
||||
vt 0.5 0.5 0
|
||||
vt 1 0.5 0
|
||||
vt 0.5 1 0
|
||||
vt 1 1 0
|
||||
vt 0 0.5 0
|
||||
vt 1 0.5 0
|
||||
vt 1 0 0
|
||||
vt 0 0 0
|
||||
vt 0 0.5 0
|
||||
vt 1 0.5 0
|
||||
vt 1 1 0
|
||||
vt 0 1 0
|
||||
vt 0.5 0 0
|
||||
vt 0 0 0
|
||||
vt 0 0.5 0
|
||||
vt 0.5 0.5 0
|
||||
vt 0 0.5 0
|
||||
vt 0.5 0.5 0
|
||||
vt 0.5 1 0
|
||||
vt 0 1 0
|
||||
|
||||
# merger
|
||||
g box
|
||||
|
||||
# reference material
|
||||
#usemtl mat01
|
||||
|
||||
# faces
|
||||
f 1/9/1 3/10/1 4/11/1
|
||||
f 4/11/1 2/12/1 1/9/1
|
||||
f 5/13/2 6/14/2 8/15/2
|
||||
f 8/15/2 7/16/2 5/13/2
|
||||
f 1/17/6 2/18/6 6/19/6
|
||||
f 6/19/6 5/20/6 1/17/6
|
||||
f 2/6/1 4/5/1 8/7/1
|
||||
f 8/7/1 6/8/1 2/6/1
|
||||
f 4/2/3 3/1/3 7/4/3
|
||||
f 7/4/3 8/3/3 4/2/3
|
||||
f 3/22/5 1/21/5 5/24/5
|
||||
f 5/24/5 7/23/5 3/22/5
|
||||
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 804 KiB After Width: | Height: | Size: 804 KiB |
|
Before Width: | Height: | Size: 383 KiB |
|
Before Width: | Height: | Size: 295 KiB After Width: | Height: | Size: 295 KiB |
|
Before Width: | Height: | Size: 380 KiB |
|
Before Width: | Height: | Size: 371 KiB |
9
examples/models/resources/models/vox/LICENSE
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
The following models are provided by the official github repo of voxel-model format by MagikaVoxel developer @ephtracy
|
||||
|
||||
GitHub official repo: https://github.com/ephtracy/voxel-model
|
||||
|
||||
- chr_knight.vox - https://github.com/ephtracy/voxel-model/blob/master/vox/character/chr_knight.vox
|
||||
- chr_sword.vox - https://github.com/ephtracy/voxel-model/blob/master/vox/character/chr_sword.vox
|
||||
- monu9.vox - https://github.com/ephtracy/voxel-model/blob/master/vox/monument/monu9.vox
|
||||
|
||||
Worth mentioning there is no license specified for the models yet: https://github.com/ephtracy/voxel-model/issues/22
|
||||
|
Before Width: | Height: | Size: 334 KiB |
|
Before Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 547 KiB |
|
Before Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 717 KiB |
|
|
@ -1,124 +0,0 @@
|
|||
#version 330
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec2 fragTexCoord;
|
||||
|
||||
// Constant values
|
||||
const float PI = 3.14159265359;
|
||||
const uint MAX_SAMPLES = 1024u;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
vec2 Hammersley(uint i, uint N);
|
||||
float RadicalInverseVdC(uint bits);
|
||||
float GeometrySchlickGGX(float NdotV, float roughness);
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness);
|
||||
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness);
|
||||
vec2 IntegrateBRDF(float NdotV, float roughness);
|
||||
|
||||
float RadicalInverseVdC(uint bits)
|
||||
{
|
||||
bits = (bits << 16u) | (bits >> 16u);
|
||||
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
||||
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
||||
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
||||
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
||||
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||
}
|
||||
|
||||
// Compute Hammersley coordinates
|
||||
vec2 Hammersley(uint i, uint N)
|
||||
{
|
||||
return vec2(float(i)/float(N), RadicalInverseVdC(i));
|
||||
}
|
||||
|
||||
// Integrate number of importance samples for (roughness and NoV)
|
||||
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)
|
||||
{
|
||||
float a = roughness*roughness;
|
||||
float phi = 2.0 * PI * Xi.x;
|
||||
float cosTheta = sqrt((1.0 - Xi.y)/(1.0 + (a*a - 1.0)*Xi.y));
|
||||
float sinTheta = sqrt(1.0 - cosTheta*cosTheta);
|
||||
|
||||
// Transform from spherical coordinates to cartesian coordinates (halfway vector)
|
||||
vec3 H = vec3(cos(phi)*sinTheta, sin(phi)*sinTheta, cosTheta);
|
||||
|
||||
// Transform from tangent space H vector to world space sample vector
|
||||
vec3 up = ((abs(N.z) < 0.999) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0));
|
||||
vec3 tangent = normalize(cross(up, N));
|
||||
vec3 bitangent = cross(N, tangent);
|
||||
vec3 sampleVec = tangent*H.x + bitangent*H.y + N*H.z;
|
||||
|
||||
return normalize(sampleVec);
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float roughness)
|
||||
{
|
||||
// For IBL k is calculated different
|
||||
float k = (roughness*roughness)/2.0;
|
||||
|
||||
float nom = NdotV;
|
||||
float denom = NdotV*(1.0 - k) + k;
|
||||
|
||||
return nom/denom;
|
||||
}
|
||||
|
||||
// Compute the geometry term for the BRDF given roughness squared, NoV, NoL
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
|
||||
{
|
||||
float NdotV = max(dot(N, V), 0.0);
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
||||
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
||||
|
||||
return ggx1*ggx2;
|
||||
}
|
||||
|
||||
// Bidirectional reflectance distribution function
|
||||
// Ref: https://github.com/HectorMF/BRDFGenerator
|
||||
vec2 IntegrateBRDF(float NdotV, float roughness)
|
||||
{
|
||||
float A = 0.0;
|
||||
float B = 0.0;
|
||||
vec3 V = vec3(sqrt(1.0 - NdotV*NdotV), 0.0, NdotV);
|
||||
vec3 N = vec3(0.0, 0.0, 1.0);
|
||||
|
||||
for (uint i = 0u; i < MAX_SAMPLES; i++)
|
||||
{
|
||||
// Generate a sample vector that's biased towards the preferred alignment direction (importance sampling)
|
||||
|
||||
vec2 Xi = Hammersley(i, MAX_SAMPLES); // Compute a Hammersely coordinate
|
||||
vec3 H = ImportanceSampleGGX(Xi, N, roughness); // Integrate number of importance samples for (roughness and NoV)
|
||||
vec3 L = normalize(2.0*dot(V, H)*H - V); // Compute reflection vector L
|
||||
|
||||
float NdotL = max(L.z, 0.0); // Compute normal dot light
|
||||
float NdotH = max(H.z, 0.0); // Compute normal dot half
|
||||
float VdotH = max(dot(V, H), 0.0); // Compute view dot half
|
||||
|
||||
if (NdotL > 0.0)
|
||||
{
|
||||
float G = GeometrySmith(N, V, L, roughness); // Compute the geometry term for the BRDF given roughness squared, NoV, NoL
|
||||
float GVis = (G*VdotH)/(NdotH*NdotV); // Compute the visibility term given G, VoH, NoH, NoV, NoL
|
||||
float Fc = pow(1.0 - VdotH, 5.0); // Compute the fresnel term given VoH
|
||||
|
||||
A += (1.0 - Fc)*GVis; // Sum the result given fresnel, geometry, visibility
|
||||
B += Fc*GVis;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate brdf average sample
|
||||
A /= float(MAX_SAMPLES);
|
||||
B /= float(MAX_SAMPLES);
|
||||
|
||||
return vec2(A, B);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
// Calculate brdf based on texture coordinates
|
||||
vec2 brdf = IntegrateBRDF(fragTexCoord.x, fragTexCoord.y);
|
||||
|
||||
// Calculate final fragment color
|
||||
finalColor = vec4(brdf.r, brdf.g, 0.0, 1.0);
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
#version 330
|
||||
|
||||
// Input vertex attributes
|
||||
in vec3 vertexPosition;
|
||||
in vec2 vertexTexCoord;
|
||||
|
||||
// Output vertex attributes (to fragment shader)
|
||||
out vec2 fragTexCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Calculate fragment position based on model transformations
|
||||
fragTexCoord = vertexTexCoord;
|
||||
|
||||
// Calculate final vertex position
|
||||
gl_Position = vec4(vertexPosition, 1.0);
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
#version 330
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec3 fragPosition;
|
||||
|
||||
// Input uniform values
|
||||
uniform samplerCube environmentMap;
|
||||
|
||||
// Constant values
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
// The sample direction equals the hemisphere's orientation
|
||||
vec3 normal = normalize(fragPosition);
|
||||
|
||||
vec3 irradiance = vec3(0.0);
|
||||
|
||||
vec3 up = vec3(0.0, 1.0, 0.0);
|
||||
vec3 right = cross(up, normal);
|
||||
up = cross(normal, right);
|
||||
|
||||
float sampleDelta = 0.025;
|
||||
float nrSamples = 0.0;
|
||||
|
||||
for (float phi = 0.0; phi < 2.0*PI; phi += sampleDelta)
|
||||
{
|
||||
for (float theta = 0.0; theta < 0.5*PI; theta += sampleDelta)
|
||||
{
|
||||
// Spherical to cartesian (in tangent space)
|
||||
vec3 tangentSample = vec3(sin(theta)*cos(phi), sin(theta)*sin(phi), cos(theta));
|
||||
|
||||
// tangent space to world
|
||||
vec3 sampleVec = tangentSample.x*right + tangentSample.y*up + tangentSample.z*normal;
|
||||
|
||||
// Fetch color from environment cubemap
|
||||
irradiance += texture(environmentMap, sampleVec).rgb*cos(theta)*sin(theta);
|
||||
nrSamples++;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate irradiance average value from samples
|
||||
irradiance = PI*irradiance*(1.0/float(nrSamples));
|
||||
|
||||
// Calculate final fragment color
|
||||
finalColor = vec4(irradiance, 1.0);
|
||||
}
|
||||
|
|
@ -1,292 +0,0 @@
|
|||
#version 330
|
||||
|
||||
#define MAX_REFLECTION_LOD 4.0
|
||||
#define MAX_DEPTH_LAYER 20
|
||||
#define MIN_DEPTH_LAYER 10
|
||||
|
||||
#define MAX_LIGHTS 4
|
||||
#define LIGHT_DIRECTIONAL 0
|
||||
#define LIGHT_POINT 1
|
||||
|
||||
struct MaterialProperty {
|
||||
vec3 color;
|
||||
int useSampler;
|
||||
sampler2D sampler;
|
||||
};
|
||||
|
||||
struct Light {
|
||||
int enabled;
|
||||
int type;
|
||||
vec3 position;
|
||||
vec3 target;
|
||||
vec4 color;
|
||||
};
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec3 fragPosition;
|
||||
in vec2 fragTexCoord;
|
||||
in vec3 fragNormal;
|
||||
in vec3 fragTangent;
|
||||
in vec3 fragBinormal;
|
||||
|
||||
// Input material values
|
||||
uniform MaterialProperty albedo;
|
||||
uniform MaterialProperty normals;
|
||||
uniform MaterialProperty metalness;
|
||||
uniform MaterialProperty roughness;
|
||||
uniform MaterialProperty occlusion;
|
||||
uniform MaterialProperty emission;
|
||||
uniform MaterialProperty height;
|
||||
|
||||
// Input uniform values
|
||||
uniform samplerCube irradianceMap;
|
||||
uniform samplerCube prefilterMap;
|
||||
uniform sampler2D brdfLUT;
|
||||
|
||||
// Input lighting values
|
||||
uniform Light lights[MAX_LIGHTS];
|
||||
|
||||
// Other uniform values
|
||||
uniform int renderMode;
|
||||
uniform vec3 viewPos;
|
||||
vec2 texCoord;
|
||||
|
||||
// Constant values
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
vec3 ComputeMaterialProperty(MaterialProperty property);
|
||||
float DistributionGGX(vec3 N, vec3 H, float roughness);
|
||||
float GeometrySchlickGGX(float NdotV, float roughness);
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness);
|
||||
vec3 fresnelSchlick(float cosTheta, vec3 F0);
|
||||
vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness);
|
||||
vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir);
|
||||
|
||||
// WARNING: There is some weird behaviour with this function, always returns black!
|
||||
// Yes, I even tried: return texture(property.sampler, texCoord).rgb;
|
||||
vec3 ComputeMaterialProperty(MaterialProperty property)
|
||||
{
|
||||
vec3 result = vec3(0.0, 0.0, 0.0);
|
||||
|
||||
if (property.useSampler == 1) result = texture(property.sampler, texCoord).rgb;
|
||||
else result = property.color;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float DistributionGGX(vec3 N, vec3 H, float roughness)
|
||||
{
|
||||
float a = roughness*roughness;
|
||||
float a2 = a*a;
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float NdotH2 = NdotH*NdotH;
|
||||
|
||||
float nom = a2;
|
||||
float denom = (NdotH2*(a2 - 1.0) + 1.0);
|
||||
denom = PI*denom*denom;
|
||||
|
||||
return nom/denom;
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float roughness)
|
||||
{
|
||||
float r = (roughness + 1.0);
|
||||
float k = r*r/8.0;
|
||||
|
||||
float nom = NdotV;
|
||||
float denom = NdotV*(1.0 - k) + k;
|
||||
|
||||
return nom/denom;
|
||||
}
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
|
||||
{
|
||||
float NdotV = max(dot(N, V), 0.0);
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
||||
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
||||
|
||||
return ggx1*ggx2;
|
||||
}
|
||||
|
||||
vec3 fresnelSchlick(float cosTheta, vec3 F0)
|
||||
{
|
||||
return F0 + (1.0 - F0)*pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness)
|
||||
{
|
||||
return F0 + (max(vec3(1.0 - roughness), F0) - F0)*pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir)
|
||||
{
|
||||
// Calculate the number of depth layers and calculate the size of each layer
|
||||
float numLayers = mix(MAX_DEPTH_LAYER, MIN_DEPTH_LAYER, abs(dot(vec3(0.0, 0.0, 1.0), viewDir)));
|
||||
float layerDepth = 1.0/numLayers;
|
||||
|
||||
// Calculate depth of current layer
|
||||
float currentLayerDepth = 0.0;
|
||||
|
||||
// Calculate the amount to shift the texture coordinates per layer (from vector P)
|
||||
// Note: height amount is stored in height material attribute color R channel (sampler use is independent)
|
||||
vec2 P = viewDir.xy*height.color.r;
|
||||
vec2 deltaTexCoords = P/numLayers;
|
||||
|
||||
// Store initial texture coordinates and depth values
|
||||
vec2 currentTexCoords = texCoords;
|
||||
float currentDepthMapValue = texture(height.sampler, currentTexCoords).r;
|
||||
|
||||
while (currentLayerDepth < currentDepthMapValue)
|
||||
{
|
||||
// Shift texture coordinates along direction of P
|
||||
currentTexCoords -= deltaTexCoords;
|
||||
|
||||
// Get depth map value at current texture coordinates
|
||||
currentDepthMapValue = texture(height.sampler, currentTexCoords).r;
|
||||
|
||||
// Get depth of next layer
|
||||
currentLayerDepth += layerDepth;
|
||||
}
|
||||
|
||||
// Get texture coordinates before collision (reverse operations)
|
||||
vec2 prevTexCoords = currentTexCoords + deltaTexCoords;
|
||||
|
||||
// Get depth after and before collision for linear interpolation
|
||||
float afterDepth = currentDepthMapValue - currentLayerDepth;
|
||||
float beforeDepth = texture(height.sampler, prevTexCoords).r - currentLayerDepth + layerDepth;
|
||||
|
||||
// Interpolation of texture coordinates
|
||||
float weight = afterDepth/(afterDepth - beforeDepth);
|
||||
vec2 finalTexCoords = prevTexCoords*weight + currentTexCoords*(1.0 - weight);
|
||||
|
||||
return finalTexCoords;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
// Calculate TBN and RM matrices
|
||||
mat3 TBN = transpose(mat3(fragTangent, fragBinormal, fragNormal));
|
||||
|
||||
// Calculate lighting required attributes
|
||||
vec3 normal = normalize(fragNormal);
|
||||
vec3 view = normalize(viewPos - fragPosition);
|
||||
vec3 refl = reflect(-view, normal);
|
||||
|
||||
// Check if parallax mapping is enabled and calculate texture coordinates to use based on height map
|
||||
// NOTE: remember that 'texCoord' variable must be assigned before calling any ComputeMaterialProperty() function
|
||||
if (height.useSampler == 1) texCoord = ParallaxMapping(fragTexCoord, view);
|
||||
else texCoord = fragTexCoord; // Use default texture coordinates
|
||||
|
||||
// Fetch material values from texture sampler or color attributes
|
||||
vec3 color = texture(albedo.sampler, texCoord).rgb; //ComputeMaterialProperty(albedo);
|
||||
vec3 metal = texture(metalness.sampler, texCoord).rgb; //ComputeMaterialProperty(metalness);
|
||||
vec3 rough = texture(roughness.sampler, texCoord).rgb; //ComputeMaterialProperty(roughness);
|
||||
vec3 emiss = texture(emission.sampler, texCoord).rgb; //ComputeMaterialProperty(emission);
|
||||
vec3 ao = texture(occlusion.sampler, texCoord).rgb; //ComputeMaterialProperty(occlusion);
|
||||
|
||||
// Check if normal mapping is enabled
|
||||
if (normals.useSampler == 1)
|
||||
{
|
||||
// Fetch normal map color and transform lighting values to tangent space
|
||||
normal = texture(normals.sampler, texCoord).rgb; //ComputeMaterialProperty(normals);
|
||||
normal = normalize(normal*2.0 - 1.0);
|
||||
normal = normalize(normal*TBN);
|
||||
|
||||
// Convert tangent space normal to world space due to cubemap reflection calculations
|
||||
refl = normalize(reflect(-view, normal));
|
||||
}
|
||||
|
||||
// Calculate reflectance at normal incidence
|
||||
vec3 F0 = vec3(0.04);
|
||||
F0 = mix(F0, color, metal.r);
|
||||
|
||||
// Calculate lighting for all lights
|
||||
vec3 Lo = vec3(0.0);
|
||||
vec3 lightDot = vec3(0.0);
|
||||
|
||||
for (int i = 0; i < MAX_LIGHTS; i++)
|
||||
{
|
||||
if (lights[i].enabled == 1)
|
||||
{
|
||||
// Calculate per-light radiance
|
||||
vec3 light = vec3(0.0);
|
||||
vec3 radiance = lights[i].color.rgb;
|
||||
if (lights[i].type == LIGHT_DIRECTIONAL) light = -normalize(lights[i].target - lights[i].position);
|
||||
else if (lights[i].type == LIGHT_POINT)
|
||||
{
|
||||
light = normalize(lights[i].position - fragPosition);
|
||||
float distance = length(lights[i].position - fragPosition);
|
||||
float attenuation = 1.0/(distance*distance);
|
||||
radiance *= attenuation;
|
||||
}
|
||||
|
||||
// Cook-torrance BRDF
|
||||
vec3 high = normalize(view + light);
|
||||
float NDF = DistributionGGX(normal, high, rough.r);
|
||||
float G = GeometrySmith(normal, view, light, rough.r);
|
||||
vec3 F = fresnelSchlick(max(dot(high, view), 0.0), F0);
|
||||
vec3 nominator = NDF*G*F;
|
||||
float denominator = 4*max(dot(normal, view), 0.0)*max(dot(normal, light), 0.0) + 0.001;
|
||||
vec3 brdf = nominator/denominator;
|
||||
|
||||
// Store to kS the fresnel value and calculate energy conservation
|
||||
vec3 kS = F;
|
||||
vec3 kD = vec3(1.0) - kS;
|
||||
|
||||
// Multiply kD by the inverse metalness such that only non-metals have diffuse lighting
|
||||
kD *= 1.0 - metal.r;
|
||||
|
||||
// Scale light by dot product between normal and light direction
|
||||
float NdotL = max(dot(normal, light), 0.0);
|
||||
|
||||
// Add to outgoing radiance Lo
|
||||
// Note: BRDF is already multiplied by the Fresnel so it doesn't need to be multiplied again
|
||||
Lo += (kD*color/PI + brdf)*radiance*NdotL*lights[i].color.a;
|
||||
lightDot += radiance*NdotL + brdf*lights[i].color.a;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate ambient lighting using IBL
|
||||
vec3 F = fresnelSchlickRoughness(max(dot(normal, view), 0.0), F0, rough.r);
|
||||
vec3 kS = F;
|
||||
vec3 kD = 1.0 - kS;
|
||||
kD *= 1.0 - metal.r;
|
||||
|
||||
// Calculate indirect diffuse
|
||||
vec3 irradiance = texture(irradianceMap, fragNormal).rgb;
|
||||
vec3 diffuse = color*irradiance;
|
||||
|
||||
// Sample both the prefilter map and the BRDF lut and combine them together as per the Split-Sum approximation
|
||||
vec3 prefilterColor = textureLod(prefilterMap, refl, rough.r*MAX_REFLECTION_LOD).rgb;
|
||||
vec2 brdf = texture(brdfLUT, vec2(max(dot(normal, view), 0.0), rough.r)).rg;
|
||||
vec3 reflection = prefilterColor*(F*brdf.x + brdf.y);
|
||||
|
||||
// Calculate final lighting
|
||||
vec3 ambient = (kD*diffuse + reflection)*ao;
|
||||
|
||||
// Calculate fragment color based on render mode
|
||||
vec3 fragmentColor = ambient + Lo + emiss; // Physically Based Rendering
|
||||
|
||||
if (renderMode == 1) fragmentColor = color; // Albedo
|
||||
else if (renderMode == 2) fragmentColor = normal; // Normals
|
||||
else if (renderMode == 3) fragmentColor = metal; // Metalness
|
||||
else if (renderMode == 4) fragmentColor = rough; // Roughness
|
||||
else if (renderMode == 5) fragmentColor = ao; // Ambient Occlusion
|
||||
else if (renderMode == 6) fragmentColor = emiss; // Emission
|
||||
else if (renderMode == 7) fragmentColor = lightDot; // Lighting
|
||||
else if (renderMode == 8) fragmentColor = kS; // Fresnel
|
||||
else if (renderMode == 9) fragmentColor = irradiance; // Irradiance
|
||||
else if (renderMode == 10) fragmentColor = reflection; // Reflection
|
||||
|
||||
// Apply HDR tonemapping
|
||||
fragmentColor = fragmentColor/(fragmentColor + vec3(1.0));
|
||||
|
||||
// Apply gamma correction
|
||||
fragmentColor = pow(fragmentColor, vec3(1.0/2.2));
|
||||
|
||||
// Calculate final fragment color
|
||||
finalColor = vec4(fragmentColor, 1.0);
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
#version 330
|
||||
|
||||
// Input vertex attributes
|
||||
in vec3 vertexPosition;
|
||||
in vec2 vertexTexCoord;
|
||||
in vec3 vertexNormal;
|
||||
in vec4 vertexTangent;
|
||||
|
||||
// Input uniform values
|
||||
uniform mat4 mvp;
|
||||
uniform mat4 matModel;
|
||||
|
||||
// Output vertex attributes (to fragment shader)
|
||||
out vec3 fragPosition;
|
||||
out vec2 fragTexCoord;
|
||||
out vec3 fragNormal;
|
||||
out vec3 fragTangent;
|
||||
out vec3 fragBinormal;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Calculate binormal from vertex normal and tangent
|
||||
vec3 vertexBinormal = cross(vertexNormal, vec3(vertexTangent));
|
||||
|
||||
// Calculate fragment normal based on normal transformations
|
||||
mat3 normalMatrix = transpose(inverse(mat3(matModel)));
|
||||
|
||||
// Calculate fragment position based on model transformations
|
||||
fragPosition = vec3(matModel*vec4(vertexPosition, 1.0));
|
||||
|
||||
// Send vertex attributes to fragment shader
|
||||
fragTexCoord = vertexTexCoord;
|
||||
fragNormal = normalize(normalMatrix*vertexNormal);
|
||||
fragTangent = normalize(normalMatrix*vec3(vertexTangent));
|
||||
fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal)*fragNormal);
|
||||
fragBinormal = normalize(normalMatrix*vertexBinormal);
|
||||
fragBinormal = cross(fragNormal, fragTangent);
|
||||
|
||||
// Calculate final vertex position
|
||||
gl_Position = mvp*vec4(vertexPosition, 1.0);
|
||||
}
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
#version 330
|
||||
|
||||
#define MAX_SAMPLES 1024u
|
||||
#define CUBEMAP_RESOLUTION 1024.0
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec3 fragPosition;
|
||||
|
||||
// Input uniform values
|
||||
uniform samplerCube environmentMap;
|
||||
uniform float roughness;
|
||||
|
||||
// Constant values
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
float DistributionGGX(vec3 N, vec3 H, float roughness);
|
||||
float RadicalInverse_VdC(uint bits);
|
||||
vec2 Hammersley(uint i, uint N);
|
||||
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness);
|
||||
|
||||
float DistributionGGX(vec3 N, vec3 H, float roughness)
|
||||
{
|
||||
float a = roughness*roughness;
|
||||
float a2 = a*a;
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float NdotH2 = NdotH*NdotH;
|
||||
|
||||
float nom = a2;
|
||||
float denom = (NdotH2*(a2 - 1.0) + 1.0);
|
||||
denom = PI*denom*denom;
|
||||
|
||||
return nom/denom;
|
||||
}
|
||||
|
||||
float RadicalInverse_VdC(uint bits)
|
||||
{
|
||||
bits = (bits << 16u) | (bits >> 16u);
|
||||
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
||||
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
||||
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
||||
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
||||
return float(bits)*2.3283064365386963e-10; // / 0x100000000
|
||||
}
|
||||
|
||||
vec2 Hammersley(uint i, uint N)
|
||||
{
|
||||
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
|
||||
}
|
||||
|
||||
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)
|
||||
{
|
||||
float a = roughness*roughness;
|
||||
float phi = 2.0*PI*Xi.x;
|
||||
float cosTheta = sqrt((1.0 - Xi.y)/(1.0 + (a*a - 1.0)*Xi.y));
|
||||
float sinTheta = sqrt(1.0 - cosTheta*cosTheta);
|
||||
|
||||
// Transform from spherical coordinates to cartesian coordinates (halfway vector)
|
||||
vec3 H = vec3(cos(phi)*sinTheta, sin(phi)*sinTheta, cosTheta);
|
||||
|
||||
// Transform from tangent space H vector to world space sample vector
|
||||
vec3 up = ((abs(N.z) < 0.999) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0));
|
||||
vec3 tangent = normalize(cross(up, N));
|
||||
vec3 bitangent = cross(N, tangent);
|
||||
vec3 sampleVec = tangent*H.x + bitangent*H.y + N*H.z;
|
||||
|
||||
return normalize(sampleVec);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
// Make the simplyfying assumption that V equals R equals the normal
|
||||
vec3 N = normalize(fragPosition);
|
||||
vec3 R = N;
|
||||
vec3 V = R;
|
||||
|
||||
vec3 prefilteredColor = vec3(0.0);
|
||||
float totalWeight = 0.0;
|
||||
|
||||
for (uint i = 0u; i < MAX_SAMPLES; i++)
|
||||
{
|
||||
// Generate a sample vector that's biased towards the preferred alignment direction (importance sampling)
|
||||
vec2 Xi = Hammersley(i, MAX_SAMPLES);
|
||||
vec3 H = ImportanceSampleGGX(Xi, N, roughness);
|
||||
vec3 L = normalize(2.0*dot(V, H)*H - V);
|
||||
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
if(NdotL > 0.0)
|
||||
{
|
||||
// Sample from the environment's mip level based on roughness/pdf
|
||||
float D = DistributionGGX(N, H, roughness);
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float HdotV = max(dot(H, V), 0.0);
|
||||
float pdf = D*NdotH/(4.0*HdotV) + 0.0001;
|
||||
|
||||
float resolution = CUBEMAP_RESOLUTION;
|
||||
float saTexel = 4.0*PI/(6.0*resolution*resolution);
|
||||
float saSample = 1.0/(float(MAX_SAMPLES)*pdf + 0.0001);
|
||||
float mipLevel = ((roughness == 0.0) ? 0.0 : 0.5*log2(saSample/saTexel));
|
||||
|
||||
prefilteredColor += textureLod(environmentMap, L, mipLevel).rgb*NdotL;
|
||||
totalWeight += NdotL;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate prefilter average color
|
||||
prefilteredColor = prefilteredColor/totalWeight;
|
||||
|
||||
// Calculate final fragment color
|
||||
finalColor = vec4(prefilteredColor, 1.0);
|
||||
}
|
||||
|
|
@ -24,8 +24,14 @@
|
|||
********************************************************************************************/
|
||||
|
||||
#include "raylib.h"
|
||||
|
||||
#include "rlgl.h" // Required for: rlDrawRenderBatchActive(), rlGetMatrixModelview(), rlGetMatrixProjection()
|
||||
#include "glad.h" // Required for: OpenGL functionality
|
||||
#if defined(__APPLE__)
|
||||
#include <OpenGL/gl3.h> // OpenGL 3 library for OSX
|
||||
#include <OpenGL/gl3ext.h> // OpenGL 3 extensions library for OSX
|
||||
#else
|
||||
#include "glad.h" // Required for: OpenGL functionality
|
||||
#endif
|
||||
#include "raymath.h" // Required for: MatrixMultiply(), MatrixToFloat()
|
||||
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
|
|
|
|||
|
|
@ -9,5 +9,3 @@
|
|||
| raysan.png | [@raysan5](https://github.com/raysan5) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | - |
|
||||
| space.png | ❔ | ❔ | - |
|
||||
| texel_checker.png | [@raysan5](https://github.com/raysan5) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | Made with [UV Checker Map Maker](http://uvchecker.byvalle.com/) |
|
||||
| egg.png | [@GoldenThumbs](https://github.com/GoldenThumbs) |
|
||||
| torus.png | [@GoldenThumbs](https://github.com/GoldenThumbs) |
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 316 B |
|
|
@ -7,30 +7,29 @@ in vec4 fragColor;
|
|||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 colDiffuse;
|
||||
uniform vec2 texScale;
|
||||
|
||||
uniform vec2 textureSize;
|
||||
uniform float outlineSize;
|
||||
uniform vec4 outlineColor;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
// Function for drawing outlines on alpha-blended textures
|
||||
vec4 DrawOutline(sampler2D tex, vec2 uv, vec2 lineScale, vec3 lineCol)
|
||||
{
|
||||
vec2 texelScale = 1.0 / lineScale;
|
||||
vec4 center = texture(tex, uv); // We sample the center texel, (with all color data)
|
||||
// Next we sample four corner texels, but only for the alpha channel (this is for the outline)
|
||||
vec4 corners;
|
||||
corners.x = texture(tex, uv+vec2( texelScale.x, texelScale.y)).a;
|
||||
corners.y = texture(tex, uv+vec2( texelScale.x,-texelScale.y)).a;
|
||||
corners.z = texture(tex, uv+vec2(-texelScale.x, texelScale.y)).a;
|
||||
corners.w = texture(tex, uv+vec2(-texelScale.x,-texelScale.y)).a;
|
||||
|
||||
float outline = min(dot(corners, vec4(1.0)), 1.0);
|
||||
vec4 col = mix(vec4(0.0), vec4(lineCol, 1.0), outline);
|
||||
col = mix(col, center, center.a);
|
||||
return col;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
finalColor = DrawOutline(texture0, fragTexCoord, texScale, vec3(0.0));
|
||||
vec4 texel = texture(texture0, fragTexCoord); // Get texel color
|
||||
vec2 texelScale = vec2(0.0);
|
||||
texelScale.x = outlineSize/textureSize.x;
|
||||
texelScale.y = outlineSize/textureSize.y;
|
||||
|
||||
// We sample four corner texels, but only for the alpha channel (this is for the outline)
|
||||
vec4 corners = vec4(0.0);
|
||||
corners.x = texture(texture0, fragTexCoord + vec2(texelScale.x, texelScale.y)).a;
|
||||
corners.y = texture(texture0, fragTexCoord + vec2(texelScale.x, -texelScale.y)).a;
|
||||
corners.z = texture(texture0, fragTexCoord + vec2(-texelScale.x, texelScale.y)).a;
|
||||
corners.w = texture(texture0, fragTexCoord + vec2(-texelScale.x, -texelScale.y)).a;
|
||||
|
||||
float outline = min(dot(corners, vec4(1.0)), 1.0);
|
||||
vec4 color = mix(vec4(0.0), outlineColor, outline);
|
||||
finalColor = mix(color, texel, texel.a);
|
||||
}
|
||||
|
Before Width: | Height: | Size: 446 B |
|
|
@ -5,12 +5,10 @@
|
|||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version.
|
||||
*
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3).
|
||||
*
|
||||
* This example has been created using raylib 3.8 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
*
|
||||
* Example contributed by Samuel Skiff (@GoldenThumbs)
|
||||
* Example contributed by Samuel Skiff (@GoldenThumbs) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2021 Samuel SKiff (@GoldenThumbs) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
|
|
@ -33,13 +31,23 @@ int main(void)
|
|||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - Apply an outline to a texture");
|
||||
|
||||
Texture2D egg = LoadTexture("resources/egg.png");
|
||||
Texture2D torus = LoadTexture("resources/torus.png");
|
||||
Texture2D texture = LoadTexture("resources/fudesumi.png");
|
||||
|
||||
Shader shdrOutline = LoadShader(0, TextFormat("resources/shaders/glsl%i/outline.fs", GLSL_VERSION));
|
||||
|
||||
float outlineScale = 16.0f;
|
||||
float textureScale[2] = { 16.0f*4, 16.0f*4 };
|
||||
SetShaderValue(shdrOutline, GetShaderLocation(shdrOutline, "texScale"), textureScale, SHADER_UNIFORM_VEC2);
|
||||
float outlineSize = 2.0f;
|
||||
float outlineColor[4] = { 1.0f, 0.0f, 0.0f, 1.0f }; // Normalized RED color
|
||||
float textureSize[2] = { (float)texture.width, (float)texture.height };
|
||||
|
||||
// Get shader locations
|
||||
int outlineSizeLoc = GetShaderLocation(shdrOutline, "outlineSize");
|
||||
int outlineColorLoc = GetShaderLocation(shdrOutline, "outlineColor");
|
||||
int textureSizeLoc = GetShaderLocation(shdrOutline, "textureSize");
|
||||
|
||||
// Set shader values (they can be changed later)
|
||||
SetShaderValue(shdrOutline, outlineSizeLoc, &outlineSize, SHADER_UNIFORM_FLOAT);
|
||||
SetShaderValue(shdrOutline, outlineColorLoc, outlineColor, SHADER_UNIFORM_VEC4);
|
||||
SetShaderValue(shdrOutline, textureSizeLoc, textureSize, SHADER_UNIFORM_VEC2);
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
|
@ -49,7 +57,10 @@ int main(void)
|
|||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// TODO: Update your variables here
|
||||
outlineSize += GetMouseWheelMove();
|
||||
if (outlineSize < 1.0f) outlineSize = 1.0f;
|
||||
|
||||
SetShaderValue(shdrOutline, outlineSizeLoc, &outlineSize, SHADER_UNIFORM_FLOAT);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
|
|
@ -59,11 +70,14 @@ int main(void)
|
|||
ClearBackground(RAYWHITE);
|
||||
|
||||
BeginShaderMode(shdrOutline);
|
||||
DrawTextureEx(egg, (Vector2){ 0, 230 }, 0.0, outlineScale, WHITE);
|
||||
DrawTextureEx(torus, (Vector2){ 544, 230 }, 0.0, outlineScale, WHITE);
|
||||
|
||||
DrawTexture(texture, GetScreenWidth()/2 - texture.width/2, -30, WHITE);
|
||||
|
||||
EndShaderMode();
|
||||
|
||||
DrawText("Shader-based outlines for textures", 190, 200, 20, LIGHTGRAY);
|
||||
DrawText("Shader-based\ntexture\noutline", 10, 10, 20, GRAY);
|
||||
|
||||
DrawText(TextFormat("Outline size: %i px", (int)outlineSize), 10, 120, 20, MAROON);
|
||||
|
||||
DrawFPS(710, 10);
|
||||
|
||||
|
|
@ -73,8 +87,7 @@ int main(void)
|
|||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadTexture(egg);
|
||||
UnloadTexture(torus);
|
||||
UnloadTexture(texture);
|
||||
UnloadShader(shdrOutline);
|
||||
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
BIN
examples/shaders/shaders_texture_outline.png
Normal file
|
After Width: | Height: | Size: 258 KiB |
|
|
@ -5,13 +5,13 @@
|
|||
* This example has been created using raylib 1.8 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
*
|
||||
* Copyright (c) 2O17 Wilhem Barbier (@nounoursheureux)
|
||||
* Copyright (c) 2O17-2021 Wilhem Barbier (@nounoursheureux) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
#include "raylib.h"
|
||||
|
||||
#define NUM_TEXTURES 7 // Currently we have 7 generation algorithms
|
||||
#define NUM_TEXTURES 6 // Currently we have 7 generation algorithms
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
|
@ -27,7 +27,6 @@ int main(void)
|
|||
Image radialGradient = GenImageGradientRadial(screenWidth, screenHeight, 0.0f, WHITE, BLACK);
|
||||
Image checked = GenImageChecked(screenWidth, screenHeight, 32, 32, RED, BLUE);
|
||||
Image whiteNoise = GenImageWhiteNoise(screenWidth, screenHeight, 0.5f);
|
||||
Image perlinNoise = GenImagePerlinNoise(screenWidth, screenHeight, 50, 50, 4.0f);
|
||||
Image cellular = GenImageCellular(screenWidth, screenHeight, 32);
|
||||
|
||||
Texture2D textures[NUM_TEXTURES] = { 0 };
|
||||
|
|
@ -37,8 +36,7 @@ int main(void)
|
|||
textures[2] = LoadTextureFromImage(radialGradient);
|
||||
textures[3] = LoadTextureFromImage(checked);
|
||||
textures[4] = LoadTextureFromImage(whiteNoise);
|
||||
textures[5] = LoadTextureFromImage(perlinNoise);
|
||||
textures[6] = LoadTextureFromImage(cellular);
|
||||
textures[5] = LoadTextureFromImage(cellular);
|
||||
|
||||
// Unload image data (CPU RAM)
|
||||
UnloadImage(verticalGradient);
|
||||
|
|
@ -46,7 +44,6 @@ int main(void)
|
|||
UnloadImage(radialGradient);
|
||||
UnloadImage(checked);
|
||||
UnloadImage(whiteNoise);
|
||||
UnloadImage(perlinNoise);
|
||||
UnloadImage(cellular);
|
||||
|
||||
int currentTexture = 0;
|
||||
|
|
@ -84,8 +81,7 @@ int main(void)
|
|||
case 2: DrawText("RADIAL GRADIENT", 580, 10, 20, LIGHTGRAY); break;
|
||||
case 3: DrawText("CHECKED", 680, 10, 20, RAYWHITE); break;
|
||||
case 4: DrawText("WHITE NOISE", 640, 10, 20, RED); break;
|
||||
case 5: DrawText("PERLIN NOISE", 630, 10, 20, RAYWHITE); break;
|
||||
case 6: DrawText("CELLULAR", 670, 10, 20, RAYWHITE); break;
|
||||
case 5: DrawText("CELLULAR", 670, 10, 20, RAYWHITE); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,16 +93,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_first_person_maze",
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_geometric_shapes", "examples\models_geometric_shapes.vcxproj", "{14BA7F98-02CC-4648-9236-676BFF9458AF}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_gltf_animation", "examples\models_gltf_animation.vcxproj", "{FADC31C3-09AA-4DB4-A289-153482D10C09}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_gltf_model", "examples\models_gltf_model.vcxproj", "{F5FC9279-DE63-4EF3-B31F-CFCEF9B11F71}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_heightmap", "examples\models_heightmap.vcxproj", "{0859A973-E4FE-4688-8D16-0253163FDE24}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_loading", "examples\models_loading.vcxproj", "{F3412853-2B6A-4334-8CF2-B796CDAE0850}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_material_pbr", "examples\models_material_pbr.vcxproj", "{3A6C48C6-80AB-456F-A3A5-969930958971}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_mesh_generation", "examples\models_mesh_generation.vcxproj", "{BE097E8F-B6F3-45DC-8A27-E0EBC31AB912}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_mesh_picking", "examples\models_mesh_picking.vcxproj", "{D03F2C82-9553-4AFA-8F49-9234009122B6}"
|
||||
|
|
@ -275,8 +269,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rlgl_standalone", "examples
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_split_screen", "examples\core_split_screen.vcxproj", "{946A1700-C7AA-46F0-AEF2-67C98B5722AC}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_mesh_magicavoxel_loading", "examples\models_mesh_magicavoxel_loading.vcxproj", "{2F1B955B-275E-4D8E-8864-06FEC44D7912}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug.DLL|x64 = Debug.DLL|x64
|
||||
|
|
@ -895,38 +887,6 @@ Global
|
|||
{14BA7F98-02CC-4648-9236-676BFF9458AF}.Release|x64.Build.0 = Release|x64
|
||||
{14BA7F98-02CC-4648-9236-676BFF9458AF}.Release|x86.ActiveCfg = Release|Win32
|
||||
{14BA7F98-02CC-4648-9236-676BFF9458AF}.Release|x86.Build.0 = Release|Win32
|
||||
{FADC31C3-09AA-4DB4-A289-153482D10C09}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
|
||||
{FADC31C3-09AA-4DB4-A289-153482D10C09}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
|
||||
{FADC31C3-09AA-4DB4-A289-153482D10C09}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
|
||||
{FADC31C3-09AA-4DB4-A289-153482D10C09}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
|
||||
{FADC31C3-09AA-4DB4-A289-153482D10C09}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{FADC31C3-09AA-4DB4-A289-153482D10C09}.Debug|x64.Build.0 = Debug|x64
|
||||
{FADC31C3-09AA-4DB4-A289-153482D10C09}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{FADC31C3-09AA-4DB4-A289-153482D10C09}.Debug|x86.Build.0 = Debug|Win32
|
||||
{FADC31C3-09AA-4DB4-A289-153482D10C09}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
|
||||
{FADC31C3-09AA-4DB4-A289-153482D10C09}.Release.DLL|x64.Build.0 = Release.DLL|x64
|
||||
{FADC31C3-09AA-4DB4-A289-153482D10C09}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
|
||||
{FADC31C3-09AA-4DB4-A289-153482D10C09}.Release.DLL|x86.Build.0 = Release.DLL|Win32
|
||||
{FADC31C3-09AA-4DB4-A289-153482D10C09}.Release|x64.ActiveCfg = Release|x64
|
||||
{FADC31C3-09AA-4DB4-A289-153482D10C09}.Release|x64.Build.0 = Release|x64
|
||||
{FADC31C3-09AA-4DB4-A289-153482D10C09}.Release|x86.ActiveCfg = Release|Win32
|
||||
{FADC31C3-09AA-4DB4-A289-153482D10C09}.Release|x86.Build.0 = Release|Win32
|
||||
{F5FC9279-DE63-4EF3-B31F-CFCEF9B11F71}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
|
||||
{F5FC9279-DE63-4EF3-B31F-CFCEF9B11F71}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
|
||||
{F5FC9279-DE63-4EF3-B31F-CFCEF9B11F71}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
|
||||
{F5FC9279-DE63-4EF3-B31F-CFCEF9B11F71}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
|
||||
{F5FC9279-DE63-4EF3-B31F-CFCEF9B11F71}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F5FC9279-DE63-4EF3-B31F-CFCEF9B11F71}.Debug|x64.Build.0 = Debug|x64
|
||||
{F5FC9279-DE63-4EF3-B31F-CFCEF9B11F71}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{F5FC9279-DE63-4EF3-B31F-CFCEF9B11F71}.Debug|x86.Build.0 = Debug|Win32
|
||||
{F5FC9279-DE63-4EF3-B31F-CFCEF9B11F71}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
|
||||
{F5FC9279-DE63-4EF3-B31F-CFCEF9B11F71}.Release.DLL|x64.Build.0 = Release.DLL|x64
|
||||
{F5FC9279-DE63-4EF3-B31F-CFCEF9B11F71}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
|
||||
{F5FC9279-DE63-4EF3-B31F-CFCEF9B11F71}.Release.DLL|x86.Build.0 = Release.DLL|Win32
|
||||
{F5FC9279-DE63-4EF3-B31F-CFCEF9B11F71}.Release|x64.ActiveCfg = Release|x64
|
||||
{F5FC9279-DE63-4EF3-B31F-CFCEF9B11F71}.Release|x64.Build.0 = Release|x64
|
||||
{F5FC9279-DE63-4EF3-B31F-CFCEF9B11F71}.Release|x86.ActiveCfg = Release|Win32
|
||||
{F5FC9279-DE63-4EF3-B31F-CFCEF9B11F71}.Release|x86.Build.0 = Release|Win32
|
||||
{0859A973-E4FE-4688-8D16-0253163FDE24}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
|
||||
{0859A973-E4FE-4688-8D16-0253163FDE24}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
|
||||
{0859A973-E4FE-4688-8D16-0253163FDE24}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
|
||||
|
|
@ -959,22 +919,6 @@ Global
|
|||
{F3412853-2B6A-4334-8CF2-B796CDAE0850}.Release|x64.Build.0 = Release|x64
|
||||
{F3412853-2B6A-4334-8CF2-B796CDAE0850}.Release|x86.ActiveCfg = Release|Win32
|
||||
{F3412853-2B6A-4334-8CF2-B796CDAE0850}.Release|x86.Build.0 = Release|Win32
|
||||
{3A6C48C6-80AB-456F-A3A5-969930958971}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
|
||||
{3A6C48C6-80AB-456F-A3A5-969930958971}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
|
||||
{3A6C48C6-80AB-456F-A3A5-969930958971}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
|
||||
{3A6C48C6-80AB-456F-A3A5-969930958971}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
|
||||
{3A6C48C6-80AB-456F-A3A5-969930958971}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3A6C48C6-80AB-456F-A3A5-969930958971}.Debug|x64.Build.0 = Debug|x64
|
||||
{3A6C48C6-80AB-456F-A3A5-969930958971}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{3A6C48C6-80AB-456F-A3A5-969930958971}.Debug|x86.Build.0 = Debug|Win32
|
||||
{3A6C48C6-80AB-456F-A3A5-969930958971}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
|
||||
{3A6C48C6-80AB-456F-A3A5-969930958971}.Release.DLL|x64.Build.0 = Release.DLL|x64
|
||||
{3A6C48C6-80AB-456F-A3A5-969930958971}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
|
||||
{3A6C48C6-80AB-456F-A3A5-969930958971}.Release.DLL|x86.Build.0 = Release.DLL|Win32
|
||||
{3A6C48C6-80AB-456F-A3A5-969930958971}.Release|x64.ActiveCfg = Release|x64
|
||||
{3A6C48C6-80AB-456F-A3A5-969930958971}.Release|x64.Build.0 = Release|x64
|
||||
{3A6C48C6-80AB-456F-A3A5-969930958971}.Release|x86.ActiveCfg = Release|Win32
|
||||
{3A6C48C6-80AB-456F-A3A5-969930958971}.Release|x86.Build.0 = Release|Win32
|
||||
{BE097E8F-B6F3-45DC-8A27-E0EBC31AB912}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
|
||||
{BE097E8F-B6F3-45DC-8A27-E0EBC31AB912}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
|
||||
{BE097E8F-B6F3-45DC-8A27-E0EBC31AB912}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
|
||||
|
|
@ -2285,22 +2229,6 @@ Global
|
|||
{946A1700-C7AA-46F0-AEF2-67C98B5722AC}.Release|x64.Build.0 = Release|x64
|
||||
{946A1700-C7AA-46F0-AEF2-67C98B5722AC}.Release|x86.ActiveCfg = Release|Win32
|
||||
{946A1700-C7AA-46F0-AEF2-67C98B5722AC}.Release|x86.Build.0 = Release|Win32
|
||||
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
|
||||
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
|
||||
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
|
||||
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
|
||||
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Debug|x64.Build.0 = Debug|x64
|
||||
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Debug|x86.Build.0 = Debug|Win32
|
||||
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
|
||||
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Release.DLL|x64.Build.0 = Release.DLL|x64
|
||||
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
|
||||
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Release.DLL|x86.Build.0 = Release.DLL|Win32
|
||||
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Release|x64.ActiveCfg = Release|x64
|
||||
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Release|x64.Build.0 = Release|x64
|
||||
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Release|x86.ActiveCfg = Release|Win32
|
||||
{2F1B955B-275E-4D8E-8864-06FEC44D7912}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -2349,11 +2277,8 @@ Global
|
|||
{5317807F-61D4-4E0F-B6DC-2D9F12621ED9} = {8716DC0F-4FDE-4F57-8E25-5F78DFB80FE1}
|
||||
{CBD6C0F8-8200-4E9A-9D7C-6505A2AA4A62} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
|
||||
{14BA7F98-02CC-4648-9236-676BFF9458AF} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
|
||||
{FADC31C3-09AA-4DB4-A289-153482D10C09} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
|
||||
{F5FC9279-DE63-4EF3-B31F-CFCEF9B11F71} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
|
||||
{0859A973-E4FE-4688-8D16-0253163FDE24} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
|
||||
{F3412853-2B6A-4334-8CF2-B796CDAE0850} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
|
||||
{3A6C48C6-80AB-456F-A3A5-969930958971} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
|
||||
{BE097E8F-B6F3-45DC-8A27-E0EBC31AB912} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
|
||||
{D03F2C82-9553-4AFA-8F49-9234009122B6} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
|
||||
{FE232CA5-6C0D-4ADF-9A21-775D4DC048D3} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
|
||||
|
|
@ -2440,7 +2365,6 @@ Global
|
|||
{6237BEDE-BAAA-4A06-9C5E-8089BAA14C8B} = {E9D708A5-9C1F-4B84-A795-C5F191801762}
|
||||
{C8765523-58F8-4C8E-9914-693396F6F0FF} = {E9D708A5-9C1F-4B84-A795-C5F191801762}
|
||||
{946A1700-C7AA-46F0-AEF2-67C98B5722AC} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
|
||||
{2F1B955B-275E-4D8E-8864-06FEC44D7912} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@
|
|||
// Module: rlgl - Configuration values
|
||||
//------------------------------------------------------------------------------------
|
||||
// Show OpenGL extensions and capabilities detailed logs on init
|
||||
//#define SUPPORT_GL_DETAILS_INFO 1
|
||||
//#define RLGL_SHOW_GL_DETAILS_INFO 1
|
||||
|
||||
//#define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 4096 // Default internal render batch elements limits
|
||||
#define RL_DEFAULT_BATCH_BUFFERS 1 // Default number of batch buffers (multi-buffering)
|
||||
|
|
|
|||
208
src/external/cgltf.h
vendored
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* cgltf - a single-file glTF 2.0 parser written in C99.
|
||||
*
|
||||
* Version: 1.10
|
||||
* Version: 1.11
|
||||
*
|
||||
* Website: https://github.com/jkuhlmann/cgltf
|
||||
*
|
||||
|
|
@ -234,6 +234,12 @@ typedef enum cgltf_light_type {
|
|||
cgltf_light_type_spot,
|
||||
} cgltf_light_type;
|
||||
|
||||
typedef enum cgltf_data_free_method {
|
||||
cgltf_data_free_method_none,
|
||||
cgltf_data_free_method_file_release,
|
||||
cgltf_data_free_method_memory_free,
|
||||
} cgltf_data_free_method;
|
||||
|
||||
typedef struct cgltf_extras {
|
||||
cgltf_size start_offset;
|
||||
cgltf_size end_offset;
|
||||
|
|
@ -250,6 +256,7 @@ typedef struct cgltf_buffer
|
|||
cgltf_size size;
|
||||
char* uri;
|
||||
void* data; /* loaded by cgltf_load_buffers */
|
||||
cgltf_data_free_method data_free_method;
|
||||
cgltf_extras extras;
|
||||
cgltf_size extensions_count;
|
||||
cgltf_extension* extensions;
|
||||
|
|
@ -372,6 +379,8 @@ typedef struct cgltf_texture
|
|||
char* name;
|
||||
cgltf_image* image;
|
||||
cgltf_sampler* sampler;
|
||||
cgltf_bool has_basisu;
|
||||
cgltf_image* basisu_image;
|
||||
cgltf_extras extras;
|
||||
cgltf_size extensions_count;
|
||||
cgltf_extension* extensions;
|
||||
|
|
@ -382,6 +391,7 @@ typedef struct cgltf_texture_transform
|
|||
cgltf_float offset[2];
|
||||
cgltf_float rotation;
|
||||
cgltf_float scale[2];
|
||||
cgltf_bool has_texcoord;
|
||||
cgltf_int texcoord;
|
||||
} cgltf_texture_transform;
|
||||
|
||||
|
|
@ -595,6 +605,7 @@ typedef struct cgltf_light {
|
|||
cgltf_float range;
|
||||
cgltf_float spot_inner_cone_angle;
|
||||
cgltf_float spot_outer_cone_angle;
|
||||
cgltf_extras extras;
|
||||
} cgltf_light;
|
||||
|
||||
struct cgltf_node {
|
||||
|
|
@ -768,6 +779,7 @@ cgltf_result cgltf_load_buffers(
|
|||
|
||||
cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data);
|
||||
|
||||
void cgltf_decode_string(char* string);
|
||||
void cgltf_decode_uri(char* uri);
|
||||
|
||||
cgltf_result cgltf_validate(cgltf_data* data);
|
||||
|
|
@ -813,7 +825,7 @@ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras*
|
|||
#include <limits.h> /* For UINT_MAX etc */
|
||||
#include <float.h> /* For FLT_MAX */
|
||||
|
||||
#if !defined(CGLTF_MALLOC) || !defined(CGLTF_FREE) || !defined(CGLTF_ATOI) || !defined(CGLTF_ATOF)
|
||||
#if !defined(CGLTF_MALLOC) || !defined(CGLTF_FREE) || !defined(CGLTF_ATOI) || !defined(CGLTF_ATOF) || !defined(CGLTF_ATOLL)
|
||||
#include <stdlib.h> /* For malloc, free, atoi, atof */
|
||||
#endif
|
||||
|
||||
|
|
@ -883,6 +895,9 @@ static const uint32_t GlbMagicBinChunk = 0x004E4942;
|
|||
#ifndef CGLTF_ATOF
|
||||
#define CGLTF_ATOF(str) atof(str)
|
||||
#endif
|
||||
#ifndef CGLTF_ATOLL
|
||||
#define CGLTF_ATOLL(str) atoll(str)
|
||||
#endif
|
||||
#ifndef CGLTF_VALIDATE_ENABLE_ASSERTS
|
||||
#define CGLTF_VALIDATE_ENABLE_ASSERTS 0
|
||||
#endif
|
||||
|
|
@ -932,7 +947,12 @@ static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* m
|
|||
{
|
||||
fseek(file, 0, SEEK_END);
|
||||
|
||||
#ifdef _WIN32
|
||||
__int64 length = _ftelli64(file);
|
||||
#else
|
||||
long length = ftell(file);
|
||||
#endif
|
||||
|
||||
if (length < 0)
|
||||
{
|
||||
fclose(file);
|
||||
|
|
@ -1120,8 +1140,8 @@ cgltf_result cgltf_parse_file(const cgltf_options* options, const char* path, cg
|
|||
return cgltf_result_invalid_options;
|
||||
}
|
||||
|
||||
void (*memory_free)(void*, void*) = options->memory.free ? options->memory.free : &cgltf_default_free;
|
||||
cgltf_result (*file_read)(const struct cgltf_memory_options*, const struct cgltf_file_options*, const char*, cgltf_size*, void**) = options->file.read ? options->file.read : &cgltf_default_file_read;
|
||||
void (*file_release)(const struct cgltf_memory_options*, const struct cgltf_file_options*, void* data) = options->file.release ? options->file.release : cgltf_default_file_release;
|
||||
|
||||
void* file_data = NULL;
|
||||
cgltf_size file_size = 0;
|
||||
|
|
@ -1135,7 +1155,7 @@ cgltf_result cgltf_parse_file(const cgltf_options* options, const char* path, cg
|
|||
|
||||
if (result != cgltf_result_success)
|
||||
{
|
||||
memory_free(options->memory.user_data, file_data);
|
||||
file_release(&options->memory, &options->file, file_data);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -1246,6 +1266,72 @@ static int cgltf_unhex(char ch)
|
|||
-1;
|
||||
}
|
||||
|
||||
void cgltf_decode_string(char* string)
|
||||
{
|
||||
char* read = strchr(string, '\\');
|
||||
if (read == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
char* write = string;
|
||||
char* last = string;
|
||||
|
||||
while (read)
|
||||
{
|
||||
// Copy characters since last escaped sequence
|
||||
cgltf_size written = read - last;
|
||||
strncpy(write, last, written);
|
||||
write += written;
|
||||
|
||||
// jsmn already checked that all escape sequences are valid
|
||||
++read;
|
||||
switch (*read++)
|
||||
{
|
||||
case '\"': *write++ = '\"'; break;
|
||||
case '/': *write++ = '/'; break;
|
||||
case '\\': *write++ = '\\'; break;
|
||||
case 'b': *write++ = '\b'; break;
|
||||
case 'f': *write++ = '\f'; break;
|
||||
case 'r': *write++ = '\r'; break;
|
||||
case 'n': *write++ = '\n'; break;
|
||||
case 't': *write++ = '\t'; break;
|
||||
case 'u':
|
||||
{
|
||||
// UCS-2 codepoint \uXXXX to UTF-8
|
||||
int character = 0;
|
||||
for (cgltf_size i = 0; i < 4; ++i)
|
||||
{
|
||||
character = (character << 4) + cgltf_unhex(*read++);
|
||||
}
|
||||
|
||||
if (character <= 0x7F)
|
||||
{
|
||||
*write++ = character & 0xFF;
|
||||
}
|
||||
else if (character <= 0x7FF)
|
||||
{
|
||||
*write++ = 0xC0 | ((character >> 6) & 0xFF);
|
||||
*write++ = 0x80 | (character & 0x3F);
|
||||
}
|
||||
else
|
||||
{
|
||||
*write++ = 0xE0 | ((character >> 12) & 0xFF);
|
||||
*write++ = 0x80 | ((character >> 6) & 0x3F);
|
||||
*write++ = 0x80 | (character & 0x3F);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
last = read;
|
||||
read = strchr(read, '\\');
|
||||
}
|
||||
|
||||
strcpy(write, last);
|
||||
}
|
||||
|
||||
void cgltf_decode_uri(char* uri)
|
||||
{
|
||||
char* write = uri;
|
||||
|
|
@ -1291,6 +1377,7 @@ cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data,
|
|||
}
|
||||
|
||||
data->buffers[0].data = (void*)data->bin;
|
||||
data->buffers[0].data_free_method = cgltf_data_free_method_none;
|
||||
}
|
||||
|
||||
for (cgltf_size i = 0; i < data->buffers_count; ++i)
|
||||
|
|
@ -1314,6 +1401,7 @@ cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data,
|
|||
if (comma && comma - uri >= 7 && strncmp(comma - 7, ";base64", 7) == 0)
|
||||
{
|
||||
cgltf_result res = cgltf_load_buffer_base64(options, data->buffers[i].size, comma + 1, &data->buffers[i].data);
|
||||
data->buffers[i].data_free_method = cgltf_data_free_method_memory_free;
|
||||
|
||||
if (res != cgltf_result_success)
|
||||
{
|
||||
|
|
@ -1328,6 +1416,7 @@ cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data,
|
|||
else if (strstr(uri, "://") == NULL && gltf_path)
|
||||
{
|
||||
cgltf_result res = cgltf_load_buffer_file(options, data->buffers[i].size, uri, gltf_path, &data->buffers[i].data);
|
||||
data->buffers[i].data_free_method = cgltf_data_free_method_file_release;
|
||||
|
||||
if (res != cgltf_result_success)
|
||||
{
|
||||
|
|
@ -1655,10 +1744,15 @@ void cgltf_free(cgltf_data* data)
|
|||
{
|
||||
data->memory.free(data->memory.user_data, data->buffers[i].name);
|
||||
|
||||
if (data->buffers[i].data != data->bin)
|
||||
if (data->buffers[i].data_free_method == cgltf_data_free_method_file_release)
|
||||
{
|
||||
file_release(&data->memory, &data->file, data->buffers[i].data);
|
||||
}
|
||||
else if (data->buffers[i].data_free_method == cgltf_data_free_method_memory_free)
|
||||
{
|
||||
data->memory.free(data->memory.user_data, data->buffers[i].data);
|
||||
}
|
||||
|
||||
data->memory.free(data->memory.user_data, data->buffers[i].uri);
|
||||
|
||||
cgltf_free_extensions(data, data->buffers[i].extensions, data->buffers[i].extensions_count);
|
||||
|
|
@ -2259,6 +2353,7 @@ cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size
|
|||
#define CGLTF_ERROR_LEGACY -3
|
||||
|
||||
#define CGLTF_CHECK_TOKTYPE(tok_, type_) if ((tok_).type != (type_)) { return CGLTF_ERROR_JSON; }
|
||||
#define CGLTF_CHECK_TOKTYPE_RETTYPE(tok_, type_, ret_) if ((tok_).type != (type_)) { return (ret_)CGLTF_ERROR_JSON; }
|
||||
#define CGLTF_CHECK_KEY(tok_) if ((tok_).type != JSMN_STRING || (tok_).size == 0) { return CGLTF_ERROR_JSON; } /* checking size for 0 verifies that a value follows the key */
|
||||
|
||||
#define CGLTF_PTRINDEX(type, idx) (type*)((cgltf_size)idx + 1)
|
||||
|
|
@ -2283,6 +2378,16 @@ static int cgltf_json_to_int(jsmntok_t const* tok, const uint8_t* json_chunk)
|
|||
return CGLTF_ATOI(tmp);
|
||||
}
|
||||
|
||||
static cgltf_size cgltf_json_to_size(jsmntok_t const* tok, const uint8_t* json_chunk)
|
||||
{
|
||||
CGLTF_CHECK_TOKTYPE_RETTYPE(*tok, JSMN_PRIMITIVE, cgltf_size);
|
||||
char tmp[128];
|
||||
int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1);
|
||||
strncpy(tmp, (const char*)json_chunk + tok->start, size);
|
||||
tmp[size] = 0;
|
||||
return (cgltf_size)CGLTF_ATOLL(tmp);
|
||||
}
|
||||
|
||||
static cgltf_float cgltf_json_to_float(jsmntok_t const* tok, const uint8_t* json_chunk)
|
||||
{
|
||||
CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE);
|
||||
|
|
@ -3024,7 +3129,7 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co
|
|||
else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0)
|
||||
{
|
||||
++i;
|
||||
out_sparse->indices_byte_offset = cgltf_json_to_int(tokens + i, json_chunk);
|
||||
out_sparse->indices_byte_offset = cgltf_json_to_size(tokens + i, json_chunk);
|
||||
++i;
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens+i, json_chunk, "componentType") == 0)
|
||||
|
|
@ -3073,7 +3178,7 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co
|
|||
else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0)
|
||||
{
|
||||
++i;
|
||||
out_sparse->values_byte_offset = cgltf_json_to_int(tokens + i, json_chunk);
|
||||
out_sparse->values_byte_offset = cgltf_json_to_size(tokens + i, json_chunk);
|
||||
++i;
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
|
|
@ -3142,7 +3247,7 @@ static int cgltf_parse_json_accessor(cgltf_options* options, jsmntok_t const* to
|
|||
{
|
||||
++i;
|
||||
out_accessor->offset =
|
||||
cgltf_json_to_int(tokens+i, json_chunk);
|
||||
cgltf_json_to_size(tokens+i, json_chunk);
|
||||
++i;
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens+i, json_chunk, "componentType") == 0)
|
||||
|
|
@ -3268,6 +3373,7 @@ static int cgltf_parse_json_texture_transform(jsmntok_t const* tokens, int i, co
|
|||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "texCoord") == 0)
|
||||
{
|
||||
++i;
|
||||
out_texture_transform->has_texcoord = 1;
|
||||
out_texture_transform->texcoord = cgltf_json_to_int(tokens + i, json_chunk);
|
||||
++i;
|
||||
}
|
||||
|
|
@ -3885,7 +3991,62 @@ static int cgltf_parse_json_texture(cgltf_options* options, jsmntok_t const* tok
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_texture->extensions_count, &out_texture->extensions);
|
||||
++i;
|
||||
|
||||
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
if (out_texture->extensions)
|
||||
{
|
||||
return CGLTF_ERROR_JSON;
|
||||
}
|
||||
|
||||
int extensions_size = tokens[i].size;
|
||||
++i;
|
||||
out_texture->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size);
|
||||
out_texture->extensions_count = 0;
|
||||
|
||||
if (!out_texture->extensions)
|
||||
{
|
||||
return CGLTF_ERROR_NOMEM;
|
||||
}
|
||||
|
||||
for (int k = 0; k < extensions_size; ++k)
|
||||
{
|
||||
CGLTF_CHECK_KEY(tokens[i]);
|
||||
|
||||
if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_texture_basisu") == 0)
|
||||
{
|
||||
out_texture->has_basisu = 1;
|
||||
++i;
|
||||
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
int num_properties = tokens[i].size;
|
||||
++i;
|
||||
|
||||
for (int t = 0; t < num_properties; ++t)
|
||||
{
|
||||
CGLTF_CHECK_KEY(tokens[i]);
|
||||
|
||||
if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0)
|
||||
{
|
||||
++i;
|
||||
out_texture->basisu_image = CGLTF_PTRINDEX(cgltf_image, cgltf_json_to_int(tokens + i, json_chunk));
|
||||
++i;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = cgltf_skip_json(tokens, i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_texture->extensions[out_texture->extensions_count++]));
|
||||
}
|
||||
|
||||
if (i < 0)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -4192,19 +4353,19 @@ static int cgltf_parse_json_meshopt_compression(cgltf_options* options, jsmntok_
|
|||
else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0)
|
||||
{
|
||||
++i;
|
||||
out_meshopt_compression->offset = cgltf_json_to_int(tokens+i, json_chunk);
|
||||
out_meshopt_compression->offset = cgltf_json_to_size(tokens+i, json_chunk);
|
||||
++i;
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteLength") == 0)
|
||||
{
|
||||
++i;
|
||||
out_meshopt_compression->size = cgltf_json_to_int(tokens+i, json_chunk);
|
||||
out_meshopt_compression->size = cgltf_json_to_size(tokens+i, json_chunk);
|
||||
++i;
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteStride") == 0)
|
||||
{
|
||||
++i;
|
||||
out_meshopt_compression->stride = cgltf_json_to_int(tokens+i, json_chunk);
|
||||
out_meshopt_compression->stride = cgltf_json_to_size(tokens+i, json_chunk);
|
||||
++i;
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0)
|
||||
|
|
@ -4290,21 +4451,21 @@ static int cgltf_parse_json_buffer_view(cgltf_options* options, jsmntok_t const*
|
|||
{
|
||||
++i;
|
||||
out_buffer_view->offset =
|
||||
cgltf_json_to_int(tokens+i, json_chunk);
|
||||
cgltf_json_to_size(tokens+i, json_chunk);
|
||||
++i;
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteLength") == 0)
|
||||
{
|
||||
++i;
|
||||
out_buffer_view->size =
|
||||
cgltf_json_to_int(tokens+i, json_chunk);
|
||||
cgltf_json_to_size(tokens+i, json_chunk);
|
||||
++i;
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteStride") == 0)
|
||||
{
|
||||
++i;
|
||||
out_buffer_view->stride =
|
||||
cgltf_json_to_int(tokens+i, json_chunk);
|
||||
cgltf_json_to_size(tokens+i, json_chunk);
|
||||
++i;
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens+i, json_chunk, "target") == 0)
|
||||
|
|
@ -4422,7 +4583,7 @@ static int cgltf_parse_json_buffer(cgltf_options* options, jsmntok_t const* toke
|
|||
{
|
||||
++i;
|
||||
out_buffer->size =
|
||||
cgltf_json_to_int(tokens+i, json_chunk);
|
||||
cgltf_json_to_size(tokens+i, json_chunk);
|
||||
++i;
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens+i, json_chunk, "uri") == 0)
|
||||
|
|
@ -4737,6 +4898,14 @@ static int cgltf_parse_json_light(cgltf_options* options, jsmntok_t const* token
|
|||
{
|
||||
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
|
||||
out_light->color[0] = 1.f;
|
||||
out_light->color[1] = 1.f;
|
||||
out_light->color[2] = 1.f;
|
||||
out_light->intensity = 1.f;
|
||||
|
||||
out_light->spot_inner_cone_angle = 0.f;
|
||||
out_light->spot_outer_cone_angle = 3.1415926535f / 4.0f;
|
||||
|
||||
int size = tokens[i].size;
|
||||
++i;
|
||||
|
||||
|
|
@ -4817,6 +4986,10 @@ static int cgltf_parse_json_light(cgltf_options* options, jsmntok_t const* token
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_light->extras);
|
||||
}
|
||||
else
|
||||
{
|
||||
i = cgltf_skip_json(tokens, i+1);
|
||||
|
|
@ -5851,6 +6024,7 @@ static int cgltf_fixup_pointers(cgltf_data* data)
|
|||
for (cgltf_size i = 0; i < data->textures_count; ++i)
|
||||
{
|
||||
CGLTF_PTRFIXUP(data->textures[i].image, data->images, data->images_count);
|
||||
CGLTF_PTRFIXUP(data->textures[i].basisu_image, data->images, data->images_count);
|
||||
CGLTF_PTRFIXUP(data->textures[i].sampler, data->samplers, data->samplers_count);
|
||||
}
|
||||
|
||||
|
|
@ -6305,7 +6479,7 @@ static void jsmn_init(jsmn_parser *parser) {
|
|||
|
||||
/* cgltf is distributed under MIT license:
|
||||
*
|
||||
* Copyright (c) 2018 Johannes Kuhlmann
|
||||
* Copyright (c) 2018-2021 Johannes Kuhlmann
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
14
src/external/dr_flac.h
vendored
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
|
||||
dr_flac - v0.12.29 - 2021-04-02
|
||||
dr_flac - v0.12.31 - 2021-08-16
|
||||
|
||||
David Reid - mackron@gmail.com
|
||||
|
||||
|
|
@ -232,7 +232,7 @@ extern "C" {
|
|||
|
||||
#define DRFLAC_VERSION_MAJOR 0
|
||||
#define DRFLAC_VERSION_MINOR 12
|
||||
#define DRFLAC_VERSION_REVISION 29
|
||||
#define DRFLAC_VERSION_REVISION 31
|
||||
#define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION)
|
||||
|
||||
#include <stddef.h> /* For size_t. */
|
||||
|
|
@ -261,7 +261,7 @@ typedef unsigned int drflac_uint32;
|
|||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
|
||||
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__)
|
||||
typedef drflac_uint64 drflac_uintptr;
|
||||
#else
|
||||
typedef drflac_uint32 drflac_uintptr;
|
||||
|
|
@ -11516,7 +11516,7 @@ static type* drflac__full_read_and_close_ ## extension (drflac* pFlac, unsigned
|
|||
DRFLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type))); \
|
||||
} else { \
|
||||
drflac_uint64 dataSize = totalPCMFrameCount*pFlac->channels*sizeof(type); \
|
||||
if (dataSize > DRFLAC_SIZE_MAX) { \
|
||||
if (dataSize > (drflac_uint64)DRFLAC_SIZE_MAX) { \
|
||||
goto on_error; /* The decoded data is too big. */ \
|
||||
} \
|
||||
\
|
||||
|
|
@ -11851,6 +11851,12 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
|
|||
/*
|
||||
REVISION HISTORY
|
||||
================
|
||||
v0.12.31 - 2021-08-16
|
||||
- Silence some warnings.
|
||||
|
||||
v0.12.30 - 2021-07-31
|
||||
- Fix platform detection for ARM64.
|
||||
|
||||
v0.12.29 - 2021-04-02
|
||||
- Fix a bug where the running PCM frame index is set to an invalid value when over-seeking.
|
||||
- Fix a decoding error due to an incorrect validation check.
|
||||
|
|
|
|||
135
src/external/dr_mp3.h
vendored
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
MP3 audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
|
||||
dr_mp3 - v0.6.27 - 2021-02-21
|
||||
dr_mp3 - v0.6.31 - 2021-08-22
|
||||
|
||||
David Reid - mackron@gmail.com
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ extern "C" {
|
|||
|
||||
#define DRMP3_VERSION_MAJOR 0
|
||||
#define DRMP3_VERSION_MINOR 6
|
||||
#define DRMP3_VERSION_REVISION 27
|
||||
#define DRMP3_VERSION_REVISION 31
|
||||
#define DRMP3_VERSION_STRING DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION)
|
||||
|
||||
#include <stddef.h> /* For size_t. */
|
||||
|
|
@ -124,7 +124,7 @@ typedef unsigned int drmp3_uint32;
|
|||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
|
||||
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__)
|
||||
typedef drmp3_uint64 drmp3_uintptr;
|
||||
#else
|
||||
typedef drmp3_uint32 drmp3_uintptr;
|
||||
|
|
@ -701,7 +701,7 @@ static int drmp3_have_simd(void)
|
|||
|
||||
#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64)
|
||||
#define DRMP3_HAVE_ARMV6 1
|
||||
static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_arm(int32_t a)
|
||||
static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_arm(drmp3_int32 a)
|
||||
{
|
||||
drmp3_int32 x = 0;
|
||||
__asm__ ("ssat %0, #16, %1" : "=r"(x) : "r"(a));
|
||||
|
|
@ -712,6 +712,31 @@ static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_ar
|
|||
#endif
|
||||
|
||||
|
||||
/* Standard library stuff. */
|
||||
#ifndef DRMP3_ASSERT
|
||||
#include <assert.h>
|
||||
#define DRMP3_ASSERT(expression) assert(expression)
|
||||
#endif
|
||||
#ifndef DRMP3_COPY_MEMORY
|
||||
#define DRMP3_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz))
|
||||
#endif
|
||||
#ifndef DRMP3_MOVE_MEMORY
|
||||
#define DRMP3_MOVE_MEMORY(dst, src, sz) memmove((dst), (src), (sz))
|
||||
#endif
|
||||
#ifndef DRMP3_ZERO_MEMORY
|
||||
#define DRMP3_ZERO_MEMORY(p, sz) memset((p), 0, (sz))
|
||||
#endif
|
||||
#define DRMP3_ZERO_OBJECT(p) DRMP3_ZERO_MEMORY((p), sizeof(*(p)))
|
||||
#ifndef DRMP3_MALLOC
|
||||
#define DRMP3_MALLOC(sz) malloc((sz))
|
||||
#endif
|
||||
#ifndef DRMP3_REALLOC
|
||||
#define DRMP3_REALLOC(p, sz) realloc((p), (sz))
|
||||
#endif
|
||||
#ifndef DRMP3_FREE
|
||||
#define DRMP3_FREE(p) free((p))
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const drmp3_uint8 *buf;
|
||||
|
|
@ -978,7 +1003,7 @@ static int drmp3_L12_dequantize_granule(float *grbuf, drmp3_bs *bs, drmp3_L12_sc
|
|||
static void drmp3_L12_apply_scf_384(drmp3_L12_scale_info *sci, const float *scf, float *dst)
|
||||
{
|
||||
int i, k;
|
||||
memcpy(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float));
|
||||
DRMP3_COPY_MEMORY(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float));
|
||||
for (i = 0; i < sci->total_bands; i++, dst += 18, scf += 6)
|
||||
{
|
||||
for (k = 0; k < 12; k++)
|
||||
|
|
@ -1123,14 +1148,14 @@ static void drmp3_L3_read_scalefactors(drmp3_uint8 *scf, drmp3_uint8 *ist_pos, c
|
|||
int cnt = scf_count[i];
|
||||
if (scfsi & 8)
|
||||
{
|
||||
memcpy(scf, ist_pos, cnt);
|
||||
DRMP3_COPY_MEMORY(scf, ist_pos, cnt);
|
||||
} else
|
||||
{
|
||||
int bits = scf_size[i];
|
||||
if (!bits)
|
||||
{
|
||||
memset(scf, 0, cnt);
|
||||
memset(ist_pos, 0, cnt);
|
||||
DRMP3_ZERO_MEMORY(scf, cnt);
|
||||
DRMP3_ZERO_MEMORY(ist_pos, cnt);
|
||||
} else
|
||||
{
|
||||
int max_scf = (scfsi < 0) ? (1 << bits) - 1 : -1;
|
||||
|
|
@ -1390,13 +1415,23 @@ static void drmp3_L3_midside_stereo(float *left, int n)
|
|||
int i = 0;
|
||||
float *right = left + 576;
|
||||
#if DRMP3_HAVE_SIMD
|
||||
if (drmp3_have_simd()) for (; i < n - 3; i += 4)
|
||||
if (drmp3_have_simd())
|
||||
{
|
||||
for (; i < n - 3; i += 4)
|
||||
{
|
||||
drmp3_f4 vl = DRMP3_VLD(left + i);
|
||||
drmp3_f4 vr = DRMP3_VLD(right + i);
|
||||
DRMP3_VSTORE(left + i, DRMP3_VADD(vl, vr));
|
||||
DRMP3_VSTORE(right + i, DRMP3_VSUB(vl, vr));
|
||||
}
|
||||
#ifdef __GNUC__
|
||||
/* Workaround for spurious -Waggressive-loop-optimizations warning from gcc.
|
||||
* For more info see: https://github.com/lieff/minimp3/issues/88
|
||||
*/
|
||||
if (__builtin_constant_p(n % 4 == 0) && n % 4 == 0)
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
for (; i < n; i++)
|
||||
{
|
||||
|
|
@ -1505,7 +1540,7 @@ static void drmp3_L3_reorder(float *grbuf, float *scratch, const drmp3_uint8 *sf
|
|||
*dst++ = src[2*len];
|
||||
}
|
||||
}
|
||||
memcpy(grbuf, scratch, (dst - scratch)*sizeof(float));
|
||||
DRMP3_COPY_MEMORY(grbuf, scratch, (dst - scratch)*sizeof(float));
|
||||
}
|
||||
|
||||
static void drmp3_L3_antialias(float *grbuf, int nbands)
|
||||
|
|
@ -1674,8 +1709,8 @@ static void drmp3_L3_imdct_short(float *grbuf, float *overlap, int nbands)
|
|||
for (;nbands > 0; nbands--, overlap += 9, grbuf += 18)
|
||||
{
|
||||
float tmp[18];
|
||||
memcpy(tmp, grbuf, sizeof(tmp));
|
||||
memcpy(grbuf, overlap, 6*sizeof(float));
|
||||
DRMP3_COPY_MEMORY(tmp, grbuf, sizeof(tmp));
|
||||
DRMP3_COPY_MEMORY(grbuf, overlap, 6*sizeof(float));
|
||||
drmp3_L3_imdct12(tmp, grbuf + 6, overlap + 6);
|
||||
drmp3_L3_imdct12(tmp + 1, grbuf + 12, overlap + 6);
|
||||
drmp3_L3_imdct12(tmp + 2, overlap, overlap + 6);
|
||||
|
|
@ -1719,7 +1754,7 @@ static void drmp3_L3_save_reservoir(drmp3dec *h, drmp3dec_scratch *s)
|
|||
}
|
||||
if (remains > 0)
|
||||
{
|
||||
memmove(h->reserv_buf, s->maindata + pos, remains);
|
||||
DRMP3_MOVE_MEMORY(h->reserv_buf, s->maindata + pos, remains);
|
||||
}
|
||||
h->reserv = remains;
|
||||
}
|
||||
|
|
@ -1728,8 +1763,8 @@ static int drmp3_L3_restore_reservoir(drmp3dec *h, drmp3_bs *bs, drmp3dec_scratc
|
|||
{
|
||||
int frame_bytes = (bs->limit - bs->pos)/8;
|
||||
int bytes_have = DRMP3_MIN(h->reserv, main_data_begin);
|
||||
memcpy(s->maindata, h->reserv_buf + DRMP3_MAX(0, h->reserv - main_data_begin), DRMP3_MIN(h->reserv, main_data_begin));
|
||||
memcpy(s->maindata + bytes_have, bs->buf + bs->pos/8, frame_bytes);
|
||||
DRMP3_COPY_MEMORY(s->maindata, h->reserv_buf + DRMP3_MAX(0, h->reserv - main_data_begin), DRMP3_MIN(h->reserv, main_data_begin));
|
||||
DRMP3_COPY_MEMORY(s->maindata + bytes_have, bs->buf + bs->pos/8, frame_bytes);
|
||||
drmp3_bs_init(&s->bs, s->maindata, bytes_have + frame_bytes);
|
||||
return h->reserv >= main_data_begin;
|
||||
}
|
||||
|
|
@ -2136,7 +2171,7 @@ static void drmp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int
|
|||
drmp3d_DCT_II(grbuf + 576*i, nbands);
|
||||
}
|
||||
|
||||
memcpy(lins, qmf_state, sizeof(float)*15*64);
|
||||
DRMP3_COPY_MEMORY(lins, qmf_state, sizeof(float)*15*64);
|
||||
|
||||
for (i = 0; i < nbands; i += 2)
|
||||
{
|
||||
|
|
@ -2152,7 +2187,7 @@ static void drmp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int
|
|||
} else
|
||||
#endif
|
||||
{
|
||||
memcpy(qmf_state, lins + nbands*64, sizeof(float)*15*64);
|
||||
DRMP3_COPY_MEMORY(qmf_state, lins + nbands*64, sizeof(float)*15*64);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2230,7 +2265,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m
|
|||
}
|
||||
if (!frame_size)
|
||||
{
|
||||
memset(dec, 0, sizeof(drmp3dec));
|
||||
DRMP3_ZERO_MEMORY(dec, sizeof(drmp3dec));
|
||||
i = drmp3d_find_frame(mp3, mp3_bytes, &dec->free_format_bytes, &frame_size);
|
||||
if (!frame_size || i + frame_size > mp3_bytes)
|
||||
{
|
||||
|
|
@ -2240,7 +2275,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m
|
|||
}
|
||||
|
||||
hdr = mp3 + i;
|
||||
memcpy(dec->header, hdr, DRMP3_HDR_SIZE);
|
||||
DRMP3_COPY_MEMORY(dec->header, hdr, DRMP3_HDR_SIZE);
|
||||
info->frame_bytes = i + frame_size;
|
||||
info->channels = DRMP3_HDR_IS_MONO(hdr) ? 1 : 2;
|
||||
info->hz = drmp3_hdr_sample_rate_hz(hdr);
|
||||
|
|
@ -2266,7 +2301,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m
|
|||
{
|
||||
for (igr = 0; igr < (DRMP3_HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*576*info->channels))
|
||||
{
|
||||
memset(scratch.grbuf[0], 0, 576*2*sizeof(float));
|
||||
DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float));
|
||||
drmp3_L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels);
|
||||
drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]);
|
||||
}
|
||||
|
|
@ -2285,7 +2320,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m
|
|||
|
||||
drmp3_L12_read_scale_info(hdr, bs_frame, sci);
|
||||
|
||||
memset(scratch.grbuf[0], 0, 576*2*sizeof(float));
|
||||
DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float));
|
||||
for (i = 0, igr = 0; igr < 3; igr++)
|
||||
{
|
||||
if (12 == (i += drmp3_L12_dequantize_granule(scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1)))
|
||||
|
|
@ -2293,7 +2328,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m
|
|||
i = 0;
|
||||
drmp3_L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]);
|
||||
drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]);
|
||||
memset(scratch.grbuf[0], 0, 576*2*sizeof(float));
|
||||
DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float));
|
||||
pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*384*info->channels);
|
||||
}
|
||||
if (bs_frame->pos > bs_frame->limit)
|
||||
|
|
@ -2396,28 +2431,6 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num
|
|||
#endif
|
||||
|
||||
|
||||
/* Standard library stuff. */
|
||||
#ifndef DRMP3_ASSERT
|
||||
#include <assert.h>
|
||||
#define DRMP3_ASSERT(expression) assert(expression)
|
||||
#endif
|
||||
#ifndef DRMP3_COPY_MEMORY
|
||||
#define DRMP3_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz))
|
||||
#endif
|
||||
#ifndef DRMP3_ZERO_MEMORY
|
||||
#define DRMP3_ZERO_MEMORY(p, sz) memset((p), 0, (sz))
|
||||
#endif
|
||||
#define DRMP3_ZERO_OBJECT(p) DRMP3_ZERO_MEMORY((p), sizeof(*(p)))
|
||||
#ifndef DRMP3_MALLOC
|
||||
#define DRMP3_MALLOC(sz) malloc((sz))
|
||||
#endif
|
||||
#ifndef DRMP3_REALLOC
|
||||
#define DRMP3_REALLOC(p, sz) realloc((p), (sz))
|
||||
#endif
|
||||
#ifndef DRMP3_FREE
|
||||
#define DRMP3_FREE(p) free((p))
|
||||
#endif
|
||||
|
||||
#define DRMP3_COUNTOF(x) (sizeof(x) / sizeof(x[0]))
|
||||
#define DRMP3_CLAMP(x, lo, hi) (DRMP3_MAX(lo, DRMP3_MIN(x, hi)))
|
||||
|
||||
|
|
@ -2649,7 +2662,7 @@ static drmp3_uint32 drmp3_decode_next_frame_ex__callbacks(drmp3* pMP3, drmp3d_sa
|
|||
|
||||
/* First we need to move the data down. */
|
||||
if (pMP3->pData != NULL) {
|
||||
memmove(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize);
|
||||
DRMP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize);
|
||||
}
|
||||
|
||||
pMP3->dataConsumed = 0;
|
||||
|
|
@ -2709,7 +2722,7 @@ static drmp3_uint32 drmp3_decode_next_frame_ex__callbacks(drmp3* pMP3, drmp3d_sa
|
|||
size_t bytesRead;
|
||||
|
||||
/* First we need to move the data down. */
|
||||
memmove(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize);
|
||||
DRMP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize);
|
||||
pMP3->dataConsumed = 0;
|
||||
|
||||
if (pMP3->dataCapacity == pMP3->dataSize) {
|
||||
|
|
@ -2754,12 +2767,22 @@ static drmp3_uint32 drmp3_decode_next_frame_ex__memory(drmp3* pMP3, drmp3d_sampl
|
|||
return 0;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->memory.pData + pMP3->memory.currentReadPos, (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos), pPCMFrames, &info);
|
||||
if (pcmFramesRead > 0) {
|
||||
pcmFramesRead = drmp3_hdr_frame_samples(pMP3->decoder.header);
|
||||
pMP3->pcmFramesConsumedInMP3Frame = 0;
|
||||
pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead;
|
||||
pMP3->mp3FrameChannels = info.channels;
|
||||
pMP3->mp3FrameSampleRate = info.hz;
|
||||
break;
|
||||
} else if (info.frame_bytes > 0) {
|
||||
/* No frames were read, but it looks like we skipped past one. Read the next MP3 frame. */
|
||||
pMP3->memory.currentReadPos += (size_t)info.frame_bytes;
|
||||
} else {
|
||||
/* Nothing at all was read. Abort. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Consume the data. */
|
||||
|
|
@ -2822,7 +2845,7 @@ static drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drm
|
|||
}
|
||||
|
||||
/* Decode the first frame to confirm that it is indeed a valid MP3 stream. */
|
||||
if (!drmp3_decode_next_frame(pMP3)) {
|
||||
if (drmp3_decode_next_frame(pMP3) == 0) {
|
||||
drmp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks); /* The call above may have allocated memory. Need to make sure it's freed before aborting. */
|
||||
return DRMP3_FALSE; /* Not a valid MP3 stream. */
|
||||
}
|
||||
|
|
@ -4177,7 +4200,7 @@ static float* drmp3__full_read_and_close_f32(drmp3* pMP3, drmp3_config* pConfig,
|
|||
|
||||
oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(float);
|
||||
newFramesBufferSize = newFramesCap * pMP3->channels * sizeof(float);
|
||||
if (newFramesBufferSize > DRMP3_SIZE_MAX) {
|
||||
if (newFramesBufferSize > (drmp3_uint64)DRMP3_SIZE_MAX) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -4244,7 +4267,7 @@ static drmp3_int16* drmp3__full_read_and_close_s16(drmp3* pMP3, drmp3_config* pC
|
|||
|
||||
oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(drmp3_int16);
|
||||
newFramesBufferSize = newFramesCap * pMP3->channels * sizeof(drmp3_int16);
|
||||
if (newFramesBufferSize > DRMP3_SIZE_MAX) {
|
||||
if (newFramesBufferSize > (drmp3_uint64)DRMP3_SIZE_MAX) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -4450,6 +4473,20 @@ counts rather than sample counts.
|
|||
/*
|
||||
REVISION HISTORY
|
||||
================
|
||||
v0.6.31 - 2021-08-22
|
||||
- Fix a bug when loading from memory.
|
||||
|
||||
v0.6.30 - 2021-08-16
|
||||
- Silence some warnings.
|
||||
- Replace memory operations with DRMP3_* macros.
|
||||
|
||||
v0.6.29 - 2021-08-08
|
||||
- Bring up to date with minimp3.
|
||||
|
||||
v0.6.28 - 2021-07-31
|
||||
- Fix platform detection for ARM64.
|
||||
- Fix a compilation error with C89.
|
||||
|
||||
v0.6.27 - 2021-02-21
|
||||
- Fix a warning due to referencing _MSC_VER when it is undefined.
|
||||
|
||||
|
|
|
|||
2366
src/external/dr_wav.h
vendored
341
src/external/msf_gif.h
vendored
|
|
@ -13,19 +13,31 @@ USAGE EXAMPLE:
|
|||
|
||||
int width = 480, height = 320, centisecondsPerFrame = 5, bitDepth = 16;
|
||||
MsfGifState gifState = {};
|
||||
// msf_gif_bgra_flag = true; //optionally, set this flag if your pixels are in BGRA format instead of RGBA
|
||||
// msf_gif_alpha_threshold = 128; //optionally, enable transparency (see function documentation below for details)
|
||||
msf_gif_begin(&gifState, width, height);
|
||||
msf_gif_frame(&gifState, ..., centisecondsPerFrame, bitDepth, width * 4); //frame 1
|
||||
msf_gif_frame(&gifState, ..., centisecondsPerFrame, bitDepth, width * 4); //frame 2
|
||||
msf_gif_frame(&gifState, ..., centisecondsPerFrame, bitDepth, width * 4); //frame 3, etc...
|
||||
MsfGifResult result = msf_gif_end(&gifState);
|
||||
if (result.data) {
|
||||
FILE * fp = fopen("MyGif.gif", "wb");
|
||||
fwrite(result.data, result.dataSize, 1, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
msf_gif_free(result);
|
||||
|
||||
Detailed function documentation can be found in the header section below.
|
||||
|
||||
|
||||
ERROR HANDLING:
|
||||
|
||||
If memory allocation fails, the functions will signal the error via their return values.
|
||||
If one function call fails, the library will free all of its allocations,
|
||||
and all subsequent calls will safely no-op and return 0 until the next call to `msf_gif_begin()`.
|
||||
Therefore, it's safe to check only the return value of `msf_gif_end()`.
|
||||
|
||||
|
||||
REPLACING MALLOC:
|
||||
|
||||
This library uses malloc+realloc+free internally for memory allocation.
|
||||
|
|
@ -39,10 +51,20 @@ REPLACING MALLOC:
|
|||
If your allocator needs a context pointer, you can set the `customAllocatorContext` field of the MsfGifState struct
|
||||
before calling msf_gif_begin(), and it will be passed to all subsequent allocator macro calls.
|
||||
|
||||
The maximum number of bytes the library will allocate to encode a single gif is bounded by the following formula:
|
||||
`(2 * 1024 * 1024) + (width * height * 8) + ((1024 + width * height * 1.5) * 3 * frameCount)`
|
||||
The peak heap memory usage in bytes, if using a general-purpose heap allocator, is bounded by the following formula:
|
||||
`(2 * 1024 * 1024) + (width * height * 9.5) + 1024 + (16 * frameCount) + (2 * sizeOfResultingGif)
|
||||
|
||||
|
||||
See end of file for license information.
|
||||
*/
|
||||
|
||||
//version 2.1
|
||||
//version 2.2
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// HEADER ///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef MSF_GIF_H
|
||||
#define MSF_GIF_H
|
||||
|
|
@ -63,12 +85,24 @@ typedef struct { //internal use
|
|||
int depth, count, rbits, gbits, bbits;
|
||||
} MsfCookedFrame;
|
||||
|
||||
typedef struct MsfGifBuffer {
|
||||
struct MsfGifBuffer * next;
|
||||
size_t size;
|
||||
uint8_t data[1];
|
||||
} MsfGifBuffer;
|
||||
|
||||
typedef size_t (* MsfGifFileWriteFunc) (const void * buffer, size_t size, size_t count, void * stream);
|
||||
typedef struct {
|
||||
MsfGifFileWriteFunc fileWriteFunc;
|
||||
void * fileWriteData;
|
||||
MsfCookedFrame previousFrame;
|
||||
uint8_t * listHead;
|
||||
uint8_t * listTail;
|
||||
MsfCookedFrame currentFrame;
|
||||
int16_t * lzwMem;
|
||||
MsfGifBuffer * listHead;
|
||||
MsfGifBuffer * listTail;
|
||||
int width, height;
|
||||
void * customAllocatorContext;
|
||||
int framesSubmitted; //needed for transparency to work correctly (because we reach into the previous frame)
|
||||
} MsfGifState;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
@ -83,7 +117,8 @@ extern "C" {
|
|||
int msf_gif_begin(MsfGifState * handle, int width, int height);
|
||||
|
||||
/**
|
||||
* @param pixelData Pointer to raw framebuffer data. Rows must be contiguous in memory, in RGBA8 format.
|
||||
* @param pixelData Pointer to raw framebuffer data. Rows must be contiguous in memory, in RGBA8 format
|
||||
* (or BGRA8 if you have set `msf_gif_bgra_flag = true`).
|
||||
* Note: This function does NOT free `pixelData`. You must free it yourself afterwards.
|
||||
* @param centiSecondsPerFrame How many hundredths of a second this frame should be displayed for.
|
||||
* Note: This being specified in centiseconds is a limitation of the GIF format.
|
||||
|
|
@ -111,6 +146,35 @@ MsfGifResult msf_gif_end(MsfGifState * handle);
|
|||
*/
|
||||
void msf_gif_free(MsfGifResult result);
|
||||
|
||||
//The gif format only supports 1-bit transparency, meaning a pixel will either be fully transparent or fully opaque.
|
||||
//Pixels with an alpha value less than the alpha threshold will be treated as transparent.
|
||||
//To enable exporting transparent gifs, set it to a value between 1 and 255 (inclusive) before calling msf_gif_frame().
|
||||
//Setting it to 0 causes the alpha channel to be ignored. Its initial value is 0.
|
||||
extern int msf_gif_alpha_threshold;
|
||||
|
||||
//Set `msf_gif_bgra_flag = true` before calling `msf_gif_frame()` if your pixels are in BGRA byte order instead of RBGA.
|
||||
extern int msf_gif_bgra_flag;
|
||||
|
||||
|
||||
|
||||
//TO-FILE FUNCTIONS
|
||||
//These functions are equivalent to the ones above, but they write results to a file incrementally,
|
||||
//instead of building a buffer in memory. This can result in lower memory usage when saving large gifs,
|
||||
//because memory usage is bounded by only the size of a single frame, and is not dependent on the number of frames.
|
||||
//There is currently no reason to use these unless you are on a memory-constrained platform.
|
||||
//If in doubt about which API to use, for now you should use the normal (non-file) functions above.
|
||||
//The signature of MsfGifFileWriteFunc matches fwrite for convenience, so that you can use the C file API like so:
|
||||
// FILE * fp = fopen("MyGif.gif", "wb");
|
||||
// msf_gif_begin_to_file(&handle, width, height, (MsfGifFileWriteFunc) fwrite, (void *) fp);
|
||||
// msf_gif_frame_to_file(...)
|
||||
// msf_gif_end_to_file(&handle);
|
||||
// fclose(fp);
|
||||
//If you use a custom file write function, you must take care to return the same values that fwrite() would return.
|
||||
//Note that all three functions will potentially write to the file.
|
||||
int msf_gif_begin_to_file(MsfGifState * handle, int width, int height, MsfGifFileWriteFunc func, void * filePointer);
|
||||
int msf_gif_frame_to_file(MsfGifState * handle, uint8_t * pixelData, int centiSecondsPerFame, int maxBitDepth, int pitchInBytes);
|
||||
int msf_gif_end_to_file(MsfGifState * handle); //returns 0 on error and non-zero on success
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif //__cplusplus
|
||||
|
|
@ -125,10 +189,6 @@ void msf_gif_free(MsfGifResult result);
|
|||
#ifndef MSF_GIF_ALREADY_IMPLEMENTED_IN_THIS_TRANSLATION_UNIT
|
||||
#define MSF_GIF_ALREADY_IMPLEMENTED_IN_THIS_TRANSLATION_UNIT
|
||||
|
||||
#ifndef MSF_GIF_BUFFER_INIT_SIZE
|
||||
#define MSF_GIF_BUFFER_INIT_SIZE 1024 * 1024 * 4 //4MB by default, you can increase this if you want to realloc less
|
||||
#endif
|
||||
|
||||
//ensure the library user has either defined all of malloc/realloc/free, or none
|
||||
#if defined(MSF_GIF_MALLOC) && defined(MSF_GIF_REALLOC) && defined(MSF_GIF_FREE) //ok
|
||||
#elif !defined(MSF_GIF_MALLOC) && !defined(MSF_GIF_REALLOC) && !defined(MSF_GIF_FREE) //ok
|
||||
|
|
@ -189,13 +249,21 @@ static inline int msf_imax(int a, int b) { return b < a? a : b; }
|
|||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
static MsfCookedFrame msf_cook_frame(void * allocContext, uint8_t * raw, uint8_t * used,
|
||||
int msf_gif_alpha_threshold = 0;
|
||||
int msf_gif_bgra_flag = 0;
|
||||
|
||||
static void msf_cook_frame(MsfCookedFrame * frame, uint8_t * raw, uint8_t * used,
|
||||
int width, int height, int pitch, int depth)
|
||||
{ MsfTimeFunc
|
||||
//bit depth for each channel
|
||||
const static int rdepths[17] = { 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5 };
|
||||
const static int gdepths[17] = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6 };
|
||||
const static int bdepths[17] = { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5 };
|
||||
const static int rdepthsArray[17] = { 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5 };
|
||||
const static int gdepthsArray[17] = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6 };
|
||||
const static int bdepthsArray[17] = { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5 };
|
||||
//this extra level of indirection looks unnecessary but we need to explicitly decay the arrays to pointers
|
||||
//in order to be able to swap them because of C's annoying not-quite-pointers, not-quite-value-types stack arrays.
|
||||
const int * rdepths = msf_gif_bgra_flag? bdepthsArray : rdepthsArray;
|
||||
const int * gdepths = gdepthsArray;
|
||||
const int * bdepths = msf_gif_bgra_flag? rdepthsArray : bdepthsArray;
|
||||
|
||||
const static int ditherKernel[16] = {
|
||||
0 << 12, 8 << 12, 2 << 12, 10 << 12,
|
||||
|
|
@ -204,13 +272,11 @@ static MsfCookedFrame msf_cook_frame(void * allocContext, uint8_t * raw, uint8_t
|
|||
15 << 12, 7 << 12, 13 << 12, 5 << 12,
|
||||
};
|
||||
|
||||
uint32_t * cooked = (uint32_t *) MSF_GIF_MALLOC(allocContext, width * height * sizeof(uint32_t));
|
||||
if (!cooked) { MsfCookedFrame blank = {0}; return blank; }
|
||||
|
||||
uint32_t * cooked = frame->pixels;
|
||||
int count = 0;
|
||||
MsfTimeLoop("do") do {
|
||||
int rbits = rdepths[depth], gbits = gdepths[depth], bbits = bdepths[depth];
|
||||
int paletteSize = 1 << (rbits + gbits + bbits);
|
||||
int paletteSize = (1 << (rbits + gbits + bbits)) + 1;
|
||||
memset(used, 0, paletteSize * sizeof(uint8_t));
|
||||
|
||||
//TODO: document what this math does and why it's correct
|
||||
|
|
@ -230,7 +296,6 @@ static MsfCookedFrame msf_cook_frame(void * allocContext, uint8_t * raw, uint8_t
|
|||
#if (defined (__SSE2__) || defined (_M_X64) || _M_IX86_FP == 2) && !defined(MSF_GIF_NO_SSE2)
|
||||
__m128i k = _mm_loadu_si128((__m128i *) &ditherKernel[(y & 3) * 4]);
|
||||
__m128i k2 = _mm_or_si128(_mm_srli_epi32(k, rbits), _mm_slli_epi32(_mm_srli_epi32(k, bbits), 16));
|
||||
// MsfTimeLoop("SIMD")
|
||||
for (; x < width - 3; x += 4) {
|
||||
uint8_t * pixels = &raw[y * pitch + x * 4];
|
||||
__m128i p = _mm_loadu_si128((__m128i *) pixels);
|
||||
|
|
@ -246,17 +311,30 @@ static MsfCookedFrame msf_cook_frame(void * allocContext, uint8_t * raw, uint8_t
|
|||
__m128i g2 = _mm_adds_epu16(g1, _mm_srli_epi32(k, gbits));
|
||||
__m128i g3 = _mm_and_si128(_mm_srli_epi32(g2, 16 - rbits - gbits), _mm_set1_epi32(gmask));
|
||||
|
||||
__m128i out = _mm_or_si128(_mm_or_si128(r3, g3), b3);
|
||||
|
||||
//mask in transparency based on threshold
|
||||
//NOTE: we can theoretically do a sub instead of srli by doing an unsigned compare via bias
|
||||
// to maybe save a TINY amount of throughput? but lol who cares maybe I'll do it later -m
|
||||
__m128i invAlphaMask = _mm_cmplt_epi32(_mm_srli_epi32(p, 24), _mm_set1_epi32(msf_gif_alpha_threshold));
|
||||
out = _mm_or_si128(_mm_and_si128(invAlphaMask, _mm_set1_epi32(paletteSize - 1)), _mm_andnot_si128(invAlphaMask, out));
|
||||
|
||||
//TODO: does storing this as a __m128i then reading it back as a uint32_t violate strict aliasing?
|
||||
uint32_t * c = &cooked[y * width + x];
|
||||
__m128i out = _mm_or_si128(_mm_or_si128(r3, g3), b3);
|
||||
_mm_storeu_si128((__m128i *) c, out);
|
||||
}
|
||||
#endif
|
||||
|
||||
//scalar cleanup loop
|
||||
// MsfTimeLoop("scalar")
|
||||
for (; x < width; ++x) {
|
||||
uint8_t * p = &raw[y * pitch + x * 4];
|
||||
|
||||
//transparent pixel if alpha is low
|
||||
if (p[3] < msf_gif_alpha_threshold) {
|
||||
cooked[y * width + x] = paletteSize - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
int dx = x & 3, dy = y & 3;
|
||||
int k = ditherKernel[dy * 4 + dx];
|
||||
cooked[y * width + x] =
|
||||
|
|
@ -267,30 +345,25 @@ static MsfCookedFrame msf_cook_frame(void * allocContext, uint8_t * raw, uint8_t
|
|||
}
|
||||
|
||||
count = 0;
|
||||
MsfTimeLoop("mark and count") for (int i = 0; i < width * height; ++i) {
|
||||
MsfTimeLoop("mark") for (int i = 0; i < width * height; ++i) {
|
||||
used[cooked[i]] = 1;
|
||||
}
|
||||
|
||||
//count used colors
|
||||
MsfTimeLoop("count") for (int j = 0; j < paletteSize; ++j) {
|
||||
//count used colors, transparent is ignored
|
||||
MsfTimeLoop("count") for (int j = 0; j < paletteSize - 1; ++j) {
|
||||
count += used[j];
|
||||
}
|
||||
} while (count >= 256 && --depth);
|
||||
|
||||
MsfCookedFrame ret = { cooked, depth, count, rdepths[depth], gdepths[depth], bdepths[depth] };
|
||||
return ret;
|
||||
*frame = ret;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Frame Compression ///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct {
|
||||
uint8_t * next;
|
||||
size_t size;
|
||||
} MsfBufferHeader;
|
||||
|
||||
static inline int msf_put_code(uint8_t * * writeHead, uint32_t * blockBits, int len, uint32_t code) {
|
||||
static inline void msf_put_code(uint8_t * * writeHead, uint32_t * blockBits, int len, uint32_t code) {
|
||||
//insert new code into block buffer
|
||||
int idx = *blockBits / 8;
|
||||
int bit = *blockBits % 8;
|
||||
|
|
@ -308,8 +381,6 @@ static inline int msf_put_code(uint8_t * * writeHead, uint32_t * blockBits, int
|
|||
(*writeHead)[0] = 255;
|
||||
memset((*writeHead) + 4, 0, 256);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -324,30 +395,29 @@ static inline void msf_lzw_reset(MsfStridedList * lzw, int tableSize, int stride
|
|||
lzw->stride = stride;
|
||||
}
|
||||
|
||||
static uint8_t * msf_compress_frame(void * allocContext, int width, int height, int centiSeconds,
|
||||
MsfCookedFrame frame, MsfCookedFrame previous, uint8_t * used)
|
||||
static MsfGifBuffer * msf_compress_frame(void * allocContext, int width, int height, int centiSeconds,
|
||||
MsfCookedFrame frame, MsfGifState * handle, uint8_t * used, int16_t * lzwMem)
|
||||
{ MsfTimeFunc
|
||||
//NOTE: we reserve enough memory for theoretical the worst case upfront because it's a reasonable amount,
|
||||
// and prevents us from ever having to check size or realloc during compression
|
||||
int maxBufSize = sizeof(MsfBufferHeader) + 32 + 256 * 3 + width * height * 3 / 2; //headers + color table + data
|
||||
uint8_t * allocation = (uint8_t *) MSF_GIF_MALLOC(allocContext, maxBufSize);
|
||||
if (!allocation) { return NULL; }
|
||||
uint8_t * writeBase = allocation + sizeof(MsfBufferHeader);
|
||||
uint8_t * writeHead = writeBase;
|
||||
int lzwAllocSize = 4096 * (frame.count + 1) * sizeof(int16_t);
|
||||
MsfStridedList lzw = { (int16_t *) MSF_GIF_MALLOC(allocContext, lzwAllocSize) };
|
||||
if (!lzw.data) { MSF_GIF_FREE(allocContext, allocation, maxBufSize); return NULL; }
|
||||
int maxBufSize = offsetof(MsfGifBuffer, data) + 32 + 256 * 3 + width * height * 3 / 2; //headers + color table + data
|
||||
MsfGifBuffer * buffer = (MsfGifBuffer *) MSF_GIF_MALLOC(allocContext, maxBufSize);
|
||||
if (!buffer) { return NULL; }
|
||||
uint8_t * writeHead = buffer->data;
|
||||
MsfStridedList lzw = { lzwMem };
|
||||
|
||||
//allocate tlb
|
||||
int totalBits = frame.rbits + frame.gbits + frame.bbits;
|
||||
int tlbSize = 1 << totalBits;
|
||||
uint8_t tlb[1 << 16]; //only 64k, so stack allocating is fine
|
||||
int tlbSize = (1 << totalBits) + 1;
|
||||
uint8_t tlb[(1 << 16) + 1]; //only 64k, so stack allocating is fine
|
||||
|
||||
//generate palette
|
||||
typedef struct { uint8_t r, g, b; } Color3;
|
||||
Color3 table[256] = { {0} };
|
||||
int tableIdx = 1; //we start counting at 1 because 0 is the transparent color
|
||||
MsfTimeLoop("table") for (int i = 0; i < tlbSize; ++i) {
|
||||
//transparent is always last in the table
|
||||
tlb[tlbSize-1] = 0;
|
||||
MsfTimeLoop("table") for (int i = 0; i < tlbSize-1; ++i) {
|
||||
if (used[i]) {
|
||||
tlb[i] = tableIdx;
|
||||
int rmask = (1 << frame.rbits) - 1;
|
||||
|
|
@ -363,19 +433,32 @@ static uint8_t * msf_compress_frame(void * allocContext, int width, int height,
|
|||
table[tableIdx].r = r | r >> frame.rbits | r >> (frame.rbits * 2) | r >> (frame.rbits * 3);
|
||||
table[tableIdx].g = g | g >> frame.gbits | g >> (frame.gbits * 2) | g >> (frame.gbits * 3);
|
||||
table[tableIdx].b = b | b >> frame.bbits | b >> (frame.bbits * 2) | b >> (frame.bbits * 3);
|
||||
if (msf_gif_bgra_flag) {
|
||||
uint8_t temp = table[tableIdx].r;
|
||||
table[tableIdx].r = table[tableIdx].b;
|
||||
table[tableIdx].b = temp;
|
||||
}
|
||||
++tableIdx;
|
||||
}
|
||||
}
|
||||
int hasTransparentPixels = used[tlbSize-1];
|
||||
|
||||
//SPEC: "Because of some algorithmic constraints however, black & white images which have one color bit
|
||||
// must be indicated as having a code size of 2."
|
||||
int tableBits = msf_imax(2, msf_bit_log(tableIdx - 1));
|
||||
int tableSize = 1 << tableBits;
|
||||
//NOTE: we don't just compare `depth` field here because it will be wrong for the first frame and we will segfault
|
||||
MsfCookedFrame previous = handle->previousFrame;
|
||||
int hasSamePal = frame.rbits == previous.rbits && frame.gbits == previous.gbits && frame.bbits == previous.bbits;
|
||||
int framesCompatible = hasSamePal && !hasTransparentPixels;
|
||||
|
||||
//NOTE: because __attribute__((__packed__)) is annoyingly compiler-specific, we do this unreadable weirdness
|
||||
char headerBytes[19] = "\x21\xF9\x04\x05\0\0\0\0" "\x2C\0\0\0\0\0\0\0\0\x80";
|
||||
//NOTE: we need to check the frame number because if we reach into the buffer prior to the first frame,
|
||||
// we'll just clobber the file header instead, which is a bug
|
||||
if (hasTransparentPixels && handle->framesSubmitted > 0) {
|
||||
handle->listTail->data[3] = 0x09; //set the previous frame's disposal to background, so transparency is possible
|
||||
}
|
||||
memcpy(&headerBytes[4], ¢iSeconds, 2);
|
||||
memcpy(&headerBytes[13], &width, 2);
|
||||
memcpy(&headerBytes[15], &height, 2);
|
||||
|
|
@ -397,12 +480,10 @@ static uint8_t * msf_compress_frame(void * allocContext, int width, int height,
|
|||
msf_lzw_reset(&lzw, tableSize, tableIdx);
|
||||
msf_put_code(&writeHead, &blockBits, msf_bit_log(lzw.len - 1), tableSize);
|
||||
|
||||
int lastCode = hasSamePal && frame.pixels[0] == previous.pixels[0]? 0 : tlb[frame.pixels[0]];
|
||||
int lastCode = framesCompatible && frame.pixels[0] == previous.pixels[0]? 0 : tlb[frame.pixels[0]];
|
||||
MsfTimeLoop("compress") for (int i = 1; i < width * height; ++i) {
|
||||
//PERF: branching vs. branchless version of this line is observed to have no discernable impact on speed
|
||||
int color = hasSamePal && frame.pixels[i] == previous.pixels[i]? 0 : tlb[frame.pixels[i]];
|
||||
//PERF: branchless version must use && otherwise it will segfault on frame 1, but it's well-predicted so OK
|
||||
// int color = (!(hasSamePal && frame.pixels[i] == previous.pixels[i])) * tlb[frame.pixels[i]];
|
||||
int color = framesCompatible && frame.pixels[i] == previous.pixels[i]? 0 : tlb[frame.pixels[i]];
|
||||
int code = (&lzw.data[lastCode * lzw.stride])[color];
|
||||
if (code < 0) {
|
||||
//write to code stream
|
||||
|
|
@ -424,9 +505,6 @@ static uint8_t * msf_compress_frame(void * allocContext, int width, int height,
|
|||
}
|
||||
}
|
||||
|
||||
MSF_GIF_FREE(allocContext, lzw.data, lzwAllocSize);
|
||||
MSF_GIF_FREE(allocContext, previous.pixels, width * height * sizeof(uint32_t));
|
||||
|
||||
//write code for leftover index buffer contents, then the end code
|
||||
msf_put_code(&writeHead, &blockBits, msf_imin(12, msf_bit_log(lzw.len - 1)), lastCode);
|
||||
msf_put_code(&writeHead, &blockBits, msf_imin(12, msf_bit_log(lzw.len)), tableSize + 1);
|
||||
|
|
@ -439,38 +517,72 @@ static uint8_t * msf_compress_frame(void * allocContext, int width, int height,
|
|||
}
|
||||
*writeHead++ = 0; //terminating block
|
||||
|
||||
//filling in buffer header and shrink buffer to fit data
|
||||
MsfBufferHeader * header = (MsfBufferHeader *) allocation;
|
||||
header->next = NULL;
|
||||
header->size = writeHead - writeBase;
|
||||
uint8_t * moved = (uint8_t *) MSF_GIF_REALLOC(allocContext, allocation, maxBufSize, writeHead - allocation);
|
||||
if (!moved) { MSF_GIF_FREE(allocContext, allocation, maxBufSize); return NULL; }
|
||||
//fill in buffer header and shrink buffer to fit data
|
||||
buffer->next = NULL;
|
||||
buffer->size = writeHead - buffer->data;
|
||||
MsfGifBuffer * moved =
|
||||
(MsfGifBuffer *) MSF_GIF_REALLOC(allocContext, buffer, maxBufSize, offsetof(MsfGifBuffer, data) + buffer->size);
|
||||
if (!moved) { MSF_GIF_FREE(allocContext, buffer, maxBufSize); return NULL; }
|
||||
return moved;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Incremental API ///
|
||||
/// To-memory API ///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const int lzwAllocSize = 4096 * 256 * sizeof(int16_t);
|
||||
|
||||
//NOTE: by C standard library conventions, freeing NULL should be a no-op,
|
||||
// but just in case the user's custom free doesn't follow that rule, we do null checks on our end as well.
|
||||
static void msf_free_gif_state(MsfGifState * handle) {
|
||||
if (handle->previousFrame.pixels) MSF_GIF_FREE(handle->customAllocatorContext, handle->previousFrame.pixels,
|
||||
handle->width * handle->height * sizeof(uint32_t));
|
||||
if (handle->currentFrame.pixels) MSF_GIF_FREE(handle->customAllocatorContext, handle->currentFrame.pixels,
|
||||
handle->width * handle->height * sizeof(uint32_t));
|
||||
if (handle->lzwMem) MSF_GIF_FREE(handle->customAllocatorContext, handle->lzwMem, lzwAllocSize);
|
||||
for (MsfGifBuffer * node = handle->listHead; node;) {
|
||||
MsfGifBuffer * next = node->next; //NOTE: we have to copy the `next` pointer BEFORE freeing the node holding it
|
||||
MSF_GIF_FREE(handle->customAllocatorContext, node, offsetof(MsfGifBuffer, data) + node->size);
|
||||
node = next;
|
||||
}
|
||||
handle->listHead = NULL; //this implicitly marks the handle as invalid until the next msf_gif_begin() call
|
||||
}
|
||||
|
||||
int msf_gif_begin(MsfGifState * handle, int width, int height) { MsfTimeFunc
|
||||
//NOTE: we cannot stomp the entire struct to zero because we must preserve `customAllocatorContext`.
|
||||
MsfCookedFrame empty = {0}; //god I hate MSVC...
|
||||
handle->previousFrame = empty;
|
||||
handle->currentFrame = empty;
|
||||
handle->width = width;
|
||||
handle->height = height;
|
||||
handle->framesSubmitted = 0;
|
||||
|
||||
//allocate memory for LZW buffer
|
||||
//NOTE: Unfortunately we can't just use stack memory for the LZW table because it's 2MB,
|
||||
// which is more stack space than most operating systems give by default,
|
||||
// and we can't realistically expect users to be willing to override that just to use our library,
|
||||
// so we have to allocate this on the heap.
|
||||
handle->lzwMem = (int16_t *) MSF_GIF_MALLOC(handle->customAllocatorContext, lzwAllocSize);
|
||||
handle->previousFrame.pixels =
|
||||
(uint32_t *) MSF_GIF_MALLOC(handle->customAllocatorContext, handle->width * handle->height * sizeof(uint32_t));
|
||||
handle->currentFrame.pixels =
|
||||
(uint32_t *) MSF_GIF_MALLOC(handle->customAllocatorContext, handle->width * handle->height * sizeof(uint32_t));
|
||||
|
||||
//setup header buffer header (lol)
|
||||
handle->listHead = (uint8_t *) MSF_GIF_MALLOC(handle->customAllocatorContext, sizeof(MsfBufferHeader) + 32);
|
||||
if (!handle->listHead) { return 0; }
|
||||
handle->listHead = (MsfGifBuffer *) MSF_GIF_MALLOC(handle->customAllocatorContext, offsetof(MsfGifBuffer, data) + 32);
|
||||
if (!handle->listHead || !handle->lzwMem || !handle->previousFrame.pixels || !handle->currentFrame.pixels) {
|
||||
msf_free_gif_state(handle);
|
||||
return 0;
|
||||
}
|
||||
handle->listTail = handle->listHead;
|
||||
MsfBufferHeader * header = (MsfBufferHeader *) handle->listHead;
|
||||
header->next = NULL;
|
||||
header->size = 32;
|
||||
handle->listHead->next = NULL;
|
||||
handle->listHead->size = 32;
|
||||
|
||||
//NOTE: because __attribute__((__packed__)) is annoyingly compiler-specific, we do this unreadable weirdness
|
||||
char headerBytes[33] = "GIF89a\0\0\0\0\x10\0\0" "\x21\xFF\x0BNETSCAPE2.0\x03\x01\0\0\0";
|
||||
char headerBytes[33] = "GIF89a\0\0\0\0\x70\0\0" "\x21\xFF\x0BNETSCAPE2.0\x03\x01\0\0\0";
|
||||
memcpy(&headerBytes[6], &width, 2);
|
||||
memcpy(&headerBytes[8], &height, 2);
|
||||
memcpy(handle->listHead + sizeof(MsfBufferHeader), headerBytes, 32);
|
||||
memcpy(handle->listHead->data, headerBytes, 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -482,86 +594,83 @@ int msf_gif_frame(MsfGifState * handle, uint8_t * pixelData, int centiSecondsPer
|
|||
if (pitchInBytes == 0) pitchInBytes = handle->width * 4;
|
||||
if (pitchInBytes < 0) pixelData -= pitchInBytes * (handle->height - 1);
|
||||
|
||||
uint8_t used[1 << 16]; //only 64k, so stack allocating is fine
|
||||
MsfCookedFrame frame =
|
||||
msf_cook_frame(handle->customAllocatorContext, pixelData, used, handle->width, handle->height, pitchInBytes,
|
||||
uint8_t used[(1 << 16) + 1]; //only 64k, so stack allocating is fine
|
||||
msf_cook_frame(&handle->currentFrame, pixelData, used, handle->width, handle->height, pitchInBytes,
|
||||
msf_imin(maxBitDepth, handle->previousFrame.depth + 160 / msf_imax(1, handle->previousFrame.count)));
|
||||
//TODO: de-duplicate cleanup code
|
||||
if (!frame.pixels) {
|
||||
MSF_GIF_FREE(handle->customAllocatorContext,
|
||||
handle->previousFrame.pixels, handle->width * handle->height * sizeof(uint32_t));
|
||||
for (uint8_t * node = handle->listHead; node;) {
|
||||
MsfBufferHeader * header = (MsfBufferHeader *) node;
|
||||
node = header->next;
|
||||
MSF_GIF_FREE(handle->customAllocatorContext, header, sizeof(MsfBufferHeader) + header->size);
|
||||
}
|
||||
handle->listHead = handle->listTail = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t * buffer = msf_compress_frame(handle->customAllocatorContext,
|
||||
handle->width, handle->height, centiSecondsPerFame, frame, handle->previousFrame, used);
|
||||
((MsfBufferHeader *) handle->listTail)->next = buffer;
|
||||
MsfGifBuffer * buffer = msf_compress_frame(handle->customAllocatorContext, handle->width, handle->height,
|
||||
centiSecondsPerFame, handle->currentFrame, handle, used, handle->lzwMem);
|
||||
if (!buffer) { msf_free_gif_state(handle); return 0; }
|
||||
handle->listTail->next = buffer;
|
||||
handle->listTail = buffer;
|
||||
if (!buffer) {
|
||||
MSF_GIF_FREE(handle->customAllocatorContext, frame.pixels, handle->width * handle->height * sizeof(uint32_t));
|
||||
MSF_GIF_FREE(handle->customAllocatorContext,
|
||||
handle->previousFrame.pixels, handle->width * handle->height * sizeof(uint32_t));
|
||||
for (uint8_t * node = handle->listHead; node;) {
|
||||
MsfBufferHeader * header = (MsfBufferHeader *) node;
|
||||
node = header->next;
|
||||
MSF_GIF_FREE(handle->customAllocatorContext, header, sizeof(MsfBufferHeader) + header->size);
|
||||
}
|
||||
handle->listHead = handle->listTail = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
handle->previousFrame = frame;
|
||||
//swap current and previous frames
|
||||
MsfCookedFrame tmp = handle->previousFrame;
|
||||
handle->previousFrame = handle->currentFrame;
|
||||
handle->currentFrame = tmp;
|
||||
|
||||
handle->framesSubmitted += 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
MsfGifResult msf_gif_end(MsfGifState * handle) { MsfTimeFunc
|
||||
if (!handle->listHead) { MsfGifResult empty = {0}; return empty; }
|
||||
|
||||
MSF_GIF_FREE(handle->customAllocatorContext,
|
||||
handle->previousFrame.pixels, handle->width * handle->height * sizeof(uint32_t));
|
||||
|
||||
//first pass: determine total size
|
||||
size_t total = 1; //1 byte for trailing marker
|
||||
for (uint8_t * node = handle->listHead; node;) {
|
||||
MsfBufferHeader * header = (MsfBufferHeader *) node;
|
||||
node = header->next;
|
||||
total += header->size;
|
||||
}
|
||||
for (MsfGifBuffer * node = handle->listHead; node; node = node->next) { total += node->size; }
|
||||
|
||||
//second pass: write data
|
||||
uint8_t * buffer = (uint8_t *) MSF_GIF_MALLOC(handle->customAllocatorContext, total);
|
||||
if (buffer) {
|
||||
uint8_t * writeHead = buffer;
|
||||
for (uint8_t * node = handle->listHead; node;) {
|
||||
MsfBufferHeader * header = (MsfBufferHeader *) node;
|
||||
memcpy(writeHead, node + sizeof(MsfBufferHeader), header->size);
|
||||
writeHead += header->size;
|
||||
node = header->next;
|
||||
for (MsfGifBuffer * node = handle->listHead; node; node = node->next) {
|
||||
memcpy(writeHead, node->data, node->size);
|
||||
writeHead += node->size;
|
||||
}
|
||||
*writeHead++ = 0x3B;
|
||||
}
|
||||
|
||||
//third pass: free buffers
|
||||
for (uint8_t * node = handle->listHead; node;) {
|
||||
MsfBufferHeader * header = (MsfBufferHeader *) node;
|
||||
node = header->next;
|
||||
MSF_GIF_FREE(handle->customAllocatorContext, header, sizeof(MsfBufferHeader) + header->size);
|
||||
}
|
||||
msf_free_gif_state(handle);
|
||||
|
||||
MsfGifResult ret = { buffer, total, total, handle->customAllocatorContext };
|
||||
return ret;
|
||||
}
|
||||
|
||||
void msf_gif_free(MsfGifResult result) {
|
||||
void msf_gif_free(MsfGifResult result) { MsfTimeFunc
|
||||
if (result.data) { MSF_GIF_FREE(result.contextPointer, result.data, result.allocSize); }
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// To-file API ///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int msf_gif_begin_to_file(MsfGifState * handle, int width, int height, MsfGifFileWriteFunc func, void * filePointer) {
|
||||
handle->fileWriteFunc = func;
|
||||
handle->fileWriteData = filePointer;
|
||||
return msf_gif_begin(handle, width, height);
|
||||
}
|
||||
|
||||
int msf_gif_frame_to_file(MsfGifState * handle, uint8_t * pixelData, int centiSecondsPerFame, int maxBitDepth, int pitchInBytes) {
|
||||
if (!msf_gif_frame(handle, pixelData, centiSecondsPerFame, maxBitDepth, pitchInBytes)) { return 0; }
|
||||
|
||||
//NOTE: this is a somewhat hacky implementation which is not perfectly efficient, but it's good enough for now
|
||||
MsfGifBuffer * head = handle->listHead;
|
||||
if (!handle->fileWriteFunc(head->data, head->size, 1, handle->fileWriteData)) { msf_free_gif_state(handle); return 0; }
|
||||
handle->listHead = head->next;
|
||||
MSF_GIF_FREE(handle->customAllocatorContext, head, offsetof(MsfGifBuffer, data) + head->size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int msf_gif_end_to_file(MsfGifState * handle) {
|
||||
//NOTE: this is a somewhat hacky implementation which is not perfectly efficient, but it's good enough for now
|
||||
MsfGifResult result = msf_gif_end(handle);
|
||||
int ret = (int) handle->fileWriteFunc(result.data, result.dataSize, 1, handle->fileWriteData);
|
||||
msf_gif_free(result);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif //MSF_GIF_ALREADY_IMPLEMENTED_IN_THIS_TRANSLATION_UNIT
|
||||
#endif //MSF_GIF_IMPL
|
||||
|
||||
|
|
@ -570,7 +679,7 @@ void msf_gif_free(MsfGifResult result) {
|
|||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2020 Miles Fogle
|
||||
Copyright (c) 2021 Miles Fogle
|
||||
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
|
||||
|
|
|
|||
21
src/external/sdefl.h
vendored
|
|
@ -1,5 +1,4 @@
|
|||
/*
|
||||
# Small Deflate
|
||||
/*# Small Deflate
|
||||
`sdefl` is a small bare bone lossless compression library in ANSI C (ISO C90)
|
||||
which implements the Deflate (RFC 1951) compressed data format specification standard.
|
||||
It is mainly tuned to get as much speed and compression ratio from as little code
|
||||
|
|
@ -33,16 +32,16 @@ this file implementation in *one* C or C++ file to prevent collisions.
|
|||
|
||||
| Compressor name | Compression| Decompress.| Compr. size | Ratio |
|
||||
| ------------------------| -----------| -----------| ----------- | ----- |
|
||||
| sdefl 1.0 -0 | 127 MB/s | 233 MB/s | 40004116 | 39.88 |
|
||||
| sdefl 1.0 -1 | 111 MB/s | 259 MB/s | 38940674 | 38.82 |
|
||||
| sdefl 1.0 -5 | 45 MB/s | 275 MB/s | 36577183 | 36.46 |
|
||||
| sdefl 1.0 -7 | 38 MB/s | 276 MB/s | 36523781 | 36.41 |
|
||||
| zlib 1.2.11 -1 | 72 MB/s | 307 MB/s | 42298774 | 42.30 |
|
||||
| zlib 1.2.11 -6 | 24 MB/s | 313 MB/s | 36548921 | 36.55 |
|
||||
| zlib 1.2.11 -9 | 20 MB/s | 314 MB/s | 36475792 | 36.48 |
|
||||
| miniz 1.0 -1 | 122 MB/s | 208 MB/s | 48510028 | 48.51 |
|
||||
| miniz 1.0 -6 | 27 MB/s | 260 MB/s | 36513697 | 36.51 |
|
||||
| miniz 1.0 -9 | 23 MB/s | 261 MB/s | 36460101 | 36.46 |
|
||||
| zlib 1.2.11 -1 | 72 MB/s | 307 MB/s | 42298774 | 42.30 |
|
||||
| zlib 1.2.11 -6 | 24 MB/s | 313 MB/s | 36548921 | 36.55 |
|
||||
| zlib 1.2.11 -9 | 20 MB/s | 314 MB/s | 36475792 | 36.48 |
|
||||
| sdefl 1.0 -0 | 127 MB/s | 371 MB/s | 40004116 | 39.88 |
|
||||
| sdefl 1.0 -1 | 111 MB/s | 398 MB/s | 38940674 | 38.82 |
|
||||
| sdefl 1.0 -5 | 45 MB/s | 420 MB/s | 36577183 | 36.46 |
|
||||
| sdefl 1.0 -7 | 38 MB/s | 423 MB/s | 36523781 | 36.41 |
|
||||
| libdeflate 1.3 -1 | 147 MB/s | 667 MB/s | 39597378 | 39.60 |
|
||||
| libdeflate 1.3 -6 | 69 MB/s | 689 MB/s | 36648318 | 36.65 |
|
||||
| libdeflate 1.3 -9 | 13 MB/s | 672 MB/s | 35197141 | 35.20 |
|
||||
|
|
@ -398,8 +397,8 @@ sdefl_precode(struct sdefl_symcnt *cnt, unsigned *freqs, unsigned *items,
|
|||
if (offlen[cnt->off - 1]) break;
|
||||
|
||||
total = (unsigned)(cnt->lit + cnt->off);
|
||||
memcpy(lens, litlen, sizeof(unsigned char) * cnt->lit);
|
||||
memcpy(lens + cnt->lit, offlen, sizeof(unsigned char) * cnt->off);
|
||||
memcpy(lens, litlen, sizeof(unsigned char) * (size_t)cnt->lit);
|
||||
memcpy(lens + cnt->lit, offlen, sizeof(unsigned char) * (size_t)cnt->off);
|
||||
do {
|
||||
unsigned len = lens[run_start];
|
||||
unsigned run_end = run_start;
|
||||
|
|
|
|||
276
src/external/sinfl.h
vendored
|
|
@ -33,16 +33,16 @@ this file implementation in *one* C or C++ file to prevent collisions.
|
|||
|
||||
| Compressor name | Compression| Decompress.| Compr. size | Ratio |
|
||||
| ------------------------| -----------| -----------| ----------- | ----- |
|
||||
| sdefl 1.0 -0 | 127 MB/s | 233 MB/s | 40004116 | 39.88 |
|
||||
| sdefl 1.0 -1 | 111 MB/s | 259 MB/s | 38940674 | 38.82 |
|
||||
| sdefl 1.0 -5 | 45 MB/s | 275 MB/s | 36577183 | 36.46 |
|
||||
| sdefl 1.0 -7 | 38 MB/s | 276 MB/s | 36523781 | 36.41 |
|
||||
| zlib 1.2.11 -1 | 72 MB/s | 307 MB/s | 42298774 | 42.30 |
|
||||
| zlib 1.2.11 -6 | 24 MB/s | 313 MB/s | 36548921 | 36.55 |
|
||||
| zlib 1.2.11 -9 | 20 MB/s | 314 MB/s | 36475792 | 36.48 |
|
||||
| miniz 1.0 -1 | 122 MB/s | 208 MB/s | 48510028 | 48.51 |
|
||||
| miniz 1.0 -6 | 27 MB/s | 260 MB/s | 36513697 | 36.51 |
|
||||
| miniz 1.0 -9 | 23 MB/s | 261 MB/s | 36460101 | 36.46 |
|
||||
| zlib 1.2.11 -1 | 72 MB/s | 307 MB/s | 42298774 | 42.30 |
|
||||
| zlib 1.2.11 -6 | 24 MB/s | 313 MB/s | 36548921 | 36.55 |
|
||||
| zlib 1.2.11 -9 | 20 MB/s | 314 MB/s | 36475792 | 36.48 |
|
||||
| sdefl 1.0 -0 | 127 MB/s | 371 MB/s | 40004116 | 39.88 |
|
||||
| sdefl 1.0 -1 | 111 MB/s | 398 MB/s | 38940674 | 38.82 |
|
||||
| sdefl 1.0 -5 | 45 MB/s | 420 MB/s | 36577183 | 36.46 |
|
||||
| sdefl 1.0 -7 | 38 MB/s | 423 MB/s | 36523781 | 36.41 |
|
||||
| libdeflate 1.3 -1 | 147 MB/s | 667 MB/s | 39597378 | 39.60 |
|
||||
| libdeflate 1.3 -6 | 69 MB/s | 689 MB/s | 36648318 | 36.65 |
|
||||
| libdeflate 1.3 -9 | 13 MB/s | 672 MB/s | 35197141 | 35.20 |
|
||||
|
|
@ -121,12 +121,15 @@ extern "C" {
|
|||
#define SINFL_OFF_TBL_SIZE 402
|
||||
|
||||
struct sinfl {
|
||||
int bits, bitcnt;
|
||||
const unsigned char *bitptr;
|
||||
unsigned long long bitbuf;
|
||||
int bitcnt;
|
||||
|
||||
unsigned lits[SINFL_LIT_TBL_SIZE];
|
||||
unsigned dsts[SINFL_OFF_TBL_SIZE];
|
||||
};
|
||||
extern int sinflate(void *out, const void *in, int size);
|
||||
extern int zsinflate(void *out, const void *in, int size);
|
||||
extern int sinflate(void *out, int cap, const void *in, int size);
|
||||
extern int zsinflate(void *out, int cap, const void *in, int size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
@ -137,6 +140,33 @@ extern int zsinflate(void *out, const void *in, int size);
|
|||
#ifdef SINFL_IMPLEMENTATION
|
||||
|
||||
#include <string.h> /* memcpy, memset */
|
||||
#include <assert.h> /* assert */
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define sinfl_likely(x) __builtin_expect((x),1)
|
||||
#define sinfl_unlikely(x) __builtin_expect((x),0)
|
||||
#else
|
||||
#define sinfl_likely(x) (x)
|
||||
#define sinfl_unlikely(x) (x)
|
||||
#endif
|
||||
|
||||
#ifndef SINFL_NO_SIMD
|
||||
#if __x86_64__ || defined(_WIN32) || defined(_WIN64)
|
||||
#include <emmintrin.h>
|
||||
#define sinfl_char16 __m128i
|
||||
#define sinfl_char16_ld(p) _mm_loadu_si128((const __m128i *)(void*)(p))
|
||||
#define sinfl_char16_str(d,v) _mm_storeu_si128((__m128i*)(void*)(d), v)
|
||||
#define sinfl_char16_char(c) _mm_set1_epi8(c)
|
||||
#elif defined(__arm__) || defined(__aarch64__)
|
||||
#include <arm_neon.h>
|
||||
#define sinfl_char16 uint8x16_t
|
||||
#define sinfl_char16_ld(p) vld1q_u8((const unsigned char*)(p))
|
||||
#define sinfl_char16_str(d,v) vst1q_u8((unsigned char*)(d), v)
|
||||
#define sinfl_char16_char(c) vdupq_n_u8(c)
|
||||
#else
|
||||
#define SINFL_NO_SIMD
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static int
|
||||
sinfl_bsr(unsigned n) {
|
||||
|
|
@ -147,20 +177,66 @@ sinfl_bsr(unsigned n) {
|
|||
return 31 - __builtin_clz(n);
|
||||
#endif
|
||||
}
|
||||
static unsigned long long
|
||||
sinfl_read64(const void *p) {
|
||||
unsigned long long n;
|
||||
memcpy(&n, p, 8);
|
||||
return n;
|
||||
}
|
||||
#ifndef SINFL_NO_SIMD
|
||||
static unsigned char*
|
||||
sinfl_write128(unsigned char *dst, sinfl_char16 w) {
|
||||
sinfl_char16_str(dst, w);
|
||||
return dst + 8;
|
||||
}
|
||||
static void
|
||||
sinfl_copy128(unsigned char **dst, unsigned char **src) {
|
||||
sinfl_char16 n = sinfl_char16_ld(*src);
|
||||
sinfl_char16_str(*dst, n);
|
||||
*dst += 16, *src += 16;
|
||||
}
|
||||
#else
|
||||
static unsigned char*
|
||||
sinfl_write64(unsigned char *dst, unsigned long long w) {
|
||||
memcpy(dst, &w, 8);
|
||||
return dst + 8;
|
||||
}
|
||||
static void
|
||||
sinfl_copy64(unsigned char **dst, unsigned char **src) {
|
||||
unsigned long long n;
|
||||
memcpy(&n, *src, 8);
|
||||
memcpy(*dst, &n, 8);
|
||||
*dst += 8, *src += 8;
|
||||
}
|
||||
#endif
|
||||
static void
|
||||
sinfl_refill(struct sinfl *s) {
|
||||
s->bitbuf |= sinfl_read64(s->bitptr) << s->bitcnt;
|
||||
s->bitptr += (63 - s->bitcnt) >> 3;
|
||||
s->bitcnt |= 56; /* bitcount is in range [56,63] */
|
||||
}
|
||||
static int
|
||||
sinfl_get(const unsigned char **src, const unsigned char *end, struct sinfl *s,
|
||||
int n) {
|
||||
const unsigned char *in = *src;
|
||||
int v = s->bits & ((1 << n)-1);
|
||||
s->bits >>= n;
|
||||
s->bitcnt = s->bitcnt - n;
|
||||
s->bitcnt = s->bitcnt < 0 ? 0 : s->bitcnt;
|
||||
while (s->bitcnt < 16 && in < end) {
|
||||
s->bits |= (*in++) << s->bitcnt;
|
||||
s->bitcnt += 8;
|
||||
}
|
||||
*src = in;
|
||||
return v;
|
||||
sinfl_peek(struct sinfl *s, int cnt) {
|
||||
assert(cnt >= 0 && cnt <= 56);
|
||||
assert(cnt <= s->bitcnt);
|
||||
return s->bitbuf & ((1ull << cnt) - 1);
|
||||
}
|
||||
static void
|
||||
sinfl_consume(struct sinfl *s, int cnt) {
|
||||
assert(cnt <= s->bitcnt);
|
||||
s->bitbuf >>= cnt;
|
||||
s->bitcnt -= cnt;
|
||||
}
|
||||
static int
|
||||
sinfl__get(struct sinfl *s, int cnt) {
|
||||
int res = sinfl_peek(s, cnt);
|
||||
sinfl_consume(s, cnt);
|
||||
return res;
|
||||
}
|
||||
static int
|
||||
sinfl_get(struct sinfl *s, int cnt) {
|
||||
sinfl_refill(s);
|
||||
return sinfl__get(s, cnt);
|
||||
}
|
||||
struct sinfl_gen {
|
||||
int len;
|
||||
|
|
@ -276,22 +352,22 @@ sinfl_build(unsigned *tbl, unsigned char *lens, int tbl_bits, int maxlen,
|
|||
}
|
||||
}
|
||||
static int
|
||||
sinfl_decode(const unsigned char **in, const unsigned char *end,
|
||||
struct sinfl *s, const unsigned *tbl, int bit_len) {
|
||||
int idx = s->bits & ((1 << bit_len) - 1);
|
||||
sinfl_decode(struct sinfl *s, const unsigned *tbl, int bit_len) {
|
||||
sinfl_refill(s);
|
||||
{int idx = sinfl_peek(s, bit_len);
|
||||
unsigned key = tbl[idx];
|
||||
if (key & 0x10) {
|
||||
/* sub-table lookup */
|
||||
int len = key & 0x0f;
|
||||
sinfl_get(in, end, s, bit_len);
|
||||
idx = s->bits & ((1 << len)-1);
|
||||
sinfl_consume(s, bit_len);
|
||||
idx = sinfl_peek(s, len);
|
||||
key = tbl[((key >> 16) & 0xffff) + (unsigned)idx];
|
||||
}
|
||||
sinfl_get(in, end, s, key & 0x0f);
|
||||
return (key >> 16) & 0x0fff;
|
||||
sinfl_consume(s, key & 0x0f);
|
||||
return (key >> 16) & 0x0fff;}
|
||||
}
|
||||
static int
|
||||
sinfl_decompress(unsigned char *out, const unsigned char *in, int size) {
|
||||
sinfl_decompress(unsigned char *out, int cap, const unsigned char *in, int size) {
|
||||
static const unsigned char order[] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
|
||||
static const short dbase[30+2] = {1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
|
||||
257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577};
|
||||
|
|
@ -302,19 +378,22 @@ sinfl_decompress(unsigned char *out, const unsigned char *in, int size) {
|
|||
static const unsigned char lbits[29+2] = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,
|
||||
4,4,4,5,5,5,5,0,0,0};
|
||||
|
||||
const unsigned char *oe = out + cap;
|
||||
const unsigned char *e = in + size, *o = out;
|
||||
enum sinfl_states {hdr,stored,fixed,dyn,blk};
|
||||
enum sinfl_states state = hdr;
|
||||
struct sinfl s = {0};
|
||||
int last = 0;
|
||||
|
||||
sinfl_get(&in,e,&s,0); /* buffer input */
|
||||
while (in < e || s.bitcnt) {
|
||||
s.bitptr = in;
|
||||
while (1) {
|
||||
switch (state) {
|
||||
case hdr: {
|
||||
int type = 0; /* block header */
|
||||
last = sinfl_get(&in,e,&s,1);
|
||||
type = sinfl_get(&in,e,&s,2);
|
||||
/* block header */
|
||||
int type = 0;
|
||||
sinfl_refill(&s);
|
||||
last = sinfl__get(&s,1);
|
||||
type = sinfl__get(&s,2);
|
||||
|
||||
switch (type) {default: return (int)(out-o);
|
||||
case 0x00: state = stored; break;
|
||||
|
|
@ -322,10 +401,12 @@ sinfl_decompress(unsigned char *out, const unsigned char *in, int size) {
|
|||
case 0x02: state = dyn; break;}
|
||||
} break;
|
||||
case stored: {
|
||||
int len; /* uncompressed block */
|
||||
sinfl_get(&in,e,&s,s.bitcnt & 7);
|
||||
len = sinfl_get(&in,e,&s,16);
|
||||
//int nlen = sinfl_get(&in,e,&s,16);
|
||||
/* uncompressed block */
|
||||
int len;
|
||||
sinfl_refill(&s);
|
||||
sinfl__get(&s,s.bitcnt & 7);
|
||||
len = sinfl__get(&s,16);
|
||||
//int nlen = sinfl__get(&s,16); // @raysan5: Unused variable?
|
||||
in -= 2; s.bitcnt = 0;
|
||||
|
||||
if (len > (e-in) || !len)
|
||||
|
|
@ -353,72 +434,111 @@ sinfl_decompress(unsigned char *out, const unsigned char *in, int size) {
|
|||
int n, i;
|
||||
unsigned hlens[SINFL_PRE_TBL_SIZE];
|
||||
unsigned char nlens[19] = {0}, lens[288+32];
|
||||
int nlit = 257 + sinfl_get(&in,e,&s,5);
|
||||
int ndist = 1 + sinfl_get(&in,e,&s,5);
|
||||
int nlen = 4 + sinfl_get(&in,e,&s,4);
|
||||
|
||||
sinfl_refill(&s);
|
||||
{int nlit = 257 + sinfl__get(&s,5);
|
||||
int ndist = 1 + sinfl__get(&s,5);
|
||||
int nlen = 4 + sinfl__get(&s,4);
|
||||
for (n = 0; n < nlen; n++)
|
||||
nlens[order[n]] = (unsigned char)sinfl_get(&in,e,&s,3);
|
||||
nlens[order[n]] = (unsigned char)sinfl_get(&s,3);
|
||||
sinfl_build(hlens, nlens, 7, 7, 19);
|
||||
|
||||
/* decode code lengths */
|
||||
for (n = 0; n < nlit + ndist;) {
|
||||
int sym = sinfl_decode(&in, e, &s, hlens, 7);
|
||||
int sym = sinfl_decode(&s, hlens, 7);
|
||||
switch (sym) {default: lens[n++] = (unsigned char)sym; break;
|
||||
case 16: for (i=3+sinfl_get(&in,e,&s,2);i;i--,n++) lens[n]=lens[n-1]; break;
|
||||
case 17: for (i=3+sinfl_get(&in,e,&s,3);i;i--,n++) lens[n]=0; break;
|
||||
case 18: for (i=11+sinfl_get(&in,e,&s,7);i;i--,n++) lens[n]=0; break;}
|
||||
case 16: for (i=3+sinfl_get(&s,2);i;i--,n++) lens[n]=lens[n-1]; break;
|
||||
case 17: for (i=3+sinfl_get(&s,3);i;i--,n++) lens[n]=0; break;
|
||||
case 18: for (i=11+sinfl_get(&s,7);i;i--,n++) lens[n]=0; break;}
|
||||
}
|
||||
/* build lit/dist tables */
|
||||
sinfl_build(s.lits, lens, 10, 15, nlit);
|
||||
sinfl_build(s.dsts, lens + nlit, 8, 15, ndist);
|
||||
state = blk;
|
||||
state = blk;}
|
||||
} break;
|
||||
case blk: {
|
||||
/* decompress block */
|
||||
int i, sym = sinfl_decode(&in, e, &s, s.lits, 10);
|
||||
if (sym > 256) {sym -= 257; /* match symbol */
|
||||
{int len = sinfl_get(&in, e, &s, lbits[sym]) + lbase[sym];
|
||||
int dsym = sinfl_decode(&in, e, &s, s.dsts, 8);
|
||||
int offs = sinfl_get(&in, e, &s, dbits[dsym]) + dbase[dsym];
|
||||
if (offs > (int)(out-o)) {
|
||||
int sym = sinfl_decode(&s, s.lits, 10);
|
||||
if (sym < 256) {
|
||||
/* literal */
|
||||
*out++ = (unsigned char)sym;
|
||||
} else if (sym > 256) {sym -= 257; /* match symbol */
|
||||
sinfl_refill(&s);
|
||||
{int len = sinfl__get(&s, lbits[sym]) + lbase[sym];
|
||||
int dsym = sinfl_decode(&s, s.dsts, 8);
|
||||
int offs = sinfl__get(&s, dbits[dsym]) + dbase[dsym];
|
||||
unsigned char *dst = out, *src = out - offs;
|
||||
if (sinfl_unlikely(offs > (int)(out-o))) {
|
||||
return (int)(out-o);
|
||||
}
|
||||
out = out + len;
|
||||
|
||||
#ifndef SINFL_NO_SIMD
|
||||
if (sinfl_likely(oe - out >= 16 * 3)) {
|
||||
if (offs >= 16) {
|
||||
/* copy match */
|
||||
sinfl_copy128(&dst, &src);
|
||||
sinfl_copy128(&dst, &src);
|
||||
do sinfl_copy128(&dst, &src);
|
||||
while (dst < out);
|
||||
} else if (offs == 1) {
|
||||
/* rle match copying */
|
||||
unsigned char c = *(out - offs);
|
||||
unsigned long w = (c << 24) | (c << 16) | (c << 8) | c;
|
||||
for (i = 0; i < len >> 2; ++i) {
|
||||
memcpy(out, &w, 4);
|
||||
out += 4;
|
||||
sinfl_char16 w = sinfl_char16_char(src[0]);
|
||||
dst = sinfl_write128(dst, w);
|
||||
dst = sinfl_write128(dst, w);
|
||||
do dst = sinfl_write128(dst, w);
|
||||
while (dst < out);
|
||||
} else {
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
do *dst++ = *src++;
|
||||
while (dst < out);
|
||||
}
|
||||
len = len & 3;
|
||||
} else if (offs >= 4) {
|
||||
}
|
||||
#else
|
||||
if (sinfl_likely(oe - out >= 3 * 8 - 3)) {
|
||||
if (offs >= 8) {
|
||||
/* copy match */
|
||||
int wcnt = len >> 2;
|
||||
for (i = 0; i < wcnt; ++i) {
|
||||
unsigned long w = 0;
|
||||
memcpy(&w, out - offs, 4);
|
||||
memcpy(out, &w, 4);
|
||||
out += 4;
|
||||
sinfl_copy64(&dst, &src);
|
||||
sinfl_copy64(&dst, &src);
|
||||
do sinfl_copy64(&dst, &src);
|
||||
while (dst < out);
|
||||
} else if (offs == 1) {
|
||||
/* rle match copying */
|
||||
unsigned int c = src[0];
|
||||
unsigned int hw = (c << 24u) | (c << 16u) | (c << 8u) | (unsigned)c;
|
||||
unsigned long long w = (unsigned long long)hw << 32llu | hw;
|
||||
dst = sinfl_write64(dst, w);
|
||||
dst = sinfl_write64(dst, w);
|
||||
do dst = sinfl_write64(dst, w);
|
||||
while (dst < out);
|
||||
} else {
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
do *dst++ = *src++;
|
||||
while (dst < out);
|
||||
}
|
||||
len = len & 3;
|
||||
}
|
||||
for (i = 0; i < len; ++i)
|
||||
{*out = *(out-offs), out++;}
|
||||
#endif
|
||||
else {
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
do *dst++ = *src++;
|
||||
while (dst < out);}
|
||||
}
|
||||
} else if (sym == 256) {
|
||||
} else {
|
||||
/* end of block */
|
||||
if (last) return (int)(out-o);
|
||||
state = hdr;
|
||||
break;
|
||||
/* literal */
|
||||
} else *out++ = (unsigned char)sym;
|
||||
}
|
||||
} break;}
|
||||
}
|
||||
return (int)(out-o);
|
||||
}
|
||||
extern int
|
||||
sinflate(void *out, const void *in, int size) {
|
||||
return sinfl_decompress((unsigned char*)out, (const unsigned char*)in, size);
|
||||
sinflate(void *out, int cap, const void *in, int size) {
|
||||
return sinfl_decompress((unsigned char*)out, cap, (const unsigned char*)in, size);
|
||||
}
|
||||
static unsigned
|
||||
sinfl_adler32(unsigned adler32, const unsigned char *in, int in_len) {
|
||||
|
|
@ -448,11 +568,11 @@ sinfl_adler32(unsigned adler32, const unsigned char *in, int in_len) {
|
|||
} return (unsigned)(s2 << 16) + (unsigned)s1;
|
||||
}
|
||||
extern int
|
||||
zsinflate(void *out, const void *mem, int size) {
|
||||
zsinflate(void *out, int cap, const void *mem, int size) {
|
||||
const unsigned char *in = (const unsigned char*)mem;
|
||||
if (size >= 6) {
|
||||
const unsigned char *eob = in + size - 4;
|
||||
int n = sinfl_decompress((unsigned char*)out, in + 2u, size);
|
||||
int n = sinfl_decompress((unsigned char*)out, cap, in + 2u, size);
|
||||
unsigned a = sinfl_adler32(1u, (unsigned char*)out, n);
|
||||
unsigned h = eob[0] << 24 | eob[1] << 16 | eob[2] << 8 | eob[3] << 0;
|
||||
return a == h ? n : -1;
|
||||
|
|
|
|||
277
src/external/stb_image.h
vendored
|
|
@ -1,4 +1,4 @@
|
|||
/* stb_image - v2.26 - public domain image loader - http://nothings.org/stb
|
||||
/* stb_image - v2.27 - public domain image loader - http://nothings.org/stb
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
Do this:
|
||||
|
|
@ -48,6 +48,7 @@ LICENSE
|
|||
|
||||
RECENT REVISION HISTORY:
|
||||
|
||||
2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
|
||||
2.26 (2020-07-13) many minor fixes
|
||||
2.25 (2020-02-02) fix warnings
|
||||
2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically
|
||||
|
|
@ -89,7 +90,7 @@ RECENT REVISION HISTORY:
|
|||
Jeremy Sawicki (handle all ImageNet JPGs)
|
||||
Optimizations & bugfixes Mikhail Morozov (1-bit BMP)
|
||||
Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query)
|
||||
Arseny Kapoulkine
|
||||
Arseny Kapoulkine Simon Breuss (16-bit PNM)
|
||||
John-Mark Allen
|
||||
Carmelo J Fdez-Aguera
|
||||
|
||||
|
|
@ -102,7 +103,7 @@ RECENT REVISION HISTORY:
|
|||
Thomas Ruf Ronny Chevalier github:rlyeh
|
||||
Janez Zemva John Bartholomew Michal Cichon github:romigrou
|
||||
Jonathan Blow Ken Hamada Tero Hanninen github:svdijk
|
||||
Laurent Gomila Cort Stratton github:snagar
|
||||
Eugene Golushkov Laurent Gomila Cort Stratton github:snagar
|
||||
Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex
|
||||
Cass Everitt Ryamond Barbiero github:grim210
|
||||
Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw
|
||||
|
|
@ -110,11 +111,13 @@ RECENT REVISION HISTORY:
|
|||
Josh Tobin Matthew Gregan github:poppolopoppo
|
||||
Julian Raschke Gregory Mullen Christian Floisand github:darealshinji
|
||||
Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007
|
||||
Brad Weinberger Matvey Cherevko [reserved]
|
||||
Brad Weinberger Matvey Cherevko github:mosra
|
||||
Luca Sas Alexander Veselov Zack Middleton [reserved]
|
||||
Ryan C. Gordon [reserved] [reserved]
|
||||
DO NOT ADD YOUR NAME HERE
|
||||
|
||||
Jacko Dirks
|
||||
|
||||
To add your name to the credits, pick a random blank space in the middle and fill it.
|
||||
80% of merge conflicts on stb PRs are due to people adding their name at the end
|
||||
of the credits.
|
||||
|
|
@ -176,6 +179,32 @@ RECENT REVISION HISTORY:
|
|||
//
|
||||
// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
|
||||
//
|
||||
// To query the width, height and component count of an image without having to
|
||||
// decode the full file, you can use the stbi_info family of functions:
|
||||
//
|
||||
// int x,y,n,ok;
|
||||
// ok = stbi_info(filename, &x, &y, &n);
|
||||
// // returns ok=1 and sets x, y, n if image is a supported format,
|
||||
// // 0 otherwise.
|
||||
//
|
||||
// Note that stb_image pervasively uses ints in its public API for sizes,
|
||||
// including sizes of memory buffers. This is now part of the API and thus
|
||||
// hard to change without causing breakage. As a result, the various image
|
||||
// loaders all have certain limits on image size; these differ somewhat
|
||||
// by format but generally boil down to either just under 2GB or just under
|
||||
// 1GB. When the decoded image would be larger than this, stb_image decoding
|
||||
// will fail.
|
||||
//
|
||||
// Additionally, stb_image will reject image files that have any of their
|
||||
// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS,
|
||||
// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit,
|
||||
// the only way to have an image with such dimensions load correctly
|
||||
// is for it to have a rather extreme aspect ratio. Either way, the
|
||||
// assumption here is that such larger images are likely to be malformed
|
||||
// or malicious. If you do need to load an image with individual dimensions
|
||||
// larger than that, and it still fits in the overall size limit, you can
|
||||
// #define STBI_MAX_DIMENSIONS on your own to be something larger.
|
||||
//
|
||||
// ===========================================================================
|
||||
//
|
||||
// UNICODE:
|
||||
|
|
@ -281,11 +310,10 @@ RECENT REVISION HISTORY:
|
|||
//
|
||||
// iPhone PNG support:
|
||||
//
|
||||
// By default we convert iphone-formatted PNGs back to RGB, even though
|
||||
// they are internally encoded differently. You can disable this conversion
|
||||
// by calling stbi_convert_iphone_png_to_rgb(0), in which case
|
||||
// you will always just get the native iphone "format" through (which
|
||||
// is BGR stored in RGB).
|
||||
// We optionally support converting iPhone-formatted PNGs (which store
|
||||
// premultiplied BGRA) back to RGB, even though they're internally encoded
|
||||
// differently. To enable this conversion, call
|
||||
// stbi_convert_iphone_png_to_rgb(1).
|
||||
//
|
||||
// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
|
||||
// pixel to remove any premultiplied alpha *only* if the image file explicitly
|
||||
|
|
@ -489,6 +517,8 @@ STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
|
|||
// as above, but only applies to images loaded on the thread that calls the function
|
||||
// this function is only available if your compiler supports thread-local variables;
|
||||
// calling it will fail to link if your compiler doesn't
|
||||
STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply);
|
||||
STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert);
|
||||
STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip);
|
||||
|
||||
// ZLIB client - used by PNG, available for other purposes
|
||||
|
|
@ -634,7 +664,7 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
|
|||
#ifdef STBI_HAS_LROTL
|
||||
#define stbi_lrot(x,y) _lrotl(x,y)
|
||||
#else
|
||||
#define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y))))
|
||||
#define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31)))
|
||||
#endif
|
||||
|
||||
#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED))
|
||||
|
|
@ -748,9 +778,12 @@ static int stbi__sse2_available(void)
|
|||
|
||||
#ifdef STBI_NEON
|
||||
#include <arm_neon.h>
|
||||
// assume GCC or Clang on ARM targets
|
||||
#ifdef _MSC_VER
|
||||
#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name
|
||||
#else
|
||||
#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef STBI_SIMD_ALIGN
|
||||
#define STBI_SIMD_ALIGN(type, name) type name
|
||||
|
|
@ -924,6 +957,7 @@ static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);
|
|||
static int stbi__pnm_test(stbi__context *s);
|
||||
static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
|
||||
static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);
|
||||
static int stbi__pnm_is16(stbi__context *s);
|
||||
#endif
|
||||
|
||||
static
|
||||
|
|
@ -998,7 +1032,7 @@ static int stbi__mad3sizes_valid(int a, int b, int c, int add)
|
|||
}
|
||||
|
||||
// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow
|
||||
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
|
||||
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM)
|
||||
static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)
|
||||
{
|
||||
return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
|
||||
|
|
@ -1021,7 +1055,7 @@ static void *stbi__malloc_mad3(int a, int b, int c, int add)
|
|||
return stbi__malloc(a*b*c + add);
|
||||
}
|
||||
|
||||
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
|
||||
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM)
|
||||
static void *stbi__malloc_mad4(int a, int b, int c, int d, int add)
|
||||
{
|
||||
if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL;
|
||||
|
|
@ -1087,9 +1121,8 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re
|
|||
ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order
|
||||
ri->num_channels = 0;
|
||||
|
||||
#ifndef STBI_NO_JPEG
|
||||
if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri);
|
||||
#endif
|
||||
// test the formats with a very explicit header first (at least a FOURCC
|
||||
// or distinctive magic number first)
|
||||
#ifndef STBI_NO_PNG
|
||||
if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri);
|
||||
#endif
|
||||
|
|
@ -1107,6 +1140,13 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re
|
|||
#ifndef STBI_NO_PIC
|
||||
if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri);
|
||||
#endif
|
||||
|
||||
// then the formats that can end up attempting to load with just 1 or 2
|
||||
// bytes matching expectations; these are prone to false positives, so
|
||||
// try them later
|
||||
#ifndef STBI_NO_JPEG
|
||||
if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri);
|
||||
#endif
|
||||
#ifndef STBI_NO_PNM
|
||||
if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri);
|
||||
#endif
|
||||
|
|
@ -1262,12 +1302,12 @@ static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, in
|
|||
|
||||
#ifndef STBI_NO_STDIO
|
||||
|
||||
#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
|
||||
#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)
|
||||
STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide);
|
||||
STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
|
||||
#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)
|
||||
STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)
|
||||
{
|
||||
return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);
|
||||
|
|
@ -1277,16 +1317,16 @@ STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wch
|
|||
static FILE *stbi__fopen(char const *filename, char const *mode)
|
||||
{
|
||||
FILE *f;
|
||||
#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
|
||||
#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)
|
||||
wchar_t wMode[64];
|
||||
wchar_t wFilename[1024];
|
||||
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)))
|
||||
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))
|
||||
return 0;
|
||||
|
||||
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)))
|
||||
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))
|
||||
return 0;
|
||||
|
||||
#if _MSC_VER >= 1400
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
if (0 != _wfopen_s(&f, wFilename, wMode))
|
||||
f = 0;
|
||||
#else
|
||||
|
|
@ -1662,7 +1702,8 @@ static int stbi__get16le(stbi__context *s)
|
|||
static stbi__uint32 stbi__get32le(stbi__context *s)
|
||||
{
|
||||
stbi__uint32 z = stbi__get16le(s);
|
||||
return z + (stbi__get16le(s) << 16);
|
||||
z += (stbi__uint32)stbi__get16le(s) << 16;
|
||||
return z;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -2090,13 +2131,12 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)
|
|||
int sgn;
|
||||
if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
|
||||
|
||||
sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB
|
||||
sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative)
|
||||
k = stbi_lrot(j->code_buffer, n);
|
||||
if (n < 0 || n >= (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))) return 0;
|
||||
j->code_buffer = k & ~stbi__bmask[n];
|
||||
k &= stbi__bmask[n];
|
||||
j->code_bits -= n;
|
||||
return k + (stbi__jbias[n] & ~sgn);
|
||||
return k + (stbi__jbias[n] & (sgn - 1));
|
||||
}
|
||||
|
||||
// get some unsigned bits
|
||||
|
|
@ -2146,7 +2186,7 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman
|
|||
|
||||
if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
|
||||
t = stbi__jpeg_huff_decode(j, hdc);
|
||||
if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG");
|
||||
if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG");
|
||||
|
||||
// 0 all the ac values now so we can do it 32-bits at a time
|
||||
memset(data,0,64*sizeof(data[0]));
|
||||
|
|
@ -2203,12 +2243,12 @@ static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__
|
|||
// first scan for DC coefficient, must be first
|
||||
memset(data,0,64*sizeof(data[0])); // 0 all the ac values now
|
||||
t = stbi__jpeg_huff_decode(j, hdc);
|
||||
if (t == -1) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
|
||||
if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
|
||||
diff = t ? stbi__extend_receive(j, t) : 0;
|
||||
|
||||
dc = j->img_comp[b].dc_pred + diff;
|
||||
j->img_comp[b].dc_pred = dc;
|
||||
data[0] = (short) (dc << j->succ_low);
|
||||
data[0] = (short) (dc * (1 << j->succ_low));
|
||||
} else {
|
||||
// refinement scan for DC coefficient
|
||||
if (stbi__jpeg_get_bit(j))
|
||||
|
|
@ -2245,7 +2285,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__
|
|||
j->code_buffer <<= s;
|
||||
j->code_bits -= s;
|
||||
zig = stbi__jpeg_dezigzag[k++];
|
||||
data[zig] = (short) ((r >> 8) << shift);
|
||||
data[zig] = (short) ((r >> 8) * (1 << shift));
|
||||
} else {
|
||||
int rs = stbi__jpeg_huff_decode(j, hac);
|
||||
if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
|
||||
|
|
@ -2263,7 +2303,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__
|
|||
} else {
|
||||
k += r;
|
||||
zig = stbi__jpeg_dezigzag[k++];
|
||||
data[zig] = (short) (stbi__extend_receive(j,s) << shift);
|
||||
data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift));
|
||||
}
|
||||
}
|
||||
} while (k <= j->spec_end);
|
||||
|
|
@ -3227,6 +3267,13 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan)
|
|||
if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v;
|
||||
}
|
||||
|
||||
// check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios
|
||||
// and I've never seen a non-corrupted JPEG file actually use them
|
||||
for (i=0; i < s->img_n; ++i) {
|
||||
if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG");
|
||||
if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG");
|
||||
}
|
||||
|
||||
// compute interleaved mcu info
|
||||
z->img_h_max = h_max;
|
||||
z->img_v_max = v_max;
|
||||
|
|
@ -3782,6 +3829,10 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
|
|||
else
|
||||
decode_n = z->s->img_n;
|
||||
|
||||
// nothing to do if no components requested; check this now to avoid
|
||||
// accessing uninitialized coutput[0] later
|
||||
if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; }
|
||||
|
||||
// resample and color-convert
|
||||
{
|
||||
int k;
|
||||
|
|
@ -3924,6 +3975,7 @@ static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int re
|
|||
{
|
||||
unsigned char* result;
|
||||
stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg));
|
||||
if (!j) return stbi__errpuc("outofmem", "Out of memory");
|
||||
STBI_NOTUSED(ri);
|
||||
j->s = s;
|
||||
stbi__setup_jpeg(j);
|
||||
|
|
@ -3936,6 +3988,7 @@ static int stbi__jpeg_test(stbi__context *s)
|
|||
{
|
||||
int r;
|
||||
stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg));
|
||||
if (!j) return stbi__err("outofmem", "Out of memory");
|
||||
j->s = s;
|
||||
stbi__setup_jpeg(j);
|
||||
r = stbi__decode_jpeg_header(j, STBI__SCAN_type);
|
||||
|
|
@ -3960,6 +4013,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)
|
|||
{
|
||||
int result;
|
||||
stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg)));
|
||||
if (!j) return stbi__err("outofmem", "Out of memory");
|
||||
j->s = s;
|
||||
result = stbi__jpeg_info_raw(j, x, y, comp);
|
||||
STBI_FREE(j);
|
||||
|
|
@ -3979,6 +4033,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)
|
|||
// fast-way is faster to check than jpeg huffman, but slow way is slower
|
||||
#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables
|
||||
#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1)
|
||||
#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet
|
||||
|
||||
// zlib-style huffman encoding
|
||||
// (jpegs packs from left, zlib from right, so can't share code)
|
||||
|
|
@ -3988,8 +4043,8 @@ typedef struct
|
|||
stbi__uint16 firstcode[16];
|
||||
int maxcode[17];
|
||||
stbi__uint16 firstsymbol[16];
|
||||
stbi_uc size[288];
|
||||
stbi__uint16 value[288];
|
||||
stbi_uc size[STBI__ZNSYMS];
|
||||
stbi__uint16 value[STBI__ZNSYMS];
|
||||
} stbi__zhuffman;
|
||||
|
||||
stbi_inline static int stbi__bitreverse16(int n)
|
||||
|
|
@ -4120,7 +4175,7 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)
|
|||
if (s >= 16) return -1; // invalid code!
|
||||
// code size is s, so:
|
||||
b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];
|
||||
if (b >= sizeof (z->size)) return -1; // some data was corrupt somewhere!
|
||||
if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere!
|
||||
if (z->size[b] != s) return -1; // was originally an assert, but report failure instead.
|
||||
a->code_buffer >>= s;
|
||||
a->num_bits -= s;
|
||||
|
|
@ -4317,7 +4372,7 @@ static int stbi__parse_zlib_header(stbi__zbuf *a)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static const stbi_uc stbi__zdefault_length[288] =
|
||||
static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] =
|
||||
{
|
||||
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
|
||||
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
|
||||
|
|
@ -4363,7 +4418,7 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
|
|||
} else {
|
||||
if (type == 1) {
|
||||
// use fixed code lengths
|
||||
if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0;
|
||||
if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0;
|
||||
if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0;
|
||||
} else {
|
||||
if (!stbi__compute_huffman_codes(a)) return 0;
|
||||
|
|
@ -4759,6 +4814,7 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3
|
|||
|
||||
// de-interlacing
|
||||
final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0);
|
||||
if (!final) return stbi__err("outofmem", "Out of memory");
|
||||
for (p=0; p < 7; ++p) {
|
||||
int xorig[] = { 0,4,0,2,0,1,0 };
|
||||
int yorig[] = { 0,0,4,0,2,0,1 };
|
||||
|
|
@ -4879,19 +4935,46 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int stbi__unpremultiply_on_load = 0;
|
||||
static int stbi__de_iphone_flag = 0;
|
||||
static int stbi__unpremultiply_on_load_global = 0;
|
||||
static int stbi__de_iphone_flag_global = 0;
|
||||
|
||||
STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)
|
||||
{
|
||||
stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply;
|
||||
stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply;
|
||||
}
|
||||
|
||||
STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
|
||||
{
|
||||
stbi__de_iphone_flag = flag_true_if_should_convert;
|
||||
stbi__de_iphone_flag_global = flag_true_if_should_convert;
|
||||
}
|
||||
|
||||
#ifndef STBI_THREAD_LOCAL
|
||||
#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global
|
||||
#define stbi__de_iphone_flag stbi__de_iphone_flag_global
|
||||
#else
|
||||
static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set;
|
||||
static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set;
|
||||
|
||||
STBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply)
|
||||
{
|
||||
stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply;
|
||||
stbi__unpremultiply_on_load_set = 1;
|
||||
}
|
||||
|
||||
STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert)
|
||||
{
|
||||
stbi__de_iphone_flag_local = flag_true_if_should_convert;
|
||||
stbi__de_iphone_flag_set = 1;
|
||||
}
|
||||
|
||||
#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \
|
||||
? stbi__unpremultiply_on_load_local \
|
||||
: stbi__unpremultiply_on_load_global)
|
||||
#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \
|
||||
? stbi__de_iphone_flag_local \
|
||||
: stbi__de_iphone_flag_global)
|
||||
#endif // STBI_THREAD_LOCAL
|
||||
|
||||
static void stbi__de_iphone(stbi__png *z)
|
||||
{
|
||||
stbi__context *s = z->s;
|
||||
|
|
@ -5272,6 +5355,32 @@ typedef struct
|
|||
int extra_read;
|
||||
} stbi__bmp_data;
|
||||
|
||||
static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress)
|
||||
{
|
||||
// BI_BITFIELDS specifies masks explicitly, don't override
|
||||
if (compress == 3)
|
||||
return 1;
|
||||
|
||||
if (compress == 0) {
|
||||
if (info->bpp == 16) {
|
||||
info->mr = 31u << 10;
|
||||
info->mg = 31u << 5;
|
||||
info->mb = 31u << 0;
|
||||
} else if (info->bpp == 32) {
|
||||
info->mr = 0xffu << 16;
|
||||
info->mg = 0xffu << 8;
|
||||
info->mb = 0xffu << 0;
|
||||
info->ma = 0xffu << 24;
|
||||
info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0
|
||||
} else {
|
||||
// otherwise, use defaults, which is all-0
|
||||
info->mr = info->mg = info->mb = info->ma = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0; // error
|
||||
}
|
||||
|
||||
static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
|
||||
{
|
||||
int hsz;
|
||||
|
|
@ -5299,6 +5408,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
|
|||
if (hsz != 12) {
|
||||
int compress = stbi__get32le(s);
|
||||
if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
|
||||
if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes
|
||||
if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel
|
||||
stbi__get32le(s); // discard sizeof
|
||||
stbi__get32le(s); // discard hres
|
||||
stbi__get32le(s); // discard vres
|
||||
|
|
@ -5313,17 +5424,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
|
|||
}
|
||||
if (info->bpp == 16 || info->bpp == 32) {
|
||||
if (compress == 0) {
|
||||
if (info->bpp == 32) {
|
||||
info->mr = 0xffu << 16;
|
||||
info->mg = 0xffu << 8;
|
||||
info->mb = 0xffu << 0;
|
||||
info->ma = 0xffu << 24;
|
||||
info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0
|
||||
} else {
|
||||
info->mr = 31u << 10;
|
||||
info->mg = 31u << 5;
|
||||
info->mb = 31u << 0;
|
||||
}
|
||||
stbi__bmp_set_mask_defaults(info, compress);
|
||||
} else if (compress == 3) {
|
||||
info->mr = stbi__get32le(s);
|
||||
info->mg = stbi__get32le(s);
|
||||
|
|
@ -5338,6 +5439,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
|
|||
return stbi__errpuc("bad BMP", "bad BMP");
|
||||
}
|
||||
} else {
|
||||
// V4/V5 header
|
||||
int i;
|
||||
if (hsz != 108 && hsz != 124)
|
||||
return stbi__errpuc("bad BMP", "bad BMP");
|
||||
|
|
@ -5345,6 +5447,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
|
|||
info->mg = stbi__get32le(s);
|
||||
info->mb = stbi__get32le(s);
|
||||
info->ma = stbi__get32le(s);
|
||||
if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs
|
||||
stbi__bmp_set_mask_defaults(info, compress);
|
||||
stbi__get32le(s); // discard color space
|
||||
for (i=0; i < 12; ++i)
|
||||
stbi__get32le(s); // discard color space parameters
|
||||
|
|
@ -5394,8 +5498,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
|
|||
psize = (info.offset - info.extra_read - info.hsz) >> 2;
|
||||
}
|
||||
if (psize == 0) {
|
||||
STBI_ASSERT(info.offset == s->callback_already_read + (int) (s->img_buffer - s->img_buffer_original));
|
||||
if (info.offset != s->callback_already_read + (s->img_buffer - s->buffer_start)) {
|
||||
if (info.offset != s->callback_already_read + (s->img_buffer - s->img_buffer_original)) {
|
||||
return stbi__errpuc("bad offset", "Corrupt BMP");
|
||||
}
|
||||
}
|
||||
|
|
@ -6342,6 +6445,7 @@ static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_c
|
|||
|
||||
// intermediate buffer is RGBA
|
||||
result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0);
|
||||
if (!result) return stbi__errpuc("outofmem", "Out of memory");
|
||||
memset(result, 0xff, x*y*4);
|
||||
|
||||
if (!stbi__pic_load_core(s,x,y,comp, result)) {
|
||||
|
|
@ -6457,6 +6561,7 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in
|
|||
static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)
|
||||
{
|
||||
stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));
|
||||
if (!g) return stbi__err("outofmem", "Out of memory");
|
||||
if (!stbi__gif_header(s, g, comp, 1)) {
|
||||
STBI_FREE(g);
|
||||
stbi__rewind( s );
|
||||
|
|
@ -6766,6 +6871,17 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
|
|||
}
|
||||
}
|
||||
|
||||
static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays)
|
||||
{
|
||||
STBI_FREE(g->out);
|
||||
STBI_FREE(g->history);
|
||||
STBI_FREE(g->background);
|
||||
|
||||
if (out) STBI_FREE(out);
|
||||
if (delays && *delays) STBI_FREE(*delays);
|
||||
return stbi__errpuc("outofmem", "Out of memory");
|
||||
}
|
||||
|
||||
static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
|
||||
{
|
||||
if (stbi__gif_test(s)) {
|
||||
|
|
@ -6777,6 +6893,10 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y,
|
|||
int stride;
|
||||
int out_size = 0;
|
||||
int delays_size = 0;
|
||||
|
||||
STBI_NOTUSED(out_size);
|
||||
STBI_NOTUSED(delays_size);
|
||||
|
||||
memset(&g, 0, sizeof(g));
|
||||
if (delays) {
|
||||
*delays = 0;
|
||||
|
|
@ -6794,26 +6914,29 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y,
|
|||
|
||||
if (out) {
|
||||
void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride );
|
||||
if (NULL == tmp) {
|
||||
STBI_FREE(g.out);
|
||||
STBI_FREE(g.history);
|
||||
STBI_FREE(g.background);
|
||||
return stbi__errpuc("outofmem", "Out of memory");
|
||||
}
|
||||
if (!tmp)
|
||||
return stbi__load_gif_main_outofmem(&g, out, delays);
|
||||
else {
|
||||
out = (stbi_uc*) tmp;
|
||||
out_size = layers * stride;
|
||||
}
|
||||
|
||||
if (delays) {
|
||||
*delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers );
|
||||
int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers );
|
||||
if (!new_delays)
|
||||
return stbi__load_gif_main_outofmem(&g, out, delays);
|
||||
*delays = new_delays;
|
||||
delays_size = layers * sizeof(int);
|
||||
}
|
||||
} else {
|
||||
out = (stbi_uc*)stbi__malloc( layers * stride );
|
||||
if (!out)
|
||||
return stbi__load_gif_main_outofmem(&g, out, delays);
|
||||
out_size = layers * stride;
|
||||
if (delays) {
|
||||
*delays = (int*) stbi__malloc( layers * sizeof(int) );
|
||||
if (!*delays)
|
||||
return stbi__load_gif_main_outofmem(&g, out, delays);
|
||||
delays_size = layers * sizeof(int);
|
||||
}
|
||||
}
|
||||
|
|
@ -7138,9 +7261,10 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
|
|||
|
||||
info.all_a = 255;
|
||||
p = stbi__bmp_parse_header(s, &info);
|
||||
if (p == NULL) {
|
||||
stbi__rewind( s );
|
||||
if (p == NULL)
|
||||
return 0;
|
||||
}
|
||||
if (x) *x = s->img_x;
|
||||
if (y) *y = s->img_y;
|
||||
if (comp) {
|
||||
|
|
@ -7206,8 +7330,8 @@ static int stbi__psd_is16(stbi__context *s)
|
|||
stbi__rewind( s );
|
||||
return 0;
|
||||
}
|
||||
(void) stbi__get32be(s);
|
||||
(void) stbi__get32be(s);
|
||||
STBI_NOTUSED(stbi__get32be(s));
|
||||
STBI_NOTUSED(stbi__get32be(s));
|
||||
depth = stbi__get16be(s);
|
||||
if (depth != 16) {
|
||||
stbi__rewind( s );
|
||||
|
|
@ -7286,7 +7410,6 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp)
|
|||
// Known limitations:
|
||||
// Does not support comments in the header section
|
||||
// Does not support ASCII image data (formats P2 and P3)
|
||||
// Does not support 16-bit-per-channel
|
||||
|
||||
#ifndef STBI_NO_PNM
|
||||
|
||||
|
|
@ -7307,7 +7430,8 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req
|
|||
stbi_uc *out;
|
||||
STBI_NOTUSED(ri);
|
||||
|
||||
if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n))
|
||||
ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n);
|
||||
if (ri->bits_per_channel == 0)
|
||||
return 0;
|
||||
|
||||
if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
|
||||
|
|
@ -7317,12 +7441,12 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req
|
|||
*y = s->img_y;
|
||||
if (comp) *comp = s->img_n;
|
||||
|
||||
if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0))
|
||||
if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0))
|
||||
return stbi__errpuc("too large", "PNM too large");
|
||||
|
||||
out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0);
|
||||
out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0);
|
||||
if (!out) return stbi__errpuc("outofmem", "Out of memory");
|
||||
stbi__getn(s, out, s->img_n * s->img_x * s->img_y);
|
||||
stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8));
|
||||
|
||||
if (req_comp && req_comp != s->img_n) {
|
||||
out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y);
|
||||
|
|
@ -7398,11 +7522,19 @@ static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)
|
|||
stbi__pnm_skip_whitespace(s, &c);
|
||||
|
||||
maxv = stbi__pnm_getinteger(s, &c); // read max value
|
||||
|
||||
if (maxv > 255)
|
||||
return stbi__err("max value > 255", "PPM image not 8-bit");
|
||||
if (maxv > 65535)
|
||||
return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images");
|
||||
else if (maxv > 255)
|
||||
return 16;
|
||||
else
|
||||
return 8;
|
||||
}
|
||||
|
||||
static int stbi__pnm_is16(stbi__context *s)
|
||||
{
|
||||
if (stbi__pnm_info(s, NULL, NULL, NULL) == 16)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -7458,6 +7590,9 @@ static int stbi__is_16_main(stbi__context *s)
|
|||
if (stbi__psd_is16(s)) return 1;
|
||||
#endif
|
||||
|
||||
#ifndef STBI_NO_PNM
|
||||
if (stbi__pnm_is16(s)) return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
19
src/external/stb_image_resize.h
vendored
|
|
@ -1,4 +1,4 @@
|
|||
/* stb_image_resize - v0.96 - public domain image resizing
|
||||
/* stb_image_resize - v0.97 - public domain image resizing
|
||||
by Jorge L Rodriguez (@VinoBS) - 2014
|
||||
http://github.com/nothings/stb
|
||||
|
||||
|
|
@ -1064,7 +1064,11 @@ static void stbir__calculate_coefficients_upsample(stbir_filter filter, float sc
|
|||
total_filter += coefficient_group[i];
|
||||
}
|
||||
|
||||
STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0);
|
||||
// NOTE(fg): Not actually true in general, nor is there any reason to expect it should be.
|
||||
// It would be true in exact math but is at best approximately true in floating-point math,
|
||||
// and it would not make sense to try and put actual bounds on this here because it depends
|
||||
// on the image aspect ratio which can get pretty extreme.
|
||||
//STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0);
|
||||
|
||||
STBIR_ASSERT(total_filter > 0.9);
|
||||
STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off.
|
||||
|
|
@ -1103,7 +1107,11 @@ static void stbir__calculate_coefficients_downsample(stbir_filter filter, float
|
|||
coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio;
|
||||
}
|
||||
|
||||
STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0);
|
||||
// NOTE(fg): Not actually true in general, nor is there any reason to expect it should be.
|
||||
// It would be true in exact math but is at best approximately true in floating-point math,
|
||||
// and it would not make sense to try and put actual bounds on this here because it depends
|
||||
// on the image aspect ratio which can get pretty extreme.
|
||||
//STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0);
|
||||
|
||||
for (i = out_last_pixel - out_first_pixel; i >= 0; i--)
|
||||
{
|
||||
|
|
@ -1552,7 +1560,6 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float
|
|||
{
|
||||
int out_pixel_index = k * 1;
|
||||
float coefficient = horizontal_coefficients[coefficient_group + k - n0];
|
||||
STBIR_ASSERT(coefficient != 0);
|
||||
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
|
||||
}
|
||||
}
|
||||
|
|
@ -1573,7 +1580,6 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float
|
|||
{
|
||||
int out_pixel_index = k * 2;
|
||||
float coefficient = horizontal_coefficients[coefficient_group + k - n0];
|
||||
STBIR_ASSERT(coefficient != 0);
|
||||
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
|
||||
output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
|
||||
}
|
||||
|
|
@ -1595,7 +1601,6 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float
|
|||
{
|
||||
int out_pixel_index = k * 3;
|
||||
float coefficient = horizontal_coefficients[coefficient_group + k - n0];
|
||||
STBIR_ASSERT(coefficient != 0);
|
||||
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
|
||||
output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
|
||||
output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
|
||||
|
|
@ -1618,7 +1623,6 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float
|
|||
{
|
||||
int out_pixel_index = k * 4;
|
||||
float coefficient = horizontal_coefficients[coefficient_group + k - n0];
|
||||
STBIR_ASSERT(coefficient != 0);
|
||||
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
|
||||
output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
|
||||
output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
|
||||
|
|
@ -1643,7 +1647,6 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float
|
|||
int c;
|
||||
int out_pixel_index = k * channels;
|
||||
float coefficient = horizontal_coefficients[coefficient_group + k - n0];
|
||||
STBIR_ASSERT(coefficient != 0);
|
||||
for (c = 0; c < channels; c++)
|
||||
output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
|
||||
}
|
||||
|
|
|
|||
62
src/external/stb_image_write.h
vendored
|
|
@ -1,4 +1,4 @@
|
|||
/* stb_image_write - v1.15 - public domain - http://nothings.org/stb
|
||||
/* stb_image_write - v1.16 - public domain - http://nothings.org/stb
|
||||
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
|
|
@ -140,6 +140,7 @@ CREDITS:
|
|||
Ivan Tikhonov
|
||||
github:ignotion
|
||||
Adam Schackart
|
||||
Andrew Kensler
|
||||
|
||||
LICENSE
|
||||
|
||||
|
|
@ -166,9 +167,9 @@ LICENSE
|
|||
#endif
|
||||
|
||||
#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations
|
||||
extern int stbi_write_tga_with_rle;
|
||||
extern int stbi_write_png_compression_level;
|
||||
extern int stbi_write_force_png_filter;
|
||||
STBIWDEF int stbi_write_tga_with_rle;
|
||||
STBIWDEF int stbi_write_png_compression_level;
|
||||
STBIWDEF int stbi_write_force_png_filter;
|
||||
#endif
|
||||
|
||||
#ifndef STBI_WRITE_NO_STDIO
|
||||
|
|
@ -178,7 +179,7 @@ STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const
|
|||
STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
|
||||
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality);
|
||||
|
||||
#ifdef STBI_WINDOWS_UTF8
|
||||
#ifdef STBIW_WINDOWS_UTF8
|
||||
STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -285,7 +286,7 @@ static void stbi__stdio_write(void *context, void *data, int size)
|
|||
fwrite(data,1,size,(FILE*) context);
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
|
||||
#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)
|
||||
#ifdef __cplusplus
|
||||
#define STBIW_EXTERN extern "C"
|
||||
#else
|
||||
|
|
@ -303,16 +304,16 @@ STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const w
|
|||
static FILE *stbiw__fopen(char const *filename, char const *mode)
|
||||
{
|
||||
FILE *f;
|
||||
#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
|
||||
#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)
|
||||
wchar_t wMode[64];
|
||||
wchar_t wFilename[1024];
|
||||
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)))
|
||||
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))
|
||||
return 0;
|
||||
|
||||
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)))
|
||||
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))
|
||||
return 0;
|
||||
|
||||
#if _MSC_VER >= 1400
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
if (0 != _wfopen_s(&f, wFilename, wMode))
|
||||
f = 0;
|
||||
#else
|
||||
|
|
@ -397,7 +398,7 @@ static void stbiw__putc(stbi__write_context *s, unsigned char c)
|
|||
|
||||
static void stbiw__write1(stbi__write_context *s, unsigned char a)
|
||||
{
|
||||
if (s->buf_used + 1 > sizeof(s->buffer))
|
||||
if ((size_t)s->buf_used + 1 > sizeof(s->buffer))
|
||||
stbiw__write_flush(s);
|
||||
s->buffer[s->buf_used++] = a;
|
||||
}
|
||||
|
|
@ -405,7 +406,7 @@ static void stbiw__write1(stbi__write_context *s, unsigned char a)
|
|||
static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
|
||||
{
|
||||
int n;
|
||||
if (s->buf_used + 3 > sizeof(s->buffer))
|
||||
if ((size_t)s->buf_used + 3 > sizeof(s->buffer))
|
||||
stbiw__write_flush(s);
|
||||
n = s->buf_used;
|
||||
s->buf_used = n+3;
|
||||
|
|
@ -490,11 +491,22 @@ static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x,
|
|||
|
||||
static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
|
||||
{
|
||||
if (comp != 4) {
|
||||
// write RGB bitmap
|
||||
int pad = (-x*3) & 3;
|
||||
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
|
||||
"11 4 22 4" "4 44 22 444444",
|
||||
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
|
||||
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
|
||||
} else {
|
||||
// RGBA bitmaps need a v4 header
|
||||
// use BI_BITFIELDS mode with 32bpp and alpha mask
|
||||
// (straight BI_RGB with alpha mask doesn't work in most readers)
|
||||
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0,
|
||||
"11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444",
|
||||
'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header
|
||||
108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header
|
||||
}
|
||||
}
|
||||
|
||||
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
|
||||
|
|
@ -622,6 +634,8 @@ STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const
|
|||
|
||||
#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#ifndef STBI_WRITE_NO_STDIO
|
||||
|
||||
static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
|
||||
{
|
||||
int exponent;
|
||||
|
|
@ -756,7 +770,7 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f
|
|||
char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
|
||||
s->func(s->context, header, sizeof(header)-1);
|
||||
|
||||
#ifdef __STDC_WANT_SECURE_LIB__
|
||||
#ifdef __STDC_LIB_EXT1__
|
||||
len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
|
||||
#else
|
||||
len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
|
||||
|
|
@ -777,7 +791,6 @@ STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x,
|
|||
return stbi_write_hdr_core(&s, x, y, comp, (float *) data);
|
||||
}
|
||||
|
||||
#ifndef STBI_WRITE_NO_STDIO
|
||||
STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
|
||||
{
|
||||
stbi__write_context s = { 0 };
|
||||
|
|
@ -968,6 +981,23 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i
|
|||
(void) stbiw__sbfree(hash_table[i]);
|
||||
STBIW_FREE(hash_table);
|
||||
|
||||
// store uncompressed instead if compression was worse
|
||||
if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) {
|
||||
stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1
|
||||
for (j = 0; j < data_len;) {
|
||||
int blocklen = data_len - j;
|
||||
if (blocklen > 32767) blocklen = 32767;
|
||||
stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression
|
||||
stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN
|
||||
stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8));
|
||||
stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN
|
||||
stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8));
|
||||
memcpy(out+stbiw__sbn(out), data+j, blocklen);
|
||||
stbiw__sbn(out) += blocklen;
|
||||
j += blocklen;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// compute adler32 on input
|
||||
unsigned int s1=1, s2=0;
|
||||
|
|
@ -1598,6 +1628,10 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
|
|||
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
/* Revision history
|
||||
1.16 (2021-07-11)
|
||||
make Deflate code emit uncompressed blocks when it would otherwise expand
|
||||
support writing BMPs with alpha channel
|
||||
1.15 (2020-07-13) unknown
|
||||
1.14 (2020-02-02) updated JPEG writer to downsample chroma channels
|
||||
1.13
|
||||
1.12
|
||||
|
|
|
|||
428
src/external/stb_perlin.h
vendored
|
|
@ -1,428 +0,0 @@
|
|||
// stb_perlin.h - v0.5 - perlin noise
|
||||
// public domain single-file C implementation by Sean Barrett
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file.
|
||||
//
|
||||
//
|
||||
// to create the implementation,
|
||||
// #define STB_PERLIN_IMPLEMENTATION
|
||||
// in *one* C/CPP file that includes this file.
|
||||
//
|
||||
//
|
||||
// Documentation:
|
||||
//
|
||||
// float stb_perlin_noise3( float x,
|
||||
// float y,
|
||||
// float z,
|
||||
// int x_wrap=0,
|
||||
// int y_wrap=0,
|
||||
// int z_wrap=0)
|
||||
//
|
||||
// This function computes a random value at the coordinate (x,y,z).
|
||||
// Adjacent random values are continuous but the noise fluctuates
|
||||
// its randomness with period 1, i.e. takes on wholly unrelated values
|
||||
// at integer points. Specifically, this implements Ken Perlin's
|
||||
// revised noise function from 2002.
|
||||
//
|
||||
// The "wrap" parameters can be used to create wraparound noise that
|
||||
// wraps at powers of two. The numbers MUST be powers of two. Specify
|
||||
// 0 to mean "don't care". (The noise always wraps every 256 due
|
||||
// details of the implementation, even if you ask for larger or no
|
||||
// wrapping.)
|
||||
//
|
||||
// float stb_perlin_noise3_seed( float x,
|
||||
// float y,
|
||||
// float z,
|
||||
// int x_wrap=0,
|
||||
// int y_wrap=0,
|
||||
// int z_wrap=0,
|
||||
// int seed)
|
||||
//
|
||||
// As above, but 'seed' selects from multiple different variations of the
|
||||
// noise function. The current implementation only uses the bottom 8 bits
|
||||
// of 'seed', but possibly in the future more bits will be used.
|
||||
//
|
||||
//
|
||||
// Fractal Noise:
|
||||
//
|
||||
// Three common fractal noise functions are included, which produce
|
||||
// a wide variety of nice effects depending on the parameters
|
||||
// provided. Note that each function will call stb_perlin_noise3
|
||||
// 'octaves' times, so this parameter will affect runtime.
|
||||
//
|
||||
// float stb_perlin_ridge_noise3(float x, float y, float z,
|
||||
// float lacunarity, float gain, float offset, int octaves)
|
||||
//
|
||||
// float stb_perlin_fbm_noise3(float x, float y, float z,
|
||||
// float lacunarity, float gain, int octaves)
|
||||
//
|
||||
// float stb_perlin_turbulence_noise3(float x, float y, float z,
|
||||
// float lacunarity, float gain, int octaves)
|
||||
//
|
||||
// Typical values to start playing with:
|
||||
// octaves = 6 -- number of "octaves" of noise3() to sum
|
||||
// lacunarity = ~ 2.0 -- spacing between successive octaves (use exactly 2.0 for wrapping output)
|
||||
// gain = 0.5 -- relative weighting applied to each successive octave
|
||||
// offset = 1.0? -- used to invert the ridges, may need to be larger, not sure
|
||||
//
|
||||
//
|
||||
// Contributors:
|
||||
// Jack Mott - additional noise functions
|
||||
// Jordan Peck - seeded noise
|
||||
//
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap);
|
||||
extern float stb_perlin_noise3_seed(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, int seed);
|
||||
extern float stb_perlin_ridge_noise3(float x, float y, float z, float lacunarity, float gain, float offset, int octaves);
|
||||
extern float stb_perlin_fbm_noise3(float x, float y, float z, float lacunarity, float gain, int octaves);
|
||||
extern float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves);
|
||||
extern float stb_perlin_noise3_wrap_nonpow2(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef STB_PERLIN_IMPLEMENTATION
|
||||
|
||||
#include <math.h> // fabs()
|
||||
|
||||
// not same permutation table as Perlin's reference to avoid copyright issues;
|
||||
// Perlin's table can be found at http://mrl.nyu.edu/~perlin/noise/
|
||||
static unsigned char stb__perlin_randtab[512] =
|
||||
{
|
||||
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
|
||||
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
|
||||
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
|
||||
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
|
||||
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
|
||||
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
|
||||
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
|
||||
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
|
||||
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
|
||||
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
|
||||
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
|
||||
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
|
||||
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
|
||||
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
|
||||
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
|
||||
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
|
||||
|
||||
// and a second copy so we don't need an extra mask or static initializer
|
||||
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
|
||||
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
|
||||
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
|
||||
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
|
||||
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
|
||||
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
|
||||
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
|
||||
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
|
||||
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
|
||||
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
|
||||
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
|
||||
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
|
||||
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
|
||||
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
|
||||
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
|
||||
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
|
||||
};
|
||||
|
||||
|
||||
// perlin's gradient has 12 cases so some get used 1/16th of the time
|
||||
// and some 2/16ths. We reduce bias by changing those fractions
|
||||
// to 5/64ths and 6/64ths
|
||||
|
||||
// this array is designed to match the previous implementation
|
||||
// of gradient hash: indices[stb__perlin_randtab[i]&63]
|
||||
static unsigned char stb__perlin_randtab_grad_idx[512] =
|
||||
{
|
||||
7, 9, 5, 0, 11, 1, 6, 9, 3, 9, 11, 1, 8, 10, 4, 7,
|
||||
8, 6, 1, 5, 3, 10, 9, 10, 0, 8, 4, 1, 5, 2, 7, 8,
|
||||
7, 11, 9, 10, 1, 0, 4, 7, 5, 0, 11, 6, 1, 4, 2, 8,
|
||||
8, 10, 4, 9, 9, 2, 5, 7, 9, 1, 7, 2, 2, 6, 11, 5,
|
||||
5, 4, 6, 9, 0, 1, 1, 0, 7, 6, 9, 8, 4, 10, 3, 1,
|
||||
2, 8, 8, 9, 10, 11, 5, 11, 11, 2, 6, 10, 3, 4, 2, 4,
|
||||
9, 10, 3, 2, 6, 3, 6, 10, 5, 3, 4, 10, 11, 2, 9, 11,
|
||||
1, 11, 10, 4, 9, 4, 11, 0, 4, 11, 4, 0, 0, 0, 7, 6,
|
||||
10, 4, 1, 3, 11, 5, 3, 4, 2, 9, 1, 3, 0, 1, 8, 0,
|
||||
6, 7, 8, 7, 0, 4, 6, 10, 8, 2, 3, 11, 11, 8, 0, 2,
|
||||
4, 8, 3, 0, 0, 10, 6, 1, 2, 2, 4, 5, 6, 0, 1, 3,
|
||||
11, 9, 5, 5, 9, 6, 9, 8, 3, 8, 1, 8, 9, 6, 9, 11,
|
||||
10, 7, 5, 6, 5, 9, 1, 3, 7, 0, 2, 10, 11, 2, 6, 1,
|
||||
3, 11, 7, 7, 2, 1, 7, 3, 0, 8, 1, 1, 5, 0, 6, 10,
|
||||
11, 11, 0, 2, 7, 0, 10, 8, 3, 5, 7, 1, 11, 1, 0, 7,
|
||||
9, 0, 11, 5, 10, 3, 2, 3, 5, 9, 7, 9, 8, 4, 6, 5,
|
||||
|
||||
// and a second copy so we don't need an extra mask or static initializer
|
||||
7, 9, 5, 0, 11, 1, 6, 9, 3, 9, 11, 1, 8, 10, 4, 7,
|
||||
8, 6, 1, 5, 3, 10, 9, 10, 0, 8, 4, 1, 5, 2, 7, 8,
|
||||
7, 11, 9, 10, 1, 0, 4, 7, 5, 0, 11, 6, 1, 4, 2, 8,
|
||||
8, 10, 4, 9, 9, 2, 5, 7, 9, 1, 7, 2, 2, 6, 11, 5,
|
||||
5, 4, 6, 9, 0, 1, 1, 0, 7, 6, 9, 8, 4, 10, 3, 1,
|
||||
2, 8, 8, 9, 10, 11, 5, 11, 11, 2, 6, 10, 3, 4, 2, 4,
|
||||
9, 10, 3, 2, 6, 3, 6, 10, 5, 3, 4, 10, 11, 2, 9, 11,
|
||||
1, 11, 10, 4, 9, 4, 11, 0, 4, 11, 4, 0, 0, 0, 7, 6,
|
||||
10, 4, 1, 3, 11, 5, 3, 4, 2, 9, 1, 3, 0, 1, 8, 0,
|
||||
6, 7, 8, 7, 0, 4, 6, 10, 8, 2, 3, 11, 11, 8, 0, 2,
|
||||
4, 8, 3, 0, 0, 10, 6, 1, 2, 2, 4, 5, 6, 0, 1, 3,
|
||||
11, 9, 5, 5, 9, 6, 9, 8, 3, 8, 1, 8, 9, 6, 9, 11,
|
||||
10, 7, 5, 6, 5, 9, 1, 3, 7, 0, 2, 10, 11, 2, 6, 1,
|
||||
3, 11, 7, 7, 2, 1, 7, 3, 0, 8, 1, 1, 5, 0, 6, 10,
|
||||
11, 11, 0, 2, 7, 0, 10, 8, 3, 5, 7, 1, 11, 1, 0, 7,
|
||||
9, 0, 11, 5, 10, 3, 2, 3, 5, 9, 7, 9, 8, 4, 6, 5,
|
||||
};
|
||||
|
||||
static float stb__perlin_lerp(float a, float b, float t)
|
||||
{
|
||||
return a + (b-a) * t;
|
||||
}
|
||||
|
||||
static int stb__perlin_fastfloor(float a)
|
||||
{
|
||||
int ai = (int) a;
|
||||
return (a < ai) ? ai-1 : ai;
|
||||
}
|
||||
|
||||
// different grad function from Perlin's, but easy to modify to match reference
|
||||
static float stb__perlin_grad(int grad_idx, float x, float y, float z)
|
||||
{
|
||||
static float basis[12][4] =
|
||||
{
|
||||
{ 1, 1, 0 },
|
||||
{ -1, 1, 0 },
|
||||
{ 1,-1, 0 },
|
||||
{ -1,-1, 0 },
|
||||
{ 1, 0, 1 },
|
||||
{ -1, 0, 1 },
|
||||
{ 1, 0,-1 },
|
||||
{ -1, 0,-1 },
|
||||
{ 0, 1, 1 },
|
||||
{ 0,-1, 1 },
|
||||
{ 0, 1,-1 },
|
||||
{ 0,-1,-1 },
|
||||
};
|
||||
|
||||
float *grad = basis[grad_idx];
|
||||
return grad[0]*x + grad[1]*y + grad[2]*z;
|
||||
}
|
||||
|
||||
float stb_perlin_noise3_internal(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed)
|
||||
{
|
||||
float u,v,w;
|
||||
float n000,n001,n010,n011,n100,n101,n110,n111;
|
||||
float n00,n01,n10,n11;
|
||||
float n0,n1;
|
||||
|
||||
unsigned int x_mask = (x_wrap-1) & 255;
|
||||
unsigned int y_mask = (y_wrap-1) & 255;
|
||||
unsigned int z_mask = (z_wrap-1) & 255;
|
||||
int px = stb__perlin_fastfloor(x);
|
||||
int py = stb__perlin_fastfloor(y);
|
||||
int pz = stb__perlin_fastfloor(z);
|
||||
int x0 = px & x_mask, x1 = (px+1) & x_mask;
|
||||
int y0 = py & y_mask, y1 = (py+1) & y_mask;
|
||||
int z0 = pz & z_mask, z1 = (pz+1) & z_mask;
|
||||
int r0,r1, r00,r01,r10,r11;
|
||||
|
||||
#define stb__perlin_ease(a) (((a*6-15)*a + 10) * a * a * a)
|
||||
|
||||
x -= px; u = stb__perlin_ease(x);
|
||||
y -= py; v = stb__perlin_ease(y);
|
||||
z -= pz; w = stb__perlin_ease(z);
|
||||
|
||||
r0 = stb__perlin_randtab[x0+seed];
|
||||
r1 = stb__perlin_randtab[x1+seed];
|
||||
|
||||
r00 = stb__perlin_randtab[r0+y0];
|
||||
r01 = stb__perlin_randtab[r0+y1];
|
||||
r10 = stb__perlin_randtab[r1+y0];
|
||||
r11 = stb__perlin_randtab[r1+y1];
|
||||
|
||||
n000 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z0], x , y , z );
|
||||
n001 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z1], x , y , z-1 );
|
||||
n010 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z0], x , y-1, z );
|
||||
n011 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z1], x , y-1, z-1 );
|
||||
n100 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z0], x-1, y , z );
|
||||
n101 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z1], x-1, y , z-1 );
|
||||
n110 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z0], x-1, y-1, z );
|
||||
n111 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z1], x-1, y-1, z-1 );
|
||||
|
||||
n00 = stb__perlin_lerp(n000,n001,w);
|
||||
n01 = stb__perlin_lerp(n010,n011,w);
|
||||
n10 = stb__perlin_lerp(n100,n101,w);
|
||||
n11 = stb__perlin_lerp(n110,n111,w);
|
||||
|
||||
n0 = stb__perlin_lerp(n00,n01,v);
|
||||
n1 = stb__perlin_lerp(n10,n11,v);
|
||||
|
||||
return stb__perlin_lerp(n0,n1,u);
|
||||
}
|
||||
|
||||
float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap)
|
||||
{
|
||||
return stb_perlin_noise3_internal(x,y,z,x_wrap,y_wrap,z_wrap,0);
|
||||
}
|
||||
|
||||
float stb_perlin_noise3_seed(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, int seed)
|
||||
{
|
||||
return stb_perlin_noise3_internal(x,y,z,x_wrap,y_wrap,z_wrap, (unsigned char) seed);
|
||||
}
|
||||
|
||||
float stb_perlin_ridge_noise3(float x, float y, float z, float lacunarity, float gain, float offset, int octaves)
|
||||
{
|
||||
int i;
|
||||
float frequency = 1.0f;
|
||||
float prev = 1.0f;
|
||||
float amplitude = 0.5f;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (i = 0; i < octaves; i++) {
|
||||
float r = stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i);
|
||||
r = offset - (float) fabs(r);
|
||||
r = r*r;
|
||||
sum += r*amplitude*prev;
|
||||
prev = r;
|
||||
frequency *= lacunarity;
|
||||
amplitude *= gain;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
float stb_perlin_fbm_noise3(float x, float y, float z, float lacunarity, float gain, int octaves)
|
||||
{
|
||||
int i;
|
||||
float frequency = 1.0f;
|
||||
float amplitude = 1.0f;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (i = 0; i < octaves; i++) {
|
||||
sum += stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i)*amplitude;
|
||||
frequency *= lacunarity;
|
||||
amplitude *= gain;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves)
|
||||
{
|
||||
int i;
|
||||
float frequency = 1.0f;
|
||||
float amplitude = 1.0f;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (i = 0; i < octaves; i++) {
|
||||
float r = stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i)*amplitude;
|
||||
sum += (float) fabs(r);
|
||||
frequency *= lacunarity;
|
||||
amplitude *= gain;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
float stb_perlin_noise3_wrap_nonpow2(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed)
|
||||
{
|
||||
float u,v,w;
|
||||
float n000,n001,n010,n011,n100,n101,n110,n111;
|
||||
float n00,n01,n10,n11;
|
||||
float n0,n1;
|
||||
|
||||
int px = stb__perlin_fastfloor(x);
|
||||
int py = stb__perlin_fastfloor(y);
|
||||
int pz = stb__perlin_fastfloor(z);
|
||||
int x_wrap2 = (x_wrap ? x_wrap : 256);
|
||||
int y_wrap2 = (y_wrap ? y_wrap : 256);
|
||||
int z_wrap2 = (z_wrap ? z_wrap : 256);
|
||||
int x0 = px % x_wrap2, x1;
|
||||
int y0 = py % y_wrap2, y1;
|
||||
int z0 = pz % z_wrap2, z1;
|
||||
int r0,r1, r00,r01,r10,r11;
|
||||
|
||||
if (x0 < 0) x0 += x_wrap2;
|
||||
if (y0 < 0) y0 += y_wrap2;
|
||||
if (z0 < 0) z0 += z_wrap2;
|
||||
x1 = (x0+1) % x_wrap2;
|
||||
y1 = (y0+1) % y_wrap2;
|
||||
z1 = (z0+1) % z_wrap2;
|
||||
|
||||
#define stb__perlin_ease(a) (((a*6-15)*a + 10) * a * a * a)
|
||||
|
||||
x -= px; u = stb__perlin_ease(x);
|
||||
y -= py; v = stb__perlin_ease(y);
|
||||
z -= pz; w = stb__perlin_ease(z);
|
||||
|
||||
r0 = stb__perlin_randtab[x0];
|
||||
r0 = stb__perlin_randtab[r0+seed];
|
||||
r1 = stb__perlin_randtab[x1];
|
||||
r1 = stb__perlin_randtab[r1+seed];
|
||||
|
||||
r00 = stb__perlin_randtab[r0+y0];
|
||||
r01 = stb__perlin_randtab[r0+y1];
|
||||
r10 = stb__perlin_randtab[r1+y0];
|
||||
r11 = stb__perlin_randtab[r1+y1];
|
||||
|
||||
n000 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z0], x , y , z );
|
||||
n001 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z1], x , y , z-1 );
|
||||
n010 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z0], x , y-1, z );
|
||||
n011 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z1], x , y-1, z-1 );
|
||||
n100 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z0], x-1, y , z );
|
||||
n101 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z1], x-1, y , z-1 );
|
||||
n110 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z0], x-1, y-1, z );
|
||||
n111 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z1], x-1, y-1, z-1 );
|
||||
|
||||
n00 = stb__perlin_lerp(n000,n001,w);
|
||||
n01 = stb__perlin_lerp(n010,n011,w);
|
||||
n10 = stb__perlin_lerp(n100,n101,w);
|
||||
n11 = stb__perlin_lerp(n110,n111,w);
|
||||
|
||||
n0 = stb__perlin_lerp(n00,n01,v);
|
||||
n1 = stb__perlin_lerp(n10,n11,v);
|
||||
|
||||
return stb__perlin_lerp(n0,n1,u);
|
||||
}
|
||||
#endif // STB_PERLIN_IMPLEMENTATION
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
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.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
35
src/external/stb_rect_pack.h
vendored
|
|
@ -1,9 +1,15 @@
|
|||
// stb_rect_pack.h - v1.00 - public domain - rectangle packing
|
||||
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
|
||||
// Sean Barrett 2014
|
||||
//
|
||||
// Useful for e.g. packing rectangular textures into an atlas.
|
||||
// Does not do rotation.
|
||||
//
|
||||
// Before #including,
|
||||
//
|
||||
// #define STB_RECT_PACK_IMPLEMENTATION
|
||||
//
|
||||
// in the file that you want to have the implementation.
|
||||
//
|
||||
// Not necessarily the awesomest packing method, but better than
|
||||
// the totally naive one in stb_truetype (which is primarily what
|
||||
// this is meant to replace).
|
||||
|
|
@ -35,6 +41,7 @@
|
|||
//
|
||||
// Version history:
|
||||
//
|
||||
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
|
||||
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
|
||||
// 0.99 (2019-02-07) warning fixes
|
||||
// 0.11 (2017-03-03) return packing success/fail result
|
||||
|
|
@ -75,11 +82,10 @@ typedef struct stbrp_context stbrp_context;
|
|||
typedef struct stbrp_node stbrp_node;
|
||||
typedef struct stbrp_rect stbrp_rect;
|
||||
|
||||
#ifdef STBRP_LARGE_RECTS
|
||||
typedef int stbrp_coord;
|
||||
#else
|
||||
typedef unsigned short stbrp_coord;
|
||||
#endif
|
||||
|
||||
#define STBRP__MAXVAL 0x7fffffff
|
||||
// Mostly for internal use, but this is the maximum supported coordinate value.
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||
// Assign packed locations to rectangles. The rectangles are of type
|
||||
|
|
@ -209,8 +215,10 @@ struct stbrp_context
|
|||
|
||||
#ifdef _MSC_VER
|
||||
#define STBRP__NOTUSED(v) (void)(v)
|
||||
#define STBRP__CDECL __cdecl
|
||||
#else
|
||||
#define STBRP__NOTUSED(v) (void)sizeof(v)
|
||||
#define STBRP__CDECL
|
||||
#endif
|
||||
|
||||
enum
|
||||
|
|
@ -253,9 +261,6 @@ STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_ou
|
|||
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||
{
|
||||
int i;
|
||||
#ifndef STBRP_LARGE_RECTS
|
||||
STBRP_ASSERT(width <= 0xffff && height <= 0xffff);
|
||||
#endif
|
||||
|
||||
for (i=0; i < num_nodes-1; ++i)
|
||||
nodes[i].next = &nodes[i+1];
|
||||
|
|
@ -274,11 +279,7 @@ STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height,
|
|||
context->extra[0].y = 0;
|
||||
context->extra[0].next = &context->extra[1];
|
||||
context->extra[1].x = (stbrp_coord) width;
|
||||
#ifdef STBRP_LARGE_RECTS
|
||||
context->extra[1].y = (1<<30);
|
||||
#else
|
||||
context->extra[1].y = 65535;
|
||||
#endif
|
||||
context->extra[1].next = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -520,7 +521,7 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i
|
|||
return res;
|
||||
}
|
||||
|
||||
static int rect_height_compare(const void *a, const void *b)
|
||||
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
|
|
@ -531,19 +532,13 @@ static int rect_height_compare(const void *a, const void *b)
|
|||
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||
}
|
||||
|
||||
static int rect_original_order(const void *a, const void *b)
|
||||
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||
}
|
||||
|
||||
#ifdef STBRP_LARGE_RECTS
|
||||
#define STBRP__MAXVAL 0xffffffff
|
||||
#else
|
||||
#define STBRP__MAXVAL 0xffff
|
||||
#endif
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||
{
|
||||
int i, all_rects_packed = 1;
|
||||
|
|
|
|||
258
src/external/stb_truetype.h
vendored
|
|
@ -1,5 +1,5 @@
|
|||
// stb_truetype.h - v1.24 - public domain
|
||||
// authored from 2009-2020 by Sean Barrett / RAD Game Tools
|
||||
// stb_truetype.h - v1.26 - public domain
|
||||
// authored from 2009-2021 by Sean Barrett / RAD Game Tools
|
||||
//
|
||||
// =======================================================================
|
||||
//
|
||||
|
|
@ -58,6 +58,8 @@
|
|||
//
|
||||
// VERSION HISTORY
|
||||
//
|
||||
// 1.26 (2021-08-28) fix broken rasterizer
|
||||
// 1.25 (2021-07-11) many fixes
|
||||
// 1.24 (2020-02-05) fix warning
|
||||
// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
|
||||
// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
|
||||
|
|
@ -270,8 +272,8 @@
|
|||
//// SAMPLE PROGRAMS
|
||||
////
|
||||
//
|
||||
// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless
|
||||
//
|
||||
// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless.
|
||||
// See "tests/truetype_demo_win32.c" for a complete version.
|
||||
#if 0
|
||||
#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation
|
||||
#include "stb_truetype.h"
|
||||
|
|
@ -297,6 +299,8 @@ void my_stbtt_initfont(void)
|
|||
void my_stbtt_print(float x, float y, char *text)
|
||||
{
|
||||
// assume orthographic projection with units = screen pixels, origin at top left
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, ftex);
|
||||
glBegin(GL_QUADS);
|
||||
|
|
@ -304,10 +308,10 @@ void my_stbtt_print(float x, float y, char *text)
|
|||
if (*text >= 32 && *text < 128) {
|
||||
stbtt_aligned_quad q;
|
||||
stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9
|
||||
glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0);
|
||||
glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0);
|
||||
glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1);
|
||||
glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1);
|
||||
glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0);
|
||||
glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0);
|
||||
glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1);
|
||||
glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1);
|
||||
}
|
||||
++text;
|
||||
}
|
||||
|
|
@ -853,6 +857,7 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s
|
|||
STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
|
||||
// frees the data allocated above
|
||||
|
||||
STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl);
|
||||
STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg);
|
||||
STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);
|
||||
// fills svg with the character's SVG data.
|
||||
|
|
@ -1539,12 +1544,12 @@ STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codep
|
|||
search += 2;
|
||||
|
||||
{
|
||||
stbtt_uint16 offset, start;
|
||||
stbtt_uint16 offset, start, last;
|
||||
stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);
|
||||
|
||||
STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item));
|
||||
start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
|
||||
if (unicode_codepoint < start)
|
||||
last = ttUSHORT(data + endCount + 2*item);
|
||||
if (unicode_codepoint < start || unicode_codepoint > last)
|
||||
return 0;
|
||||
|
||||
offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
|
||||
|
|
@ -1871,7 +1876,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
|
|||
if (comp_verts) STBTT_free(comp_verts, info->userdata);
|
||||
return 0;
|
||||
}
|
||||
if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));
|
||||
if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));
|
||||
STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));
|
||||
if (vertices) STBTT_free(vertices, info->userdata);
|
||||
vertices = tmp;
|
||||
|
|
@ -2134,7 +2139,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st
|
|||
subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
|
||||
has_subrs = 1;
|
||||
}
|
||||
// fallthrough
|
||||
// FALLTHROUGH
|
||||
case 0x1D: // callgsubr
|
||||
if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
|
||||
v = (int) s[--sp];
|
||||
|
|
@ -2239,7 +2244,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st
|
|||
} break;
|
||||
|
||||
default:
|
||||
if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254))
|
||||
if (b0 != 255 && b0 != 28 && b0 < 32)
|
||||
return STBTT__CSERR("reserved operator");
|
||||
|
||||
// push immediate
|
||||
|
|
@ -2384,7 +2389,7 @@ static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph
|
|||
static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)
|
||||
{
|
||||
stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);
|
||||
switch(coverageFormat) {
|
||||
switch (coverageFormat) {
|
||||
case 1: {
|
||||
stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
|
||||
|
||||
|
|
@ -2405,7 +2410,8 @@ static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyp
|
|||
return m;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
|
||||
|
|
@ -2429,12 +2435,10 @@ static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyp
|
|||
return startCoverageIndex + glyph - strawStart;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
// There are no other cases.
|
||||
STBTT_assert(0);
|
||||
} break;
|
||||
default: return -1; // unsupported
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
|
@ -2443,7 +2447,7 @@ static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyp
|
|||
static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
|
||||
{
|
||||
stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
|
||||
switch(classDefFormat)
|
||||
switch (classDefFormat)
|
||||
{
|
||||
case 1: {
|
||||
stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
|
||||
|
|
@ -2452,9 +2456,8 @@ static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
|
|||
|
||||
if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
|
||||
return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
|
||||
|
||||
classDefTable = classDef1ValueArray + 2 * glyphCount;
|
||||
} break;
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
|
||||
|
|
@ -2476,17 +2479,15 @@ static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
|
|||
else
|
||||
return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
|
||||
}
|
||||
|
||||
classDefTable = classRangeRecords + 6 * classRangeCount;
|
||||
} break;
|
||||
|
||||
default: {
|
||||
// There are no other cases.
|
||||
STBTT_assert(0);
|
||||
} break;
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
default:
|
||||
return -1; // Unsupported definition type, return an error.
|
||||
}
|
||||
|
||||
// "All glyphs not assigned to a class fall into class 0". (OpenType spec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Define to STBTT_assert(x) if you want to break on unimplemented formats.
|
||||
|
|
@ -2498,7 +2499,7 @@ static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, i
|
|||
stbtt_uint8 *lookupList;
|
||||
stbtt_uint16 lookupCount;
|
||||
stbtt_uint8 *data;
|
||||
stbtt_int32 i;
|
||||
stbtt_int32 i, sti;
|
||||
|
||||
if (!info->gpos) return 0;
|
||||
|
||||
|
|
@ -2518,9 +2519,9 @@ static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, i
|
|||
stbtt_uint16 lookupType = ttUSHORT(lookupTable);
|
||||
stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
|
||||
stbtt_uint8 *subTableOffsets = lookupTable + 6;
|
||||
switch(lookupType) {
|
||||
case 2: { // Pair Adjustment Positioning Subtable
|
||||
stbtt_int32 sti;
|
||||
if (lookupType != 2) // Pair Adjustment Positioning Subtable
|
||||
continue;
|
||||
|
||||
for (sti=0; sti<subTableCount; sti++) {
|
||||
stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
|
||||
stbtt_uint8 *table = lookupTable + subtableOffset;
|
||||
|
|
@ -2535,20 +2536,15 @@ static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, i
|
|||
int straw, needle;
|
||||
stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
|
||||
stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
|
||||
if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?
|
||||
stbtt_int32 valueRecordPairSizeInBytes = 2;
|
||||
stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
|
||||
stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
|
||||
stbtt_uint8 *pairValueTable = table + pairPosOffset;
|
||||
stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
|
||||
stbtt_uint8 *pairValueArray = pairValueTable + 2;
|
||||
// TODO: Support more formats.
|
||||
STBTT_GPOS_TODO_assert(valueFormat1 == 4);
|
||||
if (valueFormat1 != 4) return 0;
|
||||
STBTT_GPOS_TODO_assert(valueFormat2 == 0);
|
||||
if (valueFormat2 != 0) return 0;
|
||||
|
||||
STBTT_assert(coverageIndex < pairSetCount);
|
||||
STBTT__NOTUSED(pairSetCount);
|
||||
if (coverageIndex >= pairSetCount) return 0;
|
||||
|
||||
needle=glyph2;
|
||||
r=pairValueCount-1;
|
||||
|
|
@ -2571,12 +2567,15 @@ static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, i
|
|||
return xAdvance;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
} else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
|
||||
stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
|
||||
|
||||
if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?
|
||||
stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
|
||||
stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
|
||||
int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
|
||||
|
|
@ -2584,36 +2583,24 @@ static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, i
|
|||
|
||||
stbtt_uint16 class1Count = ttUSHORT(table + 12);
|
||||
stbtt_uint16 class2Count = ttUSHORT(table + 14);
|
||||
STBTT_assert(glyph1class < class1Count);
|
||||
STBTT_assert(glyph2class < class2Count);
|
||||
stbtt_uint8 *class1Records, *class2Records;
|
||||
stbtt_int16 xAdvance;
|
||||
|
||||
// TODO: Support more formats.
|
||||
STBTT_GPOS_TODO_assert(valueFormat1 == 4);
|
||||
if (valueFormat1 != 4) return 0;
|
||||
STBTT_GPOS_TODO_assert(valueFormat2 == 0);
|
||||
if (valueFormat2 != 0) return 0;
|
||||
if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed
|
||||
if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed
|
||||
|
||||
if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) {
|
||||
stbtt_uint8 *class1Records = table + 16;
|
||||
stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count);
|
||||
stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class);
|
||||
class1Records = table + 16;
|
||||
class2Records = class1Records + 2 * (glyph1class * class2Count);
|
||||
xAdvance = ttSHORT(class2Records + 2 * glyph2class);
|
||||
return xAdvance;
|
||||
}
|
||||
} break;
|
||||
|
||||
default: {
|
||||
// There are no other cases.
|
||||
STBTT_assert(0);
|
||||
} else
|
||||
return 0;
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
break;
|
||||
};
|
||||
|
||||
default:
|
||||
// TODO: Implement other stuff.
|
||||
break;
|
||||
return 0; // Unsupported position format
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3075,6 +3062,23 @@ static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edg
|
|||
}
|
||||
}
|
||||
|
||||
static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width)
|
||||
{
|
||||
STBTT_assert(top_width >= 0);
|
||||
STBTT_assert(bottom_width >= 0);
|
||||
return (top_width + bottom_width) / 2.0f * height;
|
||||
}
|
||||
|
||||
static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1)
|
||||
{
|
||||
return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0);
|
||||
}
|
||||
|
||||
static float stbtt__sized_triangle_area(float height, float width)
|
||||
{
|
||||
return height * width / 2;
|
||||
}
|
||||
|
||||
static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)
|
||||
{
|
||||
float y_bottom = y_top+1;
|
||||
|
|
@ -3129,13 +3133,13 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
|
|||
float height;
|
||||
// simple case, only spans one pixel
|
||||
int x = (int) x_top;
|
||||
height = sy1 - sy0;
|
||||
height = (sy1 - sy0) * e->direction;
|
||||
STBTT_assert(x >= 0 && x < len);
|
||||
scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2) * height;
|
||||
scanline_fill[x] += e->direction * height; // everything right of this pixel is filled
|
||||
scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f);
|
||||
scanline_fill[x] += height; // everything right of this pixel is filled
|
||||
} else {
|
||||
int x,x1,x2;
|
||||
float y_crossing, step, sign, area;
|
||||
float y_crossing, y_final, step, sign, area;
|
||||
// covers 2+ pixels
|
||||
if (x_top > x_bottom) {
|
||||
// flip scanline vertically; signed area is the same
|
||||
|
|
@ -3148,29 +3152,79 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
|
|||
dy = -dy;
|
||||
t = x0, x0 = xb, xb = t;
|
||||
}
|
||||
STBTT_assert(dy >= 0);
|
||||
STBTT_assert(dx >= 0);
|
||||
|
||||
x1 = (int) x_top;
|
||||
x2 = (int) x_bottom;
|
||||
// compute intersection with y axis at x1+1
|
||||
y_crossing = (x1+1 - x0) * dy + y_top;
|
||||
y_crossing = y_top + dy * (x1+1 - x0);
|
||||
|
||||
// compute intersection with y axis at x2
|
||||
y_final = y_top + dy * (x2 - x0);
|
||||
|
||||
// x1 x_top x2 x_bottom
|
||||
// y_top +------|-----+------------+------------+--------|---+------------+
|
||||
// | | | | | |
|
||||
// | | | | | |
|
||||
// sy0 | Txxxxx|............|............|............|............|
|
||||
// y_crossing | *xxxxx.......|............|............|............|
|
||||
// | | xxxxx..|............|............|............|
|
||||
// | | /- xx*xxxx........|............|............|
|
||||
// | | dy < | xxxxxx..|............|............|
|
||||
// y_final | | \- | xx*xxx.........|............|
|
||||
// sy1 | | | | xxxxxB...|............|
|
||||
// | | | | | |
|
||||
// | | | | | |
|
||||
// y_bottom +------------+------------+------------+------------+------------+
|
||||
//
|
||||
// goal is to measure the area covered by '.' in each pixel
|
||||
|
||||
// if x2 is right at the right edge of x1, y_crossing can blow up, github #1057
|
||||
// @TODO: maybe test against sy1 rather than y_bottom?
|
||||
if (y_crossing > y_bottom)
|
||||
y_crossing = y_bottom;
|
||||
|
||||
sign = e->direction;
|
||||
// area of the rectangle covered from y0..y_crossing
|
||||
area = sign * (y_crossing-sy0);
|
||||
// area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing)
|
||||
scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2);
|
||||
|
||||
step = sign * dy;
|
||||
// area of the rectangle covered from sy0..y_crossing
|
||||
area = sign * (y_crossing-sy0);
|
||||
|
||||
// area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing)
|
||||
scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top);
|
||||
|
||||
// check if final y_crossing is blown up; no test case for this
|
||||
if (y_final > y_bottom) {
|
||||
y_final = y_bottom;
|
||||
dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom
|
||||
}
|
||||
|
||||
// in second pixel, area covered by line segment found in first pixel
|
||||
// is always a rectangle 1 wide * the height of that line segment; this
|
||||
// is exactly what the variable 'area' stores. it also gets a contribution
|
||||
// from the line segment within it. the THIRD pixel will get the first
|
||||
// pixel's rectangle contribution, the second pixel's rectangle contribution,
|
||||
// and its own contribution. the 'own contribution' is the same in every pixel except
|
||||
// the leftmost and rightmost, a trapezoid that slides down in each pixel.
|
||||
// the second pixel's contribution to the third pixel will be the
|
||||
// rectangle 1 wide times the height change in the second pixel, which is dy.
|
||||
|
||||
step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x,
|
||||
// which multiplied by 1-pixel-width is how much pixel area changes for each step in x
|
||||
// so the area advances by 'step' every time
|
||||
|
||||
for (x = x1+1; x < x2; ++x) {
|
||||
scanline[x] += area + step/2;
|
||||
scanline[x] += area + step/2; // area of trapezoid is 1*step/2
|
||||
area += step;
|
||||
}
|
||||
y_crossing += dy * (x2 - (x1+1));
|
||||
STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down
|
||||
STBTT_assert(sy1 > y_final-0.01f);
|
||||
|
||||
STBTT_assert(STBTT_fabs(area) <= 1.01f);
|
||||
|
||||
scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing);
|
||||
// area covered in the last pixel is the rectangle from all the pixels to the left,
|
||||
// plus the trapezoid filled by the line segment in this pixel all the way to the right edge
|
||||
scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f);
|
||||
|
||||
// the rest of the line is filled based on the total height of the line segment in this pixel
|
||||
scanline_fill[x2] += sign * (sy1-sy0);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -3178,6 +3232,9 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
|
|||
// clipping logic. since this does not match the intended use
|
||||
// of this library, we use a different, very slow brute
|
||||
// force implementation
|
||||
// note though that this does happen some of the time because
|
||||
// x_top and x_bottom can be extrapolated at the top & bottom of
|
||||
// the shape and actually lie outside the bounding box
|
||||
int x;
|
||||
for (x=0; x < len; ++x) {
|
||||
// cases:
|
||||
|
|
@ -4414,15 +4471,14 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
|
|||
float y_frac;
|
||||
int winding = 0;
|
||||
|
||||
orig[0] = x;
|
||||
orig[1] = y;
|
||||
|
||||
// make sure y never passes through a vertex of the shape
|
||||
y_frac = (float) STBTT_fmod(y, 1.0f);
|
||||
if (y_frac < 0.01f)
|
||||
y += 0.01f;
|
||||
else if (y_frac > 0.99f)
|
||||
y -= 0.01f;
|
||||
|
||||
orig[0] = x;
|
||||
orig[1] = y;
|
||||
|
||||
// test a ray from (-infinity,y) to (x,y)
|
||||
|
|
@ -4484,7 +4540,7 @@ static float stbtt__cuberoot( float x )
|
|||
return (float) STBTT_pow( x,1.0f/3.0f);
|
||||
}
|
||||
|
||||
// x^3 + c*x^2 + b*x + a = 0
|
||||
// x^3 + a*x^2 + b*x + c = 0
|
||||
static int stbtt__solve_cubic(float a, float b, float c, float* r)
|
||||
{
|
||||
float s = -a / 3;
|
||||
|
|
@ -4589,18 +4645,17 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
|
|||
for (i=0; i < num_verts; ++i) {
|
||||
float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
|
||||
|
||||
// check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve
|
||||
float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
|
||||
if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) {
|
||||
float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;
|
||||
|
||||
float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
|
||||
if (dist2 < min_dist*min_dist)
|
||||
min_dist = (float) STBTT_sqrt(dist2);
|
||||
|
||||
if (verts[i].type == STBTT_vline) {
|
||||
float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;
|
||||
|
||||
// coarse culling against bbox
|
||||
//if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&
|
||||
// sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)
|
||||
float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
|
||||
dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
|
||||
STBTT_assert(i != 0);
|
||||
if (dist < min_dist) {
|
||||
// check position along line
|
||||
|
|
@ -4627,7 +4682,8 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
|
|||
float ax = x1-x0, ay = y1-y0;
|
||||
float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
|
||||
float mx = x0 - sx, my = y0 - sy;
|
||||
float res[3],px,py,t,it;
|
||||
float res[3] = {0.f,0.f,0.f};
|
||||
float px,py,t,it,dist2;
|
||||
float a_inv = precompute[i];
|
||||
if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula
|
||||
float a = 3*(ax*bx + ay*by);
|
||||
|
|
@ -4654,6 +4710,10 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
|
|||
float d = (mx*ax+my*ay) * a_inv;
|
||||
num = stbtt__solve_cubic(b, c, d, res);
|
||||
}
|
||||
dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
|
||||
if (dist2 < min_dist*min_dist)
|
||||
min_dist = (float) STBTT_sqrt(dist2);
|
||||
|
||||
if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {
|
||||
t = res[0], it = 1.0f - t;
|
||||
px = it*it*x0 + 2*t*it*x1 + t*t*x2;
|
||||
|
|
@ -4913,6 +4973,12 @@ STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const
|
|||
|
||||
// FULL VERSION HISTORY
|
||||
//
|
||||
// 1.25 (2021-07-11) many fixes
|
||||
// 1.24 (2020-02-05) fix warning
|
||||
// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
|
||||
// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
|
||||
// 1.21 (2019-02-25) fix warning
|
||||
// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
|
||||
// 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod
|
||||
// 1.18 (2018-01-29) add missing function
|
||||
// 1.17 (2017-07-23) make more arguments const; doc fix
|
||||
|
|
|
|||
14
src/external/vox_loader.h
vendored
|
|
@ -49,21 +49,18 @@ revision history:
|
|||
#ifndef VOX_LOADER_H
|
||||
#define VOX_LOADER_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Allow custom memory allocators
|
||||
#ifndef VOX_MALLOC
|
||||
#define VOX_MALLOC RL_MALLOC
|
||||
#define VOX_MALLOC(sz) malloc(sz)
|
||||
#endif
|
||||
#ifndef VOX_CALLOC
|
||||
#define VOX_CALLOC RL_CALLOC
|
||||
#define VOX_CALLOC(n,sz) calloc(n,sz)
|
||||
#endif
|
||||
#ifndef VOX_REALLOC
|
||||
#define VOX_REALLOC RL_REALLOC
|
||||
#define VOX_REALLOC(n,sz) realloc(n,sz)
|
||||
#endif
|
||||
#ifndef VOX_FREE
|
||||
#define VOX_FREE RL_FREE
|
||||
#define VOX_FREE(p) free(p)
|
||||
#endif
|
||||
|
||||
#define VOX_SUCCESS (0)
|
||||
|
|
@ -157,6 +154,9 @@ void Vox_FreeArrays(VoxArray3D* voxarray);
|
|||
|
||||
#ifdef VOX_LOADER_IMPLEMENTATION
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ArrayUShort helper
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ typedef struct tagBITMAPINFOHEADER {
|
|||
#endif
|
||||
|
||||
#if defined(SUPPORT_FILEFORMAT_OGG)
|
||||
// TODO: Remap malloc()/free() calls to RL_MALLOC/RL_FREE
|
||||
// TODO: Remap stb_vorbis malloc()/free() calls to RL_MALLOC/RL_FREE
|
||||
|
||||
#define STB_VORBIS_IMPLEMENTATION
|
||||
#include "external/stb_vorbis.h" // OGG loading functions
|
||||
|
|
@ -405,8 +405,6 @@ void UntrackAudioBuffer(AudioBuffer *buffer);
|
|||
// Initialize audio device
|
||||
void InitAudioDevice(void)
|
||||
{
|
||||
// TODO: Load AUDIO context memory dynamically?
|
||||
|
||||
// Init audio context
|
||||
ma_context_config ctxConfig = ma_context_config_init();
|
||||
ctxConfig.logCallback = OnLog;
|
||||
|
|
|
|||
54
src/raylib.h
|
|
@ -5,7 +5,7 @@
|
|||
* FEATURES:
|
||||
* - NO external dependencies, all required libraries included with raylib
|
||||
* - Multiplatform: Windows, Linux, FreeBSD, OpenBSD, NetBSD, DragonFly,
|
||||
* MacOS, Haiku, UWP, Android, Raspberry Pi, HTML5.
|
||||
* MacOS, Haiku, Android, Raspberry Pi, DRM native, HTML5.
|
||||
* - Written in plain C code (C99) in PascalCase/camelCase notation
|
||||
* - Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES2 - choose at compile)
|
||||
* - Unique OpenGL abstraction layer (usable as standalone module): [rlgl]
|
||||
|
|
@ -21,29 +21,28 @@
|
|||
* - Bindings to multiple programming languages available!
|
||||
*
|
||||
* NOTES:
|
||||
* One default Font is loaded on InitWindow()->LoadFontDefault() [core, text]
|
||||
* One default Texture2D is loaded on rlglInit(), 1x1 white pixel R8G8B8A8 [rlgl] (OpenGL 3.3 or ES2)
|
||||
* One default Shader is loaded on rlglInit()->rlLoadShaderDefault() [rlgl] (OpenGL 3.3 or ES2)
|
||||
* One default RenderBatch is loaded on rlglInit()->rlLoadRenderBatch() [rlgl] (OpenGL 3.3 or ES2)
|
||||
* - One default Font is loaded on InitWindow()->LoadFontDefault() [core, text]
|
||||
* - One default Texture2D is loaded on rlglInit(), 1x1 white pixel R8G8B8A8 [rlgl] (OpenGL 3.3 or ES2)
|
||||
* - One default Shader is loaded on rlglInit()->rlLoadShaderDefault() [rlgl] (OpenGL 3.3 or ES2)
|
||||
* - One default RenderBatch is loaded on rlglInit()->rlLoadRenderBatch() [rlgl] (OpenGL 3.3 or ES2)
|
||||
*
|
||||
* DEPENDENCIES (included):
|
||||
* [core] rglfw (Camilla Löwy - github.com/glfw/glfw) for window/context management and input (PLATFORM_DESKTOP)
|
||||
* [rcore] rglfw (Camilla Löwy - github.com/glfw/glfw) for window/context management and input (PLATFORM_DESKTOP)
|
||||
* [rlgl] glad (David Herberth - github.com/Dav1dde/glad) for OpenGL 3.3 extensions loading (PLATFORM_DESKTOP)
|
||||
* [raudio] miniaudio (David Reid - github.com/mackron/miniaudio) for audio device/context management
|
||||
*
|
||||
* OPTIONAL DEPENDENCIES (included):
|
||||
* [core] msf_gif (Miles Fogle) for GIF recording
|
||||
* [core] sinfl (Micha Mettke) for DEFLATE decompression algorythm
|
||||
* [core] sdefl (Micha Mettke) for DEFLATE compression algorythm
|
||||
* [textures] stb_image (Sean Barret) for images loading (BMP, TGA, PNG, JPEG, HDR...)
|
||||
* [textures] stb_image_write (Sean Barret) for image writting (BMP, TGA, PNG, JPG)
|
||||
* [textures] stb_image_resize (Sean Barret) for image resizing algorithms
|
||||
* [textures] stb_perlin (Sean Barret) for Perlin noise image generation
|
||||
* [text] stb_truetype (Sean Barret) for ttf fonts loading
|
||||
* [text] stb_rect_pack (Sean Barret) for rectangles packing
|
||||
* [models] par_shapes (Philip Rideout) for parametric 3d shapes generation
|
||||
* [models] tinyobj_loader_c (Syoyo Fujita) for models loading (OBJ, MTL)
|
||||
* [models] cgltf (Johannes Kuhlmann) for models loading (glTF)
|
||||
* [rcore] msf_gif (Miles Fogle) for GIF recording
|
||||
* [rcore] sinfl (Micha Mettke) for DEFLATE decompression algorythm
|
||||
* [rcore] sdefl (Micha Mettke) for DEFLATE compression algorythm
|
||||
* [rtextures] stb_image (Sean Barret) for images loading (BMP, TGA, PNG, JPEG, HDR...)
|
||||
* [rtextures] stb_image_write (Sean Barret) for image writting (BMP, TGA, PNG, JPG)
|
||||
* [rtextures] stb_image_resize (Sean Barret) for image resizing algorithms
|
||||
* [rtext] stb_truetype (Sean Barret) for ttf fonts loading
|
||||
* [rtext] stb_rect_pack (Sean Barret) for rectangles packing
|
||||
* [rmodels] par_shapes (Philip Rideout) for parametric 3d shapes generation
|
||||
* [rmodels] tinyobj_loader_c (Syoyo Fujita) for models loading (OBJ, MTL)
|
||||
* [rmodels] cgltf (Johannes Kuhlmann) for models loading (glTF)
|
||||
* [raudio] dr_wav (David Reid) for WAV audio file loading
|
||||
* [raudio] dr_flac (David Reid) for FLAC audio file loading
|
||||
* [raudio] dr_mp3 (David Reid) for MP3 audio file loading
|
||||
|
|
@ -83,18 +82,20 @@
|
|||
|
||||
#define RAYLIB_VERSION "4.0"
|
||||
|
||||
#ifndef RLAPI
|
||||
#define RLAPI // We are building or using rlgl as a static library (or Linux shared library)
|
||||
#endif
|
||||
|
||||
// Function specifiers in case library is build/used as a shared library (Windows)
|
||||
// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
|
||||
#if defined(_WIN32)
|
||||
#if defined(BUILD_LIBTYPE_SHARED)
|
||||
#define RLAPI __declspec(dllexport) // We are building raylib as a Win32 shared library (.dll)
|
||||
#define RLAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll)
|
||||
#elif defined(USE_LIBTYPE_SHARED)
|
||||
#define RLAPI __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll)
|
||||
#define RLAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef RLAPI
|
||||
#define RLAPI // Functions defined as 'extern' by default (implicit specifiers)
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Some basic Defines
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -1107,7 +1108,6 @@ RLAPI int GetTouchY(void); // Get touch posit
|
|||
RLAPI Vector2 GetTouchPosition(int index); // Get touch position XY for a touch point index (relative to screen size)
|
||||
RLAPI int GetTouchPointId(int index); // Get touch point identifier for given index
|
||||
RLAPI int GetTouchPointCount(void); // Get number of touch points
|
||||
RLAPI int GetTouchEvent(void); // Get last touch event registered
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Gestures and Touch Handling Functions (Module: rgestures)
|
||||
|
|
@ -1187,6 +1187,7 @@ RLAPI bool CheckCollisionPointRec(Vector2 point, Rectangle rec);
|
|||
RLAPI bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius); // Check if point is inside circle
|
||||
RLAPI bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3); // Check if point is inside a triangle
|
||||
RLAPI bool CheckCollisionLines(Vector2 startPos1, Vector2 endPos1, Vector2 startPos2, Vector2 endPos2, Vector2 *collisionPoint); // Check the collision between two lines defined by two points each, returns collision point by reference
|
||||
RLAPI bool CheckCollisionPointLine(Vector2 point, Vector2 p1, Vector2 p2, int threshold); // Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold]
|
||||
RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2); // Get collision rectangle for two rectangles collision
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
|
|
@ -1212,7 +1213,6 @@ RLAPI Image GenImageGradientH(int width, int height, Color left, Color right);
|
|||
RLAPI Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer); // Generate image: radial gradient
|
||||
RLAPI Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2); // Generate image: checked
|
||||
RLAPI Image GenImageWhiteNoise(int width, int height, float factor); // Generate image: white noise
|
||||
RLAPI Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float scale); // Generate image: perlin noise
|
||||
RLAPI Image GenImageCellular(int width, int height, int tileSize); // Generate image: cellular algorithm, bigger tileSize means bigger cells
|
||||
|
||||
// Image manipulation functions
|
||||
|
|
@ -1382,7 +1382,9 @@ RLAPI void DrawSphere(Vector3 centerPos, float radius, Color color);
|
|||
RLAPI void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere with extended parameters
|
||||
RLAPI void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere wires
|
||||
RLAPI void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone
|
||||
RLAPI void DrawCylinderEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color); // Draw a cylinder with base at startPos and top at endPos
|
||||
RLAPI void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone wires
|
||||
RLAPI void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color); // Draw a cylinder wires with base at startPos and top at endPos
|
||||
RLAPI void DrawPlane(Vector3 centerPos, Vector2 size, Color color); // Draw a plane XZ
|
||||
RLAPI void DrawRay(Ray ray, Color color); // Draw a ray line
|
||||
RLAPI void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0))
|
||||
|
|
|
|||
205
src/raymath.h
|
|
@ -51,21 +51,22 @@
|
|||
#error "Specifying both RAYMATH_IMPLEMENTATION and RAYMATH_STATIC_INLINE is contradictory"
|
||||
#endif
|
||||
|
||||
// Function specifiers definition
|
||||
#if defined(RAYMATH_IMPLEMENTATION)
|
||||
#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
|
||||
#define RMDEF __declspec(dllexport) extern inline // We are building raylib as a Win32 shared library (.dll).
|
||||
#define RMAPI __declspec(dllexport) extern inline // We are building raylib as a Win32 shared library (.dll).
|
||||
#elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED)
|
||||
#define RMDEF __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll)
|
||||
#define RMAPI __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll)
|
||||
#else
|
||||
#define RMDEF extern inline // Provide external definition
|
||||
#define RMAPI extern inline // Provide external definition
|
||||
#endif
|
||||
#elif defined(RAYMATH_STATIC_INLINE)
|
||||
#define RMDEF static inline // Functions may be inlined, no external out-of-line definition
|
||||
#define RMAPI static inline // Functions may be inlined, no external out-of-line definition
|
||||
#else
|
||||
#if defined(__TINYC__)
|
||||
#define RMDEF static inline // WARNING: Plain inline not supported by tinycc (See issue #435)
|
||||
#define RMAPI static inline // plain inline not supported by tinycc (See issue #435)
|
||||
#else
|
||||
#define RMDEF inline // Functions may be inlined or external definition used
|
||||
#define RMAPI inline // Functions may be inlined or external definition used
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
@ -160,7 +161,7 @@ typedef struct float16 {
|
|||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Clamp float value
|
||||
RMDEF float Clamp(float value, float min, float max)
|
||||
RMAPI float Clamp(float value, float min, float max)
|
||||
{
|
||||
float result = (value < min)? min : value;
|
||||
|
||||
|
|
@ -170,7 +171,7 @@ RMDEF float Clamp(float value, float min, float max)
|
|||
}
|
||||
|
||||
// Calculate linear interpolation between two floats
|
||||
RMDEF float Lerp(float start, float end, float amount)
|
||||
RMAPI float Lerp(float start, float end, float amount)
|
||||
{
|
||||
float result = start + amount*(end - start);
|
||||
|
||||
|
|
@ -178,7 +179,7 @@ RMDEF float Lerp(float start, float end, float amount)
|
|||
}
|
||||
|
||||
// Normalize input value within input range
|
||||
RMDEF float Normalize(float value, float start, float end)
|
||||
RMAPI float Normalize(float value, float start, float end)
|
||||
{
|
||||
float result = (value - start)/(end - start);
|
||||
|
||||
|
|
@ -186,7 +187,7 @@ RMDEF float Normalize(float value, float start, float end)
|
|||
}
|
||||
|
||||
// Remap input value within input range to output range
|
||||
RMDEF float Remap(float value, float inputStart, float inputEnd, float outputStart, float outputEnd)
|
||||
RMAPI float Remap(float value, float inputStart, float inputEnd, float outputStart, float outputEnd)
|
||||
{
|
||||
float result =(value - inputStart)/(inputEnd - inputStart)*(outputEnd - outputStart) + outputStart;
|
||||
|
||||
|
|
@ -198,7 +199,7 @@ RMDEF float Remap(float value, float inputStart, float inputEnd, float outputSta
|
|||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Vector with components value 0.0f
|
||||
RMDEF Vector2 Vector2Zero(void)
|
||||
RMAPI Vector2 Vector2Zero(void)
|
||||
{
|
||||
Vector2 result = { 0.0f, 0.0f };
|
||||
|
||||
|
|
@ -206,7 +207,7 @@ RMDEF Vector2 Vector2Zero(void)
|
|||
}
|
||||
|
||||
// Vector with components value 1.0f
|
||||
RMDEF Vector2 Vector2One(void)
|
||||
RMAPI Vector2 Vector2One(void)
|
||||
{
|
||||
Vector2 result = { 1.0f, 1.0f };
|
||||
|
||||
|
|
@ -214,7 +215,7 @@ RMDEF Vector2 Vector2One(void)
|
|||
}
|
||||
|
||||
// Add two vectors (v1 + v2)
|
||||
RMDEF Vector2 Vector2Add(Vector2 v1, Vector2 v2)
|
||||
RMAPI Vector2 Vector2Add(Vector2 v1, Vector2 v2)
|
||||
{
|
||||
Vector2 result = { v1.x + v2.x, v1.y + v2.y };
|
||||
|
||||
|
|
@ -222,7 +223,7 @@ RMDEF Vector2 Vector2Add(Vector2 v1, Vector2 v2)
|
|||
}
|
||||
|
||||
// Add vector and float value
|
||||
RMDEF Vector2 Vector2AddValue(Vector2 v, float add)
|
||||
RMAPI Vector2 Vector2AddValue(Vector2 v, float add)
|
||||
{
|
||||
Vector2 result = { v.x + add, v.y + add };
|
||||
|
||||
|
|
@ -230,7 +231,7 @@ RMDEF Vector2 Vector2AddValue(Vector2 v, float add)
|
|||
}
|
||||
|
||||
// Subtract two vectors (v1 - v2)
|
||||
RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2)
|
||||
RMAPI Vector2 Vector2Subtract(Vector2 v1, Vector2 v2)
|
||||
{
|
||||
Vector2 result = { v1.x - v2.x, v1.y - v2.y };
|
||||
|
||||
|
|
@ -238,7 +239,7 @@ RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2)
|
|||
}
|
||||
|
||||
// Subtract vector by float value
|
||||
RMDEF Vector2 Vector2SubtractValue(Vector2 v, float sub)
|
||||
RMAPI Vector2 Vector2SubtractValue(Vector2 v, float sub)
|
||||
{
|
||||
Vector2 result = { v.x - sub, v.y - sub };
|
||||
|
||||
|
|
@ -246,7 +247,7 @@ RMDEF Vector2 Vector2SubtractValue(Vector2 v, float sub)
|
|||
}
|
||||
|
||||
// Calculate vector length
|
||||
RMDEF float Vector2Length(Vector2 v)
|
||||
RMAPI float Vector2Length(Vector2 v)
|
||||
{
|
||||
float result = sqrtf((v.x*v.x) + (v.y*v.y));
|
||||
|
||||
|
|
@ -254,7 +255,7 @@ RMDEF float Vector2Length(Vector2 v)
|
|||
}
|
||||
|
||||
// Calculate vector square length
|
||||
RMDEF float Vector2LengthSqr(Vector2 v)
|
||||
RMAPI float Vector2LengthSqr(Vector2 v)
|
||||
{
|
||||
float result = (v.x*v.x) + (v.y*v.y);
|
||||
|
||||
|
|
@ -262,7 +263,7 @@ RMDEF float Vector2LengthSqr(Vector2 v)
|
|||
}
|
||||
|
||||
// Calculate two vectors dot product
|
||||
RMDEF float Vector2DotProduct(Vector2 v1, Vector2 v2)
|
||||
RMAPI float Vector2DotProduct(Vector2 v1, Vector2 v2)
|
||||
{
|
||||
float result = (v1.x*v2.x + v1.y*v2.y);
|
||||
|
||||
|
|
@ -270,7 +271,7 @@ RMDEF float Vector2DotProduct(Vector2 v1, Vector2 v2)
|
|||
}
|
||||
|
||||
// Calculate distance between two vectors
|
||||
RMDEF float Vector2Distance(Vector2 v1, Vector2 v2)
|
||||
RMAPI float Vector2Distance(Vector2 v1, Vector2 v2)
|
||||
{
|
||||
float result = sqrtf((v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y));
|
||||
|
||||
|
|
@ -278,7 +279,7 @@ RMDEF float Vector2Distance(Vector2 v1, Vector2 v2)
|
|||
}
|
||||
|
||||
// Calculate angle from two vectors in X-axis
|
||||
RMDEF float Vector2Angle(Vector2 v1, Vector2 v2)
|
||||
RMAPI float Vector2Angle(Vector2 v1, Vector2 v2)
|
||||
{
|
||||
float result = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI);
|
||||
|
||||
|
|
@ -288,7 +289,7 @@ RMDEF float Vector2Angle(Vector2 v1, Vector2 v2)
|
|||
}
|
||||
|
||||
// Scale vector (multiply by value)
|
||||
RMDEF Vector2 Vector2Scale(Vector2 v, float scale)
|
||||
RMAPI Vector2 Vector2Scale(Vector2 v, float scale)
|
||||
{
|
||||
Vector2 result = { v.x*scale, v.y*scale };
|
||||
|
||||
|
|
@ -296,7 +297,7 @@ RMDEF Vector2 Vector2Scale(Vector2 v, float scale)
|
|||
}
|
||||
|
||||
// Multiply vector by vector
|
||||
RMDEF Vector2 Vector2Multiply(Vector2 v1, Vector2 v2)
|
||||
RMAPI Vector2 Vector2Multiply(Vector2 v1, Vector2 v2)
|
||||
{
|
||||
Vector2 result = { v1.x*v2.x, v1.y*v2.y };
|
||||
|
||||
|
|
@ -304,7 +305,7 @@ RMDEF Vector2 Vector2Multiply(Vector2 v1, Vector2 v2)
|
|||
}
|
||||
|
||||
// Negate vector
|
||||
RMDEF Vector2 Vector2Negate(Vector2 v)
|
||||
RMAPI Vector2 Vector2Negate(Vector2 v)
|
||||
{
|
||||
Vector2 result = { -v.x, -v.y };
|
||||
|
||||
|
|
@ -312,7 +313,7 @@ RMDEF Vector2 Vector2Negate(Vector2 v)
|
|||
}
|
||||
|
||||
// Divide vector by vector
|
||||
RMDEF Vector2 Vector2Divide(Vector2 v1, Vector2 v2)
|
||||
RMAPI Vector2 Vector2Divide(Vector2 v1, Vector2 v2)
|
||||
{
|
||||
Vector2 result = { v1.x/v2.x, v1.y/v2.y };
|
||||
|
||||
|
|
@ -320,7 +321,7 @@ RMDEF Vector2 Vector2Divide(Vector2 v1, Vector2 v2)
|
|||
}
|
||||
|
||||
// Normalize provided vector
|
||||
RMDEF Vector2 Vector2Normalize(Vector2 v)
|
||||
RMAPI Vector2 Vector2Normalize(Vector2 v)
|
||||
{
|
||||
Vector2 result = { 0 };
|
||||
float length = sqrtf((v.x*v.x) + (v.y*v.y));
|
||||
|
|
@ -335,7 +336,7 @@ RMDEF Vector2 Vector2Normalize(Vector2 v)
|
|||
}
|
||||
|
||||
// Calculate linear interpolation between two vectors
|
||||
RMDEF Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount)
|
||||
RMAPI Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount)
|
||||
{
|
||||
Vector2 result = { 0 };
|
||||
|
||||
|
|
@ -346,7 +347,7 @@ RMDEF Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount)
|
|||
}
|
||||
|
||||
// Calculate reflected vector to normal
|
||||
RMDEF Vector2 Vector2Reflect(Vector2 v, Vector2 normal)
|
||||
RMAPI Vector2 Vector2Reflect(Vector2 v, Vector2 normal)
|
||||
{
|
||||
Vector2 result = { 0 };
|
||||
|
||||
|
|
@ -359,7 +360,7 @@ RMDEF Vector2 Vector2Reflect(Vector2 v, Vector2 normal)
|
|||
}
|
||||
|
||||
// Rotate vector by angle
|
||||
RMDEF Vector2 Vector2Rotate(Vector2 v, float angle)
|
||||
RMAPI Vector2 Vector2Rotate(Vector2 v, float angle)
|
||||
{
|
||||
Vector2 result = { 0 };
|
||||
|
||||
|
|
@ -370,7 +371,7 @@ RMDEF Vector2 Vector2Rotate(Vector2 v, float angle)
|
|||
}
|
||||
|
||||
// Move Vector towards target
|
||||
RMDEF Vector2 Vector2MoveTowards(Vector2 v, Vector2 target, float maxDistance)
|
||||
RMAPI Vector2 Vector2MoveTowards(Vector2 v, Vector2 target, float maxDistance)
|
||||
{
|
||||
Vector2 result = { 0 };
|
||||
|
||||
|
|
@ -393,7 +394,7 @@ RMDEF Vector2 Vector2MoveTowards(Vector2 v, Vector2 target, float maxDistance)
|
|||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Vector with components value 0.0f
|
||||
RMDEF Vector3 Vector3Zero(void)
|
||||
RMAPI Vector3 Vector3Zero(void)
|
||||
{
|
||||
Vector3 result = { 0.0f, 0.0f, 0.0f };
|
||||
|
||||
|
|
@ -401,7 +402,7 @@ RMDEF Vector3 Vector3Zero(void)
|
|||
}
|
||||
|
||||
// Vector with components value 1.0f
|
||||
RMDEF Vector3 Vector3One(void)
|
||||
RMAPI Vector3 Vector3One(void)
|
||||
{
|
||||
Vector3 result = { 1.0f, 1.0f, 1.0f };
|
||||
|
||||
|
|
@ -409,7 +410,7 @@ RMDEF Vector3 Vector3One(void)
|
|||
}
|
||||
|
||||
// Add two vectors
|
||||
RMDEF Vector3 Vector3Add(Vector3 v1, Vector3 v2)
|
||||
RMAPI Vector3 Vector3Add(Vector3 v1, Vector3 v2)
|
||||
{
|
||||
Vector3 result = { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z };
|
||||
|
||||
|
|
@ -417,7 +418,7 @@ RMDEF Vector3 Vector3Add(Vector3 v1, Vector3 v2)
|
|||
}
|
||||
|
||||
// Add vector and float value
|
||||
RMDEF Vector3 Vector3AddValue(Vector3 v, float add)
|
||||
RMAPI Vector3 Vector3AddValue(Vector3 v, float add)
|
||||
{
|
||||
Vector3 result = { v.x + add, v.y + add, v.z + add };
|
||||
|
||||
|
|
@ -425,7 +426,7 @@ RMDEF Vector3 Vector3AddValue(Vector3 v, float add)
|
|||
}
|
||||
|
||||
// Subtract two vectors
|
||||
RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2)
|
||||
RMAPI Vector3 Vector3Subtract(Vector3 v1, Vector3 v2)
|
||||
{
|
||||
Vector3 result = { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z };
|
||||
|
||||
|
|
@ -433,7 +434,7 @@ RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2)
|
|||
}
|
||||
|
||||
// Subtract vector by float value
|
||||
RMDEF Vector3 Vector3SubtractValue(Vector3 v, float sub)
|
||||
RMAPI Vector3 Vector3SubtractValue(Vector3 v, float sub)
|
||||
{
|
||||
Vector3 result = { v.x - sub, v.y - sub, v.z - sub };
|
||||
|
||||
|
|
@ -441,7 +442,7 @@ RMDEF Vector3 Vector3SubtractValue(Vector3 v, float sub)
|
|||
}
|
||||
|
||||
// Multiply vector by scalar
|
||||
RMDEF Vector3 Vector3Scale(Vector3 v, float scalar)
|
||||
RMAPI Vector3 Vector3Scale(Vector3 v, float scalar)
|
||||
{
|
||||
Vector3 result = { v.x*scalar, v.y*scalar, v.z*scalar };
|
||||
|
||||
|
|
@ -449,7 +450,7 @@ RMDEF Vector3 Vector3Scale(Vector3 v, float scalar)
|
|||
}
|
||||
|
||||
// Multiply vector by vector
|
||||
RMDEF Vector3 Vector3Multiply(Vector3 v1, Vector3 v2)
|
||||
RMAPI Vector3 Vector3Multiply(Vector3 v1, Vector3 v2)
|
||||
{
|
||||
Vector3 result = { v1.x*v2.x, v1.y*v2.y, v1.z*v2.z };
|
||||
|
||||
|
|
@ -457,7 +458,7 @@ RMDEF Vector3 Vector3Multiply(Vector3 v1, Vector3 v2)
|
|||
}
|
||||
|
||||
// Calculate two vectors cross product
|
||||
RMDEF Vector3 Vector3CrossProduct(Vector3 v1, Vector3 v2)
|
||||
RMAPI Vector3 Vector3CrossProduct(Vector3 v1, Vector3 v2)
|
||||
{
|
||||
Vector3 result = { v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x };
|
||||
|
||||
|
|
@ -465,7 +466,7 @@ RMDEF Vector3 Vector3CrossProduct(Vector3 v1, Vector3 v2)
|
|||
}
|
||||
|
||||
// Calculate one vector perpendicular vector
|
||||
RMDEF Vector3 Vector3Perpendicular(Vector3 v)
|
||||
RMAPI Vector3 Vector3Perpendicular(Vector3 v)
|
||||
{
|
||||
Vector3 result = { 0 };
|
||||
|
||||
|
|
@ -494,7 +495,7 @@ RMDEF Vector3 Vector3Perpendicular(Vector3 v)
|
|||
}
|
||||
|
||||
// Calculate vector length
|
||||
RMDEF float Vector3Length(const Vector3 v)
|
||||
RMAPI float Vector3Length(const Vector3 v)
|
||||
{
|
||||
float result = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
|
||||
|
||||
|
|
@ -502,7 +503,7 @@ RMDEF float Vector3Length(const Vector3 v)
|
|||
}
|
||||
|
||||
// Calculate vector square length
|
||||
RMDEF float Vector3LengthSqr(const Vector3 v)
|
||||
RMAPI float Vector3LengthSqr(const Vector3 v)
|
||||
{
|
||||
float result = v.x*v.x + v.y*v.y + v.z*v.z;
|
||||
|
||||
|
|
@ -510,7 +511,7 @@ RMDEF float Vector3LengthSqr(const Vector3 v)
|
|||
}
|
||||
|
||||
// Calculate two vectors dot product
|
||||
RMDEF float Vector3DotProduct(Vector3 v1, Vector3 v2)
|
||||
RMAPI float Vector3DotProduct(Vector3 v1, Vector3 v2)
|
||||
{
|
||||
float result = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z);
|
||||
|
||||
|
|
@ -518,7 +519,7 @@ RMDEF float Vector3DotProduct(Vector3 v1, Vector3 v2)
|
|||
}
|
||||
|
||||
// Calculate distance between two vectors
|
||||
RMDEF float Vector3Distance(Vector3 v1, Vector3 v2)
|
||||
RMAPI float Vector3Distance(Vector3 v1, Vector3 v2)
|
||||
{
|
||||
float result = 0.0f;
|
||||
|
||||
|
|
@ -531,7 +532,7 @@ RMDEF float Vector3Distance(Vector3 v1, Vector3 v2)
|
|||
}
|
||||
|
||||
// Calculate angle between two vectors in XY and XZ
|
||||
RMDEF Vector2 Vector3Angle(Vector3 v1, Vector3 v2)
|
||||
RMAPI Vector2 Vector3Angle(Vector3 v1, Vector3 v2)
|
||||
{
|
||||
Vector2 result = { 0 };
|
||||
|
||||
|
|
@ -546,7 +547,7 @@ RMDEF Vector2 Vector3Angle(Vector3 v1, Vector3 v2)
|
|||
}
|
||||
|
||||
// Negate provided vector (invert direction)
|
||||
RMDEF Vector3 Vector3Negate(Vector3 v)
|
||||
RMAPI Vector3 Vector3Negate(Vector3 v)
|
||||
{
|
||||
Vector3 result = { -v.x, -v.y, -v.z };
|
||||
|
||||
|
|
@ -554,7 +555,7 @@ RMDEF Vector3 Vector3Negate(Vector3 v)
|
|||
}
|
||||
|
||||
// Divide vector by vector
|
||||
RMDEF Vector3 Vector3Divide(Vector3 v1, Vector3 v2)
|
||||
RMAPI Vector3 Vector3Divide(Vector3 v1, Vector3 v2)
|
||||
{
|
||||
Vector3 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z };
|
||||
|
||||
|
|
@ -562,7 +563,7 @@ RMDEF Vector3 Vector3Divide(Vector3 v1, Vector3 v2)
|
|||
}
|
||||
|
||||
// Normalize provided vector
|
||||
RMDEF Vector3 Vector3Normalize(Vector3 v)
|
||||
RMAPI Vector3 Vector3Normalize(Vector3 v)
|
||||
{
|
||||
Vector3 result = v;
|
||||
|
||||
|
|
@ -580,7 +581,7 @@ RMDEF Vector3 Vector3Normalize(Vector3 v)
|
|||
// Orthonormalize provided vectors
|
||||
// Makes vectors normalized and orthogonal to each other
|
||||
// Gram-Schmidt function implementation
|
||||
RMDEF void Vector3OrthoNormalize(Vector3 *v1, Vector3 *v2)
|
||||
RMAPI void Vector3OrthoNormalize(Vector3 *v1, Vector3 *v2)
|
||||
{
|
||||
float length = 0.0f;
|
||||
float ilength = 0.0f;
|
||||
|
|
@ -613,7 +614,7 @@ RMDEF void Vector3OrthoNormalize(Vector3 *v1, Vector3 *v2)
|
|||
}
|
||||
|
||||
// Transforms a Vector3 by a given Matrix
|
||||
RMDEF Vector3 Vector3Transform(Vector3 v, Matrix mat)
|
||||
RMAPI Vector3 Vector3Transform(Vector3 v, Matrix mat)
|
||||
{
|
||||
Vector3 result = { 0 };
|
||||
|
||||
|
|
@ -629,7 +630,7 @@ RMDEF Vector3 Vector3Transform(Vector3 v, Matrix mat)
|
|||
}
|
||||
|
||||
// Transform a vector by quaternion rotation
|
||||
RMDEF Vector3 Vector3RotateByQuaternion(Vector3 v, Quaternion q)
|
||||
RMAPI Vector3 Vector3RotateByQuaternion(Vector3 v, Quaternion q)
|
||||
{
|
||||
Vector3 result = { 0 };
|
||||
|
||||
|
|
@ -641,7 +642,7 @@ RMDEF Vector3 Vector3RotateByQuaternion(Vector3 v, Quaternion q)
|
|||
}
|
||||
|
||||
// Calculate linear interpolation between two vectors
|
||||
RMDEF Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount)
|
||||
RMAPI Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount)
|
||||
{
|
||||
Vector3 result = { 0 };
|
||||
|
||||
|
|
@ -653,7 +654,7 @@ RMDEF Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount)
|
|||
}
|
||||
|
||||
// Calculate reflected vector to normal
|
||||
RMDEF Vector3 Vector3Reflect(Vector3 v, Vector3 normal)
|
||||
RMAPI Vector3 Vector3Reflect(Vector3 v, Vector3 normal)
|
||||
{
|
||||
Vector3 result = { 0 };
|
||||
|
||||
|
|
@ -671,7 +672,7 @@ RMDEF Vector3 Vector3Reflect(Vector3 v, Vector3 normal)
|
|||
}
|
||||
|
||||
// Get min value for each pair of components
|
||||
RMDEF Vector3 Vector3Min(Vector3 v1, Vector3 v2)
|
||||
RMAPI Vector3 Vector3Min(Vector3 v1, Vector3 v2)
|
||||
{
|
||||
Vector3 result = { 0 };
|
||||
|
||||
|
|
@ -683,7 +684,7 @@ RMDEF Vector3 Vector3Min(Vector3 v1, Vector3 v2)
|
|||
}
|
||||
|
||||
// Get max value for each pair of components
|
||||
RMDEF Vector3 Vector3Max(Vector3 v1, Vector3 v2)
|
||||
RMAPI Vector3 Vector3Max(Vector3 v1, Vector3 v2)
|
||||
{
|
||||
Vector3 result = { 0 };
|
||||
|
||||
|
|
@ -696,7 +697,7 @@ RMDEF Vector3 Vector3Max(Vector3 v1, Vector3 v2)
|
|||
|
||||
// Compute barycenter coordinates (u, v, w) for point p with respect to triangle (a, b, c)
|
||||
// NOTE: Assumes P is on the plane of the triangle
|
||||
RMDEF Vector3 Vector3Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c)
|
||||
RMAPI Vector3 Vector3Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c)
|
||||
{
|
||||
Vector3 result = { 0 };
|
||||
|
||||
|
|
@ -720,7 +721,7 @@ RMDEF Vector3 Vector3Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c)
|
|||
|
||||
// Projects a Vector3 from screen space into object space
|
||||
// NOTE: We are avoiding calling other raymath functions despite available
|
||||
RMDEF Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view)
|
||||
RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view)
|
||||
{
|
||||
Vector3 result = { 0 };
|
||||
|
||||
|
|
@ -803,7 +804,7 @@ RMDEF Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view)
|
|||
}
|
||||
|
||||
// Get Vector3 as float array
|
||||
RMDEF float3 Vector3ToFloatV(Vector3 v)
|
||||
RMAPI float3 Vector3ToFloatV(Vector3 v)
|
||||
{
|
||||
float3 buffer = { 0 };
|
||||
|
||||
|
|
@ -819,7 +820,7 @@ RMDEF float3 Vector3ToFloatV(Vector3 v)
|
|||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Compute matrix determinant
|
||||
RMDEF float MatrixDeterminant(Matrix mat)
|
||||
RMAPI float MatrixDeterminant(Matrix mat)
|
||||
{
|
||||
float result = 0.0f;
|
||||
|
||||
|
|
@ -840,7 +841,7 @@ RMDEF float MatrixDeterminant(Matrix mat)
|
|||
}
|
||||
|
||||
// Get the trace of the matrix (sum of the values along the diagonal)
|
||||
RMDEF float MatrixTrace(Matrix mat)
|
||||
RMAPI float MatrixTrace(Matrix mat)
|
||||
{
|
||||
float result = (mat.m0 + mat.m5 + mat.m10 + mat.m15);
|
||||
|
||||
|
|
@ -848,7 +849,7 @@ RMDEF float MatrixTrace(Matrix mat)
|
|||
}
|
||||
|
||||
// Transposes provided matrix
|
||||
RMDEF Matrix MatrixTranspose(Matrix mat)
|
||||
RMAPI Matrix MatrixTranspose(Matrix mat)
|
||||
{
|
||||
Matrix result = { 0 };
|
||||
|
||||
|
|
@ -873,7 +874,7 @@ RMDEF Matrix MatrixTranspose(Matrix mat)
|
|||
}
|
||||
|
||||
// Invert provided matrix
|
||||
RMDEF Matrix MatrixInvert(Matrix mat)
|
||||
RMAPI Matrix MatrixInvert(Matrix mat)
|
||||
{
|
||||
Matrix result = { 0 };
|
||||
|
||||
|
|
@ -920,7 +921,7 @@ RMDEF Matrix MatrixInvert(Matrix mat)
|
|||
}
|
||||
|
||||
// Normalize provided matrix
|
||||
RMDEF Matrix MatrixNormalize(Matrix mat)
|
||||
RMAPI Matrix MatrixNormalize(Matrix mat)
|
||||
{
|
||||
Matrix result = { 0 };
|
||||
|
||||
|
|
@ -959,7 +960,7 @@ RMDEF Matrix MatrixNormalize(Matrix mat)
|
|||
}
|
||||
|
||||
// Get identity matrix
|
||||
RMDEF Matrix MatrixIdentity(void)
|
||||
RMAPI Matrix MatrixIdentity(void)
|
||||
{
|
||||
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
|
|
@ -970,7 +971,7 @@ RMDEF Matrix MatrixIdentity(void)
|
|||
}
|
||||
|
||||
// Add two matrices
|
||||
RMDEF Matrix MatrixAdd(Matrix left, Matrix right)
|
||||
RMAPI Matrix MatrixAdd(Matrix left, Matrix right)
|
||||
{
|
||||
Matrix result = { 0 };
|
||||
|
||||
|
|
@ -995,7 +996,7 @@ RMDEF Matrix MatrixAdd(Matrix left, Matrix right)
|
|||
}
|
||||
|
||||
// Subtract two matrices (left - right)
|
||||
RMDEF Matrix MatrixSubtract(Matrix left, Matrix right)
|
||||
RMAPI Matrix MatrixSubtract(Matrix left, Matrix right)
|
||||
{
|
||||
Matrix result = { 0 };
|
||||
|
||||
|
|
@ -1021,7 +1022,7 @@ RMDEF Matrix MatrixSubtract(Matrix left, Matrix right)
|
|||
|
||||
// Get two matrix multiplication
|
||||
// NOTE: When multiplying matrices... the order matters!
|
||||
RMDEF Matrix MatrixMultiply(Matrix left, Matrix right)
|
||||
RMAPI Matrix MatrixMultiply(Matrix left, Matrix right)
|
||||
{
|
||||
Matrix result = { 0 };
|
||||
|
||||
|
|
@ -1046,7 +1047,7 @@ RMDEF Matrix MatrixMultiply(Matrix left, Matrix right)
|
|||
}
|
||||
|
||||
// Get translation matrix
|
||||
RMDEF Matrix MatrixTranslate(float x, float y, float z)
|
||||
RMAPI Matrix MatrixTranslate(float x, float y, float z)
|
||||
{
|
||||
Matrix result = { 1.0f, 0.0f, 0.0f, x,
|
||||
0.0f, 1.0f, 0.0f, y,
|
||||
|
|
@ -1058,7 +1059,7 @@ RMDEF Matrix MatrixTranslate(float x, float y, float z)
|
|||
|
||||
// Create rotation matrix from axis and angle
|
||||
// NOTE: Angle should be provided in radians
|
||||
RMDEF Matrix MatrixRotate(Vector3 axis, float angle)
|
||||
RMAPI Matrix MatrixRotate(Vector3 axis, float angle)
|
||||
{
|
||||
Matrix result = { 0 };
|
||||
|
||||
|
|
@ -1102,7 +1103,7 @@ RMDEF Matrix MatrixRotate(Vector3 axis, float angle)
|
|||
}
|
||||
|
||||
// Get x-rotation matrix (angle in radians)
|
||||
RMDEF Matrix MatrixRotateX(float angle)
|
||||
RMAPI Matrix MatrixRotateX(float angle)
|
||||
{
|
||||
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
|
|
@ -1121,7 +1122,7 @@ RMDEF Matrix MatrixRotateX(float angle)
|
|||
}
|
||||
|
||||
// Get y-rotation matrix (angle in radians)
|
||||
RMDEF Matrix MatrixRotateY(float angle)
|
||||
RMAPI Matrix MatrixRotateY(float angle)
|
||||
{
|
||||
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
|
|
@ -1140,7 +1141,7 @@ RMDEF Matrix MatrixRotateY(float angle)
|
|||
}
|
||||
|
||||
// Get z-rotation matrix (angle in radians)
|
||||
RMDEF Matrix MatrixRotateZ(float angle)
|
||||
RMAPI Matrix MatrixRotateZ(float angle)
|
||||
{
|
||||
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
|
|
@ -1160,7 +1161,7 @@ RMDEF Matrix MatrixRotateZ(float angle)
|
|||
|
||||
|
||||
// Get xyz-rotation matrix (angles in radians)
|
||||
RMDEF Matrix MatrixRotateXYZ(Vector3 ang)
|
||||
RMAPI Matrix MatrixRotateXYZ(Vector3 ang)
|
||||
{
|
||||
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
|
|
@ -1190,7 +1191,7 @@ RMDEF Matrix MatrixRotateXYZ(Vector3 ang)
|
|||
}
|
||||
|
||||
// Get zyx-rotation matrix (angles in radians)
|
||||
RMDEF Matrix MatrixRotateZYX(Vector3 ang)
|
||||
RMAPI Matrix MatrixRotateZYX(Vector3 ang)
|
||||
{
|
||||
Matrix result = { 0 };
|
||||
|
||||
|
|
@ -1225,7 +1226,7 @@ RMDEF Matrix MatrixRotateZYX(Vector3 ang)
|
|||
}
|
||||
|
||||
// Get scaling matrix
|
||||
RMDEF Matrix MatrixScale(float x, float y, float z)
|
||||
RMAPI Matrix MatrixScale(float x, float y, float z)
|
||||
{
|
||||
Matrix result = { x, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, y, 0.0f, 0.0f,
|
||||
|
|
@ -1236,7 +1237,7 @@ RMDEF Matrix MatrixScale(float x, float y, float z)
|
|||
}
|
||||
|
||||
// Get perspective projection matrix
|
||||
RMDEF Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far)
|
||||
RMAPI Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far)
|
||||
{
|
||||
Matrix result = { 0 };
|
||||
|
||||
|
|
@ -1269,7 +1270,7 @@ RMDEF Matrix MatrixFrustum(double left, double right, double bottom, double top,
|
|||
|
||||
// Get perspective projection matrix
|
||||
// NOTE: Angle should be provided in radians
|
||||
RMDEF Matrix MatrixPerspective(double fovy, double aspect, double near, double far)
|
||||
RMAPI Matrix MatrixPerspective(double fovy, double aspect, double near, double far)
|
||||
{
|
||||
Matrix result = { 0 };
|
||||
|
||||
|
|
@ -1295,7 +1296,7 @@ RMDEF Matrix MatrixPerspective(double fovy, double aspect, double near, double f
|
|||
}
|
||||
|
||||
// Get orthographic projection matrix
|
||||
RMDEF Matrix MatrixOrtho(double left, double right, double bottom, double top, double near, double far)
|
||||
RMAPI Matrix MatrixOrtho(double left, double right, double bottom, double top, double near, double far)
|
||||
{
|
||||
Matrix result = { 0 };
|
||||
|
||||
|
|
@ -1324,7 +1325,7 @@ RMDEF Matrix MatrixOrtho(double left, double right, double bottom, double top, d
|
|||
}
|
||||
|
||||
// Get camera look-at matrix (view matrix)
|
||||
RMDEF Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up)
|
||||
RMAPI Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up)
|
||||
{
|
||||
Matrix result = { 0 };
|
||||
|
||||
|
|
@ -1379,7 +1380,7 @@ RMDEF Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up)
|
|||
}
|
||||
|
||||
// Get float array of matrix data
|
||||
RMDEF float16 MatrixToFloatV(Matrix mat)
|
||||
RMAPI float16 MatrixToFloatV(Matrix mat)
|
||||
{
|
||||
float16 result = { 0 };
|
||||
|
||||
|
|
@ -1408,7 +1409,7 @@ RMDEF float16 MatrixToFloatV(Matrix mat)
|
|||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Add two quaternions
|
||||
RMDEF Quaternion QuaternionAdd(Quaternion q1, Quaternion q2)
|
||||
RMAPI Quaternion QuaternionAdd(Quaternion q1, Quaternion q2)
|
||||
{
|
||||
Quaternion result = {q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w};
|
||||
|
||||
|
|
@ -1416,7 +1417,7 @@ RMDEF Quaternion QuaternionAdd(Quaternion q1, Quaternion q2)
|
|||
}
|
||||
|
||||
// Add quaternion and float value
|
||||
RMDEF Quaternion QuaternionAddValue(Quaternion q, float add)
|
||||
RMAPI Quaternion QuaternionAddValue(Quaternion q, float add)
|
||||
{
|
||||
Quaternion result = {q.x + add, q.y + add, q.z + add, q.w + add};
|
||||
|
||||
|
|
@ -1424,7 +1425,7 @@ RMDEF Quaternion QuaternionAddValue(Quaternion q, float add)
|
|||
}
|
||||
|
||||
// Subtract two quaternions
|
||||
RMDEF Quaternion QuaternionSubtract(Quaternion q1, Quaternion q2)
|
||||
RMAPI Quaternion QuaternionSubtract(Quaternion q1, Quaternion q2)
|
||||
{
|
||||
Quaternion result = {q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w};
|
||||
|
||||
|
|
@ -1432,7 +1433,7 @@ RMDEF Quaternion QuaternionSubtract(Quaternion q1, Quaternion q2)
|
|||
}
|
||||
|
||||
// Subtract quaternion and float value
|
||||
RMDEF Quaternion QuaternionSubtractValue(Quaternion q, float sub)
|
||||
RMAPI Quaternion QuaternionSubtractValue(Quaternion q, float sub)
|
||||
{
|
||||
Quaternion result = {q.x - sub, q.y - sub, q.z - sub, q.w - sub};
|
||||
|
||||
|
|
@ -1440,7 +1441,7 @@ RMDEF Quaternion QuaternionSubtractValue(Quaternion q, float sub)
|
|||
}
|
||||
|
||||
// Get identity quaternion
|
||||
RMDEF Quaternion QuaternionIdentity(void)
|
||||
RMAPI Quaternion QuaternionIdentity(void)
|
||||
{
|
||||
Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
|
||||
|
|
@ -1448,7 +1449,7 @@ RMDEF Quaternion QuaternionIdentity(void)
|
|||
}
|
||||
|
||||
// Computes the length of a quaternion
|
||||
RMDEF float QuaternionLength(Quaternion q)
|
||||
RMAPI float QuaternionLength(Quaternion q)
|
||||
{
|
||||
float result = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
|
||||
|
||||
|
|
@ -1456,7 +1457,7 @@ RMDEF float QuaternionLength(Quaternion q)
|
|||
}
|
||||
|
||||
// Normalize provided quaternion
|
||||
RMDEF Quaternion QuaternionNormalize(Quaternion q)
|
||||
RMAPI Quaternion QuaternionNormalize(Quaternion q)
|
||||
{
|
||||
Quaternion result = { 0 };
|
||||
|
||||
|
|
@ -1473,7 +1474,7 @@ RMDEF Quaternion QuaternionNormalize(Quaternion q)
|
|||
}
|
||||
|
||||
// Invert provided quaternion
|
||||
RMDEF Quaternion QuaternionInvert(Quaternion q)
|
||||
RMAPI Quaternion QuaternionInvert(Quaternion q)
|
||||
{
|
||||
Quaternion result = q;
|
||||
|
||||
|
|
@ -1494,7 +1495,7 @@ RMDEF Quaternion QuaternionInvert(Quaternion q)
|
|||
}
|
||||
|
||||
// Calculate two quaternion multiplication
|
||||
RMDEF Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2)
|
||||
RMAPI Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2)
|
||||
{
|
||||
Quaternion result = { 0 };
|
||||
|
||||
|
|
@ -1510,7 +1511,7 @@ RMDEF Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2)
|
|||
}
|
||||
|
||||
// Scale quaternion by float value
|
||||
RMDEF Quaternion QuaternionScale(Quaternion q, float mul)
|
||||
RMAPI Quaternion QuaternionScale(Quaternion q, float mul)
|
||||
{
|
||||
Quaternion result = { 0 };
|
||||
|
||||
|
|
@ -1525,7 +1526,7 @@ RMDEF Quaternion QuaternionScale(Quaternion q, float mul)
|
|||
}
|
||||
|
||||
// Divide two quaternions
|
||||
RMDEF Quaternion QuaternionDivide(Quaternion q1, Quaternion q2)
|
||||
RMAPI Quaternion QuaternionDivide(Quaternion q1, Quaternion q2)
|
||||
{
|
||||
Quaternion result = { q1.x/q2.x, q1.y/q2.y, q1.z/q2.z, q1.w/q2.w };
|
||||
|
||||
|
|
@ -1533,7 +1534,7 @@ RMDEF Quaternion QuaternionDivide(Quaternion q1, Quaternion q2)
|
|||
}
|
||||
|
||||
// Calculate linear interpolation between two quaternions
|
||||
RMDEF Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount)
|
||||
RMAPI Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount)
|
||||
{
|
||||
Quaternion result = { 0 };
|
||||
|
||||
|
|
@ -1546,7 +1547,7 @@ RMDEF Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount)
|
|||
}
|
||||
|
||||
// Calculate slerp-optimized interpolation between two quaternions
|
||||
RMDEF Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount)
|
||||
RMAPI Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount)
|
||||
{
|
||||
Quaternion result = { 0 };
|
||||
|
||||
|
|
@ -1571,7 +1572,7 @@ RMDEF Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount)
|
|||
}
|
||||
|
||||
// Calculates spherical linear interpolation between two quaternions
|
||||
RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
|
||||
RMAPI Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
|
||||
{
|
||||
Quaternion result = { 0 };
|
||||
|
||||
|
|
@ -1613,7 +1614,7 @@ RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
|
|||
}
|
||||
|
||||
// Calculate quaternion based on the rotation from one vector to another
|
||||
RMDEF Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to)
|
||||
RMAPI Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to)
|
||||
{
|
||||
Quaternion result = { 0 };
|
||||
|
||||
|
|
@ -1641,7 +1642,7 @@ RMDEF Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to)
|
|||
}
|
||||
|
||||
// Get a quaternion for a given rotation matrix
|
||||
RMDEF Quaternion QuaternionFromMatrix(Matrix mat)
|
||||
RMAPI Quaternion QuaternionFromMatrix(Matrix mat)
|
||||
{
|
||||
Quaternion result = { 0 };
|
||||
|
||||
|
|
@ -1675,7 +1676,7 @@ RMDEF Quaternion QuaternionFromMatrix(Matrix mat)
|
|||
}
|
||||
|
||||
// Get a matrix for a given quaternion
|
||||
RMDEF Matrix QuaternionToMatrix(Quaternion q)
|
||||
RMAPI Matrix QuaternionToMatrix(Quaternion q)
|
||||
{
|
||||
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
|
|
@ -1709,7 +1710,7 @@ RMDEF Matrix QuaternionToMatrix(Quaternion q)
|
|||
|
||||
// Get rotation quaternion for an angle and axis
|
||||
// NOTE: angle must be provided in radians
|
||||
RMDEF Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle)
|
||||
RMAPI Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle)
|
||||
{
|
||||
Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
|
||||
|
|
@ -1754,7 +1755,7 @@ RMDEF Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle)
|
|||
}
|
||||
|
||||
// Get the rotation angle and axis for a given quaternion
|
||||
RMDEF void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle)
|
||||
RMAPI void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle)
|
||||
{
|
||||
if (fabs(q.w) > 1.0f)
|
||||
{
|
||||
|
|
@ -1792,7 +1793,7 @@ RMDEF void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle
|
|||
|
||||
// Get the quaternion equivalent to Euler angles
|
||||
// NOTE: Rotation order is ZYX
|
||||
RMDEF Quaternion QuaternionFromEuler(float pitch, float yaw, float roll)
|
||||
RMAPI Quaternion QuaternionFromEuler(float pitch, float yaw, float roll)
|
||||
{
|
||||
Quaternion result = { 0 };
|
||||
|
||||
|
|
@ -1813,7 +1814,7 @@ RMDEF Quaternion QuaternionFromEuler(float pitch, float yaw, float roll)
|
|||
|
||||
// Get the Euler angles equivalent to quaternion (roll, pitch, yaw)
|
||||
// NOTE: Angles are returned in a Vector3 struct in radians
|
||||
RMDEF Vector3 QuaternionToEuler(Quaternion q)
|
||||
RMAPI Vector3 QuaternionToEuler(Quaternion q)
|
||||
{
|
||||
Vector3 result = { 0 };
|
||||
|
||||
|
|
@ -1837,7 +1838,7 @@ RMDEF Vector3 QuaternionToEuler(Quaternion q)
|
|||
}
|
||||
|
||||
// Transform a quaternion given a transformation matrix
|
||||
RMDEF Quaternion QuaternionTransform(Quaternion q, Matrix mat)
|
||||
RMAPI Quaternion QuaternionTransform(Quaternion q, Matrix mat)
|
||||
{
|
||||
Quaternion result = { 0 };
|
||||
|
||||
|
|
|
|||
|
|
@ -279,7 +279,6 @@ void SetCameraMode(Camera camera, int mode)
|
|||
// System: EnableCursor(), DisableCursor()
|
||||
// Mouse: IsMouseButtonDown(), GetMousePosition(), GetMouseWheelMove()
|
||||
// Keys: IsKeyDown()
|
||||
// TODO: Port to quaternion-based camera (?)
|
||||
void UpdateCamera(Camera *camera)
|
||||
{
|
||||
static int swingCounter = 0; // Used for 1st person swinging movement
|
||||
|
|
@ -439,14 +438,57 @@ void UpdateCamera(Camera *camera)
|
|||
if (CAMERA.angle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD;
|
||||
else if (CAMERA.angle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD;
|
||||
|
||||
// Recalculate camera target considering translation and rotation
|
||||
Matrix translation = MatrixTranslate(0, 0, (CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER));
|
||||
Matrix rotation = MatrixRotateXYZ((Vector3){ PI*2 - CAMERA.angle.y, PI*2 - CAMERA.angle.x, 0 });
|
||||
Matrix transform = MatrixMultiply(translation, rotation);
|
||||
// Calculate translation matrix
|
||||
Matrix matTranslation = { 1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, (CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER),
|
||||
0.0f, 0.0f, 0.0f, 1.0f };
|
||||
|
||||
camera->target.x = camera->position.x - transform.m12;
|
||||
camera->target.y = camera->position.y - transform.m13;
|
||||
camera->target.z = camera->position.z - transform.m14;
|
||||
// Calculate rotation matrix
|
||||
Matrix matRotation = { 1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f };
|
||||
|
||||
float cosz = cosf(0.0f);
|
||||
float sinz = sinf(0.0f);
|
||||
float cosy = cosf(-(PI*2 - CAMERA.angle.x));
|
||||
float siny = sinf(-(PI*2 - CAMERA.angle.x));
|
||||
float cosx = cosf(-(PI*2 - CAMERA.angle.y));
|
||||
float sinx = sinf(-(PI*2 - CAMERA.angle.y));
|
||||
|
||||
matRotation.m0 = cosz*cosy;
|
||||
matRotation.m4 = (cosz*siny*sinx) - (sinz*cosx);
|
||||
matRotation.m8 = (cosz*siny*cosx) + (sinz*sinx);
|
||||
matRotation.m1 = sinz*cosy;
|
||||
matRotation.m5 = (sinz*siny*sinx) + (cosz*cosx);
|
||||
matRotation.m9 = (sinz*siny*cosx) - (cosz*sinx);
|
||||
matRotation.m2 = -siny;
|
||||
matRotation.m6 = cosy*sinx;
|
||||
matRotation.m10= cosy*cosx;
|
||||
|
||||
// Multiply translation and rotation matrices
|
||||
Matrix matTransform = { 0 };
|
||||
matTransform.m0 = matTranslation.m0*matRotation.m0 + matTranslation.m1*matRotation.m4 + matTranslation.m2*matRotation.m8 + matTranslation.m3*matRotation.m12;
|
||||
matTransform.m1 = matTranslation.m0*matRotation.m1 + matTranslation.m1*matRotation.m5 + matTranslation.m2*matRotation.m9 + matTranslation.m3*matRotation.m13;
|
||||
matTransform.m2 = matTranslation.m0*matRotation.m2 + matTranslation.m1*matRotation.m6 + matTranslation.m2*matRotation.m10 + matTranslation.m3*matRotation.m14;
|
||||
matTransform.m3 = matTranslation.m0*matRotation.m3 + matTranslation.m1*matRotation.m7 + matTranslation.m2*matRotation.m11 + matTranslation.m3*matRotation.m15;
|
||||
matTransform.m4 = matTranslation.m4*matRotation.m0 + matTranslation.m5*matRotation.m4 + matTranslation.m6*matRotation.m8 + matTranslation.m7*matRotation.m12;
|
||||
matTransform.m5 = matTranslation.m4*matRotation.m1 + matTranslation.m5*matRotation.m5 + matTranslation.m6*matRotation.m9 + matTranslation.m7*matRotation.m13;
|
||||
matTransform.m6 = matTranslation.m4*matRotation.m2 + matTranslation.m5*matRotation.m6 + matTranslation.m6*matRotation.m10 + matTranslation.m7*matRotation.m14;
|
||||
matTransform.m7 = matTranslation.m4*matRotation.m3 + matTranslation.m5*matRotation.m7 + matTranslation.m6*matRotation.m11 + matTranslation.m7*matRotation.m15;
|
||||
matTransform.m8 = matTranslation.m8*matRotation.m0 + matTranslation.m9*matRotation.m4 + matTranslation.m10*matRotation.m8 + matTranslation.m11*matRotation.m12;
|
||||
matTransform.m9 = matTranslation.m8*matRotation.m1 + matTranslation.m9*matRotation.m5 + matTranslation.m10*matRotation.m9 + matTranslation.m11*matRotation.m13;
|
||||
matTransform.m10 = matTranslation.m8*matRotation.m2 + matTranslation.m9*matRotation.m6 + matTranslation.m10*matRotation.m10 + matTranslation.m11*matRotation.m14;
|
||||
matTransform.m11 = matTranslation.m8*matRotation.m3 + matTranslation.m9*matRotation.m7 + matTranslation.m10*matRotation.m11 + matTranslation.m11*matRotation.m15;
|
||||
matTransform.m12 = matTranslation.m12*matRotation.m0 + matTranslation.m13*matRotation.m4 + matTranslation.m14*matRotation.m8 + matTranslation.m15*matRotation.m12;
|
||||
matTransform.m13 = matTranslation.m12*matRotation.m1 + matTranslation.m13*matRotation.m5 + matTranslation.m14*matRotation.m9 + matTranslation.m15*matRotation.m13;
|
||||
matTransform.m14 = matTranslation.m12*matRotation.m2 + matTranslation.m13*matRotation.m6 + matTranslation.m14*matRotation.m10 + matTranslation.m15*matRotation.m14;
|
||||
matTransform.m15 = matTranslation.m12*matRotation.m3 + matTranslation.m13*matRotation.m7 + matTranslation.m14*matRotation.m11 + matTranslation.m15*matRotation.m15;
|
||||
|
||||
camera->target.x = camera->position.x - matTransform.m12;
|
||||
camera->target.y = camera->position.y - matTransform.m13;
|
||||
camera->target.z = camera->position.z - matTransform.m14;
|
||||
|
||||
// If movement detected (some key pressed), increase swinging
|
||||
for (int i = 0; i < 6; i++) if (direction[i]) { swingCounter++; break; }
|
||||
|
|
@ -489,7 +531,6 @@ void UpdateCamera(Camera *camera)
|
|||
// Camera distance clamp
|
||||
if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
|
||||
|
||||
// TODO: It seems camera->position is not correctly updated or some rounding issue makes the camera move straight to camera->target...
|
||||
camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
|
||||
|
||||
if (CAMERA.angle.y <= 0.0f) camera->position.y = sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
|
||||
|
|
|
|||
116
src/rcore.c
|
|
@ -148,6 +148,7 @@
|
|||
|
||||
#if defined(SUPPORT_COMPRESSION_API)
|
||||
#define SINFL_IMPLEMENTATION
|
||||
#define SINFL_NO_SIMD
|
||||
#include "external/sinfl.h" // Deflate (RFC 1951) decompressor
|
||||
|
||||
#define SDEFL_IMPLEMENTATION
|
||||
|
|
@ -679,11 +680,11 @@ void android_main(struct android_app *app)
|
|||
char arg0[] = "raylib"; // NOTE: argv[] are mutable
|
||||
CORE.Android.app = app;
|
||||
|
||||
// TODO: Should we maybe report != 0 return codes somewhere?
|
||||
// NOTE: Return codes != 0 are skipped
|
||||
(void)main(1, (char *[]) { arg0, NULL });
|
||||
}
|
||||
|
||||
// TODO: Add this to header (if apps really need it)
|
||||
// NOTE: Add this to header (if apps really need it)
|
||||
struct android_app *GetAndroidApp(void)
|
||||
{
|
||||
return CORE.Android.app;
|
||||
|
|
@ -1518,7 +1519,6 @@ void SetWindowMinSize(int width, int height)
|
|||
}
|
||||
|
||||
// Set window dimensions
|
||||
// TODO: Issues on HighDPI scaling
|
||||
void SetWindowSize(int width, int height)
|
||||
{
|
||||
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
|
||||
|
|
@ -1527,8 +1527,7 @@ void SetWindowSize(int width, int height)
|
|||
#if defined(PLATFORM_WEB)
|
||||
//emscripten_set_canvas_size(width, height); // DEPRECATED!
|
||||
|
||||
// TODO: Below functions should be used to replace previous one but
|
||||
// they do not seem to work properly
|
||||
// TODO: Below functions should be used to replace previous one but they do not seem to work properly
|
||||
//emscripten_set_canvas_element_size("canvas", width, height);
|
||||
//emscripten_set_element_css_size("canvas", width, height);
|
||||
#endif
|
||||
|
|
@ -1537,13 +1536,25 @@ void SetWindowSize(int width, int height)
|
|||
// Get current screen width
|
||||
int GetScreenWidth(void)
|
||||
{
|
||||
return CORE.Window.currentFbo.width;
|
||||
return CORE.Window.screen.width;
|
||||
}
|
||||
|
||||
// Get current screen height
|
||||
int GetScreenHeight(void)
|
||||
{
|
||||
return CORE.Window.currentFbo.height;
|
||||
return CORE.Window.screen.height;
|
||||
}
|
||||
|
||||
// Get current render width which is equal to screen width * dpi scale
|
||||
int GetRenderWidth(void)
|
||||
{
|
||||
return CORE.Window.render.width;
|
||||
}
|
||||
|
||||
// Get current screen height which is equal to screen height * dpi scale
|
||||
int GetRenderHeight(void)
|
||||
{
|
||||
return CORE.Window.render.height;
|
||||
}
|
||||
|
||||
// Get native window handle
|
||||
|
|
@ -2135,8 +2146,8 @@ void EndTextureMode(void)
|
|||
SetupViewport(CORE.Window.render.width, CORE.Window.render.height);
|
||||
|
||||
// Reset current fbo to screen size
|
||||
CORE.Window.currentFbo.width = CORE.Window.screen.width;
|
||||
CORE.Window.currentFbo.height = CORE.Window.screen.height;
|
||||
CORE.Window.currentFbo.width = CORE.Window.render.width;
|
||||
CORE.Window.currentFbo.height = CORE.Window.render.height;
|
||||
}
|
||||
|
||||
// Begin custom shader mode
|
||||
|
|
@ -2171,7 +2182,17 @@ void BeginScissorMode(int x, int y, int width, int height)
|
|||
rlDrawRenderBatchActive(); // Update and draw internal render batch
|
||||
|
||||
rlEnableScissorTest();
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
{
|
||||
Vector2 scale = GetWindowScaleDPI();
|
||||
|
||||
rlScissor(x*scale.x, CORE.Window.currentFbo.height - (y + height)*scale.y, width*scale.x, height*scale.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
rlScissor(x, CORE.Window.currentFbo.height - (y + height), width, height);
|
||||
}
|
||||
}
|
||||
|
||||
// End scissor mode
|
||||
|
|
@ -2654,7 +2675,6 @@ void TakeScreenshot(const char *fileName)
|
|||
emscripten_run_script(TextFormat("saveFileFromMEMFSToDisk('%s','%s')", GetFileName(path), GetFileName(path)));
|
||||
#endif
|
||||
|
||||
// TODO: Verification required for log
|
||||
TRACELOG(LOG_INFO, "SYSTEM: [%s] Screenshot taken successfully", path);
|
||||
}
|
||||
|
||||
|
|
@ -3004,7 +3024,7 @@ unsigned char *DecompressData(unsigned char *compData, int compDataLength, int *
|
|||
#if defined(SUPPORT_COMPRESSION_API)
|
||||
// Decompress data from a valid DEFLATE stream
|
||||
data = RL_CALLOC(MAX_DECOMPRESSION_SIZE*1024*1024, 1);
|
||||
int length = sinflate(data, compData, compDataLength);
|
||||
int length = sinflate(data, MAX_DECOMPRESSION_SIZE, compData, compDataLength);
|
||||
unsigned char *temp = RL_REALLOC(data, length);
|
||||
|
||||
if (temp != NULL) data = temp;
|
||||
|
|
@ -3570,8 +3590,6 @@ Vector2 GetTouchPosition(int index)
|
|||
#if defined(PLATFORM_WEB) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
|
||||
if (index < MAX_TOUCH_POINTS) position = CORE.Input.Touch.position[index];
|
||||
else TRACELOG(LOG_WARNING, "INPUT: Required touch point out of range (Max touch points: %i)", MAX_TOUCH_POINTS);
|
||||
|
||||
// TODO: Touch position scaling required?
|
||||
#endif
|
||||
|
||||
return position;
|
||||
|
|
@ -3841,16 +3859,6 @@ static bool InitGraphicsDevice(int width, int height)
|
|||
TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
|
||||
#endif
|
||||
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
|
||||
TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
|
||||
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
|
||||
}
|
||||
|
||||
// Set window callback events
|
||||
glfwSetWindowSizeCallback(CORE.Window.handle, WindowSizeCallback); // NOTE: Resizing not allowed by default!
|
||||
|
|
@ -3912,8 +3920,13 @@ static bool InitGraphicsDevice(int width, int height)
|
|||
#if defined(DEFAULT_GRAPHIC_DEVICE_DRM)
|
||||
CORE.Window.fd = open(DEFAULT_GRAPHIC_DEVICE_DRM, O_RDWR);
|
||||
#else
|
||||
TRACELOG(LOG_INFO, "DISPLAY: No graphic card set, trying card1");
|
||||
CORE.Window.fd = open("/dev/dri/card1", O_RDWR); // VideoCore VI (Raspberry Pi 4)
|
||||
TRACELOG(LOG_INFO, "DISPLAY: No graphic card set, trying platform-gpu-card");
|
||||
CORE.Window.fd = open("/dev/dri/by-path/platform-gpu-card", O_RDWR); // VideoCore VI (Raspberry Pi 4)
|
||||
if ((-1 == CORE.Window.fd) || (drmModeGetResources(CORE.Window.fd) == NULL))
|
||||
{
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Failed to open platform-gpu-card, trying card1");
|
||||
CORE.Window.fd = open("/dev/dri/card1", O_RDWR); // Other Embedded
|
||||
}
|
||||
if ((-1 == CORE.Window.fd) || (drmModeGetResources(CORE.Window.fd) == NULL))
|
||||
{
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Failed to open graphic card1, trying card0");
|
||||
|
|
@ -4294,12 +4307,8 @@ static bool InitGraphicsDevice(int width, int height)
|
|||
rlLoadExtensions(eglGetProcAddress);
|
||||
#endif
|
||||
|
||||
// Initialize OpenGL context (states and resources)
|
||||
// NOTE: CORE.Window.screen.width and CORE.Window.screen.height not used, just stored as globals in rlgl
|
||||
rlglInit(CORE.Window.screen.width, CORE.Window.screen.height);
|
||||
|
||||
int fbWidth = CORE.Window.render.width;
|
||||
int fbHeight = CORE.Window.render.height;
|
||||
int fbWidth = CORE.Window.screen.width;
|
||||
int fbHeight = CORE.Window.screen.height;
|
||||
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
|
|
@ -4318,11 +4327,25 @@ static bool InitGraphicsDevice(int width, int height)
|
|||
}
|
||||
#endif
|
||||
|
||||
CORE.Window.currentFbo.width = fbWidth;
|
||||
CORE.Window.currentFbo.height = fbHeight;
|
||||
CORE.Window.render.width = CORE.Window.currentFbo.width;
|
||||
CORE.Window.render.height = CORE.Window.currentFbo.height;
|
||||
|
||||
// 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);
|
||||
|
||||
// Setup default viewport
|
||||
SetupViewport(fbWidth, fbHeight);
|
||||
|
||||
CORE.Window.currentFbo.width = CORE.Window.screen.width;
|
||||
CORE.Window.currentFbo.height = CORE.Window.screen.height;
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
|
||||
#endif
|
||||
TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
|
||||
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
|
||||
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
|
||||
|
||||
ClearBackground(RAYWHITE); // Default background color for raylib games :P
|
||||
|
||||
|
|
@ -4719,6 +4742,8 @@ void PollInputEvents(void)
|
|||
}
|
||||
}
|
||||
|
||||
CORE.Window.resizedLastFrame = false;
|
||||
|
||||
#if defined(SUPPORT_EVENTS_WAITING)
|
||||
glfwWaitEvents();
|
||||
#else
|
||||
|
|
@ -4726,10 +4751,6 @@ void PollInputEvents(void)
|
|||
#endif
|
||||
#endif // PLATFORM_DESKTOP
|
||||
|
||||
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
|
||||
CORE.Window.resizedLastFrame = false;
|
||||
#endif
|
||||
|
||||
// Gamepad support using emscripten API
|
||||
// NOTE: GLFW3 joystick functionality not available in web
|
||||
#if defined(PLATFORM_WEB)
|
||||
|
|
@ -4889,8 +4910,23 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height)
|
|||
if (IsWindowFullscreen()) return;
|
||||
|
||||
// Set current screen size
|
||||
#if defined(__APPLE__)
|
||||
CORE.Window.screen.width = width;
|
||||
CORE.Window.screen.height = height;
|
||||
#else
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
{
|
||||
Vector2 windowScaleDPI = GetWindowScaleDPI();
|
||||
|
||||
CORE.Window.screen.width = width/windowScaleDPI.x;
|
||||
CORE.Window.screen.height = height/windowScaleDPI.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE.Window.screen.width = width;
|
||||
CORE.Window.screen.height = height;
|
||||
}
|
||||
#endif
|
||||
|
||||
// NOTE: Postprocessing texture is not scaled to new size
|
||||
}
|
||||
|
|
@ -5432,8 +5468,6 @@ static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadE
|
|||
}
|
||||
else CORE.Input.Gamepad.ready[gamepadEvent->index] = false;
|
||||
|
||||
// TODO: Test gamepadEvent->index
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -5498,7 +5532,6 @@ static void RestoreKeyboard(void)
|
|||
|
||||
#if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
||||
// Process keyboard inputs
|
||||
// TODO: Most probably input reading and processing should be in a separate thread
|
||||
static void ProcessKeyboard(void)
|
||||
{
|
||||
#define MAX_KEYBUFFER_SIZE 32 // Max size in bytes to read
|
||||
|
|
@ -5853,7 +5886,7 @@ static void ConfigureEvdevDevice(char *device)
|
|||
static void PollKeyboardEvents(void)
|
||||
{
|
||||
// Scancode to keycode mapping for US keyboards
|
||||
// TODO: Probably replace this with a keymap from the X11 to get the correct regional map for the keyboard:
|
||||
// TODO: Replace this with a keymap from the X11 to get the correct regional map for the keyboard:
|
||||
// Currently non US keyboards will have the wrong mapping for some keys
|
||||
static const int keymapUS[] = {
|
||||
0, 256, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 45, 61, 259, 258, 81, 87, 69, 82, 84,
|
||||
|
|
@ -6339,7 +6372,6 @@ static void LoadAutomationEvents(const char *fileName)
|
|||
// Export recorded events into a file
|
||||
static void ExportAutomationEvents(const char *fileName)
|
||||
{
|
||||
// TODO: eventCount is required -> header? -> rAEL
|
||||
unsigned char fileId[4] = "rEP ";
|
||||
|
||||
// Save as binary
|
||||
|
|
|
|||
|
|
@ -412,7 +412,7 @@ void ProcessGestureEvent(GestureEvent event)
|
|||
}
|
||||
else if (GESTURES.Touch.pointCount > 2) // More than two touch points
|
||||
{
|
||||
// TODO.
|
||||
// TODO: Process gesture events for more than two points
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -98,7 +98,6 @@
|
|||
#include "external/glfw/src/x11_monitor.c"
|
||||
#include "external/glfw/src/x11_window.c"
|
||||
#include "external/glfw/src/xkb_unicode.c"
|
||||
// TODO: Joystick implementation
|
||||
#include "external/glfw/src/null_joystick.c"
|
||||
#include "external/glfw/src/posix_time.c"
|
||||
#include "external/glfw/src/posix_thread.c"
|
||||
|
|
|
|||