chg: bring back project generators `MAKE proj` (premake5)
chg: bring back most demos/ `MAKE demos` fix: ui: fixed crash when no cooked fonts were available (ui_notify) fix: html5: added pthreads support (@zpl-zak) fix: html5: allowed coi requests in localhost served contents (@zpl-zak) chg: html5: instantiate web server only if content is not being served chg: bring back demos/html5/ chg: bring back tools/editor/ chg: bring back some audio tunes chg: update docsmain
141
MAKE.bat
|
@ -15,9 +15,9 @@ if [ "$1" = "tidy" ]; then
|
|||
rm 0?-* 2> /dev/null
|
||||
rm fwk.o 2> /dev/null
|
||||
rm .art*.zip 2> /dev/null
|
||||
rm demos/lua/.art*.zip 2> /dev/null
|
||||
rm engine/bind/.art*.zip 2> /dev/null
|
||||
rm demos/html5/.art*.zip 2> /dev/null
|
||||
rm demos/lua/libfwk* 2> /dev/null
|
||||
rm engine/bind/libfwk* 2> /dev/null
|
||||
rm fwk_*.* 2> /dev/null
|
||||
rm 3rd_*.* 2> /dev/null
|
||||
rm libfwk* 2> /dev/null
|
||||
|
@ -63,7 +63,7 @@ while [ $# -ge 1 ]; do
|
|||
echo sh MAKE.bat [tidy]
|
||||
echo sh MAKE.bat [split,join]
|
||||
echo sh MAKE.bat [cook]
|
||||
echo sh MAKE.bat [sln]
|
||||
echo sh MAKE.bat [proj]
|
||||
exit
|
||||
fi
|
||||
if [ "$1" = "dll" ]; then
|
||||
|
@ -93,7 +93,7 @@ while [ $# -ge 1 ]; do
|
|||
if [ "$1" = "tcc" ]; then
|
||||
export cc="tcc -D__STDC_NO_VLA__"
|
||||
fi
|
||||
if [ "$1" = "sln" ]; then
|
||||
if [ "$1" = "proj" ]; then
|
||||
if [ "$(uname)" != "Darwin" ]; then
|
||||
chmod +x tools/premake5.linux
|
||||
tools/premake5.linux gmake
|
||||
|
@ -147,14 +147,14 @@ if [ "$(uname)" != "Darwin" ]; then
|
|||
chmod +x tools/xlsx2ini.linux
|
||||
chmod +x tools/premake5.linux
|
||||
chmod +x tools/ninja.linux
|
||||
chmod +x demos/lua/luajit.linux
|
||||
chmod +x engine/bind/luajit.linux
|
||||
|
||||
echo build=$build, type=$dll, cc=$cc, args=$args
|
||||
|
||||
# framework (as dynamic library)
|
||||
if [ "$dll" = "dll" ]; then
|
||||
echo libfwk.so && $cc -o libfwk.so engine/fwk.c -shared -fPIC -w -lX11 -lm -ldl -lpthread $flags $args
|
||||
cp libfwk.so demos/lua/
|
||||
cp libfwk.so engine/bind/
|
||||
export import="libfwk.so -Wl,-rpath,./"
|
||||
else
|
||||
# framework (static)
|
||||
|
@ -167,15 +167,14 @@ if [ "$(uname)" != "Darwin" ]; then
|
|||
|
||||
# demos
|
||||
echo hello && $cc -o hello hello.c -lm -ldl -lpthread -lX11 -w -Iengine/ $flags $args &
|
||||
# echo 00-ui && $cc -o 00-ui demos/00-ui.c -lm -ldl -lpthread -lX11 -w -Iengine/ $flags $import $args &
|
||||
# echo 01-sprite && $cc -o 01-sprite demos/01-sprite.c -lm -ldl -lpthread -lX11 -w -Iengine/ $flags $import $args &
|
||||
# echo 02-ddraw && $cc -o 02-ddraw demos/02-ddraw.c -lm -ldl -lpthread -lX11 -w -Iengine/ $flags $import $args &
|
||||
# echo 03-anims && $cc -o 03-anims demos/03-anims.c -lm -ldl -lpthread -lX11 -w -Iengine/ $flags $import $args &
|
||||
# echo 04-actor && $cc -o 04-actor demos/04-actor.c -lm -ldl -lpthread -lX11 -w -Iengine/ $flags $import $args &
|
||||
# echo 04-controller && $cc -o 04-controller demos/04-controller.c -lm -ldl -lpthread -lX11 -w -Iengine/ $flags $import $args &
|
||||
# echo 05-scene && $cc -o 05-scene demos/05-scene.c -lm -ldl -lpthread -lX11 -w -Iengine/ $flags $import $args &
|
||||
# echo 06-pbr && $cc -o 06-pbr demos/06-pbr.c -lm -ldl -lpthread -lX11 -w -Iengine/ $flags $import $args &
|
||||
# echo 07-network && $cc -o 07-network demos/07-network.c -lm -ldl -lpthread -lX11 -w -Iengine/ $flags $import $args
|
||||
echo 00-ui && $cc -o 00-ui demos/00-ui.c -lm -ldl -lpthread -lX11 -w -Iengine/ $flags $import $args &
|
||||
echo 01-sprite && $cc -o 01-sprite demos/01-sprite.c -lm -ldl -lpthread -lX11 -w -Iengine/ $flags $import $args &
|
||||
echo 02-ddraw && $cc -o 02-ddraw demos/02-ddraw.c -lm -ldl -lpthread -lX11 -w -Iengine/ $flags $import $args &
|
||||
echo 03-anims && $cc -o 03-anims demos/03-anims.c -lm -ldl -lpthread -lX11 -w -Iengine/ $flags $import $args &
|
||||
echo 04-actor && $cc -o 04-actor demos/04-actor.c -lm -ldl -lpthread -lX11 -w -Iengine/ $flags $import $args &
|
||||
echo 05-scene && $cc -o 05-scene demos/05-scene.c -lm -ldl -lpthread -lX11 -w -Iengine/ $flags $import $args &
|
||||
echo 06-controller && $cc -o 06-controller demos/06-controller.c -lm -ldl -lpthread -lX11 -w -Iengine/ $flags $import $args &
|
||||
echo 07-network && $cc -o 07-network demos/07-network.c -lm -ldl -lpthread -lX11 -w -Iengine/ $flags $import $args
|
||||
fi
|
||||
|
||||
if [ "$(uname)" = "Darwin" ]; then
|
||||
|
@ -202,14 +201,14 @@ if [ "$(uname)" = "Darwin" ]; then
|
|||
chmod +x tools/xlsx2ini.osx
|
||||
chmod +x tools/premake5.osx
|
||||
chmod +x tools/ninja.osx
|
||||
chmod +x demos/lua/luajit.osx
|
||||
chmod +x engine/bind/luajit.osx
|
||||
|
||||
echo build=$build, type=$dll, cc=$cc, args=$args
|
||||
|
||||
# framework (as dynamic library)
|
||||
if [ "$dll" = "dll" ]; then
|
||||
echo libfwk && cc -ObjC -dynamiclib -o libfwk.dylib engine/fwk.c -framework cocoa -framework iokit -framework audiotoolbox -w $flags $args
|
||||
cp libfwk.dylib demos/lua
|
||||
cp libfwk.dylib engine/bind
|
||||
export import=libfwk.dylib
|
||||
else
|
||||
# framework
|
||||
|
@ -222,15 +221,14 @@ if [ "$(uname)" = "Darwin" ]; then
|
|||
|
||||
# demos
|
||||
echo hello && cc -o hello -ObjC hello.c -w -Iengine/ $flags $args -framework cocoa -framework iokit -framework audiotoolbox &
|
||||
# echo 00-ui && cc -o 00-ui demos/00-ui.c -w -Iengine/ $import $flags $args -framework cocoa -framework iokit -framework audiotoolbox &
|
||||
# echo 01-sprite && cc -o 01-sprite demos/01-sprite.c -w -Iengine/ $import $flags $args -framework cocoa -framework iokit -framework audiotoolbox &
|
||||
# echo 02-ddraw && cc -o 02-ddraw demos/02-ddraw.c -w -Iengine/ $import $flags $args -framework cocoa -framework iokit -framework audiotoolbox &
|
||||
# echo 03-anims && cc -o 03-anims demos/03-anims.c -w -Iengine/ $import $flags $args -framework cocoa -framework iokit -framework audiotoolbox &
|
||||
# echo 04-actor && cc -o 04-actor demos/04-actor.c -w -Iengine/ $import $flags $args -framework cocoa -framework iokit -framework audiotoolbox &
|
||||
# echo 04-controller && cc -o 04-controller demos/04-controller.c -w -Iengine/ $import $flags $args -framework cocoa -framework iokit -framework audiotoolbox &
|
||||
# echo 05-scene && cc -o 05-scene demos/05-scene.c -w -Iengine/ $import $flags $args -framework cocoa -framework iokit -framework audiotoolbox &
|
||||
# echo 06-pbr && cc -o 06-pbr demos/06-pbr.c -w -Iengine/ $import $flags $args -framework cocoa -framework iokit -framework audiotoolbox &
|
||||
# echo 07-network && cc -o 07-network demos/07-network.c -w -Iengine/ $import $flags $args -framework cocoa -framework iokit -framework audiotoolbox
|
||||
echo 00-ui && cc -o 00-ui demos/00-ui.c -w -Iengine/ $import $flags $args -framework cocoa -framework iokit -framework audiotoolbox &
|
||||
echo 01-sprite && cc -o 01-sprite demos/01-sprite.c -w -Iengine/ $import $flags $args -framework cocoa -framework iokit -framework audiotoolbox &
|
||||
echo 02-ddraw && cc -o 02-ddraw demos/02-ddraw.c -w -Iengine/ $import $flags $args -framework cocoa -framework iokit -framework audiotoolbox &
|
||||
echo 03-anims && cc -o 03-anims demos/03-anims.c -w -Iengine/ $import $flags $args -framework cocoa -framework iokit -framework audiotoolbox &
|
||||
echo 04-actor && cc -o 04-actor demos/04-actor.c -w -Iengine/ $import $flags $args -framework cocoa -framework iokit -framework audiotoolbox &
|
||||
echo 05-scene && cc -o 05-scene demos/05-scene.c -w -Iengine/ $import $flags $args -framework cocoa -framework iokit -framework audiotoolbox &
|
||||
echo 06-controller && cc -o 06-controller demos/06-controller.c -w -Iengine/ $import $flags $args -framework cocoa -framework iokit -framework audiotoolbox &
|
||||
echo 07-network && cc -o 07-network demos/07-network.c -w -Iengine/ $import $flags $args -framework cocoa -framework iokit -framework audiotoolbox
|
||||
fi
|
||||
|
||||
exit
|
||||
|
@ -249,17 +247,18 @@ if "%1"=="-h" goto showhelp
|
|||
if "%1"=="help" (
|
||||
:showhelp
|
||||
echo %0 ; compile everything: `make dll dev` alias
|
||||
echo %0 [help] ; show this screen
|
||||
echo %0 [docs] ; generate tools/docs/docs.html file
|
||||
echo %0 [all] ; build everything
|
||||
echo %0 [bind] ; generate lua bindings
|
||||
echo %0 [cook] ; cook .zipfiles with tools/cook.ini cookbook
|
||||
echo %0 [docs] ; generate tools/docs/docs.html file
|
||||
echo %0 [help] ; show this screen
|
||||
echo %0 [proj] ; generate a xcode/gmake/ninja/visual studio solution
|
||||
echo %0 [sync] ; sync repo to latest
|
||||
echo %0 [tidy] ; clean up temp files
|
||||
echo %0 [bindings] ; generate demos/lua bindings
|
||||
echo %0 [checkmem] ; check untracked allocators in FWK
|
||||
echo %0 [split^|join] ; engine/fwk* ^>split^> engine/split/* or engine/split/* ^>join^> engine/fwk*
|
||||
echo %0 [amalgamation] ; combine engine/fwk* into a single-header file
|
||||
echo %0 [sln] ; generate a xcode/gmake/ninja/visual studio solution
|
||||
echo %0 [cl^|tcc^|cc^|gcc^|clang^|clang-cl] [dbg^|dev^|rel] [static^|dll] [nofwk^|nodemos^|noeditor] [vis] [-- args]
|
||||
echo %0 [cl^|tcc^|cc^|gcc^|clang^|clang-cl] [dbg^|dev^|rel] [static^|dll] [nofwk^|nodemos^|editor] [vis] [-- args]
|
||||
echo cl \
|
||||
echo tcc ^|
|
||||
echo cc ^| select compiler. must be accessible in PATH
|
||||
|
@ -272,8 +271,8 @@ if "%1"=="help" (
|
|||
echo static \ link fwk as static library
|
||||
echo dll / link fwk as dynamic library (dll^) (default^)
|
||||
echo nofwk \ do not compile framework
|
||||
echo nodemos ^| do not compile demos
|
||||
echo noeditor / do not compile editor
|
||||
echo demos ^| do compile demos
|
||||
echo editor / do compile editor
|
||||
echo vis ^> visualize invokation cmdline.
|
||||
echo args ^> after `--` separator is found, pass all remaining arguments to compiler as-is
|
||||
echo.
|
||||
|
@ -298,10 +297,10 @@ if "%1"=="cook" (
|
|||
exit /b
|
||||
)
|
||||
rem generate bindings
|
||||
if "%1"=="bindings" (
|
||||
if "%1"=="bind" (
|
||||
rem luajit
|
||||
tools\luajit tools\luajit_make_bindings.lua > fwk.lua
|
||||
move /y fwk.lua demos\lua
|
||||
move /y fwk.lua engine\bind
|
||||
|
||||
exit /b
|
||||
)
|
||||
|
@ -349,7 +348,7 @@ rem generate prior files to a github release
|
|||
if "%1"=="github" (
|
||||
rem call make.bat dll
|
||||
call make.bat docs
|
||||
call make.bat bindings
|
||||
call make.bat bind
|
||||
|
||||
call make.bat amalgamation
|
||||
call make.bat split
|
||||
|
@ -391,7 +390,7 @@ rem tidy environment
|
|||
if "%1"=="tidy" (
|
||||
move /y ??-*.png demos > nul 2> nul
|
||||
move /y ??-*.c demos > nul 2> nul
|
||||
del demos\lua\fwk.dll > nul 2> nul
|
||||
del engine\bind\fwk.dll > nul 2> nul
|
||||
del .temp*.* > nul 2> nul
|
||||
del *.zip > nul 2> nul
|
||||
del *.mem > nul 2> nul
|
||||
|
@ -427,10 +426,11 @@ set build=dev
|
|||
set args=-Iengine
|
||||
set other=
|
||||
set fwk=yes
|
||||
set demos=yes
|
||||
set editor=yes
|
||||
set hello=yes
|
||||
set demos=no
|
||||
set editor=no
|
||||
set vis=no
|
||||
set sln=no
|
||||
set proj=no
|
||||
set rc=0
|
||||
|
||||
:parse_args
|
||||
|
@ -454,7 +454,10 @@ set rc=0
|
|||
|
||||
if "%1"=="nofwk" set "fwk=no" && goto loop
|
||||
if "%1"=="nodemos" set "demos=no" && goto loop
|
||||
if "%1"=="demos" set "demos=yes" && set "hello=no" && goto loop
|
||||
if "%1"=="noeditor" set "editor=no" && goto loop
|
||||
if "%1"=="editor" set "editor=yes" && set "hello=no"&& goto loop
|
||||
if "%1"=="all" set "fwk=yes" && set "demos=yes" && set "editor=yes" && set "hello=yes" && goto loop
|
||||
|
||||
if "%1"=="tcc" set "cc=%1" && goto loop
|
||||
if "%1"=="cl" set "cc=%1" && goto loop
|
||||
|
@ -464,7 +467,7 @@ set rc=0
|
|||
if "%1"=="clang" set "cc=%1" && goto loop
|
||||
if "%1"=="clang-cl" set "cc=%1" && goto loop
|
||||
|
||||
if "%1"=="sln" set "sln=yes" && goto loop
|
||||
if "%1"=="proj" set "proj=yes" && goto loop
|
||||
|
||||
if not "%1"=="" set "other=!other! %1" && set "editor=no" && set "demos=no"
|
||||
|
||||
|
@ -503,9 +506,10 @@ if "!cc!"=="" (
|
|||
)
|
||||
|
||||
rem solution. @todo: lin/osx
|
||||
if "!sln!"=="yes" if not "%vs%"=="" pushd tools && premake5 vs20%vs% & popd
|
||||
if "!sln!"=="yes" pushd tools && premake5 ninja & popd
|
||||
if "!sln!"=="yes" pushd tools && premake5 gmake & popd & exit /b
|
||||
if "!proj!"=="yes" if not "%vs%"=="00" pushd tools && premake5 vs20%vs% & popd
|
||||
if "!proj!"=="yes" if "%vs%"=="00" pushd tools && premake5 vs2013 & popd
|
||||
if "!proj!"=="yes" pushd tools && premake5 ninja & popd
|
||||
if "!proj!"=="yes" pushd tools && premake5 gmake & popd & exit /b
|
||||
|
||||
rem --- pipeline
|
||||
rem cl tools/ass2iqe.c /Fetools/ass2iqe.exe /nologo /openmp /O2 /Oy /MT /DNDEBUG assimp.lib
|
||||
|
@ -645,30 +649,51 @@ if not "!other!"=="" (
|
|||
|
||||
rem framework
|
||||
if "!fwk!"=="yes" (
|
||||
if "!vis!"=="yes" echo !cc! engine\fwk.c !export! !args! ^&^& if "!dll!"=="dll" copy /y fwk.dll demos\lua ^> nul
|
||||
!echo! fwk && !cc! engine\fwk.c !export! !args! && if "!dll!"=="dll" copy /y fwk.dll demos\lua > nul || set rc=1
|
||||
if "!vis!"=="yes" echo !cc! engine\fwk.c !export! !args! ^&^& if "!dll!"=="dll" copy /y fwk.dll engine\bind ^> nul
|
||||
!echo! fwk && !cc! engine\fwk.c !export! !args! && if "!dll!"=="dll" copy /y fwk.dll engine\bind > nul || set rc=1
|
||||
)
|
||||
|
||||
rem editor
|
||||
if "!editor!"=="yes" (
|
||||
set edit=-DCOOK_ON_DEMAND -DUI_LESSER_SPACING -DUI_ICONS_SMALL
|
||||
if "!vis!"=="yes" echo !cc! !o! editor.exe tools\editor\editor.c !edit! !import! !args!
|
||||
rem !echo! editor && !cc! !o! editor.exe tools\editor\editor.c !edit! !import! !args! || set rc=1
|
||||
rem !echo! editor2 && !cc! !o! editor2.exe tools\editor\editor2.c !edit! !args! || set rc=1
|
||||
!echo! editor && !cc! !o! editor.exe tools\editor\editor.c !edit! !import! !args! || set rc=1
|
||||
!echo! editor2 && !cc! !o! editor2.exe tools\editor\editor2.c !edit! !args! || set rc=1
|
||||
)
|
||||
|
||||
rem demos
|
||||
if "!demos!"=="yes" (
|
||||
!echo! 00-ui && !cc! !o! 00-ui.exe demos\00-ui.c !import! !args! || set rc=1
|
||||
!echo! 01-sprite && !cc! !o! 01-sprite.exe demos\01-sprite.c !import! !args! || set rc=1
|
||||
!echo! 02-ddraw && !cc! !o! 02-ddraw.exe demos\02-ddraw.c !import! !args! || set rc=1
|
||||
!echo! 03-anims && !cc! !o! 03-anims.exe demos\03-anims.c !import! !args! || set rc=1
|
||||
!echo! 04-actor && !cc! !o! 04-actor.exe demos\04-actor.c !import! !args! || set rc=1
|
||||
!echo! 05-scene && !cc! !o! 05-scene.exe demos\05-scene.c !import! !args! || set rc=1
|
||||
!echo! 06-controller && !cc! !o! 06-controller.exe demos\06-controller.c !import! !args! || set rc=1
|
||||
!echo! 07-network && !cc! !o! 07-network.exe demos\07-network.c !import! !args! || set rc=1
|
||||
|
||||
!echo! 00-demo && !cc! !o! 00-demo.exe demos\00-demo.c !import! !args! || set rc=1
|
||||
!echo! 00-hello && !cc! !o! 00-hello.exe demos\00-hello.c !import! !args! || set rc=1
|
||||
!echo! 02-frustum && !cc! !o! 02-frustum.exe demos\02-frustum.c !import! !args! || set rc=1
|
||||
!echo! 04-lod && !cc! !o! 04-lod.exe demos\04-lod.c !import! !args! || set rc=1
|
||||
!echo! 99-audio && !cc! !o! 99-audio.exe demos\99-audio.c !import! !args! || set rc=1
|
||||
!echo! 99-cubemap && !cc! !o! 99-cubemap.exe demos\99-cubemap.c !import! !args! || set rc=1
|
||||
!echo! 99-easing && !cc! !o! 99-easing.exe demos\99-easing.c !import! !args! || set rc=1
|
||||
!echo! 99-font && !cc! !o! 99-font.exe demos\99-font.c !import! !args! || set rc=1
|
||||
!echo! 99-instanced && !cc! !o! 99-instanced.exe demos\99-instanced.c !import! !args! || set rc=1
|
||||
!echo! 99-material && !cc! !o! 99-material.exe demos\99-material.c !import! !args! || set rc=1
|
||||
!echo! 99-pbr && !cc! !o! 99-pbr.exe demos\99-pbr.c !import! !args! || set rc=1
|
||||
!echo! 99-script && !cc! !o! 99-script.exe demos\99-script.c !import! !args! || set rc=1
|
||||
!echo! 99-shadertoy && !cc! !o! 99-shadertoy.exe demos\99-shadertoy.c !import! !args! || set rc=1
|
||||
!echo! 99-spine && !cc! !o! 99-spine.exe demos\99-spine.c !import! !args! || set rc=1
|
||||
!echo! 99-sprite && !cc! !o! 99-sprite.exe demos\99-sprite.c !import! !args! || set rc=1
|
||||
!echo! 99-syncdemo && !cc! !o! 99-syncdemo.exe demos\99-syncdemo.c -I. !args! || set rc=1
|
||||
!echo! 99-video && !cc! !o! 99-video.exe demos\99-video.c !import! !args! || set rc=1
|
||||
)
|
||||
|
||||
rem hello
|
||||
if "!hello!"=="yes" (
|
||||
!echo! hello && !cc! !o! hello.exe hello.c !args! || set rc=1
|
||||
rem !echo! 00-ui && !cc! !o! 00-ui.exe demos\00-ui.c !import! !args! || set rc=1
|
||||
rem !echo! 01-sprite && !cc! !o! 01-sprite.exe demos\01-sprite.c !import! !args! || set rc=1
|
||||
rem !echo! 02-ddraw && !cc! !o! 02-ddraw.exe demos\02-ddraw.c !import! !args! || set rc=1
|
||||
rem !echo! 03-anims && !cc! !o! 03-anims.exe demos\03-anims.c !import! !args! || set rc=1
|
||||
rem !echo! 04-actor && !cc! !o! 04-actor.exe demos\04-actor.c !import! !args! || set rc=1
|
||||
rem !echo! 04-controller && !cc! !o! 04-controller.exe demos\04-controller.c !import! !args! || set rc=1
|
||||
rem !echo! 05-scene && !cc! !o! 05-scene.exe demos\05-scene.c !import! !args! || set rc=1
|
||||
rem !echo! 06-pbr && !cc! !o! 06-pbr.exe demos\06-pbr.c !import! !args! || set rc=1
|
||||
rem !echo! 07-network && !cc! !o! 07-network.exe demos\07-network.c !import! !args! || set rc=1
|
||||
)
|
||||
|
||||
rem user-defined apps
|
||||
|
@ -680,4 +705,4 @@ if "!vis!"=="yes" echo !cc! !other! !import! !args!
|
|||
rem PAUSE only if double-clicked from Windows explorer
|
||||
(((echo.%cmdcmdline%)|%WINDIR%\system32\find.exe /I "%~0")>nul)&&pause
|
||||
|
||||
cmd /c exit !rc!
|
||||
cmd /c exit !rc!
|
||||
|
|
214
README.md
|
@ -1,6 +1,6 @@
|
|||
<h1 align="center"><a href="https://bit.ly/-f-w-k-">F·W·K</a></h1>
|
||||
<h1 align="center"><a href="https://bit.ly/fwk2023">F·W·K</a></h1>
|
||||
<p align="center">
|
||||
3D game framework in C.<br/>
|
||||
3D game engine/framework in C, with Luajit and Python bindings now.<br/>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
|
@ -8,16 +8,12 @@
|
|||
</p>
|
||||
|
||||
## Goals
|
||||
- [x] ~~C++~~. C.
|
||||
- [x] ~~Fast~~. Naive.
|
||||
- [x] ~~Modern~~. Simple.
|
||||
- [x] ~~Full featured~~. Small.
|
||||
- [x] ~~Rich build system~~. Single file.
|
||||
- [x] ~~Royaltie fee~~. Free and unlicensed.
|
||||
- [x] ~~Full featured~~, ~~Fast~~, ~~Modern C++~~. Small, Naive, Simple C.
|
||||
- [x] ~~Rich build system~~, ~~Royaltie fee~~. Single file, Freely unlicensed.
|
||||
|
||||
## Features ᕦ(ᐛ)ᕤ
|
||||
- [x] Pipeline: configurable and integrated [asset pipeline](tools/cook.ini).
|
||||
- [x] Embedded: single-file header, all dependencies included.
|
||||
- [x] Embedded: [single-file header](engine/joint/fwk.h), all dependencies included.
|
||||
- [x] Compiler: MSVC, MINGW64, TCC, GCC, clang, clang-cl and emscripten.
|
||||
- [x] Linkage: Both static linkage and dynamic .dll/.so/.dylib support.
|
||||
- [x] Platform: Windows, Linux and OSX. Partial HTML5/Web support.
|
||||
|
@ -52,25 +48,36 @@
|
|||
- [x] Scene handling.
|
||||
- [x] Profiler, stats and leaks finder.
|
||||
- [x] [Editor (wip)](https://user-images.githubusercontent.com/35402248/174457347-f787a6a2-aac8-404c-a5da-f44310c3d432.mp4).
|
||||
- [x] [Documentation (wip)](https://bit.ly/-f-w-k-).
|
||||
- [x] [Documentation (wip)](https://bit.ly/fwk2023).
|
||||
|
||||
## Roadmap ᕕ(ᐛ)ᕗ (in order of arrival; ✱: partial support)
|
||||
- [ ] AI pass: actors, waypoints, pathfinding, behavior trees (h/fsm,goap), and navmesh generation.
|
||||
- [ ] Render pass: reverse-Z, automatic LODs, impostors, decals.
|
||||
- [ ] Materials: (colors✱, textures✱, matcaps✱, videos✱, shadertoys✱). Shadertoys as post-fx✱. <!--materials as postfx, as they have an update() method -->
|
||||
- [ ] Lighting: Hard/soft shadow mapping (VSM,CCSM). Baked lightmaps. Refl probes. Integrated PBR.
|
||||
- [ ] Network/VM pass: Entity/component/systems and worlds. <!-- W/ECS, gameobj, serialization:load/save/merge, diff/patch ;; dead reckoning, interpolation, extrapolation, bandwidth budgets -->
|
||||
- [ ] Core pass: struct serialization.
|
||||
- [ ] Message pipeline and replication. <!-- manual/replication channels, node sharding/clustering. -->
|
||||
- [ ] Digital signals, message buffering and event polling.
|
||||
- [ ] World streaming and level loading.
|
||||
- [ ] Scenegraphs and spatial partioning. BVH, PVS, occluders, frustum culling.
|
||||
- [ ] Server/client architecture. Hybrid P2P.
|
||||
- [ ] NAT traversal. Socketless API, message API and pub/sub wrappers (enet/websocket).
|
||||
- [ ] Editor pass = netbased + offline rendering + virtual input.
|
||||
- [ ] Basic: Gizmos✱, scene tree, property editor✱, load/save✱, undo/redo✱, copy/paste, on/off (vis,tick,ddraw,log), vcs.
|
||||
- [ ] Scenenode: node singleton display, node console, node labels, node outlines✱.<!-- node == gameobj ? -->
|
||||
- [ ] Debug: toggles on/off (billboards✱, materials, un/lit, cast shadows, wireframe, skybox✱/mie✱, fog/atmosphere, collide✱, physics).
|
||||
- [ ] Level: volumes, triggers, platforms, level streaming.
|
||||
- [ ] Sub-editor: timeline and data tracks, node graphs. <!-- worthy: will be reused into materials, animgraphs and blueprints -->
|
||||
- [ ] Sub-editor: Procedural content, brushes, noise and CSG.
|
||||
- [ ] Sub-editor: blendshapes, additive anims, head/foot/hand IKs.
|
||||
- [ ] Script pass: DLL✱ (module->plugin/sys), Lua✱, Luajit✱, Teal✱ and TypeScript.
|
||||
- [ ] Render pass: reverse-Z, automatic LODs, impostors, decals.
|
||||
- [ ] Materials: (colors✱, textures✱, matcaps✱, videos✱, shadertoys✱). Shadertoys as post-fx✱. <!--materials as postfx, as they have an update() method -->
|
||||
- [ ] Lighting: Hard/soft shadow mapping (VSM,CCSM). Baked lightmaps. Refl probes. Integrated PBR.
|
||||
- [ ] Tools pass
|
||||
- [ ] Extend shaders + bindings. Per-platform✱, per-type✱, per-asset options. GIF, PKM.
|
||||
- [ ] Extend atlas (sprite/lightmaps). Fit packing (sprites).
|
||||
- [ ] Extend bindings and messaging: parse C headers during cooking stage. <!-- msgs,docs,refl,meta,lua -- (*.c, *.h) as .proto/.pbc maybe, free reflection+automatic bindings -->
|
||||
- [ ] API pass
|
||||
- [ ] Extend math: quat2, bezier, catmull.
|
||||
- [ ] Discuss API and freeze it.
|
||||
- [ ] Document everything.
|
||||
|
||||
|
@ -183,17 +190,6 @@ int main() {
|
|||
}
|
||||
```
|
||||
|
||||
```C
|
||||
#include "fwk.h" // Minimal HTML5 sample
|
||||
void render(void *arg) {
|
||||
if( !input(KEY_ESC) ) puts("hello FWK from HTML5!");
|
||||
}
|
||||
int main() {
|
||||
window_create(75.0, 0); // 75% size, no extra flags
|
||||
window_loop(render, NULL); // game loop
|
||||
}
|
||||
```
|
||||
|
||||
```lua
|
||||
local fwk = require("fwk") -- Minimal Lua sample
|
||||
fwk.window_create(75.0,0) -- 75% size, no extra flags
|
||||
|
@ -203,6 +199,12 @@ end
|
|||
```
|
||||
|
||||
## Quickstart
|
||||
- Double-click `MAKE.bat` (Win) or `sh MAKE.bat` (Linux/OSX) to quick start.
|
||||
- `MAKE.bat all` (Win) or `sh MAKE.bat all` (Linux/OSX) to build everything.
|
||||
- `MAKE.bat proj` (Win) or `sh MAKE.bat proj` (Linux/OSX) to generate solutions/makefiles.
|
||||
- `MAKE.bat help` (Win) or `sh MAKE.bat help` (Linux/OSX) for a bunch of options.
|
||||
- `MAKE.bat hello.c` (Win) or `sh MAKE.bat hello.c` (Linux/OSX) to build a single executable.
|
||||
- Alternatively,
|
||||
```bat
|
||||
echo win/vc && cl hello.c
|
||||
echo win/clang-cl && clang-cl hello.c
|
||||
|
@ -215,94 +217,108 @@ echo osx && cc -ObjC hello.c -framework cocoa -framework iokit -fr
|
|||
```
|
||||
|
||||
## Cook
|
||||
- Most asset types need to be cooked before being used in your application. Some other assets like `.png` do not.
|
||||
- Cooked assets will be written into .zipfiles close to your executable, and mounted before entering game loop.
|
||||
- Cooked .zipfiles and your executable are the only required assets when releasing your game.
|
||||
- Cook manually your assets by invoking supplied [`tools/cook` standalone binary](tools/).
|
||||
- Cook automatically your assets by just playing your game: a runtime cook is already embedded into your binary.
|
||||
- In order to achieve this, ensure the [`tools/` folder](tools/) is close to your executable.
|
||||
- This folder contains all the related binaries to perform any asset conversion plus the [cookbook](tools/cook.ini) to do so.
|
||||
- Assets need to be cooked before being consumed in your application. The [tools/](tools/) folder contains all the related binaries to perform any asset processing plus the [cookbook](tools/cook.ini) to do so.
|
||||
- Your game will cook all your assets as long as the [`tools/`](tools/) folder is next to your executable. Alternatively, cook them all just by invoking supplied [`tools/cook` standalone binary](tools/).
|
||||
- In both cases, assets will be cooked and packed into .zipfiles next to your executable, then mounted before entering game loop. These .zipfiles plus your executable are the only required files when releasing your game.
|
||||
|
||||
## Extra tips
|
||||
- Any ico/png file named after the executable name will be automatically used as app icon.
|
||||
- Similar to the ico/png case above, the cooked .zipfiles can be named after the main executable as well.
|
||||
- Dropped files into game window will be imported & saved into [`import/`](art/engine/import) folder.
|
||||
- Update the gamepad controller database by upgrading the [`gamecontrollerdb.txt`](art/engine/input) file.
|
||||
- Depending on your IDE, you might need to browse to [`split/`](split/) sources when debugging FWK.
|
||||
- Dropped files into game window will be imported & saved into [`import/`](engine/art/import/) folder.
|
||||
- Update the gamepad controller database by upgrading the [`gamecontrollerdb.txt`](engine/art/input/) file.
|
||||
- Depending on your IDE, you might need to browse to [`engine/split/`](engine/split/) sources when debugging FWK.
|
||||
- Cook assets on demand, as opposed to cook all existing assets on depot, by using `--cook-on-demand` flag.
|
||||
- Linux/OSX users can optionally install wine and use the Windows tools instead (by using `--cook-wine` flag).
|
||||
- Disable automatic cooking by using `--cook-jobs=0` flag (not recommended).
|
||||
- Generate a project solution by dropping `split/fwk.h, fwk.c and fwk` files into it.
|
||||
- Generate a project solution by dropping `engine/fwk.h, fwk.c and fwk` files into it.
|
||||
- Auto-generated Luajit and Python bindings can be found in the [`engine/bind/`](engine/bind/) folder.
|
||||
<!-- - On windows + vc, you can use `make bindings` or `make docs` to generate everything prior to a release -->
|
||||
<!-- - Note: Windows: Assimp.dll may need [this package installed](https://www.microsoft.com/en-us/download/confirmation.aspx?id=30679).-->
|
||||
|
||||
## Credits (Artwork + demos)
|
||||
- [Nanofactory](https://sketchfab.com/3d-models/kgirls01-d2f946f58a8040ae993cda70c97b302c), for kgirls01 3D model (CC BY-NC-ND 4.0).
|
||||
- [RottingPixels](https://opengameart.org/content/2d-castle-platformer-tileset-16x16), for castle-tileset (CC0).
|
||||
- [wwwtyro](https://github.com/wwwtyro/glsl-atmosphere), for nicest rayleigh/mie scattering shader around (CC0).
|
||||
## Credits
|
||||
**Artwork**
|
||||
[Dean Evans, Raijin](https://youtu.be/RRvYkrrpMKo?t=147 "for the Map song (c)"),
|
||||
[FMS_Cat](https://gist.github.com/FMS-Cat/a1ccea3ce866c34706084e3526204f4f "for nicest VHS/VCR shader around (MIT)"),
|
||||
[Goblin165cm](https://sketchfab.com/3d-models/halloween-little-witch-ccc023590bfb4789af9322864e42d1ab "for witch 3D model (CC BY 4.0)"),
|
||||
[Nuulbee](https://sketchfab.com/3d-models/kgirls01-d2f946f58a8040ae993cda70c97b302c "for kgirls01 3D model (CC BY-NC-ND 4.0)"),
|
||||
[Quaternius](https://www.patreon.com/quaternius "for the lovely 3D robots (CC0)"),
|
||||
[Rotting Pixels](https://opengameart.org/content/2d-castle-platformer-tileset-16x16 "for castle-tileset (CC0)"),
|
||||
[Tom Lewandowski](https://QuestStudios.com "for his MIDI recordings (c)"),
|
||||
[Rye Terrell](https://github.com/wwwtyro/glsl-atmosphere "for nicest rayleigh/mie scattering shader around (CC0)"),
|
||||
**Tools**
|
||||
[Aaron Barany](https://github.com/akb825/Cuttlefish "for cuttlefish (APACHE2)"),
|
||||
[Arseny Kapoulkine](https://github.com/zeux/pugixml/ "for pugixml (MIT)"),
|
||||
[Assimp authors](https://github.com/assimp/assimp "for assimp (BSD3)"),
|
||||
[Bernhard Schelling](https://github.com/schellingb/TinySoundFont "for tml.h (Zlib) and tsf.h (MIT)"),
|
||||
[Christian Collins](http://www.schristiancollins.com "for GeneralUser GS soundfont (PD)"),
|
||||
[FFMPEG authors](https://www.ffmpeg.org/ "for ffmpeg (LGPL21)"),
|
||||
[Imagination](https://developer.imaginationtech.com/pvrtextool/ "for pvrtextoolcli (ITL)"),
|
||||
[Krzysztof Gabis](https://github.com/kgabis/ape "for split.py/join.py (MIT)"),
|
||||
[Lee Salzman](https://github.com/lsalzman/iqm/tree/5882b8c32fa622eba3861a621bb715d693573420/demo "for iqm.cpp (PD)"),
|
||||
[Martín Lucas Golini](https://github.com/SpartanJ/eepp/commit/8552941da19380d7a629c4da80a976aec5d39e5c "for emscripten-fs.html (CC0)"),
|
||||
[Mattias Gustavsson](https://github.com/mattiasgustavsson/libs "for mid.h (PD)"),
|
||||
[Michael Schmoock](http://github.com/willsteel/lcpp "for lcpp (MIT)"),
|
||||
[Morgan McGuire](https://casual-effects.com/markdeep/ "for markdeep (BSD2)"),
|
||||
[Olivier Lapicque, Konstanty Bialkowski](https://github.com/Konstanty/libmodplug "for libmodplug (PD)"),
|
||||
[Polyglot Team](https://docs.google.com/spreadsheets/d/17f0dQawb-s_Fd7DHgmVvJoEGDMH_yoSd8EYigrb0zmM/edit "for polyglot gamedev (CC0)"),
|
||||
[Tildearrow](https://github.com/tildearrow/furnace/ "for Furnace (GPL2)"),
|
||||
[Tomas Pettersson](http://www.drpetter.se/ "for sfxr (PD)"),
|
||||
[Tor Andersson](https://github.com/ccxvii/asstools "for assiqe.c (BSD)"),
|
||||
**Runtime**
|
||||
[Andreas Mantler](https://github.com/ands "for their math library (PD)"),
|
||||
[Barerose](https://github.com/barerose "for swrap (CC0) and math library (CC0)"),
|
||||
[Camilla Löwy](https://github.com/elmindreda "for glfw3 (Zlib)"),
|
||||
[Dave Rand](https://tools.ietf.org/html/rfc1978 "for ppp (PD)"),
|
||||
[David Herberth](https://github.com/dav1dde/ "for glad generated code (PD)"),
|
||||
[David Reid](https://github.com/mackron "for miniaudio (PD)"),
|
||||
[Dominic Szablewski](https://github.com/phoboslab/pl_mpeg "for pl_mpeg (MIT)"),
|
||||
[Dominik Madarász](https://github.com/zaklaus "for json5 parser (PD)"),
|
||||
[Eduard Suica](https://github.com/eduardsui/tlse "for tlse (PD)"),
|
||||
[Evan Wallace](https://github.com/evanw "for their math library (CC0)"),
|
||||
[Gargaj+cce/Peisik](https://github.com/gargaj/foxotron "for Foxotron/PBR shaders (UNLICENSE)"),
|
||||
[Guilherme Lampert](https://github.com/glampert "for their math library (PD)"),
|
||||
[Guillaume Vareille](http://tinyfiledialogs.sourceforge.net "for tinyfiledialogs (ZLIB)"),
|
||||
[Haruhiko Okumura](https://oku.edu.mie-u.ac.jp/~okumura/compression/ "for lzss (PD)"),
|
||||
[Igor Pavlov](https://www.7-zip.org/ "for LZMA (PD)"),
|
||||
[Ilya Muravyov](https://github.com/encode84 "for bcm, balz, crush, ulz, lz4x (PD)"),
|
||||
[Jon Olick](https://www.jonolick.com/ "for jo_mp1 and jo_mpeg (PD)"),
|
||||
[Joonas Pihlajamaa](https://github.com/jokkebk/JUnzip "for JUnzip library (PD)"),
|
||||
[Juliette Focault](https://github.com/juliettef/IconFontCppHeaders/blob/main/IconsMaterialDesign.h "for the generated MD header (ZLIB)"),
|
||||
[Kristoffer Grönlund](https://github.com/krig "for their math library (CC0)"),
|
||||
[Lee Salzman](https://github.com/lsalzman/iqm/tree/5882b8c32fa622eba3861a621bb715d693573420/demo "for IQM spec & player (PD)"),
|
||||
[Lee Salzman, V.Hrytsenko, D.Madarász](https://github.com/zpl-c/enet/ "for enet (MIT)"),
|
||||
[Libtomcrypt](https://github.com/libtom/libtomcrypt "for libtomcrypt (Unlicense)"),
|
||||
[Lua authors](https://www.lua.org/ "for Lua language (MIT)"),
|
||||
[Mattias Gustavsson](https://github.com/mattiasgustavsson/libs "for thread.h and https.h (PD)"),
|
||||
[Micha Mettke](https://github.com/vurtun "for their math library (PD)"),
|
||||
[Micha Mettke, Chris Willcocks, Dmitry Hrabrov](https://github.com/vurtun/nuklear "for nuklear (PD)"),
|
||||
[Michael Galetzka](https://github.com/Cultrarius/Swarmz "for swarmz (UNLICENSE)"),
|
||||
[Morten Vassvik](https://github.com/vassvik/mv_easy_font "for mv_easy_font (Unlicense)"),
|
||||
[Mārtiņš Možeiko](https://gist.github.com/mmozeiko/68f0a8459ef2f98bcd879158011cc275 "for A* pathfinding (PD)"),
|
||||
[Omar Cornut, vaiorabbit](https://github.com/ocornut/imgui/pull/3627 "for tables of unicode ranges (MIT-0)"),
|
||||
[Rabia Alhaffar](https://github.com/Rabios/ice_libs "for ice_batt.h (PD)"),
|
||||
[Rich Geldreich](https://github.com/richgel999/miniz "for miniz (PD)"),
|
||||
[Ross Williams](http://ross.net/compression/lzrw3a.html "for lzrw3a (PD)"),
|
||||
[Samuli Raivio](https://github.com/bqqbarbhg/bq_websocket "for bq_websocket (PD)"),
|
||||
[Sean Barrett](https://github.com/nothings "for stb_image, stb_image_write, stb_sprintf, stb_truetype and stb_vorbis (PD)"),
|
||||
[Sebastian Steinhauer](https://github.com/kieselsteini "for sts_mixer (PD)"),
|
||||
[Stan Melax, Cloud Wu](https://web.archive.org/web/20031204035320/http://www.melax.com/polychop/gdmag.pdf "for polychop C algorithm (PD)"),
|
||||
[Stefan Gustavson](https://github.com/stegu/perlin-noise "for simplex noise (PD)"),
|
||||
[Sterling Orsten](https://github.com/sgorsten "for their math library (UNLICENSE)"),
|
||||
[Tor Andersson](https://github.com/ccxvii/minilibs "for xml.c (PD)"),
|
||||
[Wolfgang Draxinger](https://github.com/datenwolf "for their math library (WTFPL2)"),
|
||||
|
||||
## Credits (Tools)
|
||||
- [Aaron Barany](https://github.com/akb825/Cuttlefish), for cuttlefish (APACHE2).
|
||||
- [Arseny Kapoulkine](https://github.com/zeux/pugixml/), for pugixml (MIT).
|
||||
- [Assimp authors](https://github.com/assimp/assimp), for assimp (BSD3).
|
||||
- [Bernhard Schelling](https://github.com/schellingb/TinySoundFont), for tml.h (Zlib) and tsf.h (MIT).
|
||||
- [ffmpeg authors](https://www.ffmpeg.org/), for ffmpeg (LGPL21).
|
||||
- [Imagination](https://developer.imaginationtech.com/pvrtextool/), for pvrtextoolcli (ITL).
|
||||
- [Krzysztof Gabis](https://github.com/kgabis/ape), for split.py/join.py (MIT).
|
||||
- [Lee Salzman](https://github.com/lsalzman/iqm/tree/5882b8c32fa622eba3861a621bb715d693573420/demo), for iqm.cpp (PD).
|
||||
- [Mattias Gustavsson](https://github.com/mattiasgustavsson/libs), for mid.h (PD).
|
||||
- [Michael Schmoock](http://github.com/willsteel/lcpp), for lcpp (MIT).
|
||||
- [Olivier Lapicque, Konstanty Bialkowski](https://github.com/Konstanty/libmodplug), for libmodplug (PD).
|
||||
- [Polyglot Team](https://docs.google.com/spreadsheets/d/17f0dQawb-s_Fd7DHgmVvJoEGDMH_yoSd8EYigrb0zmM/edit), for polyglot gamedev (CC0).
|
||||
- [Tildearrow](https://github.com/tildearrow/furnace/), for Furnace (GPL2).
|
||||
- [Tomas Pettersson](http://www.drpetter.se/), for sfxr (PD).
|
||||
- [Tor Andersson](https://github.com/ccxvii/asstools), for assiqe.c (BSD).
|
||||
|
||||
## Credits (Runtime)
|
||||
- [Barerose](https://github.com/barerose), for swrap (CC0).
|
||||
- [Camilla Löwy](https://github.com/elmindreda), for glfw3 (Zlib).
|
||||
- [Dave Rand](https://tools.ietf.org/html/rfc1978) for ppp (PD).
|
||||
- [David Herberth](https://github.com/dav1dde/), for glad generated code (PD).
|
||||
- [David Reid](https://github.com/mackron), for miniaudio (PD).
|
||||
- [Dominic Szablewski](https://github.com/phoboslab/pl_mpeg), for pl_mpeg (MIT).
|
||||
- [Dominik Madarász](https://github.com/zaklaus), for json5 parser (PD).
|
||||
- [Eduard Suica](https://github.com/eduardsui/tlse), for tlse (PD).
|
||||
- [Gargaj+cce/Peisik](https://github.com/gargaj/foxotron), for Foxotron/PBR shaders (UNLICENSE).
|
||||
- [Guillaume Vareille](http://tinyfiledialogs.sourceforge.net), for tinyfiledialogs (ZLIB).
|
||||
- [Haruhiko Okumura](https://oku.edu.mie-u.ac.jp/~okumura/compression/) for lzss (PD).
|
||||
- [Igor Pavlov](https://www.7-zip.org/) for LZMA (PD).
|
||||
- [Ilya Muravyov](https://github.com/encode84) for bcm, balz, crush, ulz, lz4x (PD).
|
||||
- [Jon Olick](https://www.jonolick.com/), for jo_mp1 and jo_mpeg (PD).
|
||||
- [Joonas Pihlajamaa](https://github.com/jokkebk/JUnzip), for JUnzip library (PD).
|
||||
- [Juliette Focault](https://github.com/juliettef/IconFontCppHeaders/blob/main/IconsMaterialDesign.h), for the generated MD header (ZLIB).
|
||||
- [Lee Salzman](https://github.com/lsalzman/iqm/tree/5882b8c32fa622eba3861a621bb715d693573420/demo), for IQM spec & player (PD).
|
||||
- [Lee Salzman, V.Hrytsenko, D.Madarász](https://github.com/zpl-c/enet/), for enet (MIT).
|
||||
- [Libtomcrypt](https://github.com/libtom/libtomcrypt), for libtomcrypt (Unlicense).
|
||||
- [Lua authors](https://www.lua.org/), for Lua language (MIT).
|
||||
- [Mārtiņš Možeiko](https://gist.github.com/mmozeiko/68f0a8459ef2f98bcd879158011cc275), for A* pathfinding (PD).
|
||||
- [Mattias Gustavsson](https://github.com/mattiasgustavsson/libs), for thread.h and https.h (PD).
|
||||
- [Micha Mettke, Chris Willcocks, Dmitry Hrabrov](https://github.com/vurtun/nuklear), for nuklear (PD).
|
||||
- [Michael Galetzka](https://github.com/Cultrarius/Swarmz), for swarmz (UNLICENSE).
|
||||
- [Omar Cornut, vaiorabbit](https://github.com/ocornut/imgui/pull/3627), for tables of unicode ranges (MIT-0).
|
||||
- [Rabia Alhaffar](https://github.com/Rabios/ice_libs), for ice_batt.h (PD).
|
||||
- [Rich Geldreich](https://github.com/richgel999/miniz), for miniz (PD).
|
||||
- [Ross Williams](http://ross.net/compression/lzrw3a.html) for lzrw3a (PD).
|
||||
- [Samuli Raivio](https://github.com/bqqbarbhg/bq_websocket), for bq_websocket (PD).
|
||||
- [Sean Barrett](https://github.com/nothings), for stb_image, stb_image_write, stb_sprintf, stb_truetype and stb_vorbis (PD).
|
||||
- [Sebastian Steinhauer](https://github.com/kieselsteini), for sts_mixer (PD).
|
||||
- [Stan Melax, Cloud Wu](https://web.archive.org/web/20031204035320/http://www.melax.com/polychop/gdmag.pdf), for polychop C algorithm (PD).
|
||||
- [Stefan Gustavson](https://github.com/stegu/perlin-noise), for simplex noise (PD).
|
||||
- [Tor Andersson](https://github.com/ccxvii/minilibs), for xml.c (PD).
|
||||
- [Vassvik](https://github.com/vassvik/mv_easy_font), for mv_easy_font (Unlicense).
|
||||
- Special thanks to [@ands](https://github.com/ands), [@barerose](https://github.com/barerose), [@datenwolf](https://github.com/datenwolf), [@evanw](https://github.com/evanw), [@glampert](https://github.com/glampert), [@krig](https://github.com/krig), [@sgorsten](https://github.com/sgorsten) and [@vurtun](https://github.com/vurtun) for their math libraries (PD,CC0,WTFPL2,CC0,PD,CC0,Unlicense,PD).
|
||||
<!--
|
||||
- [DavidLam](https://en.wikipedia.org/wiki/Tokamak_(software) "for tokamak physics engine (ZLIB)")
|
||||
- [ID Software, David St-Louis](https://github.com/Daivuk/PureDOOM "for PureDOOM (Doom License)")
|
||||
- [Miloslav Číž](https://codeberg.org/drummyfish/Anarch "for Anarch (CC0)")
|
||||
- [Rxi](https://github.com/rxi/autobatch "for lovely sprites & cats demo (MIT)")
|
||||
-->
|
||||
|
||||
## Unlicense
|
||||
This software is released into the [public domain](https://unlicense.org/). Also dual-licensed as [0-BSD](https://opensource.org/licenses/0BSD) or [MIT (No Attribution)](https://github.com/aws/mit-0) for those countries where public domain is a concern (sigh). Any contribution to this repository is implicitly subjected to the same release conditions aforementioned.
|
||||
|
||||
## Links
|
||||
<p>
|
||||
<a href="https://github.com/r-lyeh/FWK/issues"><img alt="Issues" src="https://img.shields.io/github/issues-raw/r-lyeh/FWK.svg"/></a>
|
||||
<a href="https://discord.gg/vu6Vt9d"><img alt="Discord" src="https://img.shields.io/discord/270565488365535232?color=5865F2&label=chat&logo=discord&logoColor=white"/></a><br/>
|
||||
Still looking for alternatives? [amulet](https://github.com/ianmaclarty/amulet), [aroma](https://github.com/leafo/aroma/), [astera](https://github.com/tek256/astera), [blendelf](https://github.com/jesterKing/BlendELF), [bullordengine](https://github.com/MarilynDafa/Bulllord-Engine), [candle](https://github.com/EvilPudding/candle), [cave](https://github.com/kieselsteini/cave), [chickpea](https://github.com/ivansafrin/chickpea), [corange](https://github.com/orangeduck/Corange), [cute](https://github.com/RandyGaul/cute_framework), [dos-like](https://github.com/mattiasgustavsson/dos-like), [ejoy2d](https://github.com/ejoy/ejoy2d), [exengine](https://github.com/exezin/exengine), [gunslinger](https://github.com/MrFrenik/gunslinger), [hate](https://github.com/excessive/hate), [island](https://github.com/island-org/island), [juno](https://github.com/rxi/juno), [l](https://github.com/Lyatus/L), [lgf](https://github.com/Planimeter/lgf), [limbus](https://github.com/redien/limbus), [love](https://github.com/love2d/love/), [lovr](https://github.com/bjornbytes/lovr), [mini3d](https://github.com/mini3d/mini3d), [mintaro](https://github.com/mackron/mintaro), [mio](https://github.com/ccxvii/mio), [olive.c](https://github.com/tsoding/olive.c), [opensource](https://github.com/w23/OpenSource), [ouzel](https://github.com/elnormous/ouzel/), [pez](https://github.com/prideout/pez), [pixie](https://github.com/mattiasgustavsson/pixie), [punity](https://github.com/martincohen/Punity), [r96](https://github.com/badlogic/r96), [ricotech](https://github.com/dbechrd/RicoTech), [rizz](https://github.com/septag/rizz), [tigr](https://github.com/erkkah/tigr), [yourgamelib](https://github.com/duddel/yourgamelib)
|
||||
|
||||
Still looking for alternatives?
|
||||
[amulet](https://github.com/ianmaclarty/amulet), [aroma](https://github.com/leafo/aroma/), [astera](https://github.com/tek256/astera), [blendelf](https://github.com/jesterKing/BlendELF), [bullordengine](https://github.com/MarilynDafa/Bulllord-Engine), [candle](https://github.com/EvilPudding/candle), [cave](https://github.com/kieselsteini/cave), [chickpea](https://github.com/ivansafrin/chickpea), [corange](https://github.com/orangeduck/Corange), [cute](https://github.com/RandyGaul/cute_framework), [dos-like](https://github.com/mattiasgustavsson/dos-like), [ejoy2d](https://github.com/ejoy/ejoy2d), [exengine](https://github.com/exezin/exengine), [gunslinger](https://github.com/MrFrenik/gunslinger), [hate](https://github.com/excessive/hate), [island](https://github.com/island-org/island), [juno](https://github.com/rxi/juno), [l](https://github.com/Lyatus/L), [lgf](https://github.com/Planimeter/lgf), [limbus](https://github.com/redien/limbus), [love](https://github.com/love2d/love/), [lovr](https://github.com/bjornbytes/lovr), [mini3d](https://github.com/mini3d/mini3d), [mintaro](https://github.com/mackron/mintaro), [mio](https://github.com/ccxvii/mio), [olive.c](https://github.com/tsoding/olive.c), [opensource](https://github.com/w23/OpenSource), [ouzel](https://github.com/elnormous/ouzel/), [pez](https://github.com/prideout/pez), [pixie](https://github.com/mattiasgustavsson/pixie), [punity](https://github.com/martincohen/Punity), [r96](https://github.com/badlogic/r96), [ricotech](https://github.com/dbechrd/RicoTech), [rizz](https://github.com/septag/rizz), [tigr](https://github.com/erkkah/tigr), [yourgamelib](https://github.com/duddel/yourgamelib)
|
||||
</p>
|
||||
<a href="https://github.com/r-lyeh/FWK/issues"><img alt="Issues" src="https://img.shields.io/github/issues-raw/r-lyeh/FWK.svg"/></a> <a href="https://discord.gg/vu6Vt9d"><img alt="Discord" src="https://img.shields.io/discord/270565488365535232?color=5865F2&label=chat&logo=discord&logoColor=white"/></a>
|
||||
|
|
|
@ -0,0 +1,278 @@
|
|||
// framework demo
|
||||
// - rlyeh, public domain
|
||||
|
||||
#include "fwk.h"
|
||||
|
||||
int main() {
|
||||
// options
|
||||
bool do_about = 0;
|
||||
float do_scale = 0.10f;
|
||||
bool do_debugdraw = 0;
|
||||
float do_gamepad_deadzone = 0.15f;
|
||||
vec2 do_gamepad_polarity = vec2(+1,+1);
|
||||
vec2 do_gamepad_sensitivity = vec2(0.1f,0.1f);
|
||||
vec2 do_mouse_polarity = vec2(+1,-1);
|
||||
vec2 do_mouse_sensitivity = vec2(0.2f,0.2f);
|
||||
bool do_billboard_x = 0, do_billboard_y = 0, do_billboard_z = 0;
|
||||
|
||||
// window (80% sized, MSAA x4 flag)
|
||||
window_create(80, WINDOW_MSAA4);
|
||||
window_title(__FILE__);
|
||||
|
||||
// load all fx files
|
||||
for(const char **list = file_list("./", "fx**.fs"); *list; list++) {
|
||||
fx_load(*list);
|
||||
}
|
||||
|
||||
// load skybox
|
||||
skybox_t sky = skybox(flag("--mie") ? 0 : "cubemaps/stardust", 0); // --mie for rayleigh/mie scattering
|
||||
|
||||
// load static scene
|
||||
model_t sponza;
|
||||
int do_sponza = flag("--sponza");
|
||||
if( do_sponza ) {
|
||||
sponza = model("sponza.obj", 0); // MODEL_NO_TEXTURES);
|
||||
translation44(sponza.pivot, 0,-1,0);
|
||||
rotate44(sponza.pivot, -90,1,0,0);
|
||||
scale44(sponza.pivot, 10,10,10);
|
||||
}
|
||||
|
||||
model_t shaderball;
|
||||
int do_shaderball = flag("--shaderball");
|
||||
if( do_shaderball ) {
|
||||
shaderball = model("shaderball.glb", 0);
|
||||
translation44(shaderball.pivot, 0,0,-10);
|
||||
rotate44(shaderball.pivot, -90,1,0,0);
|
||||
scale44(shaderball.pivot, 0.02,0.02,0.02);
|
||||
}
|
||||
|
||||
// animated models loading
|
||||
int model_flags = flag("--matcaps") ? MODEL_MATCAPS : 0;
|
||||
model_t girl = model("kgirl/kgirls01.fbx", model_flags);
|
||||
model_t alien = model("alien/alien_helmet.fbx", model_flags); rotation44(alien.pivot, -90,1,0,0);
|
||||
model_t george = model("robots/george.fbx", model_flags);
|
||||
model_t leela = model("robots/leela.fbx", model_flags);
|
||||
model_t mike = model("robots/mike.fbx", model_flags);
|
||||
model_t stan = model("robots/stan.fbx", model_flags);
|
||||
model_t robots[4] = { george, leela, mike, stan };
|
||||
for( int i = 0; i < countof(robots); ++i ) {
|
||||
rotation44(robots[i].pivot, -90,1,0,0);
|
||||
}
|
||||
|
||||
if( flag("--matcaps") ) {
|
||||
// patch models to use matcaps
|
||||
model_set_texture(george, texture("matcaps/3B6E10_E3F2C3_88AC2E_99CE51-256px", 0)); // green
|
||||
model_set_texture(leela, texture("matcaps/39433A_65866E_86BF8B_BFF8D8-256px", 0));
|
||||
model_set_texture(mike, texture("matcaps/394641_B1A67E_75BEBE_7D7256-256px.png", 0));
|
||||
model_set_texture(stan, texture("matcaps/test_steel", 0));
|
||||
model_set_texture(girl, texture("matcaps/material3", 0));
|
||||
model_set_texture(alien, texture("matcaps/material3", 0));
|
||||
|
||||
if( flag("--shaderball") )
|
||||
model_set_texture(shaderball, texture("matcaps/normals", 0));
|
||||
}
|
||||
|
||||
// camera
|
||||
camera_t cam = camera();
|
||||
cam.speed = 0.2f;
|
||||
|
||||
// audio (both clips & streams)
|
||||
audio_t SFX1 = audio_clip( "coin.wav" );
|
||||
audio_t SFX2 = audio_clip( "pew.sfxr" );
|
||||
audio_t BGM1 = audio_stream( "waterworld-map.fur"); // wrath_of_the_djinn.xm" );
|
||||
audio_t BGM2 = audio_stream( "larry.mid" );
|
||||
audio_t BGM3 = audio_stream( "monkey1.mid" ), BGM = BGM1;
|
||||
audio_play(SFX1, 0);
|
||||
audio_play(BGM, 0);
|
||||
|
||||
// demo loop
|
||||
while (window_swap())
|
||||
{
|
||||
// input
|
||||
if( input_down(KEY_ESC) ) break;
|
||||
if( input_down(KEY_F5) ) window_reload();
|
||||
if( input_down(KEY_W) && input_held(KEY_LCTRL) ) break;
|
||||
if( input_down(KEY_F11) ) window_fullscreen( window_has_fullscreen() ^ 1 );
|
||||
if( input_down(KEY_X) ) window_screenshot(__FILE__ ".png");
|
||||
if( input_down(KEY_Z) ) window_record(__FILE__ ".mp4");
|
||||
|
||||
// vec2 filtered_lpad = input_filter_deadzone(input2(GAMEPAD_LPAD), do_gamepad_deadzone + 1e-3);
|
||||
// vec2 filtered_rpad = input_filter_deadzone(input2(GAMEPAD_RPAD), do_gamepad_deadzone + 1e-3);
|
||||
|
||||
// fps camera
|
||||
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
|
||||
if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
|
||||
vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
|
||||
vec3 wasdecq = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-(input(KEY_C)||input(KEY_Q)),input(KEY_W)-input(KEY_S)), cam.speed);
|
||||
camera_move(&cam, wasdecq.x,wasdecq.y,wasdecq.z);
|
||||
camera_fps(&cam, mouse.x,mouse.y);
|
||||
window_cursor( !active );
|
||||
|
||||
// apply post-fxs from here
|
||||
fx_begin();
|
||||
|
||||
// queue debug drawcalls
|
||||
profile("Debugdraw") {
|
||||
ddraw_grid(0);
|
||||
ddraw_color(YELLOW);
|
||||
ddraw_text(vec3(+1,+1,-1), 0.04f, va("(%f,%f,%f)", cam.position.x,cam.position.y,cam.position.z));
|
||||
if(do_debugdraw) ddraw_demo(); // showcase many debugdraw shapes
|
||||
ddraw_color(YELLOW);
|
||||
ddraw_flush();
|
||||
}
|
||||
|
||||
// draw skybox
|
||||
profile("Skybox") {
|
||||
skybox_render(&sky, cam.proj, cam.view);
|
||||
}
|
||||
|
||||
profile("Skeletal update") if(!window_has_pause()) {
|
||||
float delta = window_delta() * 30; // 30fps anim
|
||||
|
||||
// animate girl & alien
|
||||
girl.curframe = model_animate(girl, girl.curframe + delta);
|
||||
alien.curframe = model_animate(alien, alien.curframe + delta);
|
||||
|
||||
// animate robots
|
||||
for(int i = 0; i < countof(robots); ++i) {
|
||||
robots[i].curframe = model_animate(robots[i], robots[i].curframe + delta);
|
||||
}
|
||||
}
|
||||
|
||||
profile("Skeletal render") {
|
||||
static vec3 p = {-10,0,-10}, r = {0,0,0}, s = {2,2,2};
|
||||
gizmo(&p, &r, &s);
|
||||
mat44 M; rotationq44(M, eulerq(r)); scale44(M, s.x,s.y,s.z); relocate44(M, p.x,p.y,p.z);
|
||||
|
||||
model_render(girl, cam.proj, cam.view, M, 0);
|
||||
|
||||
aabb box = model_aabb(girl, M);
|
||||
ddraw_color(YELLOW);
|
||||
ddraw_aabb(box.min, box.max);
|
||||
}
|
||||
|
||||
profile("Skeletal render") {
|
||||
static vec3 p = {+10,0,-10}, r = {0,-90,0}, s = {1,1,1};
|
||||
//gizmo(&p, &r, &s);
|
||||
mat44 M; rotationq44(M, eulerq(r)); scale44(M, s.x,s.y,s.z); relocate44(M, p.x,p.y,p.z);
|
||||
|
||||
model_render(alien, cam.proj, cam.view, M, 0);
|
||||
|
||||
aabb box = model_aabb(alien, M); // @fixme: neg Y
|
||||
ddraw_color(YELLOW);
|
||||
//ddraw_aabb(box.min, box.max);
|
||||
}
|
||||
|
||||
profile("Skeletal render") for(int i = 0; i < countof(robots); ++i) {
|
||||
float scale = 0.50;
|
||||
mat44 M; copy44(M, robots[i].pivot); translate44(M, i*3,0,0); scale44(M, scale,scale,scale);
|
||||
model_render(robots[i], cam.proj, cam.view, M, 0);
|
||||
}
|
||||
|
||||
if(do_sponza) profile("Sponza") {
|
||||
float scale = 1.00;
|
||||
mat44 M; copy44(M, sponza.pivot); translate44(M, 0,0,0); scale44(M, scale,scale,scale);
|
||||
model_render(sponza, cam.proj, cam.view, M, 0);
|
||||
}
|
||||
|
||||
if(do_shaderball) profile("Shaderball") {
|
||||
float scale = 1.00;
|
||||
mat44 M; copy44(M, shaderball.pivot); translate44(M, 0,0,0); scale44(M, scale,scale,scale);
|
||||
model_render(shaderball, cam.proj, cam.view, M, 0);
|
||||
}
|
||||
|
||||
// post-fxs end here
|
||||
fx_end();
|
||||
|
||||
// font demo
|
||||
do_once font_scales(FONT_FACE1, 48, 24, 18, 12, 9, 6);
|
||||
font_print(va(FONT_RIGHT FONT_BOTTOM FONT_H4 "%5.2f FPS", window_fps()));
|
||||
|
||||
// queue ui
|
||||
if( ui_panel("App", 0)) {
|
||||
if(ui_bool("Show debugdraw demo", &do_debugdraw)) {}
|
||||
if(ui_separator()) {}
|
||||
if(ui_slider("Gamepad deadzone", &do_gamepad_deadzone)) {}
|
||||
if(ui_float2("Gamepad polarity", do_gamepad_polarity.v2)) {}
|
||||
if(ui_float2("Gamepad sensitivity", do_gamepad_sensitivity.v2)) {}
|
||||
if(ui_separator()) {}
|
||||
if(ui_float2("Mouse polarity", do_mouse_polarity.v2)) {}
|
||||
if(ui_float2("Mouse sensitivity", do_mouse_sensitivity.v2)) {}
|
||||
if(ui_separator()) {}
|
||||
if(ui_button("About...")) { do_about = 1; audio_play(SFX1, 0); }
|
||||
if(ui_dialog("About", __FILE__ "\n" __DATE__ "\n" "Public Domain.", 0, &do_about)) {}
|
||||
ui_panel_end();
|
||||
}
|
||||
if( ui_panel("Camera", 0)) {
|
||||
if( ui_float("Speed", &cam.speed) ) {}
|
||||
if( ui_float3("Position", cam.position.v3) ) {}
|
||||
ui_panel_end();
|
||||
}
|
||||
if( ui_panel("FX", 0) ) {
|
||||
for( int i = 0; i < 64; ++i ) {
|
||||
char *name = fx_name(i); if( !name ) break;
|
||||
bool b = fx_enabled(i);
|
||||
if( ui_bool(name, &b) ) fx_enable(i, fx_enabled(i) ^ 1);
|
||||
}
|
||||
ui_panel_end();
|
||||
}
|
||||
if( ui_panel("Audio", 0)) {
|
||||
static float bgm = 1, sfx = 1, master = 1;
|
||||
if( ui_slider2("BGM", &bgm, va("%.2f", bgm))) audio_volume_stream(bgm);
|
||||
if( ui_slider2("SFX", &sfx, va("%.2f", sfx))) audio_volume_clip(sfx);
|
||||
if( ui_slider2("Master", &master, va("%.2f", master))) audio_volume_master(master);
|
||||
if( ui_label2_toolbar("BGM: Waterworld Map" /*Wrath of the Djinn"*/, ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = BGM1, AUDIO_SINGLE_INSTANCE);
|
||||
if( ui_label2_toolbar("BGM: Leisure Suit Larry", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = BGM2, AUDIO_SINGLE_INSTANCE);
|
||||
if( ui_label2_toolbar("BGM: Monkey Island", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = BGM3, AUDIO_SINGLE_INSTANCE);
|
||||
if( ui_label2_toolbar("SFX: Coin", ICON_MD_VOLUME_UP)) audio_play(SFX1, 0);
|
||||
if( ui_label2_toolbar("SFX: Pew", ICON_MD_VOLUME_UP)) audio_play(SFX2, 0);
|
||||
ui_panel_end();
|
||||
}
|
||||
|
||||
input_demo(); // show some keyboard/mouse/gamepad UI tabs
|
||||
ui_demo(1); // show all UI widgets in a tab
|
||||
}
|
||||
|
||||
// data tests (json5)
|
||||
const char json5[] =
|
||||
" /* json5 */ // comment\n"
|
||||
" abc: 42.67, def: true, integer:0x100 \n"
|
||||
" huge: 2.2239333e5, \n"
|
||||
" hello: 'world /*comment in string*/ //again', \n"
|
||||
" children : { a: 1, b: 2, c: 3 },\n"
|
||||
" array: [+1,2,-3,4,5], \n"
|
||||
" invalids : [ nan, NaN, -nan, -NaN, inf, Infinity, -inf, -Infinity ],";
|
||||
if( json_push(json5) ) {
|
||||
assert( json_float("/abc") == 42.67 );
|
||||
assert( json_int("/def") == 1 );
|
||||
assert( json_int("/integer") == 0x100 );
|
||||
assert( json_float("/huge") > 2.22e5 );
|
||||
assert( strlen(json_string("/hello")) == 35 );
|
||||
assert( json_int("/children/a") == 1 );
|
||||
assert( json_int("/children.b") == 2 );
|
||||
assert( json_int("/children[c]") == 3 );
|
||||
assert( json_int("/array[%d]", 2) == -3 );
|
||||
assert( json_count("/invalids") == 8 );
|
||||
assert( isnan(json_float("/invalids[0]")) );
|
||||
assert( !json_find("/non_existing") );
|
||||
assert( PRINTF("json5 tests OK\n") );
|
||||
json_pop();
|
||||
}
|
||||
|
||||
// data tests (xml)
|
||||
const char *xml = vfs_read("test1.xml");
|
||||
if( xml_push(xml) ) {
|
||||
puts( xml );
|
||||
puts( xml_string("/person/firstName/$") );
|
||||
puts( xml_string("/person/lastName/$") );
|
||||
puts( xml_string("/person/address/@type") );
|
||||
xml_pop();
|
||||
}
|
||||
|
||||
// network test (https)
|
||||
array(char) webfile = download("https://www.google.com/");
|
||||
printf("Network test: %d bytes downloaded from google.com\n", array_count(webfile));
|
||||
|
||||
// script test (lua)
|
||||
script_run( "-- Bye.lua\nio.write(\"script test: Bye world!, from \", _VERSION, \"\\n\")" );
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#include "fwk.h" // Minimal C sample
|
||||
int main() {
|
||||
window_create(75.0, 0); // 75% size, no extra flags
|
||||
while( window_swap() && !input(KEY_ESC) ) { // game loop
|
||||
puts("hello FWK from C!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
// hello ui: config, window, system, ui, video
|
||||
// - rlyeh, public domain.
|
||||
//
|
||||
// Compile with:
|
||||
// `make demos\00-ui.c` (windows)
|
||||
// `sh MAKE.bat demos/00-ui.c` (linux, osx)
|
||||
|
||||
#include "fwk.h"
|
||||
|
||||
int main() {
|
||||
float app_volume = 1.00f;
|
||||
unsigned app_size = flag("--fullscreen") ? 100 : 75;
|
||||
unsigned app_flags = flag("--msaa") ? WINDOW_MSAA4 : 0;
|
||||
unsigned app_target_fps = optioni("--fps", 60); // --fps=30, --fps=45, etc. defaults to 60.
|
||||
|
||||
// window api (fullscreen or 75% sized, optional MSAA flags)
|
||||
window_create(app_size, app_flags);
|
||||
window_title(__FILE__);
|
||||
window_fps_lock(app_target_fps);
|
||||
|
||||
// load video
|
||||
video_t *v = video( "pexels-pachon-in-motion-17486489.mp4", VIDEO_RGB );
|
||||
|
||||
// app loop
|
||||
while( window_swap() ) {
|
||||
// input controls
|
||||
if( input(KEY_ESC) ) break;
|
||||
|
||||
// profile api
|
||||
texture_t *textures;
|
||||
profile( "Video decoder" ) {
|
||||
// video api: decode frame and get associated textures (audio is sent to audiomixer automatically)
|
||||
textures = video_decode( v );
|
||||
// fullscreen video
|
||||
// if(video_is_rgb(v)) fullscreen_quad_rgb( textures[0], 1.3f );
|
||||
// else fullscreen_quad_ycbcr( textures, 1.3f );
|
||||
}
|
||||
|
||||
// create menubar on top
|
||||
int choice1 = ui_menu("File;Shell;Exit");
|
||||
int choice2 = ui_menu("Help;About");
|
||||
if( choice1 == 1 ) system(ifdef(win32, "start \"\" cmd", ifdef(osx, "open sh", "xdg-open sh")));
|
||||
if( choice1 == 2 ) exit(0);
|
||||
|
||||
// showcase a few ui widgets
|
||||
ui_demo(0);
|
||||
|
||||
// create ui panel
|
||||
if( ui_panel("myPanel", PANEL_OPEN) ) {
|
||||
// Print some numbers
|
||||
ui_section("Stats");
|
||||
ui_label2("FPS", va("%5.2f", window_fps()));
|
||||
ui_separator();
|
||||
|
||||
// add some buttons
|
||||
ui_section("Buttons");
|
||||
if( ui_button("Screenshot") ) window_screenshot(__FILE__ ".png"), ui_notify(0,ICON_MD_WARNING "Screenshot");
|
||||
if( ui_button("Record Video") ) window_record(__FILE__ ".mp4"), ui_notify(0,ICON_MD_WARNING "Recoding video");
|
||||
if( ui_button("Toggle fullscreen") ) window_fullscreen( !window_has_fullscreen() );
|
||||
ui_separator();
|
||||
|
||||
// some more video controls
|
||||
ui_section("Video");
|
||||
if( ui_button("Rewind") ) video_seek(v, video_position(v) - 3);
|
||||
if( ui_button("Pause") ) video_pause(v, video_is_paused(v) ^ 1);
|
||||
if( ui_button("Forward") ) video_seek(v, video_position(v) + 3);
|
||||
if( ui_slider2("Volume", &app_volume, va("%.2f", app_volume))) audio_volume_master(app_volume);
|
||||
|
||||
// end of panel. must be enclosed within same if() branch.
|
||||
ui_panel_end();
|
||||
}
|
||||
|
||||
// create window
|
||||
static int open = 1;
|
||||
if( ui_window("myWindow", &open) ) {
|
||||
// present decoded texture in a widget, without any label (NULL)
|
||||
ui_texture( NULL, textures[0] );
|
||||
// end of window. must be enclosed within same if() branch.
|
||||
ui_window_end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this demo supersedes following old sources:
|
||||
// https://github.com/r-lyeh/FWK/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-hello.c
|
||||
// https://github.com/r-lyeh/FWK/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-video.c
|
|
@ -0,0 +1,167 @@
|
|||
// sprite demo: window, audio, camera, font, tiled, render, fx, spritesheet, input, ui. @todo: finish spine
|
||||
// - rlyeh, public domain.
|
||||
//
|
||||
// Compile with:
|
||||
// `make demos\01-sprite.c` (windows)
|
||||
// `sh MAKE.bat demos/01-sprite.c` (linux, osx)
|
||||
|
||||
#include "fwk.h"
|
||||
|
||||
void demo_kids(vec3 offs) {
|
||||
// init
|
||||
static texture_t kids; do_once kids = texture( "spriteSheetExample.png", TEXTURE_LINEAR );
|
||||
static vec3 pos[2] = {{490,362},{442,362}}, vel[2] = {0};
|
||||
static int row[2] = {0,3}, frame[2] = {0};
|
||||
static int inputs[2][4] = {{KEY_W,KEY_A,KEY_S,KEY_D},{KEY_UP,KEY_LEFT,KEY_DOWN,KEY_RIGHT}};
|
||||
|
||||
// move
|
||||
for( int i = 0; i < countof(pos); ++i ) {
|
||||
vel[i].x = input(inputs[i][3]) - input(inputs[i][1]);
|
||||
vel[i].y = input(inputs[i][2]) - input(inputs[i][0]);
|
||||
pos[i].x = fmod(pos[i].x + vel[i].x, window_width() + 128);
|
||||
pos[i].y = fmod(pos[i].y + vel[i].y, window_height() + 128);
|
||||
frame[i] += vel[i].x || vel[i].y;
|
||||
}
|
||||
|
||||
// render
|
||||
for( int i = 0; i < countof(pos); ++i ) {
|
||||
int col = frame[i] / 10, num_frame = row[i] * 4 + col % 4; // 4x4 tilesheet
|
||||
float position[3] = {pos[i].x,pos[i].y,pos[i].y}, offset[2]={0,0}, scale[2]={0.5,0.5};
|
||||
float spritesheet[3]={num_frame,4,4};
|
||||
sprite_sheet(kids,
|
||||
spritesheet, // num_frame in a 4x4 spritesheet
|
||||
position, 0, // position(x,y,depth:sort-by-Y), angle
|
||||
offset, scale, // offset(x,y), scale(x,y)
|
||||
false, WHITE, false // is_additive, tint color, resolution-independent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void demo_hud() {
|
||||
// draw pixel-art hud, 16x16 ui element, scaled and positioned in resolution-independant way
|
||||
static texture_t inputs; do_once inputs = texture( "prompts_tilemap_34x24_16x16x1.png", TEXTURE_LINEAR );
|
||||
float spritesheet[3] = {17,34,24}, offset[2] = {0, - 2*absf(sin(window_time()*5))}; // sprite cell and animation
|
||||
float scale[2] = {3, 3}, tile_w = 16 * scale[0], tile_h = 16 * scale[1]; // scaling
|
||||
float position[3] = {window_width() - tile_w, window_height() - tile_h, window_height() }; // position in screen-coordinates (x,y,z-index)
|
||||
sprite_sheet(inputs, spritesheet, position, 0/*deg*/, offset, scale, false, WHITE, 1);
|
||||
}
|
||||
|
||||
int main() {
|
||||
// window (80% sized, MSAA x4 flag)
|
||||
window_create(80.0, WINDOW_MSAA4);
|
||||
window_title(__FILE__);
|
||||
|
||||
// tiled map
|
||||
tiled_t tmx = tiled(vfs_read("castle.tmx"));
|
||||
// tmx.parallax = true;
|
||||
|
||||
// spine model
|
||||
//spine_t *spn = spine("goblins.json", "goblins.atlas", 0);
|
||||
|
||||
// camera 2d
|
||||
camera_t cam = camera();
|
||||
cam.position = vec3(window_width()/2, window_height()/2, 3); // at(CX,CY) zoom(x3)
|
||||
camera_enable(&cam);
|
||||
|
||||
// audio (both clips & streams)
|
||||
audio_t clip1 = audio_clip( "coin.wav" );
|
||||
audio_t clip2 = audio_clip( "pew.sfxr" );
|
||||
audio_t stream1 = audio_stream( "larry.mid" );
|
||||
audio_t stream2 = audio_stream( "monkey1.mid" );
|
||||
audio_t BGM = stream1;
|
||||
audio_play(BGM, 0);
|
||||
|
||||
// font config: faces (6 max) and colors (10 max)
|
||||
#define FONT_CJK FONT_FACE3
|
||||
#define FONT_YELLOW FONT_COLOR2
|
||||
#define FONT_LIME FONT_COLOR3
|
||||
font_face(FONT_CJK, "mplus-1p-medium.ttf", 48.f, FONT_JP|FONT_2048); // CJK|FONT_2048|FONT_OVERSAMPLE_Y);
|
||||
font_color(FONT_YELLOW, RGB4(255,255,0,255));
|
||||
font_color(FONT_LIME, RGB4(128,255,0,255));
|
||||
|
||||
// fx: load all post fx files in all subdirs. enable a few filters by default
|
||||
fx_load("fx**.fs");
|
||||
fx_enable(fx_find("fxCRT2.fs"), 1);
|
||||
fx_enable(fx_find("fxGrain.fs"), 1);
|
||||
fx_enable(fx_find("fxContrast.fs"), 1);
|
||||
fx_enable(fx_find("fxVignette.fs"), 1);
|
||||
|
||||
// demo loop
|
||||
while (window_swap() && !input_down(KEY_ESC)) {
|
||||
|
||||
// handle input
|
||||
if( input_down(KEY_F5) ) window_reload();
|
||||
if( input_down(KEY_F11) ) window_fullscreen( !window_has_fullscreen() );
|
||||
|
||||
// camera panning (x,y) & zooming (z)
|
||||
if( !ui_hover() && !ui_active() ) {
|
||||
if( input(MOUSE_L) ) cam.position.x += input_diff(MOUSE_X);
|
||||
if( input(MOUSE_L) ) cam.position.y += input_diff(MOUSE_Y);
|
||||
cam.position.z += input_diff(MOUSE_W) * 0.1;
|
||||
}
|
||||
|
||||
// apply post-fxs from here
|
||||
fx_begin();
|
||||
|
||||
profile("Rendering") {
|
||||
vec3 center = add3(cam.position,vec3(-window_width()/1,-window_height()/2,0));
|
||||
// render tiled map
|
||||
tiled_render(tmx, center);
|
||||
//
|
||||
demo_kids(vec3(0,0,1));
|
||||
demo_hud();
|
||||
// render spine model
|
||||
// spine_animate(spn, !window_has_pause() * window_delta());
|
||||
// spine_render(spn, vec3(cam.position.x, cam.position.y, 1), true );
|
||||
// sprite_flush();
|
||||
}
|
||||
|
||||
// subtitle sample
|
||||
font_print(
|
||||
FONT_BOTTOM FONT_CENTER
|
||||
FONT_CJK FONT_H1
|
||||
FONT_YELLOW "私はガラスを食べられます。" FONT_LIME "それは私を傷つけません。\n"
|
||||
);
|
||||
|
||||
// post-fxs end here
|
||||
fx_end();
|
||||
|
||||
// ui
|
||||
if( ui_panel("Audio", 0)) {
|
||||
static float bgm = 1, sfx = 1, master = 1;
|
||||
if( ui_slider2("BGM", &bgm, va("%.2f", bgm))) audio_volume_stream(bgm);
|
||||
if( ui_slider2("SFX", &sfx, va("%.2f", sfx))) audio_volume_clip(sfx);
|
||||
if( ui_slider2("Master", &master, va("%.2f", master))) audio_volume_master(master);
|
||||
if( ui_label2_toolbar("BGM: Leisure Suit Larry", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = stream1, AUDIO_SINGLE_INSTANCE);
|
||||
if( ui_label2_toolbar("BGM: Monkey Island", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = stream2, AUDIO_SINGLE_INSTANCE);
|
||||
if( ui_label2_toolbar("SFX: Coin", ICON_MD_VOLUME_UP)) audio_play(clip1, 0);
|
||||
if( ui_label2_toolbar("SFX: Pew", ICON_MD_VOLUME_UP)) audio_play(clip2, 0);
|
||||
ui_panel_end();
|
||||
}
|
||||
if( ui_panel("Tiled", 0)) {
|
||||
ui_float("Zoom in", &cam.position.z);
|
||||
tiled_ui(&tmx);
|
||||
ui_panel_end();
|
||||
}
|
||||
/*if( ui_panel("Spine", 0)) {
|
||||
spine_ui(spn);
|
||||
ui_panel_end();
|
||||
}*/
|
||||
if( ui_panel("FX", 0) ) {
|
||||
for( int i = 0; i < 64; ++i ) {
|
||||
char *name = fx_name(i); if( !name ) break;
|
||||
bool b = fx_enabled(i);
|
||||
if( ui_bool(name, &b) ) fx_enable(i, fx_enabled(i) ^ 1);
|
||||
}
|
||||
ui_panel_end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this demo supersedes following old sources:
|
||||
// https://github.com/r-lyeh/FWK/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-audio.c
|
||||
// https://github.com/r-lyeh/FWK/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-font.c
|
||||
// https://github.com/r-lyeh/FWK/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-spine.c
|
||||
// https://github.com/r-lyeh/FWK/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-sprite.c
|
||||
// https://github.com/r-lyeh/FWK/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-tiled.c
|
||||
// https://github.com/r-lyeh/FWK/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-tilemap.c
|
|
@ -0,0 +1,119 @@
|
|||
// ddraw demo: fps camera, renderdd, collide, math, ui, fx
|
||||
// - rlyeh, public domain.
|
||||
//
|
||||
// Compile with:
|
||||
// `make demos\02-ddraw.c` (windows)
|
||||
// `sh MAKE.bat demos/02-ddraw.c` (linux, osx)
|
||||
|
||||
#include "fwk.h"
|
||||
|
||||
int main() {
|
||||
bool do_colliders_demo = 1;
|
||||
bool do_debugdraw_demo = 0;
|
||||
|
||||
// 75% size, MSAAx2
|
||||
window_create(75.0, WINDOW_MSAA2);
|
||||
window_title(__FILE__);
|
||||
|
||||
// camera that points to origin
|
||||
camera_t cam = camera();
|
||||
// load skybox folder (no flags)
|
||||
skybox_t sky = skybox("cubemaps/stardust", 0);
|
||||
// load all postfx files in all subdirs
|
||||
fx_load("fx**.fs");
|
||||
|
||||
// main loop
|
||||
while( window_swap() ) {
|
||||
|
||||
// input handler
|
||||
if (input_down(KEY_F11) ) window_fullscreen( window_has_fullscreen()^1 );
|
||||
if (input_down(KEY_ESC) ) break;
|
||||
|
||||
// fps camera
|
||||
profile("FPS camera") {
|
||||
if( input(GAMEPAD_CONNECTED) ) {
|
||||
vec2 filtered_lpad = input_filter_deadzone(input2(GAMEPAD_LPAD), 0.15f/*do_gamepad_deadzone*/ + 1e-3 );
|
||||
vec2 filtered_rpad = input_filter_deadzone(input2(GAMEPAD_RPAD), 0.15f/*do_gamepad_deadzone*/ + 1e-3 );
|
||||
vec2 mouse = scale2(vec2(filtered_rpad.x, filtered_rpad.y), 1.0f);
|
||||
vec3 wasdec = scale3(vec3(filtered_lpad.x, input(GAMEPAD_LT) - input(GAMEPAD_RT), filtered_lpad.y), 1.0f);
|
||||
camera_move(&cam, wasdec.x,wasdec.y,wasdec.z);
|
||||
camera_fps(&cam, mouse.x,mouse.y);
|
||||
window_cursor( true );
|
||||
} else {
|
||||
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
|
||||
if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
|
||||
vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
|
||||
vec3 wasdecq = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-(input(KEY_C)||input(KEY_Q)),input(KEY_W)-input(KEY_S)), cam.speed);
|
||||
camera_move(&cam, wasdecq.x,wasdecq.y,wasdecq.z);
|
||||
camera_fps(&cam, mouse.x,mouse.y);
|
||||
window_cursor( !active );
|
||||
}
|
||||
}
|
||||
|
||||
fx_begin();
|
||||
|
||||
// draw skybox
|
||||
skybox_render(&sky, cam.proj, cam.view);
|
||||
|
||||
// world
|
||||
ddraw_grid(0);
|
||||
|
||||
// boids
|
||||
static swarm_t sw;
|
||||
profile("boids") {
|
||||
do_once sw = swarm();
|
||||
do_once array_push(sw.steering_targets, vec3(0,0,0));
|
||||
do_once for(int i = 0; i < 100; ++i)
|
||||
array_push(sw.boids, boid(scale3(rnd3(),10), rnd3())); // pos,vel
|
||||
|
||||
// move
|
||||
sw.steering_targets[0] = cam.position;
|
||||
swarm_update(&sw, window_delta());
|
||||
|
||||
// draw
|
||||
for (int j = 0, end = array_count(sw.boids); j < end; ++j) {
|
||||
vec3 dir = norm3(sub3(sw.boids[j].position, sw.boids[j].prev_position));
|
||||
ddraw_boid(sw.boids[j].position, dir);
|
||||
}
|
||||
}
|
||||
|
||||
// showcase many debugdraw shapes
|
||||
if( do_debugdraw_demo ) {
|
||||
ddraw_demo();
|
||||
}
|
||||
|
||||
// showcase many colliding tests
|
||||
if( do_colliders_demo ) {
|
||||
collide_demo();
|
||||
}
|
||||
|
||||
fx_end();
|
||||
|
||||
// ui
|
||||
if( ui_panel("App", 0) ) {
|
||||
ui_bool("Collide demo", &do_colliders_demo);
|
||||
ui_bool("DebugDraw demo", &do_debugdraw_demo);
|
||||
ui_panel_end();
|
||||
}
|
||||
if( ui_panel("Swarm", 0) ) {
|
||||
ui_swarm(&sw);
|
||||
ui_panel_end();
|
||||
}
|
||||
if( ui_panel("Camera", 0)) {
|
||||
if( ui_float("Speed", &cam.speed) ) {}
|
||||
if( ui_float3("Position", cam.position.v3) ) {}
|
||||
ui_panel_end();
|
||||
}
|
||||
if( ui_panel("FX", 0) ) {
|
||||
for( int i = 0; i < 64; ++i ) {
|
||||
char *name = fx_name(i); if( !name ) break;
|
||||
bool b = fx_enabled(i);
|
||||
if( ui_bool(name, &b) ) fx_enable(i, fx_enabled(i) ^ 1);
|
||||
}
|
||||
ui_panel_end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this demo supersedes following old sources:
|
||||
// https://github.com/r-lyeh/FWK/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-collide.c
|
|
@ -0,0 +1,65 @@
|
|||
#include "fwk.h"
|
||||
|
||||
void ddraw_camera(camera_t *c) {
|
||||
vec3 center = c->position;
|
||||
// ddraw_prism(add3(center,vec3(2,0,0)), 0.5, 1, vec3(-1,0,0), 4); // center,radius,height,normal,segments
|
||||
// ddraw_box(center, vec3(2,2,1)); // center,extents
|
||||
|
||||
mat33 r; rotationq33(r, eulerq(vec3(-c->yaw,-c->pitch,0)));
|
||||
ddraw_cube33(center, vec3(2,2,2), r);
|
||||
|
||||
ddraw_circle(add3(center,vec3(+1,1,0)), vec3(0,0,1), 0.8); // pos,normal,radius
|
||||
ddraw_circle(add3(center,vec3(-1,1,0)), vec3(0,0,1), 0.8); // pos,normal,radius
|
||||
|
||||
mat44 projview; multiply44x2(projview, c->proj, c->view);
|
||||
ddraw_frustum(projview);
|
||||
}
|
||||
|
||||
int main() {
|
||||
window_create(0.75, 0);
|
||||
|
||||
camera_t cam = camera();
|
||||
camera_t cam2 = camera();
|
||||
|
||||
int spin = 1;
|
||||
|
||||
while( window_swap() ) {
|
||||
if(input_down(KEY_SPACE)) spin^=1;
|
||||
// spin 2nd camera
|
||||
double t = window_time(), c = cos(t), s = sin(t);
|
||||
if(spin)
|
||||
camera_teleport(&cam2, vec3(c * 100, 100, s * 100));
|
||||
camera_lookat(&cam2, vec3(0,0,0));
|
||||
|
||||
// fps camera
|
||||
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
|
||||
if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
|
||||
vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
|
||||
vec3 wasdecq = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-(input(KEY_C)||input(KEY_Q)),input(KEY_W)-input(KEY_S)), cam.speed);
|
||||
camera_move(&cam, wasdecq.x,wasdecq.y,wasdecq.z);
|
||||
camera_fps(&cam, mouse.x,mouse.y);
|
||||
window_cursor( !active );
|
||||
|
||||
mat44 projview; multiply44x2(projview, cam2.proj, cam2.view);
|
||||
frustum f = frustum_build(projview);
|
||||
|
||||
ddraw_ground(0);
|
||||
ddraw_camera(&cam2);
|
||||
|
||||
int drawn = 0, total = 0;
|
||||
for(int z = -300; z < 300; z += 5) {
|
||||
for(int x = -300; x < 300; x += 5) {
|
||||
vec3 min = vec3(x, 0, z);
|
||||
vec3 max = add3(min, vec3(2.5,2.5,2.5));
|
||||
|
||||
if( frustum_test_aabb(f, aabb(min, max)) ) {
|
||||
ddraw_aabb( min, max );
|
||||
++drawn;
|
||||
}
|
||||
++total;
|
||||
}
|
||||
}
|
||||
|
||||
font_print(va(FONT_RIGHT "%d/%d cubes drawn", drawn, total));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
// anims demo: input, mesh, anim, render, fx, ui, instancing
|
||||
// - rlyeh, public domain.
|
||||
//
|
||||
// Compile with:
|
||||
// `make demos\03-anims.c` (windows)
|
||||
// `sh MAKE.bat demos/03-anims.c` (linux, osx)
|
||||
//
|
||||
// @todo: instanced poses, instanced render_bones
|
||||
// @todo: ik, modify bone transform (bone space)
|
||||
|
||||
#include "fwk.h"
|
||||
|
||||
typedef struct anims_t {
|
||||
int inuse; // animation number in use
|
||||
float speed; // x1.00
|
||||
array(anim_t) anims; // [begin,end,flags] frames of every animation in set
|
||||
array(mat44) M; // instanced transforms
|
||||
} anims_t;
|
||||
|
||||
anims_t animations(const char *pathfile, int flags) {
|
||||
anims_t a = {0};
|
||||
char *anim_file = vfs_read(pathfile);
|
||||
for each_substring(anim_file, "\r\n", anim) {
|
||||
int from, to;
|
||||
char anim_name[128] = {0};
|
||||
if( sscanf(anim, "%*s %d-%d %127[^\r\n]", &from, &to, anim_name) != 3) continue;
|
||||
array_push(a.anims, !!strstri(anim_name, "loop") ? loop(from, to, 0, 0) : clip(from, to, 0, 0)); // [from,to,flags]
|
||||
array_back(a.anims)->name = strswap(strswap(strswap(STRDUP(anim_name), "Loop", ""), "loop", ""), "()", "");
|
||||
}
|
||||
array_resize(a.M, 32*32);
|
||||
for(int z = 0, i = 0; z < 32; ++z) {
|
||||
for(int x = 0; x < 32; ++x, ++i) {
|
||||
vec3 p = vec3(-x*3,0,-z*3);
|
||||
vec3 r = vec3(0,0,0);
|
||||
vec3 s = vec3(2,2,2);
|
||||
compose44(a.M[i], p, eulerq(r), s);
|
||||
}
|
||||
}
|
||||
a.speed = 1.0;
|
||||
return a;
|
||||
}
|
||||
|
||||
int main() {
|
||||
bool do_showaabb = 0;
|
||||
bool do_showbones = 0;
|
||||
bool do_showmodel = 1;
|
||||
bool do_showgizmo = 1;
|
||||
|
||||
// 75% sized, MSAAx2
|
||||
window_create(75, WINDOW_MSAA2);
|
||||
window_title(__FILE__);
|
||||
|
||||
camera_t cam = camera();
|
||||
skybox_t sky = skybox("cubemaps/stardust", 0);
|
||||
model_t mdl = model("kgirls01.fbx", 0);
|
||||
anims_t a = animations("kgirl/animlist.txt", 0);
|
||||
|
||||
// load all postfx files in all subdirs
|
||||
fx_load("fx**.fs");
|
||||
|
||||
while( window_swap() && !input(KEY_ESC) ) {
|
||||
// fps camera
|
||||
if( input(GAMEPAD_CONNECTED) ) {
|
||||
vec2 filtered_lpad = input_filter_deadzone(input2(GAMEPAD_LPAD), 0.15f/*do_gamepad_deadzone*/ + 1e-3 );
|
||||
vec2 filtered_rpad = input_filter_deadzone(input2(GAMEPAD_RPAD), 0.15f/*do_gamepad_deadzone*/ + 1e-3 );
|
||||
vec2 mouse = scale2(vec2(filtered_rpad.x, filtered_rpad.y), 1.0f);
|
||||
vec3 wasdec = scale3(vec3(filtered_lpad.x, input(GAMEPAD_LT) - input(GAMEPAD_RT), filtered_lpad.y), 1.0f);
|
||||
camera_move(&cam, wasdec.x,wasdec.y,wasdec.z);
|
||||
camera_fps(&cam, mouse.x,mouse.y);
|
||||
window_cursor( true );
|
||||
} else {
|
||||
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
|
||||
if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
|
||||
vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
|
||||
vec3 wasdecq = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-(input(KEY_C)||input(KEY_Q)),input(KEY_W)-input(KEY_S)), cam.speed);
|
||||
camera_move(&cam, wasdecq.x,wasdecq.y,wasdecq.z);
|
||||
camera_fps(&cam, mouse.x,mouse.y);
|
||||
window_cursor( !active );
|
||||
}
|
||||
|
||||
// skeletal update
|
||||
static bool is_dragging_slider = 0;
|
||||
vec2i anim = vec2i( a.anims[ a.inuse ].from, a.anims[ a.inuse ].to );
|
||||
profile("Skeletal update") {
|
||||
float delta = window_delta() * 30 * a.speed * !is_dragging_slider; // 30fps anim timer
|
||||
if(!window_has_pause()) mdl.curframe = model_animate_clip(mdl, mdl.curframe + delta, anim.min, anim.max, a.anims[a.inuse].flags & ANIM_LOOP );
|
||||
}
|
||||
|
||||
// render
|
||||
fx_begin();
|
||||
|
||||
// Skybox
|
||||
profile("Skybox") {
|
||||
skybox_render(&sky, cam.proj, cam.view);
|
||||
}
|
||||
|
||||
// ground
|
||||
ddraw_ground(0);
|
||||
ddraw_flush();
|
||||
|
||||
// characters
|
||||
static int NUM_INSTANCES = 1;
|
||||
profile("Skeletal render") {
|
||||
if( do_showmodel ) model_render_instanced(mdl, cam.proj, cam.view, a.M, 0, NUM_INSTANCES);
|
||||
|
||||
if( do_showbones ) model_render_skeleton(mdl, a.M[0]);
|
||||
|
||||
if( do_showaabb ) {
|
||||
aabb box = model_aabb(mdl, a.M[0]);
|
||||
ddraw_aabb(box.min, box.max);
|
||||
}
|
||||
|
||||
if( do_showgizmo ) {
|
||||
static vec3 p = {0,0,0}, r = {0,0,0}, s = {2,2,2};
|
||||
gizmo(&p, &r, &s);
|
||||
compose44(a.M[0], p, eulerq(r), s);
|
||||
}
|
||||
}
|
||||
|
||||
fx_end();
|
||||
|
||||
if( ui_panel("Animation", 0) ) {
|
||||
if( ui_bool("Show aabb", &do_showaabb) );
|
||||
if( ui_bool("Show bones", &do_showbones) );
|
||||
if( ui_bool("Show models", &do_showmodel) );
|
||||
if( ui_bool("Show gizmo", &do_showgizmo) );
|
||||
ui_separator();
|
||||
|
||||
if( ui_int("Instances", &NUM_INSTANCES)) NUM_INSTANCES = clampi(NUM_INSTANCES, 1, array_count(a.M));
|
||||
ui_separator();
|
||||
|
||||
ui_label(va("Anim %s [%d.. %.2f ..%d]", a.anims[ a.inuse ].name, anim.min, mdl.curframe, anim.max ));
|
||||
|
||||
// normalize curframe into [0..1] range
|
||||
is_dragging_slider = 0;
|
||||
float range = (mdl.curframe - anim.min) / ((anim.max - anim.min) + !(anim.max - anim.min));
|
||||
if( ui_slider2("Frame", &range, va("%.2f/%d %02d%%", mdl.curframe - anim.min, anim.max - anim.min, (int)(range * 100.f))) ) {
|
||||
mdl.curframe = range * (anim.max - anim.min) + anim.min;
|
||||
is_dragging_slider = 1;
|
||||
}
|
||||
|
||||
ui_slider2("Speed", &a.speed, va("x%.2f", a.speed));
|
||||
ui_separator();
|
||||
|
||||
for( int i = 0; i < array_count(a.anims); ++i ) {
|
||||
bool selected = a.inuse == i;
|
||||
float progress = selected ? (mdl.curframe - anim.min) * 100.f / (anim.max - anim.min) : 0.f;
|
||||
const char *caption = va("%s%s%s %.2f%%", selected ? "*":"", a.anims[i].name, a.anims[i].flags & ANIM_LOOP ? " (Loop)":"", progress);
|
||||
int choice = ui_label2_toolbar(caption, va("%s %s %s", ICON_MD_REPLAY_CIRCLE_FILLED, a.inuse == i && a.speed <= 0 ? ICON_MD_NOT_STARTED : ICON_MD_PAUSE_CIRCLE, ICON_MD_PLAY_CIRCLE) );
|
||||
if( choice == 1 ) { // play/restart
|
||||
if( mdl.curframe >= anim.max ) mdl.curframe = anim.min; // restart animation
|
||||
a.speed = 1.0f;
|
||||
a.inuse = i;
|
||||
}
|
||||
if( choice == 2 ) { // pause/advance-frame
|
||||
if(a.speed <= 0) mdl.curframe = (int)mdl.curframe + 1;
|
||||
a.speed = 0.0f;
|
||||
a.inuse = i;
|
||||
}
|
||||
if( choice == 3 ) { // loop on/off
|
||||
if( a.anims[i].flags & ANIM_LOOP )
|
||||
a.anims[ i ].flags &= ~ANIM_LOOP;
|
||||
else
|
||||
a.anims[ i ].flags |= ANIM_LOOP;
|
||||
a.inuse = i;
|
||||
}
|
||||
}
|
||||
ui_panel_end();
|
||||
}
|
||||
if( ui_panel("FX", 0) ) {
|
||||
for( int i = 0; i < 64; ++i ) {
|
||||
char *name = fx_name(i); if( !name ) break;
|
||||
bool b = fx_enabled(i);
|
||||
if( ui_bool(name, &b) ) fx_enable(i, b);
|
||||
}
|
||||
ui_panel_end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @todo: controller demo: root motion on/off
|
||||
// @todo: controller demo: anim controller.lua
|
||||
|
||||
// this demo supersedes following old sources:
|
||||
// https://github.com/r-lyeh/FWK/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-anims.c
|
||||
// https://github.com/r-lyeh/FWK/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-instanced.c
|
|
@ -0,0 +1,150 @@
|
|||
// actor controller demo: anims, anim blending, input, math
|
||||
// - rlyeh, public domain.
|
||||
//
|
||||
// Compile with:
|
||||
// `make demos\04-actor.c` (windows)
|
||||
// `sh MAKE.bat demos/04-actor.c` (linux, osx)
|
||||
|
||||
#include "fwk.h"
|
||||
|
||||
int main() {
|
||||
// create window (75% sized, MSAAx4)
|
||||
window_create(75, WINDOW_MSAA4);
|
||||
window_title(__FILE__);
|
||||
|
||||
// set up our players
|
||||
struct player_t {
|
||||
const char *name;
|
||||
model_t mdl;
|
||||
anim_t idle, run; // anim clips
|
||||
float keys[4], scale; // up,down,left,right
|
||||
vec2 inertia; // [forward,yaw]
|
||||
vec3 pivot, speed; // [pitch,yaw,roll] [turn speed,forward speed,anim speed fps]
|
||||
vec3 pos, dir, pad; // [position] [facing dir] [gamepad accumulator]
|
||||
bool notified;
|
||||
float brain[4]; // AI
|
||||
} player[3] = {
|
||||
{ "PLAYER-1", model("kgirls01.fbx", 0), loop(0,60,0.25,0), loop(66,85,0.25,0), // idle anim [0..60], run anim [66..85]
|
||||
{KEY_UP,KEY_DOWN,KEY_LEFT,KEY_RIGHT}, 2, {0.90,0.80}, {-100}, {3, 0.30, 30}, {0}, {1} },
|
||||
{ "PLAYER-2", model("george.fbx", 0), loop(0,100,0.25,0), loop(372,396,0.25,0), // idle anim [0..100], run anim [372..396]
|
||||
{KEY_I,KEY_K,KEY_J,KEY_L}, 1, {0.95,0.90}, {-90,-90}, {1.75, 0.25, 24}, {-5}, {1} },
|
||||
{ "PLAYER-3", model("alien.fbx", 0), loop(110,208,0.25,0), loop(360,380,0.25,0), // idle anim [110..208], run anim [360..380]
|
||||
{KEY_W,KEY_S,KEY_A,KEY_D}, 0.85, {0.85,0.75}, {-90,-90}, {3.5, 0.35, 60}, {5}, {1} }
|
||||
};
|
||||
|
||||
// camera that points to origin, skybox, and a background tune
|
||||
camera_t cam = camera();
|
||||
skybox_t sky = skybox("cubemaps/stardust", 0);
|
||||
audio_play( audio_stream("waterworld-map.fur"), 0 );
|
||||
|
||||
// game loop
|
||||
while( window_swap() ) {
|
||||
// world: skybox, position markers and ground grid
|
||||
skybox_render(&sky, cam.proj, cam.view);
|
||||
for( int i = 0; i < countof(player); ++i )
|
||||
ddraw_position_dir(player[i].pos, player[i].dir, 1.0f);
|
||||
ddraw_grid(0);
|
||||
ddraw_flush();
|
||||
|
||||
// move and render players
|
||||
for( int i = 0; i < countof(player); ++i ) {
|
||||
struct player_t *p = &player[i];
|
||||
|
||||
// capture inputs
|
||||
p->brain[0] = input(p->keys[0]);
|
||||
p->brain[1] = input(p->keys[1]);
|
||||
p->brain[2] = input(p->keys[2]);
|
||||
p->brain[3] = input(p->keys[3]);
|
||||
|
||||
// setup waypoints for PLAYER-1
|
||||
static array(vec3) points;
|
||||
if( input_down(MOUSE_L) && !ui_hover() ) {
|
||||
vec3 pt = editor_pick(input(MOUSE_X), input(MOUSE_Y));
|
||||
hit *h = ray_hit_plane(ray(cam.position, pt), plane(vec3(0,0,0),vec3(0,1,0)));
|
||||
if(h) array_push(points, h->p);
|
||||
}
|
||||
// ddraw waypoints
|
||||
ddraw_color(YELLOW);
|
||||
for( int i = 1; i < array_count(points); ++i) ddraw_line(points[i-1],points[i]);
|
||||
for( int i = 0; i < array_count(points); ++i) ddraw_circle(points[i], vec3(0,1,0), 1); // prism(points[i], 1, 0, vec3(0,1,0), 4);
|
||||
ddraw_color(RED);
|
||||
for( int i = 0; i < array_count(points); ++i) ddraw_point(points[i]);
|
||||
ddraw_color(WHITE);
|
||||
// move thru waypoints (PLAYER-1 only)
|
||||
if( i == 0 && array_count(points) ) {
|
||||
struct player_t *p = &player[i];
|
||||
vec3 dst = points[0];
|
||||
vec3 vector1 = norm3(vec3(p->dir.x,0,p->dir.z));
|
||||
vec3 vector2 = norm3(sub3(dst,p->pos));
|
||||
|
||||
float angle = atan2(vector2.z, vector2.x) - atan2(vector1.z, vector1.x);
|
||||
angle *= 180 / C_PI;
|
||||
// range [0, 360)
|
||||
// if (angle < 0) { angle += 2 * 180; }
|
||||
// range (-180, 180]
|
||||
if (angle > 180) { angle -= 2 * 180; }
|
||||
else if (angle <= -180) { angle += 2 * 180; }
|
||||
|
||||
float dist = len3(sub3(p->pos, dst));
|
||||
if(dist < 1) {
|
||||
// goal
|
||||
array_pop_front(points);
|
||||
}
|
||||
else {
|
||||
if( dist < 10 && abs(angle) > 10 ) {
|
||||
// spin only
|
||||
p->brain[ angle < 0 ? 2 : 3 ] = 1;
|
||||
}
|
||||
else {
|
||||
// spin
|
||||
p->brain[ angle < 0 ? 2 : 3 ] = 1;
|
||||
// move forward
|
||||
p->brain[ 0 ] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// accumulate movement
|
||||
float yaw = p->brain[2] - p->brain[3];
|
||||
float fwd = p->brain[0] - p->brain[1]; if(fwd<0) fwd = 0;
|
||||
p->pad.x = p->pad.x * p->inertia.y + yaw * (1-p->inertia.y);
|
||||
p->pad.y = p->pad.y * p->inertia.x + fwd * (1-p->inertia.x);
|
||||
|
||||
// rotate yaw dir, then apply into position
|
||||
p->dir = rotatey3(p->dir, p->speed.x * p->pad.x);
|
||||
p->pos = add3(p->pos, scale3(p->dir, p->speed.y * p->pad.y));
|
||||
|
||||
// animate clips and blend
|
||||
anim_t *primary = fwd ? &p->run : &p->idle;
|
||||
anim_t *secondary = fwd ? &p->idle : &p->run;
|
||||
model_animate_blends(p->mdl, primary, secondary, window_delta() * p->speed.z);
|
||||
|
||||
// render model. transforms on top of initial pivot and scale
|
||||
mat44 M; compose44(M, p->pos, eulerq(add3(p->pivot,vec3(atan2(p->dir.z,p->dir.x)*180/C_PI,0,0))),vec3(p->scale,p->scale,p->scale));
|
||||
model_render(p->mdl, cam.proj, cam.view, M, 0);
|
||||
|
||||
// ui
|
||||
if( yaw||fwd ) if( !p->notified ) p->notified = 1, ui_notify(0, va(ICON_MD_GAMEPAD " %s joined the game.", p->name));
|
||||
ddraw_text(p->pos, 0.01, va("%s: %6.3f", fwd?"run":"idle", (fwd ? p->run : p->idle).timer ));
|
||||
}
|
||||
|
||||
// look at the players that are moving; center of their triangle otherwise.
|
||||
float A = len3(player[0].pad); if(A<0.01) A=0;
|
||||
float B = len3(player[1].pad); if(B<0.01) B=0;
|
||||
float C = len3(player[2].pad); if(C<0.01) C=0;
|
||||
float weight = A + B + C;
|
||||
if( weight ) A /= weight, B /= weight, C /= weight; else A = B = C = 0.33333;
|
||||
vec3 target = add3(add3(scale3(player[0].pos,A), scale3(player[1].pos,B)), scale3(player[2].pos,C));
|
||||
// smooth target before sending to camera
|
||||
static vec3 smooth; camera_lookat(&cam, smooth = mix3(target,smooth,!weight ? 0.98 : 0.95));
|
||||
|
||||
// ui
|
||||
if( ui_panel("Controls", 0) ) {
|
||||
ui_label2("Girl", ICON_MD_MOUSE " Set Waypoint");
|
||||
ui_label2("Girl", ICON_MD_GAMEPAD " CURSOR keys");
|
||||
ui_label2("Alien", ICON_MD_GAMEPAD " W,A,S,D keys");
|
||||
ui_label2("Robot", ICON_MD_GAMEPAD " I,J,K,L keys");
|
||||
ui_panel_end();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,230 @@
|
|||
// scene demo
|
||||
// - rlyeh, public domain
|
||||
|
||||
#include "fwk.h"
|
||||
|
||||
int main() {
|
||||
// options
|
||||
bool do_twosided = 1;
|
||||
bool do_wireframe = 0;
|
||||
bool do_billboard_x = 0, do_billboard_y = 0, do_billboard_z = 0;
|
||||
|
||||
// window (80% sized, MSAA x4 flag)
|
||||
window_create(80, WINDOW_MSAA4);
|
||||
window_title(__FILE__);
|
||||
|
||||
// load all postfx files in all subdirs
|
||||
fx_load("fx**.fs");
|
||||
|
||||
// scene loading
|
||||
#define SCENE(...) #__VA_ARGS__
|
||||
const char *my_scene = SCENE([
|
||||
{
|
||||
skybox: 'cubemaps/stardust/',
|
||||
},
|
||||
{
|
||||
position:[-5.0,-2.0,2.0],
|
||||
rotation: [90.0,0.0,180.0],
|
||||
scale:0.20,
|
||||
//anchor/pivot:[],
|
||||
// vertex:'p3 t2',
|
||||
mesh:'models/witch/witch.obj',
|
||||
texture:'models/witch/witch_diffuse.tga.png',
|
||||
// swapzy:true,
|
||||
flipuv:false,
|
||||
},
|
||||
{
|
||||
position:[-5.0,-2.0,2.0],
|
||||
rotation: [90.0,0.0,180.0],
|
||||
scale:2.20,
|
||||
//anchor/pivot:[],
|
||||
// vertex:'p3 t2',
|
||||
mesh:'models/witch/witch_object.obj',
|
||||
texture:'models/witch/witch_object_diffuse.tga.png',
|
||||
// swapzy:true,
|
||||
flipuv:false,
|
||||
},
|
||||
]);
|
||||
int num_spawned = scene_merge(my_scene);
|
||||
object_t *obj1 = scene_index(0);
|
||||
object_t *obj2 = scene_index(1);
|
||||
|
||||
// manual spawn & loading
|
||||
model_t m1 = model("kgirl/kgirls01.fbx", 0); //MODEL_NO_ANIMS);
|
||||
texture_t t1 = texture("kgirl/g01_texture.png", TEXTURE_RGB);
|
||||
object_t* obj3 = scene_spawn();
|
||||
object_model(obj3, m1);
|
||||
object_diffuse(obj3, t1);
|
||||
object_scale(obj3, vec3(3,3,3));
|
||||
object_move(obj3, vec3(-10,0,-10));
|
||||
object_pivot(obj3, vec3(-90+180,180,0));
|
||||
|
||||
// camera
|
||||
camera_t cam = camera();
|
||||
cam.speed = 0.2f;
|
||||
|
||||
// demo loop
|
||||
while (window_swap())
|
||||
{
|
||||
// input
|
||||
if( input_down(KEY_ESC) ) break;
|
||||
|
||||
// fps camera
|
||||
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
|
||||
window_cursor( !active );
|
||||
|
||||
if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
|
||||
vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
|
||||
vec3 wasdecq = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-(input(KEY_C)||input(KEY_Q)),input(KEY_W)-input(KEY_S)), cam.speed);
|
||||
camera_move(&cam, wasdecq.x,wasdecq.y,wasdecq.z);
|
||||
camera_fps(&cam, mouse.x,mouse.y);
|
||||
|
||||
// queue model scale bounces
|
||||
float t = fmod(window_time(), 0.3) / 0.3;
|
||||
float s = 0.01f * ease_ping_pong(t, ease_in_cubic,ease_out_cubic);
|
||||
object_scale(obj1, vec3(0.20f - s,0.20f + s,0.20f - s));
|
||||
object_scale(obj2, vec3(0.20f - s,0.20f + s,0.20f - s));
|
||||
|
||||
// queue model billboard
|
||||
object_billboard(obj1, (do_billboard_x << 2)|(do_billboard_y << 1)|(do_billboard_z << 0));
|
||||
object_billboard(obj2, (do_billboard_x << 2)|(do_billboard_y << 1)|(do_billboard_z << 0));
|
||||
|
||||
// queue model rotation
|
||||
//object_rotate(obj3, vec3(0,1*window_time() * 20,0));
|
||||
|
||||
// flush render scene (background objects: skybox)
|
||||
profile("Scene background") {
|
||||
scene_render(SCENE_BACKGROUND);
|
||||
}
|
||||
|
||||
// queue debug drawcalls
|
||||
profile("Debugdraw") {
|
||||
ddraw_ground(0);
|
||||
ddraw_color(YELLOW);
|
||||
ddraw_text(vec3(+1,+1,-1), 0.04f, va("(%f,%f,%f)", cam.position.x,cam.position.y,cam.position.z));
|
||||
ddraw_color(YELLOW);
|
||||
ddraw_flush();
|
||||
}
|
||||
|
||||
// apply post-fxs from here
|
||||
fx_begin();
|
||||
|
||||
// render scene (foreground objects) with post-effects
|
||||
profile("Scene foreground") {
|
||||
int scene_flags = 0;
|
||||
scene_flags |= do_wireframe ? SCENE_WIREFRAME : 0;
|
||||
scene_flags |= do_twosided ? 0 : SCENE_CULLFACE;
|
||||
scene_render(SCENE_FOREGROUND | scene_flags);
|
||||
}
|
||||
|
||||
profile("Skeletal update") if(!window_has_pause()) {
|
||||
float delta = window_delta() * 30 ; // 30fps anim
|
||||
m1.curframe = model_animate(m1, m1.curframe + delta);
|
||||
|
||||
ddraw_text(vec3(-10,5,-10), 0.05, va("Frame: %.1f", m1.curframe));
|
||||
}
|
||||
|
||||
// post-fxs end here
|
||||
fx_end();
|
||||
|
||||
// queue ui
|
||||
if( ui_panel("Camera", 0)) {
|
||||
if( ui_float("Speed", &cam.speed) ) {}
|
||||
if( ui_float3("Position", &cam.position.x) ) {}
|
||||
ui_panel_end();
|
||||
}
|
||||
if( ui_panel("Scene", 0)) {
|
||||
if(ui_toggle("Billboard X", &do_billboard_x)) {}
|
||||
if(ui_toggle("Billboard Y", &do_billboard_y)) {}
|
||||
if(ui_toggle("Billboard Z", &do_billboard_z)) {}
|
||||
if(ui_separator()) {}
|
||||
if(ui_bool("Wireframe", &do_wireframe)) {}
|
||||
if(ui_bool("Two sided", &do_twosided)) {}
|
||||
ui_panel_end();
|
||||
}
|
||||
if( ui_panel("FX", 0) ) {
|
||||
for( int i = 0; i < 64; ++i ) {
|
||||
char *name = fx_name(i); if( !name ) break;
|
||||
bool b = fx_enabled(i);
|
||||
if( ui_bool(name, &b) ) fx_enable(i, fx_enabled(i) ^ 1);
|
||||
}
|
||||
ui_panel_end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// material demo
|
||||
// - rlyeh, public domain
|
||||
//
|
||||
// @todo: object_print(obj, "");
|
||||
|
||||
// create camera
|
||||
camera_t cam = camera();
|
||||
// load video, RGB texture, no audio
|
||||
video_t *v = video( "pexels-pachon-in-motion-17486489.mp4", VIDEO_RGB | VIDEO_NO_AUDIO ); video_seek(v, 30);
|
||||
// load texture
|
||||
texture_t t1 = texture("kgirl/g01_texture.png", TEXTURE_RGB);
|
||||
texture_t t2 = texture("matcaps/material3", 0);
|
||||
// load model
|
||||
model_t m1 = model("suzanne.obj", MODEL_NO_ANIMATIONS);
|
||||
model_t m2 = model("suzanne.obj", MODEL_NO_ANIMATIONS|MODEL_MATCAPS);
|
||||
|
||||
// spawn object1 (diffuse)
|
||||
object_t* obj1 = scene_spawn();
|
||||
object_model(obj1, m1);
|
||||
object_diffuse(obj1, t1);
|
||||
object_scale(obj1, vec3(3,3,3));
|
||||
object_move(obj1, vec3(-10+5*0,0,-10));
|
||||
object_pivot(obj1, vec3(0,90,0));
|
||||
|
||||
// spawn object2 (matcap)
|
||||
object_t* obj2 = scene_spawn();
|
||||
object_model(obj2, m2);
|
||||
object_diffuse(obj2, t2);
|
||||
object_scale(obj2, vec3(3,3,3));
|
||||
object_move(obj2, vec3(-10+5*2,0,-10));
|
||||
object_pivot(obj2, vec3(0,90,0));
|
||||
|
||||
// spawn object2 (video)
|
||||
object_t* obj3 = scene_spawn();
|
||||
object_model(obj3, m1);
|
||||
object_diffuse(obj3, video_textures(v)[0]);
|
||||
object_scale(obj3, vec3(3,3,3));
|
||||
object_move(obj3, vec3(-10+5*1,0,-10));
|
||||
object_pivot(obj3, vec3(0,90,0));
|
||||
|
||||
// @todo: add shadertoy material
|
||||
static model_t cube; do_once cube = model("cube.obj", 0);
|
||||
static shadertoy_t s; do_once s = shadertoy("shadertoys/4ttGWM.fs", 256);
|
||||
model_set_texture(cube, shadertoy_render(&s, window_delta())->tx);
|
||||
model_render(cube, cam.proj, cam.view, cube.pivot, 0);
|
||||
|
||||
while(window_swap() && !input(KEY_ESC)) {
|
||||
// draw environment
|
||||
viewport_color( RGB3(22,22,32) );
|
||||
ddraw_grid(0);
|
||||
ddraw_flush();
|
||||
|
||||
// update video
|
||||
video_decode( v );
|
||||
|
||||
// draw scene
|
||||
scene_render(SCENE_FOREGROUND);
|
||||
}
|
||||
|
||||
// load static scene
|
||||
// model_t sponza = model("sponza.obj", MODEL_MATCAPS);
|
||||
// model_set_texture(sponza, texture("matcaps/normals", 0));
|
||||
// translation44(sponza.pivot, 0,-1,0);
|
||||
// rotate44(sponza.pivot, -90,1,0,0);
|
||||
// scale44(sponza.pivot, 10,10,10);
|
||||
// model_render(sponza, cam.proj, cam.view, sponza.pivot, 0);
|
||||
|
||||
// this demo supersedes following old sources:
|
||||
// https://github.com/r-lyeh/FWK/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-material.c
|
||||
// https://github.com/r-lyeh/FWK/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-shadertoy.c
|
||||
|
||||
#endif
|
|
@ -0,0 +1,288 @@
|
|||
// full controller demo: anims, input, collide; @todo: gamepad, input opts, easing on hits, notify on gamepad connect
|
||||
// - rlyeh, public domain.
|
||||
//
|
||||
// Compile with:
|
||||
// `make demos\04-controller.c` (windows)
|
||||
// `sh MAKE.bat demos/04-controller.c` (linux, osx)
|
||||
|
||||
#include "fwk.h"
|
||||
|
||||
int main() {
|
||||
// 75% window, MSAAx2 flag
|
||||
window_create(75, WINDOW_MSAA2);
|
||||
|
||||
// fx: load all post fx files in all subdirs
|
||||
fx_load("fx**.fs");
|
||||
|
||||
// create a camera
|
||||
camera_t cam = camera();
|
||||
camera_enable(&cam);
|
||||
|
||||
// config 3d model #1
|
||||
model_t witch = model("witch/witch.obj", 0);
|
||||
model_set_texture(witch, texture("witch/witch_diffuse.tga.png", 0));
|
||||
mat44 witch_pivot; vec3 witch_p = {-5,0,-5}, witch_r={-180,180,0}, witch_s={0.1,-0.1,0.1};
|
||||
|
||||
// config 3d model #2
|
||||
model_t girl = model("kgirl/kgirls01.fbx", 0);
|
||||
mat44 girl_pivot; vec3 girl_p = {0,0,0}, girl_r = {270,0,0}, girl_s = {2,2,2};
|
||||
|
||||
// skybox
|
||||
skybox_t sky = skybox("cubemaps/stardust", 0);
|
||||
|
||||
// BGM
|
||||
audio_play( audio_stream("waterworld-map.fur"), 0 );
|
||||
|
||||
// editor loop
|
||||
while( window_swap() ) {
|
||||
|
||||
// game camera
|
||||
profile("Game.Camera") {
|
||||
camera_t *cam = camera_get_active();
|
||||
|
||||
static vec3 source;
|
||||
do_once source = cam->position;
|
||||
|
||||
vec3 target = add3(girl_p, vec3(0,10,0));
|
||||
target = add3(target, scale3(norm3(sub3(source, target)), 10.0));
|
||||
source = mix3(source, target, 1-0.99f);
|
||||
|
||||
camera_teleport(cam, source);
|
||||
camera_lookat(cam, vec3(girl_p.x,0,girl_p.z));
|
||||
}
|
||||
|
||||
// render begin (postfx)
|
||||
fx_begin();
|
||||
|
||||
// skybox
|
||||
skybox_render(&sky, cam.proj, cam.view);
|
||||
|
||||
// world
|
||||
ddraw_grid(0);
|
||||
ddraw_flush();
|
||||
|
||||
// models
|
||||
compose44(girl.pivot, girl_p, eulerq(girl_r), girl_s);
|
||||
model_render(girl, cam.proj, cam.view, girl.pivot, 0);
|
||||
|
||||
compose44(witch.pivot, witch_p, eulerq(witch_r), witch_s);
|
||||
model_render(witch, cam.proj, cam.view, witch.pivot, 0);
|
||||
|
||||
// render end (postfx)
|
||||
fx_end();
|
||||
|
||||
// input controllers
|
||||
|
||||
double GAME_JUMP_DOWN = input_down(KEY_Z);
|
||||
double GAME_FIRE_DOWN = input_down(KEY_X);
|
||||
double GAME_JUMP = input(KEY_Z);
|
||||
double GAME_FIRE = input(KEY_X);
|
||||
double GAME_LEFT = input(KEY_J);
|
||||
double GAME_RIGHT = input(KEY_L);
|
||||
double GAME_UP = input(KEY_I);
|
||||
double GAME_DOWN = input(KEY_K);
|
||||
double GAME_AXISX = input(KEY_L) - input(KEY_J);
|
||||
double GAME_AXISY = input(KEY_I) - input(KEY_K);
|
||||
|
||||
if( !input_anykey() ) {
|
||||
if( input(GAMEPAD_CONNECTED) ) {
|
||||
vec2 filtered_lpad = input_filter_deadzone(input2(GAMEPAD_LPAD), 0.15f /*15% deadzone*/);
|
||||
GAME_JUMP_DOWN = input_down(GAMEPAD_A);
|
||||
GAME_FIRE_DOWN = input_down(GAMEPAD_B) || input_down(GAMEPAD_X) || input_down(GAMEPAD_Y);
|
||||
GAME_JUMP = input(GAMEPAD_A);
|
||||
GAME_FIRE = input(GAMEPAD_B) || input(GAMEPAD_X) || input(GAMEPAD_Y);
|
||||
GAME_AXISX = filtered_lpad.x;
|
||||
GAME_AXISY = filtered_lpad.y;
|
||||
}
|
||||
}
|
||||
|
||||
// animation controllers
|
||||
|
||||
profile("Game.Animate scene") if( !window_has_pause() ) {
|
||||
float delta = window_delta() * 30; // 30fps anim
|
||||
|
||||
// animate girl
|
||||
girl.curframe = model_animate(girl, girl.curframe + delta);
|
||||
|
||||
// jump controller: jump duration=1.5s, jump height=6 units, anims (expo->circ)
|
||||
float jump_delta = 1.0;
|
||||
static double jump_timer = 0, jump_ss = 1.5, jump_h = 6;
|
||||
if( GAME_JUMP_DOWN ) if( jump_timer == 0 ) jump_timer = time_ss();
|
||||
jump_delta = clampf(time_ss() - jump_timer, 0, jump_ss) * (1.0/jump_ss);
|
||||
if( jump_delta >= 1 ) { jump_timer = 0; }
|
||||
float y = ease_ping_pong( jump_delta, ease_out_expo, ease_out_circ);
|
||||
girl_p.y = y * jump_h;
|
||||
|
||||
// punch controller
|
||||
float punch_delta = 1;
|
||||
if( jump_delta >= 1 ) {
|
||||
static vec3 origin;
|
||||
static double punch_timer = 0, punch_ss = 0.5;
|
||||
if( GAME_FIRE_DOWN ) if( punch_timer == 0 ) punch_timer = time_ss(), origin = girl_p;
|
||||
punch_delta = clampf(time_ss() - punch_timer, 0, punch_ss) * (1.0/punch_ss);
|
||||
if( punch_delta >= 1 ) { punch_timer = 0; }
|
||||
else {
|
||||
float x = ease_out_expo( punch_delta );
|
||||
vec3 fwd = rotate3q(vec3(0,0,1), eulerq(vec3(girl_r.x - 170,girl_r.y,girl_r.z)));
|
||||
vec3 mix = mix3(girl_p, add3(origin,scale3(fwd,x*2)), x);
|
||||
girl_p.x = mix.x, girl_p.z = mix.z;
|
||||
}
|
||||
}
|
||||
|
||||
int modern_controller = 1;
|
||||
int running = 0;
|
||||
|
||||
// girl controller
|
||||
|
||||
// locomotion vars
|
||||
float speed = 0.2f * delta;
|
||||
float yaw_boost = GAME_AXISY > 0 ? 1.0 : 1.75;
|
||||
if(punch_delta < 1) yaw_boost = 0.0; // if firing...
|
||||
else if(punch_delta <= 0.1) yaw_boost = 4.0; // unless initial punch chaining, extra yaw
|
||||
|
||||
// old fashioned locomotion controller (boat controller)
|
||||
if(!modern_controller) {
|
||||
running = GAME_AXISY > 0;
|
||||
|
||||
girl_r.x -= 170;
|
||||
quat q = eulerq(girl_r); // += custom.pivot
|
||||
vec3 rgt = rotate3q(vec3(1,0,0), q);
|
||||
vec3 up = rotate3q(vec3(0,1,0), q);
|
||||
vec3 fwd = rotate3q(vec3(0,0,1), q);
|
||||
vec3 dir = scale3(fwd, speed * GAME_AXISY * (GAME_AXISY > 0 ? 2.0 : 0.5));
|
||||
girl_r.x += speed * 20.0 * yaw_boost * GAME_AXISX; // yaw
|
||||
girl_p = add3(girl_p, dir);
|
||||
girl_r.x += 170;
|
||||
}
|
||||
|
||||
// modern locomotion controller (mario 3d)
|
||||
if(modern_controller) {
|
||||
running = GAME_AXISX != 0 || GAME_AXISY != 0;
|
||||
|
||||
camera_t *cam = camera_get_active();
|
||||
vec3 fwd = sub3(girl_p, cam->position); fwd.y = 0; fwd = norm3(fwd);
|
||||
vec3 rgt = norm3(cross3(fwd, vec3(0,1,0)));
|
||||
|
||||
// target
|
||||
vec3 dir = add3(
|
||||
scale3(fwd, GAME_AXISY),
|
||||
scale3(rgt, GAME_AXISX)
|
||||
); dir.y = 0; dir = norm3(dir);
|
||||
|
||||
// smoothing
|
||||
static vec3 olddir; do_once olddir = dir;
|
||||
dir = mix3(dir, olddir, 1 - (yaw_boost / 4.0) * 0.85);
|
||||
olddir = dir;
|
||||
|
||||
// vis
|
||||
// ddraw_arrow(girl_p, add3(girl_p,scale3(dir,10)));
|
||||
|
||||
// apply direction
|
||||
girl_p = add3(girl_p, scale3(dir, speed * 2));
|
||||
|
||||
// apply rotation
|
||||
{
|
||||
girl_r.x -= 170;
|
||||
quat q = eulerq(girl_r);
|
||||
vec3 fwdg = rotate3q(vec3(0,0,1), q);
|
||||
girl_r.x += 170;
|
||||
|
||||
//float cosAngle = dot3(dir,fwdg);
|
||||
//float angle = acos(cosAngle) * TO_DEG;
|
||||
float angle = TO_DEG * ( atan2(fwdg.z, fwdg.x) - atan2(dir.z, dir.x));
|
||||
|
||||
if( !isnan(angle) ) {
|
||||
girl_r.x -= angle;
|
||||
while(girl_r.x> 180) girl_r.x-=360;
|
||||
while(girl_r.x<-180) girl_r.x+=360;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// anim loops
|
||||
if( jump_delta < 1 ) { // jump/kick anim
|
||||
#if 0
|
||||
girl.curframe = clampf(girl.curframe, 184, 202);
|
||||
if( girl.curframe > 202-4 && GAME_FIRE_DOWN ) girl.curframe = 184+4;
|
||||
#else
|
||||
#define loopf(frame, min, max) (frame < min ? min : frame > max ? min + frame - max : frame)
|
||||
if(girl.curframe >= 203)
|
||||
girl.curframe = loopf(girl.curframe, 203, 220);
|
||||
else
|
||||
girl.curframe = clampf(girl.curframe, 184, 202);
|
||||
if( girl.curframe > 202-4 && girl.curframe < 208 && GAME_FIRE_DOWN ) girl.curframe = 203;
|
||||
#endif
|
||||
}
|
||||
else if( punch_delta < 1 ) { // punch anim
|
||||
girl.curframe = clampf(girl.curframe, 90, 101);
|
||||
if( girl.curframe > 101-6 && GAME_FIRE_DOWN ) girl.curframe = 101-6;
|
||||
}
|
||||
else if( running ) {
|
||||
// loop running anim
|
||||
if( girl.curframe < 65 ) girl.curframe = 65;
|
||||
if( girl.curframe > 85 ) girl.curframe = 65;
|
||||
}
|
||||
else { // loop idle anim
|
||||
if( girl.curframe > 59 ) girl.curframe = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Game collisions
|
||||
|
||||
profile("Game.collisions") {
|
||||
bool punching = girl.curframe >= 90 && girl.curframe < 101;
|
||||
bool air_kicking = girl.curframe >= 184 && girl.curframe < 202;
|
||||
bool jump_kicking = girl.curframe >= 203 && girl.curframe < 220;
|
||||
bool attacking = punching || air_kicking || jump_kicking;
|
||||
|
||||
if( attacking ) {
|
||||
aabb boxg = model_aabb(girl, girl_pivot);
|
||||
aabb boxw = model_aabb(witch, witch_pivot);
|
||||
#if 0 // halve aabb. ok
|
||||
{
|
||||
vec3 diag = sub3(boxg.max, boxg.min);
|
||||
vec3 halve = scale3(diag, 0.25);
|
||||
vec3 center = scale3(add3(boxg.min, boxg.max), 0.5);
|
||||
boxg.min = sub3(center, halve);
|
||||
boxg.max = add3(center, halve);
|
||||
}
|
||||
#endif
|
||||
hit* h = aabb_hit_aabb(boxg, boxw);
|
||||
if( h && GAME_FIRE ) {
|
||||
vec3 dir = norm3(sub3(witch_p, girl_p));
|
||||
witch_p = add3(witch_p, mul3(dir,vec3(1,0,1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ui
|
||||
if( ui_panel("Input", 0) ) { // @todo: showcase input binding
|
||||
ui_section("Controllers");
|
||||
ui_label("Gamepad #1");
|
||||
ui_label("Keys I/J/K/L + Z/X");
|
||||
ui_panel_end();
|
||||
}
|
||||
if( ui_panel("FX", 0) ) {
|
||||
for( int i = 0; i < 64; ++i ) {
|
||||
char *name = fx_name(i); if( !name ) break;
|
||||
bool b = fx_enabled(i);
|
||||
if( ui_bool(name, &b) ) fx_enable(i, b);
|
||||
}
|
||||
ui_panel_end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vec2 do_gamepad_polarity = vec2(+1,+1);
|
||||
// vec2 do_gamepad_sensitivity = vec2(0.1f,0.1f);
|
||||
// vec2 do_mouse_polarity = vec2(+1,-1);
|
||||
// vec2 do_mouse_sensitivity = vec2(0.2f,0.2f);
|
||||
// float do_gamepad_deadzone = 0.15f;//
|
||||
//
|
||||
// if(ui_separator()) {}
|
||||
// if(ui_slider("Gamepad deadzone", &do_gamepad_deadzone)) {}
|
||||
// if(ui_float2("Gamepad polarity", do_gamepad_polarity.v2)) {}
|
||||
// if(ui_float2("Gamepad sensitivity", do_gamepad_sensitivity.v2)) {}
|
||||
// if(ui_separator()) {}
|
||||
// if(ui_float2("Mouse polarity", do_mouse_polarity.v2)) {}
|
||||
// if(ui_float2("Mouse sensitivity", do_mouse_sensitivity.v2)) {}//
|
|
@ -0,0 +1,88 @@
|
|||
// network demo: sockets, downloads, script, @todo: ecs, vm, obj, teal
|
||||
// - rlyeh, public domain.
|
||||
//
|
||||
// Compile with:
|
||||
// `make demos\07-network.c` (windows)
|
||||
// `sh MAKE.bat demos/07-network.c` (linux, osx)
|
||||
|
||||
#include "fwk.h"
|
||||
|
||||
volatile int client_socket = -1;
|
||||
volatile int server_socket = -1;
|
||||
|
||||
int server_echo(int cli) {
|
||||
ui_notify("Server: client connected", va("Address %s:%s", tcp_host(cli), tcp_port(cli)));
|
||||
char buf[128];
|
||||
int len = tcp_recv(cli, buf, 128);
|
||||
if( len > 0 ) tcp_send(cli, buf, len); // echo
|
||||
tcp_close(cli);
|
||||
return 1;
|
||||
}
|
||||
int server_thread(void *userdata) {
|
||||
server_socket = tcp_bind("0.0.0.0", "8080", 10); // port "0" for auto
|
||||
for(;;) {
|
||||
tcp_peek(server_socket, server_echo);
|
||||
sleep_ms(100);
|
||||
}
|
||||
}
|
||||
void client_message(const char *msg) {
|
||||
client_socket = tcp_open("127.0.0.1", "8080");
|
||||
if( client_socket >= 0 ) {
|
||||
tcp_send(client_socket, msg, strlen(msg));
|
||||
char buf[128];
|
||||
int rlen = tcp_recv(client_socket, buf, 128);
|
||||
if(rlen > 0) ui_notify("Client", va("Received '%.*s' from server", rlen, buf));
|
||||
// tcp_close(client_socket);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
window_create(0.85, 0);
|
||||
window_title(__FILE__);
|
||||
while(window_swap()) {
|
||||
static int ui_open; ui_open = 1;
|
||||
if( ui_window("Network", &ui_open) ) {
|
||||
|
||||
if( ui_button("Server: listen") ) { do_once thread(server_thread, NULL); }
|
||||
ui_label(server_socket >= 0 ? "Listening at 8080 port" : "Not ready");
|
||||
|
||||
ui_separator();
|
||||
|
||||
if( ui_button("Client: send message") ) client_message("Hi");
|
||||
ui_label(client_socket >= 0 ? va("Connected to server. My address is %s:%s", tcp_host(client_socket), tcp_port(client_socket)) : "Not connected");
|
||||
|
||||
ui_separator();
|
||||
|
||||
if( ui_button("Download test (https)")) {
|
||||
array(char) webfile = download("https://www.google.com/"); // @leak
|
||||
ui_notify("Download test", va("%d bytes downloaded from google.com", array_count(webfile)));
|
||||
}
|
||||
|
||||
ui_separator();
|
||||
|
||||
if( ui_button("Script test")) {
|
||||
script_run( "ui_notify(\"Script test\", \"Hello from \" .. _VERSION)");
|
||||
script_run( "-- Bye.lua\nio.write(\"script test: Bye world!, from \", _VERSION, \"\\n\")" );
|
||||
}
|
||||
|
||||
ui_window_end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this demo supersedes following old sources:
|
||||
// https://github.com/r-lyeh/FWK/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-demo.c
|
||||
// https://github.com/r-lyeh/FWK/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-script.c
|
||||
// https://github.com/r-lyeh/FWK/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-socket.c
|
||||
|
||||
#if 0 // teal
|
||||
script_run("local tl=require(\"tl\")\ntl.loader()");
|
||||
script_run("addsub = require(\"s2\"); print (addsub.add(10, 20))");
|
||||
s2.tl:
|
||||
local function add(a: number, b: number): number
|
||||
return a + b
|
||||
end
|
||||
local s = add(1,2)
|
||||
print(s)
|
||||
#endif
|
|
@ -0,0 +1,39 @@
|
|||
// audio demo
|
||||
// - rlyeh, public domain
|
||||
|
||||
#include "fwk.h"
|
||||
|
||||
int main() {
|
||||
// window (80% sized, MSAA x4 flag)
|
||||
window_create(80, WINDOW_MSAA4 | WINDOW_SQUARE);
|
||||
|
||||
// audio (both streams & clips)
|
||||
audio_t stream1 = audio_stream( "wrath_of_the_djinn.xm" );
|
||||
audio_t stream2 = audio_stream( "larry.mid" );
|
||||
audio_t stream3 = audio_stream( "monkey1.mid" );
|
||||
audio_t stream4 = audio_stream( "waterworld-map.fur" );
|
||||
audio_t BGM = stream1;
|
||||
audio_play(BGM, 0);
|
||||
|
||||
audio_t SFX1 = audio_clip( "coin.wav" );
|
||||
audio_t SFX2 = audio_clip( "pew.sfxr" );
|
||||
audio_play(SFX1, 0);
|
||||
|
||||
// demo loop
|
||||
while (window_swap() && !input_down(KEY_ESC)) {
|
||||
static int open = 1;
|
||||
if( ui_window("Audio", &open)) {
|
||||
static float bgm = 1, sfx = 1, master = 1;
|
||||
if( ui_slider2("BGM", &bgm, va("%.2f", bgm))) audio_volume_stream(bgm);
|
||||
if( ui_slider2("SFX", &sfx, va("%.2f", sfx))) audio_volume_clip(sfx);
|
||||
if( ui_slider2("Master", &master, va("%.2f", master))) audio_volume_master(master);
|
||||
if( ui_label2_toolbar("BGM: Wrath of the Djinn", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = stream1, AUDIO_SINGLE_INSTANCE);
|
||||
if( ui_label2_toolbar("BGM: Leisure Suit Larry", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = stream2, AUDIO_SINGLE_INSTANCE);
|
||||
if( ui_label2_toolbar("BGM: Monkey Island", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = stream3, AUDIO_SINGLE_INSTANCE);
|
||||
if( ui_label2_toolbar("BGM: Waterworld Map", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = stream4, AUDIO_SINGLE_INSTANCE);
|
||||
if( ui_label2_toolbar("SFX: Coin", ICON_MD_VOLUME_UP)) audio_play(SFX1, 0);
|
||||
if( ui_label2_toolbar("SFX: Pew", ICON_MD_VOLUME_UP)) audio_play(SFX2, 0);
|
||||
ui_window_end();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
#include "fwk.h"
|
||||
|
||||
int SKY_DIR = 0;
|
||||
const char *SKY_DIRS[] = {
|
||||
"cubemaps/bridge3/",
|
||||
"cubemaps/colors/",
|
||||
"cubemaps/colors2/",
|
||||
"cubemaps/mountain/",
|
||||
"cubemaps/room/",
|
||||
"cubemaps/stardust/",
|
||||
"hdr/MonValley_G_DirtRoad_1k.hdr",
|
||||
"hdr/Factory_Catwalk_1k.hdr",
|
||||
"hdr/Shiodome_Stairs_1k.hdr",
|
||||
};
|
||||
|
||||
int OBJ_MDL = 0;
|
||||
const char *OBJ_MDLS[] = {
|
||||
"meshes/sphere.obj",
|
||||
"meshes/suzanne.obj",
|
||||
"meshes/gazebo.obj",
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
window_create(85, WINDOW_MSAA8);
|
||||
|
||||
camera_t cam = camera();
|
||||
skybox_t sky = {0};
|
||||
model_t mdl = {0};
|
||||
|
||||
bool initialized = 0;
|
||||
bool must_reload = 0;
|
||||
|
||||
while( window_swap()) {
|
||||
// reloading
|
||||
if( must_reload ) {
|
||||
must_reload = 0;
|
||||
skybox_destroy(&sky);
|
||||
model_destroy(mdl);
|
||||
initialized = 0;
|
||||
}
|
||||
if( !initialized ) {
|
||||
initialized = 1;
|
||||
sky = skybox(SKY_DIRS[SKY_DIR], 0);
|
||||
mdl = model(OBJ_MDLS[OBJ_MDL], 0);
|
||||
rotation44(mdl.pivot, 0, 1,0,0); // @fixme: -90,1,0,0 -> should we rotate SHMs as well? compensate rotation in shader?
|
||||
}
|
||||
|
||||
// fps camera
|
||||
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
|
||||
window_cursor( !active );
|
||||
|
||||
if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
|
||||
vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
|
||||
vec3 wasdec = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-input(KEY_C),input(KEY_W)-input(KEY_S)), cam.speed);
|
||||
camera_move(&cam, wasdec.x,wasdec.y,wasdec.z);
|
||||
camera_fps(&cam, mouse.x,mouse.y);
|
||||
|
||||
// render
|
||||
mat44 mvp; multiply44x2(mvp, cam.proj, cam.view);
|
||||
{
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
//glDisable(GL_CULL_FACE);
|
||||
|
||||
// mesh
|
||||
glDepthMask(GL_TRUE);
|
||||
glUseProgram(mdl.program);
|
||||
glUniform3fv(glGetUniformLocation(mdl.program, "u_coefficients_sh"), 9, &sky.cubemap.sh[0].x);
|
||||
glUniform1i(glGetUniformLocation(mdl.program, "u_textured"), false);
|
||||
model_render(mdl, cam.proj, cam.view, mdl.pivot, 0);
|
||||
|
||||
// sky
|
||||
skybox_render(&sky, cam.proj, cam.view);
|
||||
}
|
||||
|
||||
if( ui_panel("Scene", 0)) {
|
||||
if( ui_list("Skybox", SKY_DIRS, countof(SKY_DIRS), &SKY_DIR) ) {
|
||||
must_reload = 1;
|
||||
}
|
||||
if( ui_list("Model", OBJ_MDLS, countof(OBJ_MDLS), &OBJ_MDL) ) {
|
||||
must_reload = 1;
|
||||
}
|
||||
ui_separator();
|
||||
for (int i = 0; i < 9; i++) {
|
||||
vec3 remap = scale3(add3(sky.cubemap.sh[i], vec3(1,1,1)), 127.5f); // -1..+1 -> 0..255
|
||||
ui_color3(va("SH Coefficient [%d]", i), &remap.x);
|
||||
sky.cubemap.sh[i] = sub3(scale3(remap, 1/127.5f), vec3(1,1,1));
|
||||
}
|
||||
ui_panel_end();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
#include "fwk.h"
|
||||
|
||||
struct {
|
||||
float (*ease)(float);
|
||||
const char *name;
|
||||
} easings[] = {
|
||||
{ease_linear, "ease_linear"},
|
||||
{ease_out_sine, "ease_out_sine"},
|
||||
{ease_out_quad, "ease_out_quad"},
|
||||
{ease_out_cubic, "ease_out_cubic"},
|
||||
{ease_out_quart, "ease_out_quart"},
|
||||
{ease_out_quint, "ease_out_quint"},
|
||||
{ease_out_expo, "ease_out_expo"},
|
||||
{ease_out_circ, "ease_out_circ"},
|
||||
{ease_out_back, "ease_out_back"},
|
||||
{ease_out_elastic, "ease_out_elastic"},
|
||||
{ease_out_bounce, "ease_out_bounce"},
|
||||
{ease_in_sine, "ease_in_sine"},
|
||||
{ease_in_quad, "ease_in_quad"},
|
||||
{ease_in_cubic, "ease_in_cubic"},
|
||||
{ease_in_quart, "ease_in_quart"},
|
||||
{ease_in_quint, "ease_in_quint"},
|
||||
{ease_in_expo, "ease_in_expo"},
|
||||
{ease_in_circ, "ease_in_circ"},
|
||||
{ease_in_back, "ease_in_back"},
|
||||
{ease_in_elastic, "ease_in_elastic"},
|
||||
{ease_in_bounce, "ease_in_bounce"},
|
||||
{ease_inout_sine, "ease_inout_sine"},
|
||||
{ease_inout_quad, "ease_inout_quad"},
|
||||
{ease_inout_cubic, "ease_inout_cubic"},
|
||||
{ease_inout_quart, "ease_inout_quart"},
|
||||
{ease_inout_quint, "ease_inout_quint"},
|
||||
{ease_inout_expo, "ease_inout_expo"},
|
||||
{ease_inout_circ, "ease_inout_circ"},
|
||||
{ease_inout_back, "ease_inout_back"},
|
||||
{ease_inout_elastic, "ease_inout_elastic"},
|
||||
{ease_inout_bounce, "ease_inout_bounce"},
|
||||
{ease_inout_perlin, "ease_inout_perlin"},
|
||||
};
|
||||
|
||||
int main() {
|
||||
window_create(0.75, WINDOW_SQUARE);
|
||||
while(window_swap()) {
|
||||
static double timer = 0; timer = fmod(timer+window_delta(), 2); // loops every 2s
|
||||
|
||||
static int open = 1;
|
||||
if( ui_window("ease", &open) ) {
|
||||
float linear_delta = timer / 2.f; // delta is [0..1]
|
||||
for( int i = 0; i < countof(easings); ++i) {
|
||||
float nonlinear_delta = easings[i].ease(linear_delta);
|
||||
// visualize
|
||||
ui_slider( easings[i].name, &nonlinear_delta );
|
||||
}
|
||||
ui_window_end();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
#include "fwk.h"
|
||||
|
||||
int main() {
|
||||
window_create(0.75, WINDOW_MSAA8);
|
||||
|
||||
// style: our aliases
|
||||
#define FONT_REGULAR FONT_FACE1
|
||||
#define FONT_ITALIC FONT_FACE2
|
||||
#define FONT_BOLD FONT_FACE3
|
||||
#define FONT_JAPANESE FONT_FACE4
|
||||
#define FONT_MONOSPACE FONT_FACE5
|
||||
|
||||
#define FONT_GRAY FONT_COLOR2
|
||||
#define FONT_ORANGE FONT_COLOR3
|
||||
#define FONT_LIME FONT_COLOR4
|
||||
#define FONT_GREEN FONT_COLOR5
|
||||
#define FONT_CYAN FONT_COLOR6
|
||||
|
||||
#define FONT_LARGEST FONT_H1
|
||||
#define FONT_LARGE FONT_H2
|
||||
#define FONT_MEDIUM FONT_H3
|
||||
#define FONT_NORMAL FONT_H4
|
||||
#define FONT_SMALL FONT_H5
|
||||
#define FONT_TINY FONT_H6
|
||||
|
||||
// style: atlas size, unicode ranges and font faces (up to 6 faces)
|
||||
font_face(FONT_REGULAR, "Carlito-Regular.ttf", 48.f, FONT_EU|FONT_AR|FONT_RU|FONT_2048);
|
||||
font_face(FONT_ITALIC, "Carlito-Italic.ttf", 48.f, FONT_EU|FONT_AR|FONT_RU|FONT_2048);
|
||||
font_face(FONT_BOLD, "Carlito-Bold.ttf", 48.f, FONT_EU|FONT_AR|FONT_RU|FONT_2048);
|
||||
font_face(FONT_JAPANESE, "mplus-1p-medium.ttf", 48.f, FONT_JP|FONT_2048); // CJK|FONT_2048|FONT_OVERSAMPLE_Y);
|
||||
font_face(FONT_MONOSPACE, "Inconsolata-Regular.ttf", 24.f, FONT_EU|FONT_512);
|
||||
|
||||
// style: colors (up to 10 colors)
|
||||
font_color(FONT_GRAY, RGB4(100,100,100,255));
|
||||
font_color(FONT_ORANGE, RGB4(255,192,0,255));
|
||||
font_color(FONT_LIME, RGB4(192,255,0,255));
|
||||
font_color(FONT_GREEN, RGB4(0,255,192,255));
|
||||
font_color(FONT_CYAN, RGB4(0,192,255,255));
|
||||
|
||||
// prepare color highlighting for following code snippet
|
||||
const char *source =
|
||||
FONT_MONOSPACE FONT_LARGEST
|
||||
"int main(int argc, char **argv) {\n"
|
||||
" for( int i = 0; i < 10; ++i)\n"
|
||||
" puts(\"hello world\");\n"
|
||||
" return 0;\n"
|
||||
"}\n";
|
||||
const void *colors = font_colorize(source, "void,int,char", "if,else,for,do,while,return,switch,case,break,default,");
|
||||
|
||||
// demo loop
|
||||
while( window_swap() && !input(KEY_ESC) ) {
|
||||
ddraw_grid(0);
|
||||
|
||||
// initial spacing
|
||||
font_goto(0, 50);
|
||||
|
||||
// print a code snippet with syntax highlighting
|
||||
font_highlight(source, colors);
|
||||
|
||||
// print a few strings with markup codes
|
||||
font_print(
|
||||
FONT_REGULAR
|
||||
FONT_LARGEST FONT_GRAY "The quick "
|
||||
FONT_LARGE FONT_LIME "brown "
|
||||
FONT_MEDIUM FONT_GRAY "fox "
|
||||
FONT_NORMAL "jumps over "
|
||||
FONT_SMALL "the lazy "
|
||||
FONT_TINY "dog.\n");
|
||||
|
||||
font_print(
|
||||
FONT_REGULAR FONT_LARGE FONT_CYAN
|
||||
"Now is the time for all " FONT_ITALIC "good men " FONT_REGULAR "to come to the aid of " FONT_BOLD "the party.\n");
|
||||
|
||||
font_print(
|
||||
FONT_ITALIC FONT_LARGE FONT_GREEN
|
||||
"Ég get etið gler án þess að meiða mig!\n");
|
||||
|
||||
font_print(
|
||||
FONT_BOLD FONT_LARGE FONT_ORANGE
|
||||
"Эх, чужак! Общий съём цен шляп (юфть)—вдрызг!.\n");
|
||||
|
||||
font_print(
|
||||
FONT_JAPANESE
|
||||
"私はガラスを食べられます。それは私を傷つけません。\n");
|
||||
|
||||
font_print( "This text ");
|
||||
font_print( "should display concatenated, ");
|
||||
font_print( "as there are no linefeeds.\n" );
|
||||
|
||||
// i18n: pangrams.txt file, line browser
|
||||
static int counter = 0;
|
||||
static array(char*) lines; do_once lines = strsplit( vfs_read("pangrams.txt"), "\r\n" );
|
||||
counter += input_down(KEY_RIGHT)-input_down(KEY_LEFT);
|
||||
counter += counter < 0 ? array_count(lines) : 0;
|
||||
font_print( va("<< %s >>\n", lines[counter % array_count(lines)]) );
|
||||
|
||||
// this does not work yet. you cant chain alignments yet...
|
||||
//font_print(FONT_TOP "Top" FONT_MIDDLE "Middle" FONT_BASELINE "Baseline" FONT_BOTTOM "Bottom\n");
|
||||
//font_print(FONT_LEFT "Left" FONT_CENTER "Center" FONT_RIGHT "Right\n");
|
||||
|
||||
// ... alignment must be the first tag in a string for now. this is a temporary hack.
|
||||
font_print(FONT_LEFT "left");
|
||||
font_print(FONT_CENTER "center");
|
||||
font_print(FONT_RIGHT "right");
|
||||
|
||||
font_print(FONT_TOP FONT_CENTER "top\n");
|
||||
font_print(FONT_MIDDLE FONT_RIGHT "middle\n");
|
||||
font_print(FONT_BASELINE FONT_RIGHT "baseline\n");
|
||||
font_print(FONT_BOTTOM FONT_CENTER "bottom\n");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
// instanced models demo
|
||||
// - rlyeh, public domain.
|
||||
|
||||
#include "fwk.h"
|
||||
|
||||
int main() {
|
||||
window_create(75, WINDOW_MSAA2);
|
||||
window_title(__FILE__);
|
||||
|
||||
camera_t cam = camera();
|
||||
skybox_t sky = skybox("cubemaps/stardust", 0);
|
||||
model_t girl = model("kgirls01.fbx", 0);
|
||||
|
||||
while( window_swap() ) {
|
||||
if(input(KEY_F5)) window_reload();
|
||||
if(input(KEY_ESC)) break;
|
||||
|
||||
// fps camera
|
||||
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
|
||||
window_cursor( !active );
|
||||
|
||||
if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
|
||||
vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
|
||||
vec3 wasdec = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-input(KEY_C),input(KEY_W)-input(KEY_S)), cam.speed);
|
||||
camera_move(&cam, wasdec.x,wasdec.y,wasdec.z);
|
||||
camera_fps(&cam, mouse.x,mouse.y);
|
||||
|
||||
// ground rendering
|
||||
ddraw_ground(0);
|
||||
ddraw_flush();
|
||||
|
||||
// skeletal
|
||||
profile("Skeletal update") {
|
||||
float delta = window_has_pause() ? 0 : window_delta() * 30; // 30fps anim
|
||||
girl.curframe = model_animate(girl, girl.curframe + delta);
|
||||
}
|
||||
|
||||
profile("Skeletal render") {
|
||||
enum { ROW = 32, MAX_INSTANCES = ROW * ROW };
|
||||
static mat44 M[MAX_INSTANCES];
|
||||
|
||||
do_once {
|
||||
int i = 0;
|
||||
for(int z = 0; z < ROW; ++z) {
|
||||
for(int x = 0; x < ROW; ++x, ++i) {
|
||||
vec3 p = vec3(-x*3,0,-z*3);
|
||||
vec3 r = vec3(0,0,0);
|
||||
vec3 s = vec3(2,2,2);
|
||||
rotationq44(M[i], eulerq(r)); scale44(M[i], s.x,s.y,s.z); relocate44(M[i], p.x,p.y,p.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
model_render_instanced(girl, cam.proj, cam.view, M, 0, MAX_INSTANCES);
|
||||
}
|
||||
|
||||
// skybox
|
||||
profile("Skybox") {
|
||||
skybox_render(&sky, cam.proj, cam.view);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
// material demo
|
||||
// - rlyeh, public domain
|
||||
//
|
||||
// @todo: object_print(obj, "");
|
||||
|
||||
#include "fwk.h"
|
||||
|
||||
int main() {
|
||||
// create the window
|
||||
window_create( 0.75f, WINDOW_MSAA8 );
|
||||
|
||||
// create camera
|
||||
camera_t cam = camera();
|
||||
// load video, RGB texture, no audio
|
||||
video_t *v = video( "pexels-pachon-in-motion-17486489.mp4", VIDEO_RGB | VIDEO_NO_AUDIO ); video_seek(v, 30);
|
||||
// load texture
|
||||
texture_t t1 = texture("kgirl/g01_texture.png", TEXTURE_RGB);
|
||||
texture_t t2 = texture("matcaps/material3", 0);
|
||||
// load model
|
||||
model_t m1 = model("suzanne.obj", MODEL_NO_ANIMATIONS);
|
||||
model_t m2 = model("suzanne.obj", MODEL_NO_ANIMATIONS|MODEL_MATCAPS);
|
||||
|
||||
// spawn object1 (diffuse)
|
||||
object_t* obj1 = scene_spawn();
|
||||
object_model(obj1, m1);
|
||||
object_diffuse(obj1, t1);
|
||||
object_scale(obj1, vec3(3,3,3));
|
||||
object_move(obj1, vec3(-10+5*0,0,-10));
|
||||
object_pivot(obj1, vec3(0,90,0));
|
||||
|
||||
// spawn object2 (matcap)
|
||||
object_t* obj2 = scene_spawn();
|
||||
object_model(obj2, m2);
|
||||
object_diffuse(obj2, t2);
|
||||
object_scale(obj2, vec3(3,3,3));
|
||||
object_move(obj2, vec3(-10+5*2,0,-10));
|
||||
object_pivot(obj2, vec3(0,90,0));
|
||||
|
||||
// spawn object2 (video)
|
||||
object_t* obj3 = scene_spawn();
|
||||
object_model(obj3, m1);
|
||||
object_diffuse(obj3, video_textures(v)[0]);
|
||||
object_scale(obj3, vec3(3,3,3));
|
||||
object_move(obj3, vec3(-10+5*1,0,-10));
|
||||
object_pivot(obj3, vec3(0,90,0));
|
||||
|
||||
while(window_swap() && !input(KEY_ESC)) {
|
||||
// draw environment
|
||||
viewport_color( RGB3(22,22,32) );
|
||||
ddraw_grid(0);
|
||||
ddraw_flush();
|
||||
|
||||
// update video
|
||||
video_decode( v );
|
||||
|
||||
// draw scene
|
||||
scene_render(SCENE_FOREGROUND);
|
||||
|
||||
// fps camera
|
||||
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
|
||||
if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
|
||||
vec2 mouselook = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
|
||||
vec3 wasdec = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-input(KEY_C),input(KEY_W)-input(KEY_S)), cam.speed);
|
||||
camera_move(&cam, wasdec.x,wasdec.y,wasdec.z);
|
||||
camera_fps(&cam, mouselook.x,mouselook.y);
|
||||
window_cursor( !active );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,675 @@
|
|||
// PBR model viewer. Based on Foxotron by @gargaj + cce/Peisik (UNLICENSE).
|
||||
// - rlyeh, public domain.
|
||||
//
|
||||
// @todo: Middle mouse button to pan camera @todo
|
||||
|
||||
#include "fwk.h"
|
||||
|
||||
#if is(tcc) && !is(win32) // @todo: remove this & test on linux
|
||||
int log2_64 (uint64_t value) {
|
||||
const int tab64[64] = {
|
||||
63, 0, 58, 1, 59, 47, 53, 2,
|
||||
60, 39, 48, 27, 54, 33, 42, 3,
|
||||
61, 51, 37, 40, 49, 18, 28, 20,
|
||||
55, 30, 34, 11, 43, 14, 22, 4,
|
||||
62, 57, 46, 52, 38, 26, 32, 41,
|
||||
50, 36, 17, 19, 29, 10, 13, 21,
|
||||
56, 45, 25, 31, 35, 16, 9, 12,
|
||||
44, 24, 15, 8, 23, 7, 6, 5};
|
||||
value |= value >> 1;
|
||||
value |= value >> 2;
|
||||
value |= value >> 4;
|
||||
value |= value >> 8;
|
||||
value |= value >> 16;
|
||||
value |= value >> 32;
|
||||
return tab64[((uint64_t)((value - (value >> 1))*0x07EDD5E59A4E28C2)) >> 58];
|
||||
}
|
||||
#define log2 log2_64
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// textures
|
||||
|
||||
texture_t *LoadTextureRGBA8( const char *pathfile, unsigned flags ) {
|
||||
int flags_hdr = strendi(pathfile, ".hdr") ? TEXTURE_FLOAT | TEXTURE_RGBA : 0;
|
||||
texture_t t = texture(pathfile, flags | TEXTURE_LINEAR | TEXTURE_MIPMAPS | TEXTURE_REPEAT | flags_hdr);
|
||||
if( t.id == texture_checker().id ) {
|
||||
return NULL;
|
||||
}
|
||||
texture_t *tex = CALLOC(1, sizeof(texture_t));
|
||||
*tex = t;
|
||||
return tex;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// models
|
||||
|
||||
typedef struct Mesh {
|
||||
GLuint vao, vbo, ibo;
|
||||
|
||||
int vert_stride;
|
||||
void *vert_stream;
|
||||
int num_verts, num_tris;
|
||||
|
||||
int material_idx;
|
||||
bool transparent;
|
||||
|
||||
vec3 aabb_min, aabb_max;
|
||||
} Mesh;
|
||||
|
||||
typedef struct Model {
|
||||
array(Mesh) meshes;
|
||||
array(pbr_material_t) materials;
|
||||
unsigned shader;
|
||||
} Model;
|
||||
|
||||
bool ModelLoad( Model *G, const char *_path );
|
||||
void ModelDestroy( Model *G );
|
||||
void ModelRebind( Model *G, unsigned shader );
|
||||
void ModelRender( Model *G, const mat44 _worldRootMatrix );
|
||||
|
||||
void ModelDestroy( Model *G) {
|
||||
for( int i = 0, end = array_count(G->materials); i < end; ++i ) {
|
||||
pbr_material_destroy(&G->materials[i]);
|
||||
}
|
||||
array_free(G->materials);
|
||||
|
||||
for( int i = 0, end = array_count(G->meshes); i < end; ++i ) {
|
||||
Mesh *it = &G->meshes[i];
|
||||
glDeleteBuffers( 1, &it->ibo );
|
||||
glDeleteBuffers( 1, &it->vbo );
|
||||
glDeleteVertexArrays( 1, &it->vao );
|
||||
}
|
||||
array_free(G->meshes);
|
||||
}
|
||||
|
||||
bool ModelLoad( Model *G, const char *_path ) {
|
||||
ModelDestroy(G);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
Model g = {0};
|
||||
*G = g;
|
||||
|
||||
model_t m = model(_path, 0);
|
||||
|
||||
int scn_num_meshes = m.num_meshes;
|
||||
int scn_num_materials = array_count(m.materials);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
for( int i = 0; i < scn_num_materials; i++ ) {
|
||||
const char *name = m.materials[i].name;
|
||||
|
||||
PRINTF("Loading material %d/%d: '%s'\n", i + 1, scn_num_materials, name);
|
||||
|
||||
pbr_material_t mt;
|
||||
pbr_material(&mt, name);
|
||||
|
||||
array_push(G->materials, mt);
|
||||
}
|
||||
|
||||
for( int i = 0; i < scn_num_meshes; i++ ) {
|
||||
PRINTF("Loading mesh %d/%d\n", i + 1, scn_num_meshes);
|
||||
|
||||
int verts = m.num_verts;
|
||||
int faces = m.num_triangles;
|
||||
unsigned material_index = 0; // &m.iqm->meshes[i].material; // aiGetMeshMaterialIndex(scn_mesh[i]);
|
||||
|
||||
bool has_data = verts && faces;
|
||||
if( !has_data ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PRINTF("Loading mesh v%d/f%d\n", verts, faces);
|
||||
|
||||
Mesh mesh = { 0 };
|
||||
|
||||
mesh.vao = m.vao;
|
||||
mesh.vbo = m.vbo;
|
||||
mesh.ibo = m.ibo;
|
||||
|
||||
mat44 id; id44(id);
|
||||
mesh.aabb_min = model_aabb(m, id).min;
|
||||
mesh.aabb_max = model_aabb(m, id).max;
|
||||
|
||||
// p3 n3 t3 b3 u2
|
||||
|
||||
mesh.vert_stride = m.stride;
|
||||
mesh.vert_stream = m.verts;
|
||||
|
||||
mesh.num_verts = verts;
|
||||
mesh.num_tris = faces;
|
||||
|
||||
mesh.material_idx = material_index;
|
||||
|
||||
// By importing materials before meshes we can investigate whether a mesh is transparent and flag it as such.
|
||||
const pbr_material_t* mtl = G->materials ? &G->materials[mesh.material_idx] : NULL;
|
||||
mesh.transparent = false;
|
||||
if( mtl ) {
|
||||
mesh.transparent |= mtl->albedo .texture ? mtl->albedo .texture->transparent : mtl->albedo .color.a < 1.0f;
|
||||
mesh.transparent |= mtl->diffuse.texture ? mtl->diffuse.texture->transparent : mtl->diffuse.color.a < 1.0f;
|
||||
}
|
||||
|
||||
array_push(G->meshes, mesh);
|
||||
}
|
||||
|
||||
#if 0
|
||||
G->mGlobalAmbient = vec4( 0.3,0.3,0.3,0.3 );
|
||||
int scn_num_lights = 0;
|
||||
for( int i = 0; i < scn_num_lights; i++ ) {
|
||||
PRINTF("Loading light %d/%d\n", i + 1, scn_num_lights);
|
||||
|
||||
vec4 *color = aiGetLightColor(scn_light[i]);
|
||||
char *type = aiGetLightType(scn_light[i]);
|
||||
if( 0 == strcmp(type, "AMBIENT") ) {
|
||||
memcpy( &G->mGlobalAmbient, &color->r, sizeof( float ) * 4 );
|
||||
} else {
|
||||
// @todo
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ModelRender( Model *G, const mat44 _worldRootMatrix ) {
|
||||
unsigned _shader = G->shader;
|
||||
shader_bind( _shader );
|
||||
|
||||
shader_vec4("global_ambient", vec4(1,1,1,1)); // unused
|
||||
|
||||
// loop thrice: first opaque, then transparent backface, then transparent frontface
|
||||
for(int j = 0; j < 3; ++j) {
|
||||
bool bTransparentPass = j > 0;
|
||||
if(bTransparentPass) {
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
glCullFace( j == 1 ? GL_FRONT : GL_BACK ); // glDepthMask( GL_FALSE);
|
||||
}
|
||||
|
||||
mat44 mat_world; copy44(mat_world, _worldRootMatrix); // @fixme mMatrices[ node.mID ] * _worldRootMatrix
|
||||
shader_mat44( "mat_world", mat_world );
|
||||
|
||||
for( int i = 0, end = array_count(G->meshes); i < end; i++ ) {
|
||||
const Mesh *mesh = &G->meshes[ i ];
|
||||
// Postpone rendering transparent meshes
|
||||
if(mesh->transparent != bTransparentPass)
|
||||
continue;
|
||||
|
||||
const pbr_material_t *material = &G->materials[ mesh->material_idx ];
|
||||
shader_colormap( "map_diffuse", material->diffuse );
|
||||
shader_colormap( "map_normals", material->normals );
|
||||
shader_colormap( "map_specular", material->specular );
|
||||
shader_colormap( "map_albedo", material->albedo );
|
||||
shader_colormap( "map_roughness", material->roughness );
|
||||
shader_colormap( "map_metallic", material->metallic );
|
||||
shader_colormap( "map_ao", material->ao );
|
||||
shader_colormap( "map_ambient", material->ambient );
|
||||
shader_colormap( "map_emissive", material->emissive );
|
||||
shader_float( "specular_shininess", material->specular_shininess ); // unused, basic_specgloss.fs only
|
||||
|
||||
shader_vec2( "resolution", vec2(window_width(),window_height()));
|
||||
|
||||
glActiveTexture(GL_TEXTURE0); // be nice to Mesa before rendering
|
||||
glBindVertexArray( mesh->vao );
|
||||
glDrawElements( GL_TRIANGLES, mesh->num_tris * 3, GL_UNSIGNED_INT, NULL );
|
||||
}
|
||||
|
||||
if(bTransparentPass) {
|
||||
glDisable( GL_BLEND );
|
||||
// glDepthMask( GL_TRUE );
|
||||
}
|
||||
}
|
||||
|
||||
//glBindVertexArray( 0 );
|
||||
//glUseProgram( 0 );
|
||||
}
|
||||
|
||||
static
|
||||
void G_SetupVertexArray( unsigned _shader, const char *name, int stride, int num_floats, int *offset, int opt_location ) {
|
||||
int location = opt_location >= 0 ? opt_location : glGetAttribLocation( _shader, name );
|
||||
if( location >= 0 ) {
|
||||
glVertexAttribPointer( location, num_floats, GL_FLOAT, GL_FALSE, stride, (GLvoid *)(uintptr_t)(*offset) );
|
||||
glEnableVertexAttribArray( location );
|
||||
}
|
||||
*offset += num_floats * sizeof( GLfloat );
|
||||
}
|
||||
|
||||
void ModelRebind( Model *G, unsigned _shader ) {
|
||||
shader_bind(_shader);
|
||||
if(_shader == G->shader) return;
|
||||
G->shader = _shader;
|
||||
|
||||
for( int i = 0, end = array_count(G->meshes); i < end; i++ ) {
|
||||
const Mesh *mesh = &G->meshes[ i ];
|
||||
|
||||
glBindVertexArray( mesh->vao );
|
||||
glBindBuffer( GL_ARRAY_BUFFER, mesh->vbo );
|
||||
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, mesh->ibo );
|
||||
|
||||
glDisableVertexAttribArray( 0 );
|
||||
glDisableVertexAttribArray( 1 );
|
||||
glDisableVertexAttribArray( 2 );
|
||||
glDisableVertexAttribArray( 3 );
|
||||
glDisableVertexAttribArray( 4 );
|
||||
glDisableVertexAttribArray( 5 );
|
||||
glDisableVertexAttribArray( 6 );
|
||||
glDisableVertexAttribArray( 7 );
|
||||
|
||||
int offset = 0, stride = mesh->vert_stride;
|
||||
G_SetupVertexArray( _shader, "in_pos", stride, 3, &offset, -1/*0*/ );
|
||||
G_SetupVertexArray( _shader, "in_texcoord", stride, 2, &offset, -1/*1*/ );
|
||||
G_SetupVertexArray( _shader, "in_normal", stride, 3, &offset, -1/*2*/ );
|
||||
G_SetupVertexArray( _shader, "in_tangent", stride, 4, &offset, -1/*3*/ );
|
||||
|
||||
//glBindVertexArray( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// skyboxes
|
||||
|
||||
// Extracts single key value from an HDRLabs IBL file. Returns an empty string on error.
|
||||
static const char *ibl_readkey( const char* pathfile, const char* key ) {
|
||||
char *data = vfs_read(pathfile);
|
||||
if( data ) {
|
||||
const char *found = strstr(data, va("%s=", key));
|
||||
if( found ) return found + strlen(key) + 1;
|
||||
found = strstr(data, va("%s =", key));
|
||||
if( found ) return found + strlen(key) + 2;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
typedef struct Skybox {
|
||||
vec3 sunColor; float sunYaw, sunPitch; // ibl settings
|
||||
texture_t *reflection; // reflection map (hdr)
|
||||
texture_t *env; // irradiance map (env)
|
||||
} Skybox;
|
||||
|
||||
Skybox g_skybox = { {1,1,1} };
|
||||
|
||||
void SkyboxDestroy( Skybox *s ) {
|
||||
if( s->reflection ) texture_destroy( s->reflection );
|
||||
if( s->env ) texture_destroy( s->env );
|
||||
*s = (Skybox){0};
|
||||
}
|
||||
|
||||
bool SkyboxLoad( Skybox *s, const char **slots ) { // hdr,env,ibl
|
||||
SkyboxDestroy( s );
|
||||
|
||||
const char* reflectionPath = slots[0];
|
||||
const char* envPath = slots[1];
|
||||
const char* iblPath = slots[2];
|
||||
|
||||
// unsigned invalid = texture_checker().id;
|
||||
|
||||
// Reflection map
|
||||
if( reflectionPath ) {
|
||||
if( (s->reflection = LoadTextureRGBA8( reflectionPath, TEXTURE_SRGB )) != NULL ) {
|
||||
glBindTexture( GL_TEXTURE_2D, s->reflection->id );
|
||||
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
}
|
||||
|
||||
// Irradiance map
|
||||
if( envPath ) {
|
||||
if( (s->env = LoadTextureRGBA8( envPath, TEXTURE_SRGB )) != NULL ) {
|
||||
glBindTexture( GL_TEXTURE_2D, s->env->id );
|
||||
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
}
|
||||
|
||||
// Sun color & direction from .ibl file
|
||||
s->sunColor = vec3(1,1,1);
|
||||
s->sunYaw = 0, s->sunPitch = 0;
|
||||
if( iblPath ) {
|
||||
vec3 sc; if( 3 == sscanf(ibl_readkey(iblPath, "SUNcolor"), "%f,%f,%f", &sc.x, &sc.y, &sc.z) ) {
|
||||
s->sunColor = scale3(sc, 1/255.f);
|
||||
}
|
||||
vec2 uv = vec2(atof(ibl_readkey(iblPath, "SUNu")), atof(ibl_readkey(iblPath, "SUNv")));
|
||||
if( len2(uv) > 0 ) {
|
||||
s->sunYaw = C_PI * (-2. * uv.x + 0.5f);
|
||||
s->sunPitch = (0.5f - uv.y) * C_PI;
|
||||
}
|
||||
}
|
||||
|
||||
return s->reflection && s->env;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// main
|
||||
|
||||
const char *shader_names[] = {"Physically Based", "Basic SpecGloss" };
|
||||
const char *shaders[][2] = { // name, vs, fs
|
||||
{ "Shaders/pbr.vs", "Shaders/pbr.fs" },
|
||||
{ "Shaders/basic_specgloss.vs", "Shaders/basic_specgloss.fs" }
|
||||
};
|
||||
|
||||
const char *skyboxes[][3] = { // reflection, env, metadata
|
||||
{"hdr/Tokyo_BigSight_1k.hdr","hdr/Tokyo_BigSight_Env.hdr","hdr/Tokyo_BigSight.ibl"},
|
||||
{"hdr/GCanyon_C_YumaPoint_1k.hdr","hdr/GCanyon_C_YumaPoint_Env.hdr","hdr/GCanyon_C_YumaPoint.ibl"},
|
||||
{"hdr/Factory_Catwalk_1k.hdr","hdr/Factory_Catwalk_Env.hdr","hdr/Factory_Catwalk.ibl"},
|
||||
{"hdr/MonValley_G_DirtRoad_1k.hdr","hdr/MonValley_G_DirtRoad_Env.hdr","hdr/MonValley_G_DirtRoad.ibl"},
|
||||
{"hdr/Shiodome_Stairs_1k.hdr","hdr/Shiodome_Stairs_Env.hdr","hdr/Shiodome_Stairs.ibl"},
|
||||
};
|
||||
|
||||
Model gModel;
|
||||
unsigned gShader = ~0u;
|
||||
unsigned gShaderConfig = ~0u;
|
||||
|
||||
bool LoadShaderConfig( int slot ) { // name,vs,fs
|
||||
unsigned newShader = shader( vfs_read(shaders[slot][0]), vfs_read(shaders[slot][1]), NULL, NULL );
|
||||
if( newShader == ~0u ) return false;
|
||||
|
||||
shader_destroy( gShader );
|
||||
gShaderConfig = slot;
|
||||
gShader = newShader;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void camera_fit(camera_t *cam) {
|
||||
vec3 target = scale3( add3( gModel.meshes[0].aabb_min, gModel.meshes[0].aabb_max ), 0.5f);
|
||||
float distance = len3( sub3( gModel.meshes[0].aabb_max, gModel.meshes[0].aabb_min ) ) * 0.85f;
|
||||
cam->position = add3(target, scale3(norm3(sub3(cam->position,target)), distance));
|
||||
camera_lookat(cam, vec3(0,0,0));
|
||||
}
|
||||
|
||||
int main( int argc, const char *argv[] ) {
|
||||
window_create( 75, WINDOW_MSAA2 );
|
||||
window_title(__FILE__);
|
||||
|
||||
// load all fx files in all subdirs
|
||||
fx_load("fx**.fs");
|
||||
|
||||
if( !LoadShaderConfig( 0 ) ) {
|
||||
return -4;
|
||||
}
|
||||
|
||||
brdf_lut();
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Mainloop
|
||||
float model_yaw = 0, model_pitch = 0;
|
||||
float lightYaw = 0.0f;
|
||||
float lightPitch = 0.0f;
|
||||
vec4 skyBackgroundColor = vec4(0.01,0.01,0.02,1); // vec4(1,0,0,1);
|
||||
float skyExposure = 1.0; // plain 'exposure' instead? this is camera related
|
||||
float skyBlur = 0.00; // 0.00
|
||||
float skyOpacity = 0.99; // 0.99
|
||||
bool do_wireframe = false;
|
||||
bool do_xzySpace = true; // xzySpace or xyzSpace
|
||||
bool do_flipY = false;
|
||||
const mat44 xzyMatrix = {
|
||||
1, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0,+1, 0, 0,
|
||||
0, 0, 0, 1 };
|
||||
|
||||
camera_t cam = camera(); cam.speed = 0.1;
|
||||
|
||||
int firstskyboxes = 0; // 0: tokyo_bigsight
|
||||
SkyboxLoad( &g_skybox, &skyboxes[firstskyboxes][0] );
|
||||
lightYaw = g_skybox.sunYaw;
|
||||
lightPitch = g_skybox.sunPitch;
|
||||
|
||||
unsigned skysphereShader = shader( vfs_read("Skyboxes/skysphere.vs"), vfs_read("Skyboxes/skysphere.fs"), NULL, NULL );
|
||||
Model skysphere = { 0 }; ModelLoad(&skysphere, "Skyboxes/skysphere.fbx"); ModelRebind(&skysphere, skysphereShader);
|
||||
|
||||
if( ModelLoad( &gModel, argc > 1 && argv[1][0] != '-' ? argv[ 1 ] : "damagedhelmet.gltf" ) ) {
|
||||
ModelRebind( &gModel, gShader );
|
||||
}
|
||||
|
||||
cam.position = vec3(+1,0,+1);
|
||||
camera_fit(&cam);
|
||||
|
||||
static mat44 worldRootXYZ; do_once id44(worldRootXYZ); // mat44( 1.0f );
|
||||
|
||||
while( window_swap() && !input(KEY_ESC) ) {
|
||||
|
||||
if( input(KEY_F5) ) window_reload();
|
||||
if( input_down( KEY_F ) ) camera_fit(&cam);
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
static int fps_mode;
|
||||
if(input_down(KEY_TAB)) { fps_mode ^= 1; camera_fit(&cam); }
|
||||
if(fps_mode) {
|
||||
// fps camera
|
||||
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
|
||||
window_cursor( !active );
|
||||
if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
|
||||
vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
|
||||
vec3 wasdecq = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-(input(KEY_C)||input(KEY_Q)),input(KEY_W)-input(KEY_S)), cam.speed);
|
||||
camera_move(&cam, wasdecq.x,wasdecq.y,wasdecq.z);
|
||||
camera_fps(&cam, mouse.x,mouse.y);
|
||||
} else {
|
||||
// orbit camera
|
||||
window_cursor( true );
|
||||
bool active = !ui_active() && !ui_hover() && !gizmo_active();
|
||||
vec2 inc_mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active * input(MOUSE_L));
|
||||
float inc_distance = -0.2f * active * input_diff(MOUSE_W);
|
||||
camera_orbit(&cam, inc_mouse.x, inc_mouse.y, inc_distance);
|
||||
// rotate model
|
||||
model_yaw -= input_diff(MOUSE_X) * 0.2f * active * input(MOUSE_R);
|
||||
model_pitch += input_diff(MOUSE_Y) * 0.2f * active * input(MOUSE_R);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
glClearColor( skyBackgroundColor.r, skyBackgroundColor.g, skyBackgroundColor.b, skyBackgroundColor.a );
|
||||
glEnable(GL_CULL_FACE);
|
||||
glFrontFace(GL_CCW);
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Mesh state
|
||||
|
||||
fx_begin();
|
||||
|
||||
profile("PBR Model (bindings)") {
|
||||
ModelRebind( &gModel, gShader );
|
||||
|
||||
shader_mat44( "mat_projection", cam.proj );
|
||||
|
||||
//cameraPosition = scale3(cameraPosition, gCameraDistance);
|
||||
shader_vec3( "camera_position", cam.position );
|
||||
|
||||
vec3 lightDirection = vec3( 0, 0, 1 );
|
||||
lightDirection = rotatex3( lightDirection, deg(lightPitch) );
|
||||
lightDirection = rotatey3( lightDirection, deg(lightYaw) );
|
||||
|
||||
vec3 fillLightDirection = vec3( 0, 0, 1 );
|
||||
fillLightDirection = rotatex3( fillLightDirection, deg(lightPitch - 0.4f) );
|
||||
fillLightDirection = rotatey3( fillLightDirection, deg(lightYaw + 0.8f) );
|
||||
|
||||
shader_vec3( "lights[0].direction", lightDirection );
|
||||
shader_vec3( "lights[0].color", g_skybox.sunColor );
|
||||
shader_vec3( "lights[1].direction", fillLightDirection );
|
||||
shader_vec3( "lights[1].color", vec3( 0.5f, 0.5f, 0.5f ) );
|
||||
shader_vec3( "lights[2].direction", neg3(fillLightDirection) );
|
||||
shader_vec3( "lights[2].color", vec3( 0.25f, 0.25f, 0.25f ) );
|
||||
|
||||
shader_float( "skysphere_rotation", lightYaw - g_skybox.sunYaw );
|
||||
|
||||
mat44 viewMatrix, inv_viewMatrix;
|
||||
copy44(viewMatrix, cam.view);
|
||||
invert44( inv_viewMatrix, viewMatrix);
|
||||
shader_mat44( "mat_view", viewMatrix );
|
||||
shader_mat44( "mat_view_inverse", inv_viewMatrix );
|
||||
|
||||
shader_bool( "has_tex_skysphere", g_skybox.reflection != NULL );
|
||||
shader_bool( "has_tex_skyenv", g_skybox.env != NULL );
|
||||
if( g_skybox.reflection ) {
|
||||
float mipCount = floor( log2( g_skybox.reflection->h ) );
|
||||
shader_texture( "tex_skysphere", *g_skybox.reflection );
|
||||
shader_float( "skysphere_mip_count", mipCount );
|
||||
}
|
||||
if( g_skybox.env ) {
|
||||
shader_texture( "tex_skyenv", *g_skybox.env );
|
||||
}
|
||||
shader_texture( "tex_brdf_lut", brdf_lut() );
|
||||
shader_float( "exposure", skyExposure );
|
||||
shader_uint( "frame_count", (unsigned)window_frame() );
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Mesh render
|
||||
|
||||
mat44 M;
|
||||
copy44( M, do_xzySpace ? xzyMatrix : worldRootXYZ );
|
||||
if( do_flipY ) scale44( M, 1,-1,1 );
|
||||
rotate44( M, model_yaw, 0,0,1 );
|
||||
rotate44( M, model_pitch, 1,0,0 );
|
||||
|
||||
profile("PBR Model (render)") {
|
||||
ModelRender( &gModel, M );
|
||||
}
|
||||
|
||||
profile("PBR Model (wireframe)") {
|
||||
if( do_wireframe ) {
|
||||
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
|
||||
glDepthFunc( GL_LEQUAL );
|
||||
|
||||
shader_float("exposure", 100.0f );
|
||||
ModelRender( &gModel, M );
|
||||
|
||||
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
|
||||
glDepthFunc( GL_LESS );
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Skysphere render
|
||||
|
||||
profile("PBR Skybox") {
|
||||
ModelRebind(&skysphere, skysphereShader );
|
||||
|
||||
mat44 projview; multiply44x2(projview, cam.proj, cam.view);
|
||||
shader_mat44( "mat_mvp", projview );
|
||||
|
||||
shader_bool( "has_tex_skysphere", g_skybox.reflection != NULL );
|
||||
shader_bool( "has_tex_skyenv", g_skybox.env != NULL );
|
||||
|
||||
if( g_skybox.reflection ) {
|
||||
const float mipCount = floor( log2( g_skybox.reflection->h ) );
|
||||
shader_texture( "tex_skysphere", *g_skybox.reflection );
|
||||
shader_float( "skysphere_mip_count", mipCount );
|
||||
}
|
||||
|
||||
if( g_skybox.env ) {
|
||||
shader_texture( "tex_skyenv", *g_skybox.env );
|
||||
}
|
||||
|
||||
shader_vec4( "background_color", skyBackgroundColor );
|
||||
shader_float( "skysphere_blur", skyBlur );
|
||||
shader_float( "skysphere_opacity", skyOpacity );
|
||||
shader_float( "skysphere_rotation", lightYaw - g_skybox.sunYaw );
|
||||
shader_float( "exposure", skyExposure );
|
||||
shader_uint( "frame_count", (unsigned)window_frame() );
|
||||
|
||||
glDepthFunc( GL_LEQUAL );
|
||||
ModelRender(&skysphere, worldRootXYZ );
|
||||
glDepthFunc( GL_LESS );
|
||||
}
|
||||
|
||||
fx_end();
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// UI
|
||||
|
||||
if( ui_panel( "Viewer", 0 ) ) {
|
||||
ui_bool( "Wireframe", &do_wireframe );
|
||||
ui_separator();
|
||||
|
||||
if( ui_radio("Shader config:", shader_names, countof(shader_names), &gShaderConfig) ) {
|
||||
LoadShaderConfig( gShaderConfig );
|
||||
ModelRebind(&gModel, gShader );
|
||||
}
|
||||
|
||||
ui_separator();
|
||||
for( int i = 0; i < countof(skyboxes); i++ ) {
|
||||
const char *filename = skyboxes[i][0];
|
||||
bool selected = !strcmp(g_skybox.reflection->filename, file_name(filename));
|
||||
if( ui_bool( filename, &selected ) ) {
|
||||
SkyboxLoad( &g_skybox, &skyboxes[i][0] );
|
||||
lightYaw = g_skybox.sunYaw;
|
||||
lightPitch = g_skybox.sunPitch;
|
||||
}
|
||||
}
|
||||
|
||||
ui_separator();
|
||||
ui_float( "Sky exposure", &skyExposure); skyExposure = clampf(skyExposure, 0.1f, 4.0f );
|
||||
ui_float( "Sky blur", &skyBlur); skyBlur = clampf(skyBlur, 0.0f, 1.0f );
|
||||
ui_float( "Sky opacity", &skyOpacity); skyOpacity = clampf(skyOpacity, 0.0f, 1.0f );
|
||||
ui_color4f( "Sky background", (float *) &skyBackgroundColor.x );
|
||||
|
||||
ui_separator();
|
||||
ui_float( "SunLight Yaw", &lightYaw );
|
||||
ui_float( "SunLight Pitch", &lightPitch );
|
||||
|
||||
ui_panel_end();
|
||||
}
|
||||
|
||||
if( ui_panel( "Model", 0 ) ) {
|
||||
ui_label(va("Material count: %d", array_count(gModel.materials)));
|
||||
ui_label(va("Mesh count: %d", array_count(gModel.meshes)));
|
||||
int triCount = 0; for( int i = 0, end = array_count(gModel.meshes); i < end; ++i ) triCount += gModel.meshes[i].num_tris;
|
||||
ui_label(va("Triangle count: %d", triCount));
|
||||
ui_separator();
|
||||
|
||||
bool xyzSpace = !do_xzySpace;
|
||||
if( ui_bool( "XYZ space", &xyzSpace ) ) {
|
||||
do_xzySpace = !do_xzySpace;
|
||||
}
|
||||
ui_bool( "XZY space", &do_xzySpace );
|
||||
ui_bool( "invert Y", &do_flipY );
|
||||
|
||||
ui_separator();
|
||||
for( int i = 0, end = array_count(gModel.materials); i < end; ++i ) {
|
||||
pbr_material_t *it = &gModel.materials[i];
|
||||
ui_label(va("Name: %s", it->name));
|
||||
ui_float( "Specular shininess", &it->specular_shininess );
|
||||
ui_separator(); if(ui_colormap( "Albedo", &it->albedo )) colormap(&it->albedo , dialog_load(), 1);
|
||||
ui_separator(); if(ui_colormap( "Ambient", &it->ambient )) colormap(&it->ambient , dialog_load(), 0);
|
||||
ui_separator(); if(ui_colormap( "AO", &it->ao )) colormap(&it->ao , dialog_load(), 0);
|
||||
ui_separator(); if(ui_colormap( "Diffuse", &it->diffuse )) colormap(&it->diffuse , dialog_load(), 1);
|
||||
ui_separator(); if(ui_colormap( "Emissive", &it->emissive )) colormap(&it->emissive , dialog_load(), 1);
|
||||
ui_separator(); if(ui_colormap( "Metallic", &it->metallic )) colormap(&it->metallic , dialog_load(), 0);
|
||||
ui_separator(); if(ui_colormap( "Normal", &it->normals )) colormap(&it->normals , dialog_load(), 0);
|
||||
ui_separator(); if(ui_colormap( "Roughness", &it->roughness )) colormap(&it->roughness, dialog_load(), 0);
|
||||
ui_separator(); if(ui_colormap( "Specular", &it->specular )) colormap(&it->specular , dialog_load(), 0);
|
||||
}
|
||||
|
||||
ui_panel_end();
|
||||
}
|
||||
|
||||
if( ui_panel("FX", 0) ) {
|
||||
for( int i = 0; i < 64; ++i ) {
|
||||
char *name = fx_name(i); if( !name ) break;
|
||||
bool b = fx_enabled(i);
|
||||
if( ui_bool(name, &b) ) fx_enable(i, fx_enabled(i) ^ 1);
|
||||
}
|
||||
ui_panel_end();
|
||||
}
|
||||
|
||||
if( ui_panel("Help", 0)) {
|
||||
if( fps_mode ) {
|
||||
ui_label("TAB: switch to Orbit camera mode");
|
||||
ui_label("WASD,QEC: move camera");
|
||||
ui_label("Drag + Mouse Button: camera freelook");
|
||||
} else {
|
||||
ui_label("TAB: switch to FPS camera mode");
|
||||
ui_label("Drag + Left Mouse Button: orbit camera");
|
||||
ui_label("Drag + Right Mouse Button: rotate model");
|
||||
ui_label("Mouse wheel: camera distance");
|
||||
}
|
||||
ui_label("F: center view");
|
||||
ui_panel_end();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#include "fwk.h"
|
||||
|
||||
#define SCRIPT(...) #__VA_ARGS__
|
||||
|
||||
#if 0 // teal
|
||||
script_run("local tl=require(\"tl\")\ntl.loader()");
|
||||
script_run("addsub = require(\"s2\"); print (addsub.add(10, 20))");
|
||||
s2.tl:
|
||||
local function add(a: number, b: number): number
|
||||
return a + b
|
||||
end
|
||||
local s = add(1,2)
|
||||
print(s)
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
script_init();
|
||||
|
||||
script_run(SCRIPT(
|
||||
window_create(75.0,0);
|
||||
while window_swap() do
|
||||
ddraw_grid(10);
|
||||
if ui_panel("Hello from Lua!", 0) then
|
||||
ui_panel_end();
|
||||
end;
|
||||
end;
|
||||
));
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
// shadertoy viewer
|
||||
// - rlyeh, public domain
|
||||
|
||||
#include "fwk.h"
|
||||
|
||||
int main() {
|
||||
window_create(75, 0); // WINDOW_MSAA8);
|
||||
window_title(__FILE__);
|
||||
|
||||
const char **list = file_list("demos/art/shadertoys/", "**.fs");
|
||||
if(!list[0]) exit(-1);
|
||||
array(char*) browser = 0;
|
||||
while(*list) array_push(browser, STRDUP(file_name(*list++)));
|
||||
int browser_count = array_count(browser);
|
||||
|
||||
shadertoy_t sh = {0};
|
||||
|
||||
while(window_swap()) {
|
||||
// selector
|
||||
int next = input_down(KEY_UP) || input_down(KEY_LEFT);
|
||||
int prev = input_down(KEY_DOWN) || input_down(KEY_RIGHT);
|
||||
static int selector = 0;
|
||||
static int reload = 1;
|
||||
if( next ) if( selector > 0 ) --selector, reload = 1;
|
||||
if( prev ) if( selector < browser_count - 1 ) ++selector, reload = 1;
|
||||
if( reload ) {
|
||||
reload = 0;
|
||||
window_title(va("FWK - %s", browser[selector]));
|
||||
sh = shadertoy( browser[selector], 0 );
|
||||
}
|
||||
|
||||
// draw
|
||||
shadertoy_render(&sh, window_delta());
|
||||
|
||||
// UI
|
||||
if( ui_panel("Shadertoy", 1)) {
|
||||
for( int i = 0; i < browser_count; ++i ) {
|
||||
bool in_use = i == selector;
|
||||
if( ui_bool(browser[i], &in_use) ) {
|
||||
reload = 1;
|
||||
selector = i;
|
||||
}
|
||||
}
|
||||
ui_panel_end();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,568 @@
|
|||
// spine json loader (wip)
|
||||
// - rlyeh, public domain
|
||||
//
|
||||
// [ref] http://es.esotericsoftware.com/spine-json-format
|
||||
//
|
||||
// notable misses:
|
||||
// - mesh deforms
|
||||
// - cubic beziers
|
||||
// - shears
|
||||
// - bounding boxes
|
||||
|
||||
#include "fwk.h"
|
||||
#define spine spine2
|
||||
#define spine_render spine_render2
|
||||
#define spine_ui spine_ui2
|
||||
#define spine_animate spine_animate2
|
||||
#define spine_skin spine_skin2
|
||||
|
||||
enum { _64 = 64 }; // max bones
|
||||
|
||||
typedef struct spine_bone_t {
|
||||
char *name, *parent;
|
||||
struct spine_bone_t *parent_bone;
|
||||
|
||||
float z; // draw order usually matches bone-id. ie, zindex == bone_id .. root(0) < chest (mid) < finger(top)
|
||||
|
||||
float x, y, deg; // base
|
||||
float x2, y2, deg2; // accum / temporaries during bone transform time
|
||||
float x3, y3, deg3; // values from timeline
|
||||
|
||||
unsigned rect_id;
|
||||
unsigned atlas_id;
|
||||
} spine_bone_t;
|
||||
|
||||
typedef struct spine_slot_t {
|
||||
char *name, *bone, *attach;
|
||||
} spine_slot_t;
|
||||
|
||||
typedef struct spine_rect_t {
|
||||
char *name;
|
||||
float x,y,w,h,sx,sy,deg;
|
||||
} spine_rect_t;
|
||||
|
||||
typedef struct spine_skin_t {
|
||||
char *name;
|
||||
array(spine_rect_t) rects;
|
||||
} spine_skin_t;
|
||||
|
||||
typedef struct spine_animkey_t { // offline; only during loading
|
||||
float time, curve[4]; // time is mandatory, curve is optional
|
||||
union {
|
||||
char *name; // type: attachment (mode-1)
|
||||
struct { float deg; }; // type: rotate (mode-2)
|
||||
struct { float x,y; }; // type: translate (mode-3)
|
||||
};
|
||||
} spine_animkey_t;
|
||||
|
||||
#if 0
|
||||
typedef struct spine_pose_t { // runtime; only during playing
|
||||
unsigned frame;
|
||||
array(vec4) xform; // entry per bone. translation(x,y),rotation(z),attachment-id(w)
|
||||
} spine_pose_t;
|
||||
#endif
|
||||
|
||||
typedef struct spine_anim_t {
|
||||
char *name;
|
||||
union {
|
||||
#if 0
|
||||
struct {
|
||||
unsigned frames;
|
||||
array(spine_pose_t) poses;
|
||||
};
|
||||
#endif
|
||||
struct {
|
||||
array(spine_animkey_t) attach_keys[_64];
|
||||
array(spine_animkey_t) rotate_keys[_64];
|
||||
array(spine_animkey_t) translate_keys[_64];
|
||||
};
|
||||
};
|
||||
} spine_anim_t;
|
||||
|
||||
typedef struct spine_atlas_t {
|
||||
char *name;
|
||||
float x,y,w,h,deg;
|
||||
} spine_atlas_t;
|
||||
|
||||
typedef struct spine_t {
|
||||
char *name;
|
||||
texture_t texture;
|
||||
unsigned skin;
|
||||
array(spine_bone_t) bones;
|
||||
array(spine_slot_t) slots;
|
||||
array(spine_skin_t) skins;
|
||||
array(spine_anim_t) anims;
|
||||
array(spine_atlas_t) atlas;
|
||||
// anim controller
|
||||
unsigned inuse;
|
||||
float time, maxtime;
|
||||
} spine_t;
|
||||
|
||||
// ---
|
||||
|
||||
void spine_convert_animkeys_to_animpose(spine_anim_t *input) {
|
||||
spine_anim_t copy = *input; // @todo
|
||||
// @leak: attach/rot/tra keys
|
||||
}
|
||||
|
||||
int find_bone_id(spine_t *s, const char *bone_name) {
|
||||
for( unsigned i = 0, end = array_count(s->bones); i < end; ++i )
|
||||
if( !strcmp(s->bones[i].name, bone_name)) return i;
|
||||
return -1;
|
||||
}
|
||||
spine_bone_t *find_bone(spine_t *s, const char *bone_name) {
|
||||
int bone_id = find_bone_id(s, bone_name);
|
||||
return bone_id >= 0 ? &s->bones[bone_id] : NULL;
|
||||
}
|
||||
|
||||
void spine_skin(spine_t *p, unsigned skin) {
|
||||
if( !p->texture.id ) return;
|
||||
if( skin >= array_count(p->skins) ) return;
|
||||
|
||||
p->skin = skin;
|
||||
|
||||
char *skin_name = va("%s/", p->skins[skin].name);
|
||||
int header = strlen(skin_name);
|
||||
|
||||
for( int i = 0; i < array_count(p->atlas); ++i) {
|
||||
if(!strbeg(p->atlas[i].name, skin_name)) continue;
|
||||
|
||||
int bone_id = find_bone_id(p, p->atlas[i].name+header );
|
||||
if( bone_id < 0 ) continue;
|
||||
|
||||
p->bones[bone_id].atlas_id = i;
|
||||
}
|
||||
|
||||
for( int i = 0; i < array_count(p->skins[p->skin].rects); ++i) {
|
||||
int bone_id = find_bone_id(p, p->skins[p->skin].rects[i].name );
|
||||
if( bone_id < 0 ) continue;
|
||||
|
||||
p->bones[bone_id].rect_id = i;
|
||||
}
|
||||
}
|
||||
|
||||
spine_t spine(const char *file_json, const char *file_atlas, unsigned flags) {
|
||||
spine_t z = {0}, t = z;
|
||||
|
||||
char *atlas = vfs_read(file_atlas);
|
||||
if(!atlas || !atlas[0]) return z;
|
||||
|
||||
// goblins.png
|
||||
// size: 1024, 128
|
||||
// filter: Linear, Linear
|
||||
// pma: true
|
||||
// dagger
|
||||
// bounds: 2, 18, 26, 108
|
||||
// goblin/eyes-closed
|
||||
// bounds: 2, 4, 34, 12
|
||||
spine_atlas_t *sa = 0;
|
||||
const char *last_id = 0;
|
||||
const char *texture_name = 0;
|
||||
const char *texture_filter = 0;
|
||||
const char *texture_format = 0;
|
||||
const char *texture_repeat = 0;
|
||||
float texture_width = 0, texture_height = 0, temp;
|
||||
for each_substring(atlas, "\r\n", it) {
|
||||
it += strspn(it, " \t\f\v");
|
||||
/**/ if( strbeg(it, "pma:" ) || strbeg(it, "index:") ) {} // ignored
|
||||
else if( strbeg(it, "size:" ) ) sscanf(it+5, "%f,%f", &texture_width, &texture_height);
|
||||
else if( strbeg(it, "rotate:" ) ) { float tmp; tmp=sa->w,sa->w=sa->h,sa->h=tmp; sa->deg = 90; } // assert(val==90)
|
||||
else if( strbeg(it, "repeat:" ) ) texture_repeat = it+7; // temp string
|
||||
else if( strbeg(it, "filter:" ) ) texture_filter = it+7; // temp string
|
||||
else if( strbeg(it, "format:" ) ) texture_format = it+7; // temp string
|
||||
else if( strbeg(it, "bounds:" ) ) {
|
||||
sscanf(it+7, "%f,%f,%f,%f", &sa->x, &sa->y, &sa->w, &sa->h);
|
||||
}
|
||||
else if( !texture_name ) texture_name = va("%s", it);
|
||||
else {
|
||||
array_push(t.atlas, ((spine_atlas_t){0}) );
|
||||
sa = &t.atlas[array_count(t.atlas) - 1];
|
||||
sa->name = STRDUP(it);
|
||||
}
|
||||
}
|
||||
for( int i = 0; i < array_count(t.atlas); ++i ) {
|
||||
sa = &t.atlas[i];
|
||||
sa->x /= texture_width, sa->y /= texture_height;
|
||||
sa->w /= texture_width, sa->h /= texture_height;
|
||||
}
|
||||
|
||||
if(!texture_name) return z;
|
||||
|
||||
t.texture = texture(texture_name, 0); // @todo: add texture flags here
|
||||
|
||||
json_push(vfs_read(file_json)); // @fixme: json_push_from_file() ?
|
||||
|
||||
array_resize(t.bones, json_count("/bones"));
|
||||
array_reserve(t.slots, json_count("/slots"));
|
||||
array_resize(t.skins, json_count("/skins"));
|
||||
array_resize(t.anims, json_count("/animations"));
|
||||
|
||||
for( int i = 0, end = json_count("/bones"); i < end; ++i ) {
|
||||
spine_bone_t v = {0};
|
||||
v.name = STRDUP(json_string("/bones[%d]/name", i));
|
||||
v.parent = STRDUP(json_string("/bones[%d]/parent", i));
|
||||
v.x = json_float("/bones[%d]/x", i);
|
||||
v.y = json_float("/bones[%d]/y", i);
|
||||
v.z = i;
|
||||
v.deg = json_float("/bones[%d]/rotation", i);
|
||||
t.bones[i] = v;
|
||||
|
||||
for( int j = i-1; j > 0; --j ) {
|
||||
if( strcmp(t.bones[j].name,v.parent) ) continue;
|
||||
t.bones[i].parent_bone = &t.bones[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for( int i = 0, end = json_count("/slots"); i < end; ++i ) {
|
||||
spine_slot_t v = {0};
|
||||
v.name = STRDUP(json_string("/slots[%d]/name", i));
|
||||
v.bone = STRDUP(json_string("/slots[%d]/bone", i));
|
||||
v.attach = STRDUP(json_string("/slots[%d]/attachment", i));
|
||||
|
||||
array_push(t.slots, v);
|
||||
|
||||
// slots define draw-order. so, update draw-order/zindex in bone
|
||||
spine_bone_t *b = find_bone(&t, v.name);
|
||||
if( b ) b->z = i;
|
||||
}
|
||||
|
||||
for( int i = 0, end = json_count("/skins"); i < end; ++i ) {
|
||||
spine_skin_t v = {0};
|
||||
v.name = STRDUP(json_string("/skins[%d]/name", i));
|
||||
|
||||
for( int j = 0, jend = json_count("/skins[%d]/attachments",i); j < jend; ++j ) // /skins/default/
|
||||
for( int k = 0, kend = json_count("/skins[%d]/attachments[%d]",i,j); k < kend; ++k ) { // /skins/default/left hand item/
|
||||
spine_rect_t r = {0};
|
||||
r.name = STRDUP(json_key("/skins[%d]/attachments[%d][%d]",i,j,k)); // stringf("%s-%s-%s", json_key("/skins[%d]",i), json_key("/skins[%d][%d]",i,j), json_key("/skins[%d][%d][%d]",i,j,k));
|
||||
r.x = json_float("/skins[%d]/attachments[%d][%d]/x",i,j,k);
|
||||
r.y = json_float("/skins[%d]/attachments[%d][%d]/y",i,j,k);
|
||||
r.sx= json_float("/skins[%d]/attachments[%d][%d]/scaleX",i,j,k); r.sx += !r.sx;
|
||||
r.sy= json_float("/skins[%d]/attachments[%d][%d]/scaleY",i,j,k); r.sy += !r.sy;
|
||||
r.w = json_float("/skins[%d]/attachments[%d][%d]/width",i,j,k);
|
||||
r.h = json_float("/skins[%d]/attachments[%d][%d]/height",i,j,k);
|
||||
r.deg = json_float("/skins[%d]/attachments[%d][%d]/rotation",i,j,k);
|
||||
array_push(v.rects, r);
|
||||
}
|
||||
|
||||
t.skins[i] = v;
|
||||
}
|
||||
|
||||
#if 1
|
||||
// simplify:
|
||||
// merge /skins/default into existing /skins/*, then delete /skins/default
|
||||
if( array_count(t.skins) > 1 ) {
|
||||
for( int i = 1; i < array_count(t.skins); ++i ) {
|
||||
for( int j = 0; j < array_count(t.skins[0].rects); ++j ) {
|
||||
array_push(t.skins[i].rects, t.skins[0].rects[j]);
|
||||
}
|
||||
}
|
||||
// @leak @fixme: free(t.skins[0])
|
||||
for( int i = 0; i < array_count(t.skins)-1; ++i ) {
|
||||
t.skins[i] = t.skins[i+1];
|
||||
}
|
||||
array_pop(t.skins);
|
||||
}
|
||||
#endif
|
||||
|
||||
for( int i = 0, end = json_count("/animations"); i < end; ++i ) {
|
||||
int id;
|
||||
const char *name;
|
||||
|
||||
spine_anim_t v = {0};
|
||||
v.name = STRDUP(json_key("/animations[%d]", i));
|
||||
|
||||
// slots / attachments
|
||||
|
||||
for( int j = 0, jend = json_count("/animations[%d]/slots",i); j < jend; ++j )
|
||||
for( int k = 0, kend = json_count("/animations[%d]/slots[%d]",i,j); k < kend; ++k ) // ids
|
||||
{
|
||||
int bone_id = find_bone_id(&t, json_key("/animations[%d]/bones[%d]",i,j));
|
||||
if( bone_id < 0 ) continue;
|
||||
|
||||
for( int l = 0, lend = json_count("/animations[%d]/slots[%d][%d]",i,j,k); l < lend; ++l ) { // channels (rot,tra,attach)
|
||||
spine_animkey_t key = {0};
|
||||
|
||||
key.name = STRDUP(json_string("/animations[%d]/slots[%d][%d][%d]/name",i,j,k,l));
|
||||
key.time = json_float("/animations[%d]/slots[%d][%d][%d]/time",i,j,k,l);
|
||||
if( json_count("/animations[%d]/slots[%d][%d][%d]/curve",i,j,k,l) == 4 ) {
|
||||
key.curve[0] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[0]",i,j,k,l);
|
||||
key.curve[1] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[1]",i,j,k,l);
|
||||
key.curve[2] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[2]",i,j,k,l);
|
||||
key.curve[3] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[3]",i,j,k,l);
|
||||
}
|
||||
|
||||
// @todo: convert name to id
|
||||
// for(id = 0; t.bones[id].name && strcmp(t.bones[id].name,key.name); ++id)
|
||||
// printf("%s vs %s\n", key.name, t.bones[id].name);
|
||||
|
||||
array_push(v.attach_keys[bone_id], key);
|
||||
}
|
||||
}
|
||||
|
||||
// bones
|
||||
|
||||
for( int j = 0, jend = json_count("/animations[%d]/bones",i); j < jend; ++j ) // slots or bones
|
||||
for( int k = 0, kend = json_count("/animations[%d]/bones[%d]",i,j); k < kend; ++k ) { // bone ids
|
||||
int bone_id = find_bone_id(&t, json_key("/animations[%d]/bones[%d]",i,j));
|
||||
if( bone_id < 0 ) continue;
|
||||
|
||||
// parse bones
|
||||
for( int l = 0, lend = json_count("/animations[%d]/bones[%d][%d]",i,j,k); l < lend; ++l ) { // channels (rot,tra,attach)
|
||||
const char *channel = json_key("/animations[%d]/bones[%d][%d]",i,j,k);
|
||||
int track = !strcmp(channel, "rotate") ? 1 : !strcmp(channel, "translate") ? 2 : 0;
|
||||
if( !track ) continue;
|
||||
|
||||
spine_animkey_t key = {0};
|
||||
|
||||
key.time = json_float("/animations[%d]/bones[%d][%d][%d]/time",i,j,k,l);
|
||||
if( json_count("/animations[%d]/bones[%d][%d][%d]/curve",i,j,k,l) == 4 ) {
|
||||
key.curve[0] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[0]",i,j,k,l);
|
||||
key.curve[1] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[1]",i,j,k,l);
|
||||
key.curve[2] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[2]",i,j,k,l);
|
||||
key.curve[3] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[3]",i,j,k,l);
|
||||
}
|
||||
|
||||
if( track == 1 )
|
||||
key.deg = json_float("/animations[%d]/bones[%d][%d][%d]/value",i,j,k,l), // "/angle"
|
||||
array_push(v.rotate_keys[bone_id], key);
|
||||
else
|
||||
key.x = json_float("/animations[%d]/bones[%d][%d][%d]/x",i,j,k,l),
|
||||
key.y = json_float("/animations[%d]/bones[%d][%d][%d]/y",i,j,k,l),
|
||||
array_push(v.translate_keys[bone_id], key);
|
||||
}
|
||||
}
|
||||
|
||||
t.anims[i] = v;
|
||||
}
|
||||
|
||||
json_pop();
|
||||
|
||||
spine_skin(&t, 0);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void spine_render(spine_t *p, vec3 offset, unsigned flags) {
|
||||
if( !p->texture.id ) return;
|
||||
if( !flags ) return;
|
||||
|
||||
ddraw_push_2d();
|
||||
if( flags & 2 ) ddraw_line(vec3(0,0,0), vec3(window_width(),window_height(),0));
|
||||
if( flags & 2 ) ddraw_line(vec3(window_width(),0,0), vec3(0,window_height(),0));
|
||||
|
||||
for( int i = 1; i < array_count(p->bones); ++i ) {
|
||||
spine_bone_t *self = &p->bones[i];
|
||||
|
||||
static array(spine_bone_t*) chain = 0; array_resize(chain, 0);
|
||||
for( spine_bone_t *next = self; next ; next = next->parent_bone ) {
|
||||
array_push(chain, next);
|
||||
}
|
||||
|
||||
vec3 target = {0}, prev = {0};
|
||||
for( int j = 1, end = array_count(chain); j < end; ++j ) { // traverse from root(skipped) -> `i` bone direction
|
||||
int j_opposite = (end - 1) - j;
|
||||
|
||||
spine_bone_t *b = chain[j_opposite]; // bone
|
||||
spine_bone_t *pb = chain[j_opposite+1]; // parent bone
|
||||
|
||||
prev = target;
|
||||
|
||||
const float deg2rad = C_PI / 180;
|
||||
b->x2 = b->x3 + pb->x2 + b->x * cos( -pb->deg2 * deg2rad ) - b->y * sin( -pb->deg2 * deg2rad );
|
||||
b->y2 = -b->y3 + pb->y2 - b->y * cos( pb->deg2 * deg2rad ) + b->x * sin( pb->deg2 * deg2rad );
|
||||
b->deg2 = -b->deg3 + pb->deg2 - b->deg;
|
||||
|
||||
target = vec3(b->x2,b->y2,b->deg2);
|
||||
}
|
||||
|
||||
float deg = target.z, deg_prev = prev.z;
|
||||
target.z = 0; prev.z = 0;
|
||||
|
||||
target = add3(target, offset);
|
||||
prev = add3(prev, offset);
|
||||
|
||||
if( flags & 2 ) {
|
||||
ddraw_point( target );
|
||||
ddraw_text( target, -0.25f, self->name );
|
||||
ddraw_line( target, prev ); // from bone to parent
|
||||
}
|
||||
if( flags & 1 ) {
|
||||
vec4 rect = ptr4(&p->atlas[self->atlas_id].x);
|
||||
float zindex = self->z;
|
||||
float offsx = 0; // -(rect.w * p->texture.w); // -p->atlas[self->atlas_id].w - (self->rect_id ? p->skins[p->skin].rects[self->rect_id].w/2 : 0);
|
||||
float offsy = 0; // /*-(rect.z * p->texture.h)*2*/ -p->atlas[self->atlas_id].h - (self->rect_id ? p->skins[p->skin].rects[self->rect_id].h/2 : 0);
|
||||
float deg_rect = self->rect_id ? p->skins[p->skin].rects[self->rect_id].deg : 0;
|
||||
float tilt = p->atlas[self->atlas_id].deg + self->deg2 - deg_rect; // + self->deg2 + deg_rect + p->atlas[self->atlas_id].deg
|
||||
unsigned tint = ~0u;
|
||||
sprite_rect(p->texture, rect, zindex, add3(vec3(target.x,target.y,1),vec3(offsx,offsy,0)), tilt, tint);
|
||||
}
|
||||
}
|
||||
|
||||
ddraw_pop_2d();
|
||||
ddraw_flush();
|
||||
}
|
||||
|
||||
void spine_animate(spine_t *p, float *time, float *maxtime, float delta) {
|
||||
if( !p->texture.id ) return;
|
||||
|
||||
if( delta > 1/120.f ) delta = 1/120.f;
|
||||
if( *time >= *maxtime ) *time = 0; else *time += delta;
|
||||
|
||||
// reset root // needed?
|
||||
p->bones[0].x2 = 0;
|
||||
p->bones[0].y2 = 0;
|
||||
p->bones[0].deg2 = 0;
|
||||
p->bones[0].x3 = 0;
|
||||
p->bones[0].y3 = 0;
|
||||
p->bones[0].deg3 = 0;
|
||||
|
||||
for( int i = 0, end = array_count(p->bones); i < end; ++i) {
|
||||
// @todo: attach channel
|
||||
// @todo: per channel: if curve == linear || curve == stepped || array_count(curve) == 4 {...}
|
||||
for each_array_ptr(p->anims[p->inuse].rotate_keys[i], spine_animkey_t, r) {
|
||||
double r0 = r->time;
|
||||
*maxtime = maxf( *maxtime, r0 );
|
||||
if( absf(*time - r0) < delta ) {
|
||||
p->bones[i].deg3 = r->deg;
|
||||
}
|
||||
}
|
||||
for each_array_ptr(p->anims[p->inuse].translate_keys[i], spine_animkey_t, r) {
|
||||
double r0 = r->time;
|
||||
*maxtime = maxf( *maxtime, r0 );
|
||||
if( absf(*time - r0) < delta ) {
|
||||
p->bones[i].x3 = r->x;
|
||||
p->bones[i].y3 = r->y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void spine_ui(spine_t *p) {
|
||||
|
||||
if( ui_collapse(va("Anims: %d", array_count(p->anims)), va("%p-a", p))) {
|
||||
for each_array_ptr(p->anims, spine_anim_t, q) {
|
||||
if(ui_slider2("", &p->time, va("%.2f/%.0f %.2f%%", p->time, p->maxtime, p->time * 100.f))) {
|
||||
spine_animate(p, &p->time, &p->maxtime, 0);
|
||||
}
|
||||
|
||||
int choice = ui_label2_toolbar(q->name, ICON_MD_PAUSE_CIRCLE " " ICON_MD_PLAY_CIRCLE);
|
||||
if( choice == 1 ) window_pause( 0 ); // play
|
||||
if( choice == 2 ) window_pause( 1 ); // pause
|
||||
|
||||
for( int i = 0; i < _64; ++i ) {
|
||||
ui_separator();
|
||||
ui_label(va("Bone %d: Attachment keys", i));
|
||||
for each_array_ptr(q->attach_keys[i], spine_animkey_t, r) {
|
||||
ui_label(va("%.2f [%.2f %.2f %.2f %.2f] %s", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->name));
|
||||
}
|
||||
ui_label(va("Bone %d: Rotate keys", i));
|
||||
for each_array_ptr(q->rotate_keys[i], spine_animkey_t, r) {
|
||||
ui_label(va("%.2f [%.2f %.2f %.2f %.2f] %.2f deg", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->deg));
|
||||
}
|
||||
ui_label(va("Bone %d: Translate keys", i));
|
||||
for each_array_ptr(q->translate_keys[i], spine_animkey_t, r) {
|
||||
ui_label(va("%.2f [%.2f %.2f %.2f %.2f] (%.2f,%.2f)", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->x, r->y));
|
||||
}
|
||||
}
|
||||
}
|
||||
ui_collapse_end();
|
||||
}
|
||||
if( ui_collapse(va("Bones: %d", array_count(p->bones)), va("%p-b", p))) {
|
||||
for each_array_ptr(p->bones, spine_bone_t, q)
|
||||
if( ui_collapse(q->name, va("%p-b2", q)) ) {
|
||||
ui_label2("Parent:", q->parent);
|
||||
ui_label2("X:", va("%.2f", q->x));
|
||||
ui_label2("Y:", va("%.2f", q->y));
|
||||
ui_label2("Rotation:", va("%.2f", q->deg));
|
||||
ui_collapse_end();
|
||||
}
|
||||
ui_collapse_end();
|
||||
}
|
||||
if( ui_collapse(va("Slots: %d", array_count(p->slots)), va("%p-s", p))) {
|
||||
for each_array_ptr(p->slots, spine_slot_t, q)
|
||||
if( ui_collapse(q->name, va("%p-s2", q)) ) {
|
||||
ui_label2("Bone:", q->bone);
|
||||
ui_label2("Attachment:", q->attach);
|
||||
ui_collapse_end();
|
||||
}
|
||||
ui_collapse_end();
|
||||
}
|
||||
if( ui_collapse(va("Skins: %d", array_count(p->skins)), va("%p-k", p))) {
|
||||
for each_array_ptr(p->skins, spine_skin_t, q)
|
||||
if( ui_collapse(q->name, va("%p-k2", q)) ) {
|
||||
for each_array_ptr(q->rects, spine_rect_t, r)
|
||||
if( ui_collapse(r->name, va("%p-k3", r)) ) {
|
||||
ui_label2("X:", va("%.2f", r->x));
|
||||
ui_label2("Y:", va("%.2f", r->y));
|
||||
ui_label2("Scale X:", va("%.2f", r->sx));
|
||||
ui_label2("Scale Y:", va("%.2f", r->sy));
|
||||
ui_label2("Width:", va("%.2f", r->w));
|
||||
ui_label2("Height:", va("%.2f", r->h));
|
||||
ui_label2("Rotation:", va("%.2f", r->deg));
|
||||
ui_collapse_end();
|
||||
|
||||
|
||||
spine_bone_t *b = find_bone(p, r->name);
|
||||
if( b ) {
|
||||
static float tilt = 0;
|
||||
if( input(KEY_LCTRL) ) tilt += 60*1/60.f; else tilt = 0;
|
||||
spine_atlas_t *r = p->atlas + b->atlas_id;
|
||||
sprite_flush();
|
||||
camera_get_active()->position = vec3(0,0,2);
|
||||
vec4 rect = ptr4(&r->x); float zindex = 0; vec3 xy_zoom = vec3(0,0,0); unsigned tint = ~0u;
|
||||
sprite_rect(p->texture,
|
||||
// rect: vec4(r->x*1.0/p->texture.w,r->y*1.0/p->texture.h,(r->x+r->w)*1.0/p->texture.w,(r->y+r->h)*1.0/p->texture.h),
|
||||
ptr4(&r->x), // atlas
|
||||
0, vec3(0,0,0), r->deg + tilt, tint);
|
||||
sprite_flush();
|
||||
camera_get_active()->position = vec3(+window_width()/3,window_height()/2.25,2);
|
||||
}
|
||||
}
|
||||
ui_collapse_end();
|
||||
}
|
||||
ui_collapse_end();
|
||||
}
|
||||
|
||||
if( ui_int("Use skin", &p->skin) ) {
|
||||
p->skin = clampf(p->skin, 0, array_count(p->skins) - 1);
|
||||
spine_skin(p, p->skin);
|
||||
}
|
||||
|
||||
if( p->texture.id ) ui_texture(0, p->texture);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main() {
|
||||
window_create(0.75, 0);
|
||||
|
||||
camera_t cam = camera();
|
||||
cam.position = vec3(0,0,1);
|
||||
camera_enable(&cam);
|
||||
|
||||
spine_t s = spine("goblins.json", "goblins.atlas", 0);
|
||||
|
||||
while( window_swap() ) {
|
||||
camera_get_active()->position.x = window_width()/2;
|
||||
camera_get_active()->position.y = window_height()/2;
|
||||
|
||||
static bool do_skin = 1, do_skel = 1;
|
||||
spine_animate(&s, &s.time, &s.maxtime, !window_has_pause() * window_delta());
|
||||
|
||||
spine_render(&s, vec3(window_width()/2, window_height()/2, 0), do_skin );
|
||||
sprite_flush();
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
spine_render(&s, vec3(window_width()/2, window_height()/2, 0), (do_skel*2));
|
||||
|
||||
if( ui_panel("Spine", 0) ) {
|
||||
if(ui_button("Load")) {
|
||||
s = spine("goblins.json", "goblins.atlas", 0);
|
||||
}
|
||||
spine_ui(&s);
|
||||
if(ui_bool("Draw Skin", &do_skin));
|
||||
if(ui_bool("Draw Skeleton", &do_skel));
|
||||
ui_panel_end();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
// sprite routines
|
||||
// - rlyeh,
|
||||
//
|
||||
// credits: original lovely demo by rxi (MIT License).
|
||||
// see https://github.com/rxi/autobatch/tree/master/demo/cats
|
||||
|
||||
#include "fwk.h"
|
||||
|
||||
texture_t kids, catImage, shadowImage, inputs;
|
||||
int NUM_SPRITES = 100, NUM_SPRITES_CHANGED = 1;
|
||||
|
||||
typedef struct Cat {
|
||||
int cat, flip;
|
||||
double x, y;
|
||||
double vx, vy;
|
||||
double animSpeed;
|
||||
double moveTimer;
|
||||
double elapsed;
|
||||
} Cat;
|
||||
|
||||
void demo_cats() {
|
||||
static array(Cat) cats = 0;
|
||||
|
||||
// init
|
||||
if( NUM_SPRITES_CHANGED ) {
|
||||
NUM_SPRITES_CHANGED = 0;
|
||||
|
||||
array_resize(cats, NUM_SPRITES); int i = 0;
|
||||
for each_array_ptr(cats, Cat, c) {
|
||||
randset(i++);
|
||||
c->x = randf() * window_width();
|
||||
c->y = randf() * window_height();
|
||||
c->vx = c->vy = 0;
|
||||
c->cat = randi(0, 4);
|
||||
c->flip = randf() < 0.5;
|
||||
c->animSpeed = 0.8 + randf() * 0.3;
|
||||
c->moveTimer = 0;
|
||||
c->elapsed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// move
|
||||
const float dt = 1/120.f;
|
||||
const int appw = window_width(), apph = window_height();
|
||||
|
||||
enum { yscale = 1 };
|
||||
for( int i = 0; i < NUM_SPRITES; ++i ) {
|
||||
Cat *c = &cats[i];
|
||||
// Add velocity to position //and wrap to screen
|
||||
c->x += yscale * c->vx * dt; // % ;
|
||||
c->y += yscale * c->vy * dt; // % (int)window_height();
|
||||
if( c->x < 0 ) c->x += appw; else if( c->x > appw ) c->x -= appw;
|
||||
if( c->y < 0 ) c->y += apph; else if( c->y > apph ) c->y -= apph;
|
||||
// Faster animation if walking
|
||||
int boost = c->vx == 0 && c->vy == 0 ? 1 : 3;
|
||||
// Update elapsed time
|
||||
c->elapsed += dt * boost;
|
||||
// Update move timer -- if we hit zero then change or zero velocity
|
||||
c->moveTimer -= dt * boost;
|
||||
if (c->moveTimer < 0) {
|
||||
if (randf() < .2) {
|
||||
c->vx = (randf() * 2 - 1) * 30 * 2;
|
||||
c->vy = (randf() * 2 - 1) * 15 * 2;
|
||||
c->flip = c->vx < 0;
|
||||
} else {
|
||||
c->vx = c->vy = 0;
|
||||
}
|
||||
c->moveTimer = 1 + randf() * 5;
|
||||
}
|
||||
}
|
||||
|
||||
// render
|
||||
uint32_t white = rgba(255,255,255,255);
|
||||
uint32_t alpha = rgba(255,255,255,255*0.6);
|
||||
for( int i = 0; i < NUM_SPRITES; ++i ) {
|
||||
Cat *c = &cats[i];
|
||||
// Get current animation frame (8x4 tilesheet)
|
||||
double e = c->elapsed * c->animSpeed;
|
||||
double frame_num = c->cat * 8 + floor( ((int)(e * 8)) % 4 );
|
||||
frame_num = c->vx != 0 || c->vy != 0 ? frame_num + 4 : frame_num;
|
||||
// Get x scale based on flip flag
|
||||
int xscale = yscale * (c->flip ? -1 : 1);
|
||||
// Draw
|
||||
float angle = 0; //fmod(window_time()*360/5, 360);
|
||||
float scale[2] = { 2*xscale, 2*yscale };
|
||||
float position[3] = { c->x,c->y,c->y }, no_offset[2] = {0,0}, spritesheet[3] = { frame_num,8,4 };
|
||||
sprite_sheet(catImage,
|
||||
spritesheet, // frame_number in a 8x4 spritesheet
|
||||
position, angle, // position(x,y,depth: sort by Y), angle
|
||||
no_offset, scale, // offset(x,y), scale(x,y)
|
||||
0,white,0 // is_additive, tint color, resolution independant
|
||||
);
|
||||
float position_neg_sort[3] = { c->x,c->y,-c->y }, offset[2] = {-1,5}, no_spritesheet[3] = {0,0,0};
|
||||
sprite_sheet(shadowImage,
|
||||
no_spritesheet, // no frame_number (0x0 spritesheet)
|
||||
position_neg_sort, angle, // position(x,y,depth: sort by Y), angle
|
||||
offset, scale, // offset(x,y), scale(x,y)
|
||||
0,alpha,0 // is_additive, tint color, resolution independant
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void demo_kids() {
|
||||
static int angle; //++angle;
|
||||
static int *x, *y, *v;
|
||||
|
||||
// init
|
||||
if( NUM_SPRITES_CHANGED ) {
|
||||
NUM_SPRITES_CHANGED = 0;
|
||||
|
||||
y = (int*)REALLOC(y, 0 );
|
||||
x = (int*)REALLOC(x, NUM_SPRITES * sizeof(int) );
|
||||
y = (int*)REALLOC(y, NUM_SPRITES * sizeof(int) );
|
||||
v = (int*)REALLOC(v, NUM_SPRITES * sizeof(int) );
|
||||
for( int i = 0; i < NUM_SPRITES; ++i ) {
|
||||
randset(i);
|
||||
x[i] = randi(0, window_width());
|
||||
y[i] = randi(0, window_height());
|
||||
v[i] = randi(1, 3);
|
||||
}
|
||||
}
|
||||
|
||||
// config
|
||||
const int appw = window_width(), apph = window_height();
|
||||
|
||||
// move & render
|
||||
for( int i = 0; i < NUM_SPRITES; ++i ) {
|
||||
y[i] = (y[i] + v[i]) % (apph + 128);
|
||||
int col = ((x[i] / 10) % 4); // 4x4 tilesheet
|
||||
int row = ((y[i] / 10) % 4);
|
||||
int num_frame = col * 4 + row;
|
||||
float position[3] = {x[i],y[i],y[i]}, offset[2]={0,0}, scale[2]={1,1}, spritesheet[3]={num_frame,4,4};
|
||||
sprite_sheet(kids,
|
||||
spritesheet, // num_frame in a 4x4 spritesheet
|
||||
position, angle, // position(x,y,depth: sort by Y), angle
|
||||
offset, scale, // offset(x,y), scale(x,y)
|
||||
0, ~0u, 0 // is_additive, tint color, resolution independant
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
window_create(75.f, 0);
|
||||
window_title("FWK - Sprite");
|
||||
|
||||
// options
|
||||
int do_cats = 1;
|
||||
NUM_SPRITES = optioni("--num_sprites,-N", NUM_SPRITES);
|
||||
if(do_cats) NUM_SPRITES/=2; // cat-sprite+cat-shadow == 2 sprites
|
||||
|
||||
// load sprites and sheets
|
||||
kids = texture( "spriteSheetExample.png", TEXTURE_LINEAR );
|
||||
catImage = texture( "cat.png", TEXTURE_LINEAR ); //
|
||||
shadowImage = texture( "cat-shadow.png", TEXTURE_LINEAR );
|
||||
inputs = texture( "prompts_tilemap_34x24_16x16x1.png", TEXTURE_LINEAR );
|
||||
|
||||
// load all post fx files
|
||||
for(const char **list = file_list("./","fx**.fs"); *list; list++) {
|
||||
fx_load(*list);
|
||||
}
|
||||
|
||||
// init camera (x,y) (z = zoom)
|
||||
camera_t cam = camera();
|
||||
cam.position = vec3(window_width()/2,window_height()/2,1);
|
||||
camera_enable(&cam);
|
||||
|
||||
while(window_swap()) {
|
||||
if( input(KEY_F5)) window_reload();
|
||||
if( input(KEY_F11)) window_fullscreen( window_has_fullscreen() ^ 1);
|
||||
if( input(KEY_ESC) ) break;
|
||||
|
||||
viewport_color3(vec3(0.4,0.4,0.4));
|
||||
|
||||
// camera panning (x,y) & zooming (z)
|
||||
if( !ui_hover() && !ui_active() ) {
|
||||
if( input(MOUSE_L) ) cam.position.x -= input_diff(MOUSE_X);
|
||||
if( input(MOUSE_L) ) cam.position.y -= input_diff(MOUSE_Y);
|
||||
cam.position.z += input_diff(MOUSE_W) * 0.1; // cam.p.z += 0.001f; for tests
|
||||
}
|
||||
|
||||
// apply post-fxs from here
|
||||
fx_begin();
|
||||
|
||||
profile("Sprite batching") {
|
||||
if(do_cats) demo_cats(); else demo_kids();
|
||||
}
|
||||
|
||||
// flush retained renderer, so we ensure the fbos are up to date before fx_end()
|
||||
profile("Sprite flushing") {
|
||||
sprite_flush();
|
||||
}
|
||||
|
||||
// post-fxs end here
|
||||
fx_end();
|
||||
|
||||
// draw pixel-art hud, 16x16 ui element, scaled and positioned in resolution-independant way
|
||||
{
|
||||
vec3 old_pos = camera_get_active()->position;
|
||||
|
||||
sprite_flush();
|
||||
camera_get_active()->position = vec3(window_width()/2,window_height()/2,1);
|
||||
|
||||
float zindex = window_height(); // large number, on top
|
||||
float spritesheet[3] = {17,34,24}, offset[2] = {0, - 2*absf(sin(window_time()*5))}; // sprite cell and animation
|
||||
float scale[2] = {3, 3}, tile_w = 16 * scale[0], tile_h = 16 * scale[1]; // scaling
|
||||
float position[3] = {window_width() - tile_w, window_height() - tile_h, zindex }; // position in screen-coordinates
|
||||
sprite_sheet(inputs, spritesheet, position, 0/*rotation*/, offset, scale, false/*is_additive*/, WHITE/*color*/, false/*resolution_independant*/);
|
||||
|
||||
sprite_flush();
|
||||
camera_get_active()->position = old_pos;
|
||||
}
|
||||
|
||||
if( ui_panel("Sprite", 0) ) {
|
||||
const char *labels[] = {"Kids","Cats"};
|
||||
if( ui_list("Sprite type", labels, countof(labels), &do_cats) ) NUM_SPRITES_CHANGED = 1;
|
||||
if( ui_int("Number of Sprites", &NUM_SPRITES) ) NUM_SPRITES_CHANGED = 1;
|
||||
if( ui_clampf("Zoom", &cam.position.z, 0.1, 10));
|
||||
ui_panel_end();
|
||||
}
|
||||
if( ui_panel("FX", 0) ) {
|
||||
for( int i = 0; i < 64; ++i ) {
|
||||
char *name = fx_name(i); if( !name ) break;
|
||||
bool b = fx_enabled(i);
|
||||
if( ui_bool(name, &b) ) fx_enable(i, fx_enabled(i) ^ 1);
|
||||
}
|
||||
ui_panel_end();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
#define FWK_IMPLEMENTATION
|
||||
#include "engine/joint/fwk.h"
|
||||
#include "fwk_netsync.h"
|
||||
|
||||
enum { MAX_NPCS = 5 };
|
||||
struct player_t {
|
||||
uint64_t seen_until;
|
||||
float x,y,z,angle;
|
||||
uint32_t color;
|
||||
};
|
||||
struct npc_t {
|
||||
float x,y,z;
|
||||
uint32_t color;
|
||||
};
|
||||
struct world_t {
|
||||
struct player_t player[MAX_CLIENTS];
|
||||
struct npc_t npc[MAX_NPCS];
|
||||
} world = {0};
|
||||
|
||||
char *show_notification(char *msg) {
|
||||
printf("notif %s\n", msg);
|
||||
ui_notify("server", msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bind_netbuffers(int64_t self_id) {
|
||||
uint32_t colors[] = { ORANGE,GREEN,RED,CYAN,PURPLE,YELLOW,GRAY,PINK,AQUA };
|
||||
for (int64_t i=0; i<MAX_NPCS; ++i) {
|
||||
// as an example, let only server to set initial pos
|
||||
if (self_id==0) {
|
||||
world.npc[i].x = i*3.f + 4.f;
|
||||
}
|
||||
world.npc[i].color = colors[i%(sizeof colors / sizeof colors[0])];
|
||||
network_buffer(&world.npc[i], sizeof(struct npc_t), NETWORK_RECV, 0);
|
||||
}
|
||||
|
||||
for (int64_t i=0; i<MAX_CLIENTS; ++i) {
|
||||
world.player[i].color = colors[i%(sizeof colors / sizeof colors[0])];
|
||||
network_buffer(&world.player[i], sizeof(struct player_t), i!=self_id ? NETWORK_RECV : NETWORK_SEND, i /* each client owns exactly 1 buffer */);
|
||||
};
|
||||
|
||||
// register server->client rpc
|
||||
if (self_id > 0) {
|
||||
network_rpc("char* show_notification(char*)", show_notification);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
// ifdef(win32, FreeConsole()); // tty_detach()
|
||||
|
||||
// network setup
|
||||
network_create("127.0.0.1", 0, flag("--client") ? NETWORK_CONNECT : 0);
|
||||
int64_t self_id = network_get(NETWORK_RANK);
|
||||
bind_netbuffers(self_id);
|
||||
|
||||
// game setup
|
||||
camera_t cam = camera();
|
||||
window_create( 0.35f, WINDOW_MSAA8|WINDOW_SQUARE );
|
||||
struct player_t *self = &world.player[self_id];
|
||||
|
||||
// game loop
|
||||
while( window_swap() && !input(KEY_ESC) ) {
|
||||
// network sync
|
||||
char **event = network_sync(0); // timeout_ms:0
|
||||
while(*event) printf( "network event: %s\n", *event++ );
|
||||
|
||||
self_id = network_get(NETWORK_RANK);
|
||||
if (network_get(NETWORK_LIVE) == 0) {
|
||||
network_create("127.0.0.1", 0, flag("--client") ? NETWORK_CONNECT|NETWORK_NOFAIL : 0);
|
||||
self_id = network_get(NETWORK_RANK);
|
||||
if (self_id != -1) {
|
||||
bind_netbuffers(self_id);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* quick hack to broadcast notif from host */
|
||||
if (self_id == 0 && input_down(KEY_F3)) {
|
||||
printf("rpc %s\n", "show_notification \"hi, sailor!\"");
|
||||
network_rpc_send(rand()%4, "show_notification \"hi, sailor!\"");
|
||||
}
|
||||
|
||||
// camera tracking
|
||||
cam.position = vec3(self->x,100,self->z);
|
||||
camera_lookat(&cam, vec3(self->x,0,self->z));
|
||||
|
||||
// input - move player
|
||||
float iy = input(KEY_UP) - input(KEY_DOWN);
|
||||
float ix = input(KEY_RIGHT) - input(KEY_LEFT);
|
||||
if( iy || ix ) {
|
||||
self->x += iy*window_delta()*15;
|
||||
self->z += ix*window_delta()*15;
|
||||
}
|
||||
self->seen_until = date_epoch() + 4;
|
||||
|
||||
// npc - update npc movement on server-side
|
||||
if (self_id == 0) {
|
||||
for (int i = 0; i < MAX_NPCS; ++i) {
|
||||
struct npc_t *n = &world.npc[i];
|
||||
n->z = sinf(window_time())*4.f;
|
||||
}
|
||||
}
|
||||
|
||||
// background - draw grid
|
||||
ddraw_ground(0);
|
||||
|
||||
// foreground - draw all players
|
||||
for( int id = 0; id < MAX_CLIENTS; ++id ) {
|
||||
struct player_t *p = &world.player[id];
|
||||
if (p->seen_until < date_epoch()) continue; /* skip inactive players */
|
||||
ddraw_color( p->color );
|
||||
ddraw_capsule(vec3(p->x,0,p->z), vec3(p->x,2,p->z), 1);
|
||||
ddraw_text(vec3(p->x,4,p->z), 0.01, va("player #%d", id));
|
||||
}
|
||||
for( int id = 0; id < MAX_NPCS; ++id ) {
|
||||
struct npc_t *p = &world.npc[id];
|
||||
ddraw_color( p->color );
|
||||
ddraw_capsule(vec3(p->x,0,p->z), vec3(p->x,2,p->z), 1);
|
||||
ddraw_text(vec3(p->x,4,p->z), 0.01, va("npc #%d", id));
|
||||
}
|
||||
|
||||
// stats
|
||||
window_title(va("player #%lld", self_id));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
// video player
|
||||
// - rlyeh, public domain
|
||||
|
||||
#include "fwk.h"
|
||||
|
||||
int main() {
|
||||
// 75% window, msaa x2
|
||||
window_create( 75, WINDOW_MSAA2 );
|
||||
|
||||
// load video
|
||||
int is_rgb = flag("--rgb") ? 1 : 0;
|
||||
video_t *v = video( "pexels-pachon-in-motion-17486489.mp4", is_rgb ? VIDEO_RGB : VIDEO_YCBCR );
|
||||
|
||||
while( window_swap() ) {
|
||||
// decode video frame and get associated textures (audio is automatically sent to audiomixer)
|
||||
texture_t *textures;
|
||||
profile( "Video decoder" ) {
|
||||
textures = video_decode( v );
|
||||
}
|
||||
|
||||
// present decoded textures as a fullscreen composed quad
|
||||
profile( "Video quad" ) {
|
||||
if(is_rgb) fullscreen_quad_rgb( textures[0], 1.3f );
|
||||
else fullscreen_quad_ycbcr( textures, 1.3f );
|
||||
}
|
||||
|
||||
// input controls
|
||||
if( input(KEY_ESC) ) break;
|
||||
|
||||
// ui video
|
||||
if( ui_panel("Video", 0) ) {
|
||||
if( ui_button("Rewind") ) video_seek(v, video_position(v) - 3);
|
||||
if( ui_button("Pause") ) video_pause(v, video_is_paused(v) ^ 1);
|
||||
if( ui_button("Forward") ) video_seek(v, video_position(v) + 3);
|
||||
ui_panel_end();
|
||||
}
|
||||
// audio
|
||||
if( ui_panel("Audio", 0)) {
|
||||
static float master = 1;
|
||||
if( ui_slider2("Master", &master, va("%.2f", master))) audio_volume_master(master);
|
||||
ui_panel_end();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash 2>nul || goto :windows
|
||||
|
||||
sh ../MAKE.bat demos
|
||||
|
||||
exit
|
||||
|
||||
:windows
|
||||
|
||||
pushd ..
|
||||
call MAKE.bat demos %*
|
||||
popd
|
|
@ -0,0 +1,15 @@
|
|||
[bt]
|
||||
any
|
||||
run:no
|
||||
not
|
||||
run:no
|
||||
run:no
|
||||
all
|
||||
run:yes
|
||||
run:yes
|
||||
run:no
|
||||
loop:2
|
||||
run:hi
|
||||
loop:3
|
||||
sleep:1
|
||||
run:hi
|
|
@ -0,0 +1,38 @@
|
|||
SIERRA ON-LINE, INC.
|
||||
3-D Animated Adventure Game Soundtrack Series
|
||||
===============================================
|
||||
LEISURE SUIT LARRY III: PASSIONATE PATTI-
|
||||
IN PURSUIT OF THE PULSATING PECTORALS
|
||||
|
||||
|
||||
"TAWNI AT THE BEACH"
|
||||
Mike Dana
|
||||
===============================================
|
||||
Copyright (c)1989 Sierra On-Line, Inc.
|
||||
===============================================
|
||||
|
||||
GENERAL MIDI VERSION
|
||||
|
||||
System Requirements:
|
||||
|
||||
- MIDI Playback Software capable of reading Type 1 Standard
|
||||
MIDI File format
|
||||
- General MIDI sound device (Wave Table or better recommended)
|
||||
|
||||
|
||||
This Standard MIDI File was recorded directly from Sierra's "Leisure Suit
|
||||
Larry 3" adventure game. It has been converted from the MT-32 version for
|
||||
playback on General MIDI sound cards. A Wave Table or better sound card is
|
||||
highly recommended for optimal playback.
|
||||
|
||||
Recorded/converted for General MIDI by Tom Lewandowski.
|
||||
Address questions or comments to:
|
||||
|
||||
QUEST STUDIOS
|
||||
Tom Lewandowski
|
||||
tom@queststudios.com
|
||||
|
||||
www.QuestStudios.com
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 36 KiB |
|
@ -0,0 +1,13 @@
|
|||
Author
|
||||
======
|
||||
|
||||
This is the work of Emil Persson, aka Humus.
|
||||
http://www.humus.name
|
||||
|
||||
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
This work is licensed under a Creative Commons Attribution 3.0 Unported License.
|
||||
http://creativecommons.org/licenses/by/3.0/
|
|
@ -0,0 +1,95 @@
|
|||
Copyright (c) 2010-2013 by tyPoland Lukasz Dziedzic with Reserved Font Name "Carlito".
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License,
|
||||
Version 1.1 as shown below.
|
||||
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
|
||||
PREAMBLE The goals of the Open Font License (OFL) are to stimulate
|
||||
worldwide development of collaborative font projects, to support the font
|
||||
creation efforts of academic and linguistic communities, and to provide
|
||||
a free and open framework in which fonts may be shared and improved in
|
||||
partnership with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves.
|
||||
The fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply to
|
||||
any document created using the fonts or their derivatives.
|
||||
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such.
|
||||
This may include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components
|
||||
as distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting ? in part or in whole ?
|
||||
any of the components of the Original Version, by changing formats or
|
||||
by porting the Font Software to a new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical writer
|
||||
or other person who contributed to the Font Software.
|
||||
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,in
|
||||
Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the
|
||||
corresponding Copyright Holder. This restriction only applies to the
|
||||
primary font name as presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole, must
|
||||
be distributed entirely under this license, and must not be distributed
|
||||
under any other license. The requirement for fonts to remain under
|
||||
this license does not apply to any document created using the Font
|
||||
Software.
|
||||
|
||||
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are not met.
|
||||
|
||||
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
|
||||
DEALINGS IN THE FONT SOFTWARE.
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
Copyright (c) 2010-2013 by tyPoland Lukasz Dziedzic with Reserved Font Name "Carlito".
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License,
|
||||
Version 1.1 as shown below.
|
||||
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
|
||||
PREAMBLE The goals of the Open Font License (OFL) are to stimulate
|
||||
worldwide development of collaborative font projects, to support the font
|
||||
creation efforts of academic and linguistic communities, and to provide
|
||||
a free and open framework in which fonts may be shared and improved in
|
||||
partnership with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves.
|
||||
The fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply to
|
||||
any document created using the fonts or their derivatives.
|
||||
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such.
|
||||
This may include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components
|
||||
as distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting ? in part or in whole ?
|
||||
any of the components of the Original Version, by changing formats or
|
||||
by porting the Font Software to a new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical writer
|
||||
or other person who contributed to the Font Software.
|
||||
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,in
|
||||
Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the
|
||||
corresponding Copyright Holder. This restriction only applies to the
|
||||
primary font name as presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole, must
|
||||
be distributed entirely under this license, and must not be distributed
|
||||
under any other license. The requirement for fonts to remain under
|
||||
this license does not apply to any document created using the Font
|
||||
Software.
|
||||
|
||||
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are not met.
|
||||
|
||||
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
|
||||
DEALINGS IN THE FONT SOFTWARE.
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
M+ FONTS Copyright (C) 2002-2016 M+ FONTS PROJECT
|
||||
|
||||
-
|
||||
|
||||
LICENSE_E
|
||||
|
||||
|
||||
|
||||
|
||||
These fonts are free software.
|
||||
Unlimited permission is granted to use, copy, and distribute them, with
|
||||
or without modification, either commercially or noncommercially.
|
||||
THESE FONTS ARE PROVIDED "AS IS" WITHOUT WARRANTY.
|
||||
|
||||
|
||||
http://mplus-fonts.sourceforge.jp/mplus-outline-fonts/
|
|
@ -0,0 +1,54 @@
|
|||
Arabic: صِف خَلقَ خَودِ كَمِثلِ الشَمسِ إِذ بَزَغَت — يَحظى الضَجيعُ بِها نَجلاءَ مِعطارِ
|
||||
Armenian: Կրնամ ապակի ուտել և ինծի անհանգիստ չըներ
|
||||
Belarusian: У Іўі худы жвавы чорт у зялёнай камізэльцы пабег пад'есці фаршу з юшкай
|
||||
Braille (EN): ⠊⠀⠉⠁⠝⠀⠑⠁⠞⠀⠛⠇⠁⠎⠎⠀⠁⠝⠙⠀⠊⠞⠀⠙⠕⠑⠎⠝⠞⠀⠓⠥⠗⠞⠀⠍⠑...
|
||||
Bulgarian: Ах чудна българска земьо, полюшвай цъфтящи жита.
|
||||
Chinese: 我能吞下玻璃而不伤身体。...
|
||||
Chinese(TD): 我能吞下玻璃而不傷身體。...
|
||||
Czech: Nechť již hříšné saxofony ďáblů rozezvučí síň úděsnými tóny waltzu, tanga a quickstepu.
|
||||
Dutch: Pa's wijze lynx bezag vroom het fikse aquaduct.
|
||||
English: The quick brown fox jumps over the lazy dog.
|
||||
Estonian: Põdur Zagrebi tšellomängija-följetonist Ciqo külmetas kehvas garaažis
|
||||
Ethiopian: ሰማይ አይታረስ ንጉሥ አይከሰስ። ብላ ካለኝ እንደአባቴ በቆመጠኝ። ጌጥ ያለቤቱ ቁምጥና ነው። ...
|
||||
Finnish: Charles Darwin jammaili Åken hevixylofonilla Qatarin yöpub Zeligissä.
|
||||
French: Voix ambiguë d’un cœur qui au zéphyr préfère les jattes de kiwi.
|
||||
Georgian: მინას ვჭამ და არა მტკივა...
|
||||
German: Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich.
|
||||
Greek(Ancient): Ἄδμηθ’, ὁρᾷς γὰρ τἀμὰ πράγμαθ’ ὡς ἔχει, λέξαι θέλω σοι πρὶν θανεῖν ἃ βούλομαι.
|
||||
Greek: Ταχίστη αλώπηξ βαφής ψημένη γη, δρασκελίζει υπέρ νωθρού κυνός.
|
||||
Guarani: Hĩlandiagua kuñanguéra oho peteĩ saʼyju ypaʼũme Gavõme omboʼe hag̃ua ingyleñeʼẽ mitãnguérare neʼẽndyʼỹ.
|
||||
Hebrew: דג סקרן שט בים מאוכזב ולפתע מצא לו חברה
|
||||
Hindi: ऋषियों को सताने वाले दुष्ट राक्षसों के राजा रावण का सर्वनाश करने वाले विष्णुवतार भगवान श्रीराम, अयोध्या के महाराज दशरथ के बड़े सपुत्र थे।
|
||||
Hungarian: Jó foxim és don Quijote húszwattos lámpánál ülve egy pár bűvös cipőt készít.
|
||||
Icelandic: Kæmi ný öxi hér, ykist þjófum nú bæði víl og ádrepa.
|
||||
Igbo: Nne, nna, wepụ he’l’ụjọ dum n’ime ọzụzụ ụmụ, vufesi obi nye Chukwu, ṅụrịanụ, gbakọọnụ kpaa, kwee ya ka o guzoshie ike; ọ ghaghị ito, nwapụta ezi agwa
|
||||
IPA: ɢʷɯʔ.nas.doːŋ.kʰlja] [ŋan.ȵʑi̯wo.ɕi̯uĕn.ɣwa]
|
||||
Irish: Ċuaiġ bé ṁórṡáċ le dlúṫspád fíorḟinn trí hata mo ḋea-ṗorcáin ḃig.
|
||||
Japanese: いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす(ん)
|
||||
Japanese/2: 私はガラスを食べられます。それは私を傷つけません。
|
||||
Korean: 키스의 고유조건은 입술끼리 만나야 하고 특별한 기술은 필요치 않다
|
||||
Latvian: Muļķa hipiji mēģina brīvi nogaršot celofāna žņaudzējčūsku.
|
||||
Lithuanian: Įlinkdama fechtuotojo špaga sublykčiojusi pragręžė apvalų arbūzą.
|
||||
Macedonian: Ѕидарски пејзаж: шугав билмез со чудење џвака ќофте и кељ на туѓ цех.
|
||||
Maths: 2H₂+O₂⇌2H₂O,R=4kΩ,⌀200mm;⎷a²+b³c₈;∀x∈ℝ:⌈x⌉=−⌊−x⌋,α∧¬β=¬(¬α∨β);ℕ⊆ℕ₀⊂ℤ⊂ℚ⊂ℝ⊂ℂ
|
||||
Mongolian: Щётканы фермд пийшин цувъя. Бөгж зогсч хэльюү
|
||||
Nepali: म काँच खान सक्छू र मलाई केहि नी हुन्न् ।
|
||||
Norwegian: Høvdingens kjære squaw får litt pizza i Mexico by
|
||||
Old Norse(rune): ᛖᚴ ᚷᛖᛏ ᛖᛏᛁ ᚧ ᚷᛚᛖᚱ ᛘᚾ ᚦᛖᛋᛋ ᚨᚧ ᚡᛖ ᚱᚧᚨ ᛋᚨᚱ ...
|
||||
Polish: Pchnąć w tę łódź jeża lub ośm skrzyń fig.
|
||||
Portuguese: Luís argüia à Júlia que «brações, fé, chá, óxido, pôr, zângão» eram palavras do português.
|
||||
Quotes: ‘single’ “double” “curly” ‚deutsche‘ „Anführ“ \"'´`
|
||||
Romanian: Înjurând pițigăiat, zoofobul comandă vexat whisky și tequila.
|
||||
Russian: Эх, чужак! Общий съём цен шляп (юфть)—вдрызг!.
|
||||
Serbian: Ајшо, лепото и чежњо, за љубав срца мога дођи у Хаџиће на кафу.
|
||||
Serbian(2): Ajšo, lepoto i čežnjo, za ljubav srca moga dođi u Hadžiće na kafu.
|
||||
Slovak: Kŕdeľ ďatľov učí koňa žrať kôru + š
|
||||
Spanish: Benjamín pidió una bebida de kiwi y fresa; Noé, sin vergüenza, la más exquisita champaña del menú. + ḷḷ ḥ
|
||||
Swedish: Yxskaftbud, ge vår wczonmö iqhjälp.
|
||||
Taiwanese: Góa ē-tàng chia̍h po-lê, mā bē tio̍h-siong.
|
||||
Thai: เป็นมนุษย์สุดประเสริฐเลิศคุณค่า กว่าบรรดาฝูงสัตว์เดรัจฉาน จงฝ่าฟันพัฒนาวิชาการ อย่าล้างผลาญฤๅเข่นฆ่าบีฑาใคร ไม่ถือโทษโกรธแช่งซัดฮึดฮัดด่า หัดอภัยเหมือนกีฬาอัชฌาสัย ปฏิบัติประพฤติกฎกำหนดใจ พูดจาให้จ๊ะๆ จ๋าๆ น่าฟังเอยฯ
|
||||
Tibetan: ༈ དཀར་མཛེས་ཨ་ཡིག་ལས་འཁྲུངས་ཡེ་ཤེས་གཏེར། །ཕས་རྒོལ་ཝ་སྐྱེས་ཟིལ་གནོན་གདོང་ལྔ་བཞིན། །ཆགས་ཐོགས་ཀུན་བྲལ་མཚུངས་མེད་འཇམ་བྱངས་མཐུས། །མ་ཧཱ་མཁས་པའི་གཙོ་བོ་ཉིད་གྱུར་ཅིག།
|
||||
Turkish: Saf ve haydut kız çocuğu bin plaj görmüş.
|
||||
Ukrainian: Жебракують філософи при ґанку церкви в Гадячі, ще й шатро їхнє п’яне знаємо.
|
||||
Vietnamese: Do bạch kim rất quý nên sẽ dùng để lắp vô xương
|
||||
Welsh: Parciais fy jac codi baw hud llawn dŵr ger tŷ Mabon.
|
|
@ -0,0 +1,154 @@
|
|||
/**
|
||||
* (c) 2021 FMS_Cat
|
||||
* Original shader: https://www.shadertoy.com/view/MdffD7
|
||||
* I dumbass don't know what it says despite it's my own shader
|
||||
*/
|
||||
/*
|
||||
* Copyright 2021 FMS_Cat
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define half2 vec2
|
||||
#define half3 vec3
|
||||
#define half4 vec4
|
||||
#define saturate(c) clamp(c, 0.0, 1.0)
|
||||
|
||||
//uniform float iTime;
|
||||
uniform float iScale;
|
||||
//uniform vec2 iResolution;
|
||||
uniform vec4 iBackground;
|
||||
|
||||
const float PI = 3.14159265f;
|
||||
|
||||
const int SAMPLES = 6;
|
||||
|
||||
const float COLOR_NOISE_AMP = 0.1f;
|
||||
const vec3 YIQ_OFFSET = vec3( -0.1f, -0.1f, 0.0f );
|
||||
const vec3 YIQ_AMP = vec3( 1.2f, 1.1f, 1.5f );
|
||||
|
||||
bool validuv( vec2 uv )
|
||||
{
|
||||
return 0.0f < uv.x && uv.x < 1.0f && 0.0f < uv.y && uv.y < 1.0f;
|
||||
}
|
||||
|
||||
vec2 yflip( vec2 uv )
|
||||
{
|
||||
return vec2( uv.x, 1.0 - uv.y );
|
||||
}
|
||||
|
||||
float fs( float s )
|
||||
{
|
||||
return fract( sin( s * 114.514f ) * 1919.810f );
|
||||
}
|
||||
|
||||
float fs2( vec2 s )
|
||||
{
|
||||
return fs( s.x + fs( s.y ) );
|
||||
}
|
||||
|
||||
mat2x2 rotate2D( float t )
|
||||
{
|
||||
return mat2x2( cos( t ), sin( t ), -sin( t ), cos( t ) );
|
||||
}
|
||||
|
||||
vec3 rgb2yiq( vec3 rgb )
|
||||
{
|
||||
return mat3x3( 0.299f, 0.596f, 0.211f, 0.587f, -0.274f, -0.523f, 0.114f, -0.322f, 0.312f ) * rgb;
|
||||
}
|
||||
|
||||
vec3 yiq2rgb( vec3 yiq )
|
||||
{
|
||||
return mat3x3( 1.000f, 1.000f, 1.000f, 0.956f, -0.272f, -1.106f, 0.621f, -0.647f, 1.703f ) * yiq;
|
||||
}
|
||||
|
||||
float v2Random( vec2 v )
|
||||
{
|
||||
vec2 vf = fract( v * 256.0f );
|
||||
vec2 vi = floor( v * 256.0f ) / 256.0f;
|
||||
vec2 d = vec2( 0.0f, 1.0f / 256.0f );
|
||||
|
||||
return mix(
|
||||
mix( fs2( vi + d.xx ), fs2( vi + d.yx ), vf.x ),
|
||||
mix( fs2( vi + d.xy ), fs2( vi + d.yy ), vf.x ),
|
||||
vf.y
|
||||
);
|
||||
}
|
||||
|
||||
half3 vhsTex2D( vec2 uv ) {
|
||||
if ( validuv( uv ) ) {
|
||||
half3 yiq = half3( 0.0f, 0.0f, 0.0f );
|
||||
for ( int i = 0; i < SAMPLES; i ++ ) {
|
||||
vec2 uvt = uv - vec2( float( i ), 0.0f ) / iResolution;
|
||||
if ( validuv( uvt ) ) {
|
||||
half4 tex = texture(iChannel0, uvt );
|
||||
yiq += (
|
||||
rgb2yiq( mix( iBackground.rgb, tex.rgb, tex.a ) ) *
|
||||
vec2( float( i ), float( SAMPLES - 1 - i ) ).yxx / float( SAMPLES - 1 )
|
||||
) / float( SAMPLES ) * 2.0f;
|
||||
}
|
||||
}
|
||||
return yiq2rgb( yiq );
|
||||
}
|
||||
return half3( 0.1f, 0.1f, 0.1f );
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
|
||||
vec2 uv = fragCoord.xy / iResolution.xy;
|
||||
|
||||
vec2 uvt = yflip( uv );
|
||||
vec3 col = vec3( 0.0f, 0.0f, 0.0f );
|
||||
|
||||
// tape wave
|
||||
uvt.x += ( v2Random( vec2( uvt.y / 10.0f, iTime / 10.0f ) / 1.0f ) - 0.5f ) / iResolution.x * 1.0f;
|
||||
uvt.x += ( v2Random( vec2( uvt.y, iTime * 10.0f ) ) - 0.5f ) / iResolution.x * 1.0f;
|
||||
|
||||
// tape crease
|
||||
float tcPhase = smoothstep( 0.9f, 0.96f, sin( uvt.y * 8.0f - ( iTime + 0.14f * v2Random( iTime * vec2( 0.67f, 0.59f ) ) ) * PI * 1.2f ) );
|
||||
float tcNoise = smoothstep( 0.3f, 1.0f, v2Random( vec2( uvt.y * 4.77f, iTime ) ) );
|
||||
float tc = tcPhase * tcNoise;
|
||||
uvt.x = uvt.x - tc / iResolution.x * 8.0f;
|
||||
|
||||
// switching noise
|
||||
float snPhase = smoothstep( 6.0f / iResolution.y, 0.0f, uvt.y );
|
||||
uvt.y += snPhase * 0.3f;
|
||||
uvt.x += snPhase * ( ( v2Random( vec2( uv.y * 100.0f, iTime * 10.0f ) ) - 0.5f ) / iResolution.x * 24.0f );
|
||||
|
||||
// fetch
|
||||
half4 tex = texture(iChannel0, uv);
|
||||
half3 color = vhsTex2D( yflip( uvt ) );
|
||||
color = pow( color, vec3(0.4545f) );
|
||||
|
||||
// crease noise
|
||||
float cn = tcNoise * ( 0.3f + 0.7f * tcPhase );
|
||||
if ( 0.29f < cn ) {
|
||||
vec2 uvtt = ( uvt + vec2( 1.0f, 0.0f ) * v2Random( vec2( uvt.y, iTime ) ) ) * vec2( 0.1f, 1.0f );
|
||||
float n0 = v2Random( uvtt );
|
||||
float n1 = v2Random( uvtt + vec2( 1.0f, 0.0f ) / iResolution.x );
|
||||
if ( n1 < n0 ) {
|
||||
color = mix( color, vec3( 2.0f, 2.0f, 2.0f ), pow( n0, 10.0f ) );
|
||||
}
|
||||
}
|
||||
|
||||
// ac beat
|
||||
color *= 1.0f + 0.1f * smoothstep( 0.4f, 0.6f, v2Random( vec2( 0.0f, 0.1f * ( uv.y + iTime * 0.2f ) ) / 10.0f ) );
|
||||
|
||||
// color noise
|
||||
half2 noiseuv = uvt + vec2( fs( iTime ), fs( iTime / 0.7f ) );
|
||||
half3 noise = half3(
|
||||
v2Random( noiseuv ),
|
||||
v2Random( noiseuv + 0.7f ),
|
||||
v2Random( noiseuv + 1.4f )
|
||||
);
|
||||
color = saturate( color );
|
||||
|
||||
// yiq
|
||||
color = rgb2yiq( color );
|
||||
color += COLOR_NOISE_AMP * ( noise - 0.5f );
|
||||
color = YIQ_OFFSET + YIQ_AMP * color;
|
||||
color = yiq2rgb( color );
|
||||
color = pow( color, vec3(2.2f) );
|
||||
|
||||
fragColor = half4( color, tex.a );
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
[Header]
|
||||
ICOfile = "Tokyo_BigSight_thumb.jpg"
|
||||
PREVIEWfile = "Tokyo_BigSight_preview.jpg"
|
||||
Name = "Tokyo BigSight"
|
||||
Author = "Blochi"
|
||||
Location = "Tokyo"
|
||||
Comment = "Conference center main entrance at night, big patterns on floor and ceiling"
|
||||
GEOlat = 35.6174260000000020
|
||||
GEOlong = 139.7786560000000100
|
||||
Link = "http://www.hdrlabs.com/sibl/archive.html"
|
||||
Date = "2009:12:165"
|
||||
Time = "20:00:00"
|
||||
Height = 1.600000
|
||||
|
||||
[Background]
|
||||
BGfile = "Tokyo_BigSight_8k.jpg"
|
||||
BGmap = 1
|
||||
BGu = 0.000000
|
||||
BGv = 0.000000
|
||||
BGheight = 4096
|
||||
|
||||
[Enviroment]
|
||||
EVfile = "Tokyo_BigSight_Env.hdr"
|
||||
EVmap = 1
|
||||
EVu = 0.000000
|
||||
EVv = 0.000000
|
||||
EVheight = 180
|
||||
EVmulti = 1.000000
|
||||
EVgamma = 1.800000
|
||||
|
||||
[Reflection]
|
||||
REFfile = "Tokyo_BigSight_3k.hdr"
|
||||
REFmap = 1
|
||||
REFu = 0.000000
|
||||
REFv = 0.000000
|
||||
REFheight = 1600
|
||||
REFmulti = 1.000000
|
||||
REFgamma = 1.800000
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
The listed files are the original work of the following authors, graciously made available under the terms of their respective licenses. Note that in some cases these files have been reduced in size or quality to save space. I strongly encourage interested parties to view the full quality files in their original locations.
|
||||
|
||||
Author: Blochi
|
||||
Source: http://www.hdrlabs.com/sibl/archive.html
|
||||
License: Creative Commons Attribution-Noncommercial-Share Alike 3.0 License
|
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 59 KiB |
After Width: | Height: | Size: 135 KiB |
|
@ -0,0 +1,12 @@
|
|||
------------------------------------------------------
|
||||
LowPoly Models by @Quaternius
|
||||
Consider supporting me on Patreon, even $1 helps me a lot!
|
||||
|
||||
https://www.patreon.com/quaternius
|
||||
-------------------------------------------------------
|
||||
|
||||
License:
|
||||
CC0 1.0 Universal (CC0 1.0)
|
||||
Public Domain Dedication
|
||||
https://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
------------------------------------------------------
|
||||
LowPoly Models by @Quaternius
|
||||
Consider supporting me on Patreon, even $1 helps me a lot!
|
||||
|
||||
https://www.patreon.com/quaternius
|
||||
-------------------------------------------------------
|
||||
|
||||
License:
|
||||
CC0 1.0 Universal (CC0 1.0)
|
||||
Public Domain Dedication
|
||||
https://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
After Width: | Height: | Size: 2.2 MiB |
|
@ -0,0 +1,9 @@
|
|||
# Halloween Little Witch
|
||||
|
||||
## Source
|
||||
|
||||
[https://sketchfab.com/models/ccc023590bfb4789af9322864e42d1ab](https://sketchfab.com/models/ccc023590bfb4789af9322864e42d1ab)
|
||||
|
||||
## License
|
||||
|
||||
[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/)
|
After Width: | Height: | Size: 457 KiB |
After Width: | Height: | Size: 342 KiB |
After Width: | Height: | Size: 545 KiB |
|
@ -0,0 +1,204 @@
|
|||
{
|
||||
"accessors" : [
|
||||
{
|
||||
"bufferView" : 0,
|
||||
"componentType" : 5123,
|
||||
"count" : 46356,
|
||||
"max" : [
|
||||
14555
|
||||
],
|
||||
"min" : [
|
||||
0
|
||||
],
|
||||
"type" : "SCALAR"
|
||||
},
|
||||
{
|
||||
"bufferView" : 1,
|
||||
"componentType" : 5126,
|
||||
"count" : 14556,
|
||||
"max" : [
|
||||
0.9424954056739807,
|
||||
0.8128451108932495,
|
||||
0.900973916053772
|
||||
],
|
||||
"min" : [
|
||||
-0.9474585652351379,
|
||||
-1.18715500831604,
|
||||
-0.9009949564933777
|
||||
],
|
||||
"type" : "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView" : 2,
|
||||
"componentType" : 5126,
|
||||
"count" : 14556,
|
||||
"max" : [
|
||||
1.0,
|
||||
1.0,
|
||||
1.0
|
||||
],
|
||||
"min" : [
|
||||
-1.0,
|
||||
-1.0,
|
||||
-1.0
|
||||
],
|
||||
"type" : "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView" : 3,
|
||||
"componentType" : 5126,
|
||||
"count" : 14556,
|
||||
"max" : [
|
||||
0.9999759793281555,
|
||||
1.998665988445282
|
||||
],
|
||||
"min" : [
|
||||
0.002448640065267682,
|
||||
1.0005531199858524
|
||||
],
|
||||
"type" : "VEC2"
|
||||
}
|
||||
],
|
||||
"asset" : {
|
||||
"generator" : "Khronos Blender glTF 2.0 exporter",
|
||||
"version" : "2.0"
|
||||
},
|
||||
"bufferViews" : [
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteLength" : 92712,
|
||||
"byteOffset" : 0,
|
||||
"target" : 34963
|
||||
},
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteLength" : 174672,
|
||||
"byteOffset" : 92712,
|
||||
"target" : 34962
|
||||
},
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteLength" : 174672,
|
||||
"byteOffset" : 267384,
|
||||
"target" : 34962
|
||||
},
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteLength" : 116448,
|
||||
"byteOffset" : 442056,
|
||||
"target" : 34962
|
||||
}
|
||||
],
|
||||
"buffers" : [
|
||||
{
|
||||
"byteLength" : 558504,
|
||||
"uri" : "DamagedHelmet.bin"
|
||||
}
|
||||
],
|
||||
"images" : [
|
||||
{
|
||||
"uri" : "Default_albedo.jpg"
|
||||
},
|
||||
{
|
||||
"uri" : "Default_metalRoughness.jpg"
|
||||
},
|
||||
{
|
||||
"uri" : "Default_emissive.jpg"
|
||||
},
|
||||
{
|
||||
"uri" : "Default_AO.jpg"
|
||||
},
|
||||
{
|
||||
"uri" : "Default_normal.jpg"
|
||||
}
|
||||
],
|
||||
"materials" : [
|
||||
{
|
||||
"emissiveFactor" : [
|
||||
1.0,
|
||||
1.0,
|
||||
1.0
|
||||
],
|
||||
"emissiveTexture" : {
|
||||
"index" : 2
|
||||
},
|
||||
"name" : "Material_MR",
|
||||
"normalTexture" : {
|
||||
"index" : 4
|
||||
},
|
||||
"occlusionTexture" : {
|
||||
"index" : 3
|
||||
},
|
||||
"pbrMetallicRoughness" : {
|
||||
"baseColorTexture" : {
|
||||
"index" : 0
|
||||
},
|
||||
"metallicRoughnessTexture" : {
|
||||
"index" : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"meshes" : [
|
||||
{
|
||||
"name" : "mesh_helmet_LP_13930damagedHelmet",
|
||||
"primitives" : [
|
||||
{
|
||||
"attributes" : {
|
||||
"NORMAL" : 2,
|
||||
"POSITION" : 1,
|
||||
"TEXCOORD_0" : 3
|
||||
},
|
||||
"indices" : 0,
|
||||
"material" : 0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes" : [
|
||||
{
|
||||
"mesh" : 0,
|
||||
"name" : "node_damagedHelmet_-6514",
|
||||
"rotation" : [
|
||||
0.7071068286895752,
|
||||
0.0,
|
||||
-0.0,
|
||||
0.7071068286895752
|
||||
]
|
||||
}
|
||||
],
|
||||
"samplers" : [
|
||||
{}
|
||||
],
|
||||
"scene" : 0,
|
||||
"scenes" : [
|
||||
{
|
||||
"name" : "Scene",
|
||||
"nodes" : [
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures" : [
|
||||
{
|
||||
"sampler" : 0,
|
||||
"source" : 0
|
||||
},
|
||||
{
|
||||
"sampler" : 0,
|
||||
"source" : 1
|
||||
},
|
||||
{
|
||||
"sampler" : 0,
|
||||
"source" : 2
|
||||
},
|
||||
{
|
||||
"sampler" : 0,
|
||||
"source" : 3
|
||||
},
|
||||
{
|
||||
"sampler" : 0,
|
||||
"source" : 4
|
||||
}
|
||||
]
|
||||
}
|
After Width: | Height: | Size: 353 KiB |
After Width: | Height: | Size: 914 KiB |
After Width: | Height: | Size: 95 KiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 506 KiB |
|
@ -0,0 +1,15 @@
|
|||
# Damaged Helmet
|
||||
|
||||
## Screenshot
|
||||
|
||||
![screenshot](screenshot/screenshot.png)
|
||||
|
||||
## License Information
|
||||
|
||||
Battle Damaged Sci-fi Helmet - PBR by [theblueturtle_](https://sketchfab.com/theblueturtle_), published under a Creative Commons Attribution-NonCommercial license
|
||||
|
||||
https://sketchfab.com/models/b81008d513954189a063ff901f7abfe4
|
||||
|
||||
## Modifications
|
||||
|
||||
The original model was built on an early draft of glTF 2.0 that did not become final. This new model has been imported and re-exported from Blender to bring it into alignment with the final release glTF 2.0 specification.
|
|
@ -0,0 +1,5 @@
|
|||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
vec2 uv = fragCoord.xy / iResolution.xy;
|
||||
fragColor = vec4(uv,0.5+0.5*sin(iGlobalTime),1.0);
|
||||
}
|
|
@ -0,0 +1,436 @@
|
|||
// Wolfenstein. Created by Reinder Nijhoff 2013
|
||||
// @reindernijhoff
|
||||
//
|
||||
// https://www.shadertoy.com/view/4sfGWX
|
||||
//
|
||||
|
||||
#define NUM_MATERIALS 3
|
||||
#define NUM_OBJECTS 1
|
||||
#define SECONDS_IN_ROOM 3.
|
||||
#define ROOM_SIZE 10.
|
||||
#define MAXSTEPS 17
|
||||
#define MATERIAL_DOOR 200
|
||||
#define MATERIAL_DOORWAY 201
|
||||
|
||||
#define COL(r,g,b) vec3(r/255.,g/255.,b/255.)
|
||||
|
||||
#define time (iGlobalTime+40.)
|
||||
vec3 rdcenter;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Math functions
|
||||
|
||||
float hash( const float n ) {
|
||||
return fract(sin(n*14.1234512)*51231.545341231);
|
||||
}
|
||||
float hash( const vec2 x ) {
|
||||
float n = dot( x, vec2(14.1432,1131.15532) );
|
||||
return fract(sin(n)*51231.545341231);
|
||||
}
|
||||
float crossp( const vec2 a, const vec2 b ) { return a.x*b.y - a.y*b.x; }
|
||||
vec3 rotate(vec3 r, float v){ return vec3(r.x*cos(v)+r.z*sin(v),r.y,r.z*cos(v)-r.x*sin(v));}
|
||||
bool intersectSegment(const vec3 ro, const vec3 rd, const vec2 a, const vec2 b, out float dist, out float u) {
|
||||
vec2 p = ro.xz; vec2 r = rd.xz;
|
||||
vec2 q = a-p; vec2 s = b-a;
|
||||
float rCrossS = crossp(r, s);
|
||||
|
||||
if( rCrossS == 0.){
|
||||
return false;
|
||||
}
|
||||
dist = crossp(q, s) / rCrossS;
|
||||
u = crossp(q, r) / rCrossS;
|
||||
|
||||
if(0. <= dist && 0. <= u && u <= 1.){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Material helper functions
|
||||
|
||||
float onCircle( const vec2 c, const vec2 centre, const float radius ) {
|
||||
return clamp( 4.*(radius - distance(c,centre)), 0., 1. );
|
||||
}
|
||||
float onCircleLine( const vec2 c, const vec2 centre, const float radius ) {
|
||||
return clamp( 1.-1.5*abs(radius - distance(c,centre)), 0., 1. );
|
||||
}
|
||||
float onLine( const float c, const float b ) {
|
||||
return clamp( 1.-abs(b-c), 0., 1. );
|
||||
}
|
||||
float onBand( const float c, const float mi, const float ma ) {
|
||||
return clamp( (ma-c+1.), 0., 1. )*clamp( (c-mi+1.), 0., 1. );
|
||||
}
|
||||
float onLineSegmentX( const vec2 c, const float b, const float mi, const float ma ) {
|
||||
return onLine( c.x, b )*onBand( c.y, mi, ma );
|
||||
}
|
||||
float onLineSegmentY( const vec2 c, const float b, const float mi, const float ma ) {
|
||||
return onLine( c.y, b )*onBand( c.x, mi, ma );
|
||||
}
|
||||
float onRect( const vec2 c, const vec2 lt, const vec2 rb ) {
|
||||
return onBand( c.x, lt.x, rb.x )*onBand( c.y, lt.y, rb.y );
|
||||
}
|
||||
vec3 addBevel( const vec2 c, const vec2 lt, const vec2 rb, const float size, const float strength, const float lil, const float lit, const vec3 col ) {
|
||||
float xl = clamp( (c.x-lt.x)/size, 0., 1. );
|
||||
float xr = clamp( (rb.x-c.x)/size, 0., 1. );
|
||||
float yt = clamp( (c.y-lt.y)/size, 0., 1. );
|
||||
float yb = clamp( (rb.y-c.y)/size, 0., 1. );
|
||||
|
||||
return mix( col, col*clamp(1.0+strength*(lil*(xl-xr)+lit*(yb-yt)), 0., 2.), onRect( c, lt, rb ) );
|
||||
}
|
||||
vec3 addKnob( const vec2 c, const vec2 centre, const float radius, const float strength, const vec3 col ) {
|
||||
vec2 lv = normalize( centre-c );
|
||||
return mix( col, col*(1.0+strength*dot(lv,vec2(-0.7071,0.7071))), onCircle(c, centre, radius ) );
|
||||
}
|
||||
float stepeq( float a, float b ) {
|
||||
return step( a, b )*step( b, a );
|
||||
}
|
||||
//----------------------------------------------------------------------
|
||||
// Generate materials!
|
||||
|
||||
void getMaterialColor( const int material, in vec2 uv, const float decorationHash, out vec3 col ) {
|
||||
vec3 fgcol;
|
||||
|
||||
uv = floor( mod(uv+64., vec2(64.)) );
|
||||
vec2 uvs = uv / 64.;
|
||||
|
||||
// basecolor
|
||||
vec3 basecol = vec3( mix(55./255.,84./255.,uvs.y ) );
|
||||
float br = hash(uv);
|
||||
col = basecol;
|
||||
// grey bricks
|
||||
if( material == 0 || material == 1 ) {
|
||||
vec2 buv = vec2( mod(uv.x+1. + (floor((uv.y+1.) / 16.) * 16.), 32.) , mod( uv.y+1., 16.) );
|
||||
float bbr = mix( 190./255., 91./255., (buv.y)/14. ) + 0.05*br;
|
||||
if ( buv.x < 2. || buv.y < 2.) {
|
||||
bbr = 72./255.;
|
||||
}
|
||||
col = vec3(bbr*0.95);
|
||||
col = addBevel( buv, vec2(1.,1.), vec2( 31.5, 15.), 2., 0.35, 1., 1., col);
|
||||
// blue wall
|
||||
if( material == 1 ) {
|
||||
col *= 1.3*COL(11.,50.,209.);
|
||||
col = mix( col, COL(2.,15.,86.), onBand(uv.y,14.,49.));
|
||||
col = mix( col, COL(9.,44.,185.)*(0.9+0.1*br), onBand(uv.y,16.,47.));
|
||||
col = mix( col, COL(3.,25.,122.), onBand(uv.y,21.,42.));
|
||||
col = addBevel( uv, vec2(-1.,16.), vec2( 65., 21.), 1., 0.35, 1., 1., col);
|
||||
col = addBevel( uv, vec2(-1.,43.), vec2( 65., 48.), 1., 0.35, 1., 1., col);
|
||||
|
||||
col = mix( col, COL(2.,11.,74.), onRect(uv, vec2(22.,22.), vec2(42.,42.)));
|
||||
col = mix( col, COL(9.,44.,185.)*(0.95+0.1*br), onRect(uv, vec2(22.,23.), vec2(42.,40.)));
|
||||
col = addBevel( uv, vec2(22.,23.), vec2(42.,40.), 1., 0.2, -1., 1., col);
|
||||
col = mix( col, mix(COL(2.,11.,74.), COL(3.,25.,122.), (uv.x-26.)/3.), onRect(uv, vec2(26.,23.), vec2(29.,29.)));
|
||||
col = mix( col, mix(COL(2.,11.,74.), COL(3.,25.,122.), (uv.y-34.)/2.), onRect(uv, vec2(22.,34.), vec2(29.,36.)));
|
||||
col = mix( col, mix(COL(2.,11.,74.), COL(3.,25.,122.), (uv.y-27.)/2.), onRect(uv, vec2(35.,27.), vec2(42.,29.)));
|
||||
col = mix( col, mix(COL(2.,11.,74.), COL(3.,25.,122.), (uv.y-34.)/8.), onRect(uv, vec2(35.,34.), vec2(38.,42.)));
|
||||
}
|
||||
}
|
||||
// wooden wall
|
||||
else if( material == 2 ) {
|
||||
float mx = mod( uv.x, 64./5. );
|
||||
float h1 = hash( floor(uv.x/(64./5.)) );
|
||||
float h2 = hash( 1.+1431.16*floor(uv.x/(64./5.)) );
|
||||
col = mix( COL(115.,75.,43.),COL( 71.,56.,26.), smoothstep( 0.2, 1., (0.7+h2)*abs(mod( h2-uv.y*(0.05+0.1*h2)+(1.+h1+h2)*sin(mx*(0.1+0.2*h2)), 2. )-1.) ) );
|
||||
|
||||
col = mix( col, mix(COL(40.,31.,13.), COL(142.,91.,56.), (uv.x)/2.), step(uv.x,2.) );
|
||||
col = mix( col, mix(COL(40.,31.,13.), COL(142.,91.,56.), (uv.x-10.)/2.), step(10.,uv.x)*step(uv.x,12.) );
|
||||
col = mix( col, mix(COL(40.,31.,13.), COL(142.,91.,56.), (uv.x-26.)/2.), step(26.,uv.x)*step(uv.x,28.) );
|
||||
col = mix( col, mix(COL(40.,31.,13.), COL(142.,91.,56.), (uv.x-40.)/2.), step(40.,uv.x)*step(uv.x,42.) );
|
||||
col = mix( col, mix(COL(40.,31.,13.), COL(142.,91.,56.), (uv.x-54.)/2.), step(54.,uv.x)*step(uv.x,56.) );
|
||||
|
||||
col = mix( col, mix(COL(83.,60.,31.), COL(142.,91.,56.), (uv.x- 8.)), step( 8.,uv.x)*step(uv.x,9.) );
|
||||
col = mix( col, mix(COL(83.,60.,31.), COL(142.,91.,56.), (uv.x-24.)), step(24.,uv.x)*step(uv.x,25.) );
|
||||
col = mix( col, mix(COL(83.,60.,31.), COL(142.,91.,56.), (uv.x-38.)), step(38.,uv.x)*step(uv.x,39.) );
|
||||
col = mix( col, mix(COL(83.,60.,31.), COL(142.,91.,56.), (uv.x-52.)), step(52.,uv.x)*step(uv.x,53.) );
|
||||
col = mix( col, mix(COL(83.,60.,31.), COL(142.,91.,56.), (uv.x-62.)), step(62.,uv.x) );
|
||||
|
||||
col = mix( col, mix(COL(40.,31.,13.), COL(142.,91.,56.), (uv.y)/2.), step(uv.y,2.) );
|
||||
col *= 1.-0.3*stepeq(uv.y,3.);
|
||||
}
|
||||
// door
|
||||
else if( material == MATERIAL_DOOR ) {
|
||||
fgcol = COL(44., 176., 175.)*(0.95+0.15*sin(-0.25+ 4.*((-0.9-uvs.y)/(1.3-0.8*uvs.x)) ) );
|
||||
fgcol = addBevel( uv, vec2(-1.,1.), vec2(62.,66.), 2., 0.4, -1., -1., fgcol);
|
||||
fgcol = addBevel( uv, vec2( 6.,6.), vec2(57.,57.), 2.25, 0.5, -1., -1., fgcol);
|
||||
fgcol = mix( addKnob( mod( uv, vec2(8.) ), vec2(3.5), 1.65, 0.5, fgcol ), fgcol, onRect( uv, vec2( 6.,6.), vec2(57.,57.)) ) ;
|
||||
|
||||
//knob
|
||||
fgcol *= 1.-0.2*onRect( uv, vec2( 13.5, 28.5 ), vec2( 22.5, 44.5 ) );
|
||||
fgcol = mix( fgcol, mix( COL(44.,44.,44.),COL(152.,152.,152.), ((uv.x+(43.-uv.y)-15.)/25. ) ), onRect( uv, vec2( 15., 27. ), vec2( 24., 43. ) ) );
|
||||
fgcol = addBevel( uv, vec2( 15., 27. ), vec2( 24., 43. ), 1., 0.45, 1., 1., fgcol);
|
||||
fgcol = mix( fgcol, addKnob( mod( uv, vec2(6.) ), vec2(4.25,5.5), 1.15, 0.75, fgcol ), onRect( uv, vec2( 15., 27. ), vec2( 24., 43. ) ) ) ;
|
||||
|
||||
fgcol *= 1.-0.5*onRect( uv, vec2( 16.5, 33.5 ), vec2( 20.5, 38.5 ) );
|
||||
fgcol = mix( fgcol, mix( COL(88.,84.,11.),COL(251.,242.,53.), ((uv.x+(37.-uv.y)-18.)/7. ) ), onRect( uv, vec2( 18., 33. ), vec2( 21., 37. ) ) );
|
||||
fgcol = mix( fgcol, COL(0.,0.,0.), onRect( uv, vec2( 19., 34. ), vec2( 20., 35.7 ) ) );
|
||||
|
||||
fgcol *= 1.-0.2*onRect( uv, vec2( 6.5, 29.5 ), vec2( 10.5, 41.5 ) );
|
||||
fgcol = mix( fgcol, mix( COL(88.,84.,11.),COL(251.,242.,53.), ((uv.x+(40.-uv.y)-9.)/13. ) ), onRect( uv, vec2( 9., 29. ), vec2( 11., 40. ) ) );
|
||||
fgcol = addBevel( uv, vec2( 9., 29. ), vec2( 11., 40. ), 0.75, 0.5, 1., 1., fgcol);
|
||||
|
||||
col = mix( basecol, fgcol, onRect( uv, vec2(1.,1.), vec2(62.,62.) ) );
|
||||
}
|
||||
// doorway
|
||||
else if( material == MATERIAL_DOORWAY ) {
|
||||
fgcol = COL(44., 176., 175.)*(0.95+0.15*sin(-0.25+ 4.*((-0.9-uvs.y)/(1.3-0.8*uvs.x)) ) );
|
||||
vec2 uvhx = vec2( 32.-abs(uv.x-32.), uv.y );
|
||||
fgcol = addBevel( uvhx, vec2(-1.,1.), vec2(28.,66.), 2., 0.4, -1., -1., fgcol);
|
||||
fgcol = addBevel( uvhx, vec2( 6.,6.), vec2(23.,57.), 2.25, 0.5, -1., -1., fgcol);
|
||||
fgcol = mix( addKnob( vec2( mod( uvhx.x, 22. ), mod( uvhx.y, 28. )), vec2(3.5), 1.65, 0.5, fgcol ), fgcol, onRect( uvhx, vec2( 6.,6.), vec2(24.,57.)) ) ;
|
||||
fgcol = mix( fgcol, vec3(0.), onRect( uv, vec2( 29., 1.), vec2( 35., 63.) ) );
|
||||
col = mix( basecol, fgcol, onRect( uv, vec2(1.,1.), vec2(62.,62.) ) );
|
||||
}
|
||||
|
||||
// prison door
|
||||
if( decorationHash > 0.93 && material < (NUM_MATERIALS+1) ) {
|
||||
vec4 prisoncoords = vec4(12.,14.,52.,62.);
|
||||
// shadow
|
||||
col *= 1.-0.5*onRect( uv, vec2( 11., 13. ), vec2( 53., 63. ) );
|
||||
// hinge
|
||||
col = mix( col, COL(72.,72.,72.), stepeq(uv.x, 53.)*step( mod(uv.y+2.,25.), 5.)*step(13.,uv.y) );
|
||||
col = mix( col, COL(100.,100.,100.), stepeq(uv.x, 53.)*step( mod(uv.y+1.,25.), 3.)*step(13.,uv.y) );
|
||||
|
||||
vec3 pcol = vec3(0.)+COL(100.,100.,100.)*step( mod(uv.x-4., 7.), 0. );
|
||||
pcol += COL(55.,55.,55.)*step( mod(uv.x-5., 7.), 0. );
|
||||
pcol = addBevel(uv, vec2(0.,17.), vec2(63.,70.), 3., 0.8, 0., -1., pcol);
|
||||
pcol = addBevel(uv, vec2(0.,45.), vec2(22.,70.), 3., 0.8, 0., -1., pcol);
|
||||
|
||||
fgcol = COL(72.,72.,72.);
|
||||
fgcol = addBevel(uv, prisoncoords.xy, prisoncoords.zw+vec2(1.,1.), 1., 0.5, -1., 1., fgcol );
|
||||
fgcol = addBevel(uv, prisoncoords.xy+vec2(3.,3.), prisoncoords.zw-vec2(2.,1.), 1., 0.5, 1., -1., fgcol );
|
||||
fgcol = mix( fgcol, pcol, onRect( uv, prisoncoords.xy+vec2(3.,3.), prisoncoords.zw-vec2(3.,2.) ) );
|
||||
fgcol = mix( fgcol, COL(72.,72.,72.), onRect( uv, vec2(15.,32.5), vec2(21.,44.) ) );
|
||||
|
||||
fgcol = mix( fgcol, mix( COL(0.,0.,0.), COL(43.,43.,43.), (uv.y-37.) ), stepeq(uv.x, 15.)*step(37.,uv.y)*step(uv.y,38.) );
|
||||
fgcol = mix( fgcol, mix( COL(0.,0.,0.), COL(43.,43.,43.), (uv.y-37.)/3. ), stepeq(uv.x, 17.)*step(37.,uv.y)*step(uv.y,40.) );
|
||||
fgcol = mix( fgcol, COL(43.,43.,43.), stepeq(uv.x, 18.)*step(37.,uv.y)*step(uv.y,41.) );
|
||||
fgcol = mix( fgcol, mix( COL(0.,0.,0.), COL(100.,100.,100.), (uv.y-37.)/3. ), stepeq(uv.x, 18.)*step(36.,uv.y)*step(uv.y,40.) );
|
||||
fgcol = mix( fgcol, COL(43.,43.,43.), stepeq(uv.x, 19.)*step(37.,uv.y)*step(uv.y,40.) );
|
||||
|
||||
fgcol = mix( fgcol, mix( COL(84.,84.,84.), COL(108.,108.,108.), (uv.x-15.)/2. ), stepeq(uv.y, 32.)*step(15.,uv.x)*step(uv.x,17.) );
|
||||
fgcol = mix( fgcol, COL(81.,81.,81.), stepeq(uv.y, 32.)*step(20.,uv.x)*step(uv.x,21.) );
|
||||
|
||||
col = mix( col, fgcol, onRect( uv, prisoncoords.xy, prisoncoords.zw ) );
|
||||
}
|
||||
// flag
|
||||
else if( decorationHash > 0.63 && material < (NUM_MATERIALS+1) ) {
|
||||
vec2 uvc = uv-vec2(32.,30.);
|
||||
|
||||
// shadow
|
||||
vec4 shadowcoords = vec4( 14., 7.,
|
||||
54., max( 56. + sin( uv.x*0.32-1. ),56.) );
|
||||
col *= 1.-0.3*onRect( uv, vec2( 6., 6. ), vec2( 61., 7. ) );
|
||||
col *= 1.-0.3*clamp( 0.25*(56.-uv.x), 0., 1.)*onRect( uv, shadowcoords.xy, shadowcoords.zw );
|
||||
|
||||
// rod
|
||||
col = mix( col, COL(250.,167.,98.), onLineSegmentX( vec2( abs(uv.x-32.), uv.y ), 26., 4., 6.5 ) );
|
||||
col = mix( col, COL(251.,242.,53.), onLineSegmentY( uv, 5., 4., 60. ) );
|
||||
col = mix( col, COL(155.,76.,17.), onLineSegmentY( uv, 6., 4., 60. ) );
|
||||
col = mix( col, COL(202.,96.,25.), onLineSegmentY( vec2( abs(uv.x-32.), uv.y ), 6., 26., 28. ) );
|
||||
col = mix( col, COL(251.,242.,53.), onLineSegmentX( vec2( abs(uv.x-32.), uv.y ), 25., 3., 7. ) );
|
||||
col = mix( col, COL(252.,252.,217.), onLineSegmentX( vec2( abs(uv.x-32.), uv.y ), 25., 4.3, 5.5 ) );
|
||||
col = mix( col, COL(252.,252.,217.), onLineSegmentX( vec2( abs(uv.x-32.), uv.y ), 26., 5.3, 5.5 ) );
|
||||
col = mix( col, COL(0.,0.,0.), onLineSegmentY( vec2( abs(uv.x-32.), uv.y ), 6., 18.3, 19.5 ) );
|
||||
|
||||
// flag
|
||||
vec4 flagcoords = vec4( 13., min( 9.5 - pow(5.5* (uvs.x-0.5), 2.), 9. ),
|
||||
51., max( 55. + sin( uv.x*0.4+2.7 ),55.) );
|
||||
|
||||
fgcol = COL(249.,41.,27.);
|
||||
|
||||
fgcol = mix( fgcol, COL(255.,255.,255.), onBand( min(abs(uvc.x), abs(uvc.y)), 2., 4. ) );
|
||||
fgcol = mix( fgcol, COL(72.,72.,72.), onLine( min(abs(uvc.x), abs(uvc.y)), 3. ) );
|
||||
|
||||
fgcol = mix( fgcol, COL(255.,255.,255.), onCircle( uv, vec2(32.,30.), 12.5 ) );
|
||||
fgcol = mix( fgcol, COL(0.,0.,0.), onCircleLine( uv, vec2(32.,30.), 11. ) );
|
||||
fgcol = mix( fgcol, COL(0.,0.,0.), onCircleLine( uv, vec2(32.,30.), 9. ) );
|
||||
|
||||
vec2 uvr = vec2( (uvc.x-uvc.y)*0.7071, (uvc.y+uvc.x)*0.7071)*sign( uvc.x+0.5 );
|
||||
fgcol = mix( fgcol, COL(72.,72.,72.), onRect( uvr, vec2(-1.,-1.), vec2(1.,4.) ) );
|
||||
fgcol = mix( fgcol, COL(72.,72.,72.), onRect( uvr, vec2(-4.2, 4.2), vec2(1.,6.15) ) );
|
||||
fgcol = mix( fgcol, COL(72.,72.,72.), onRect( uvr, vec2(-1.,-1.), vec2(4.,1.) ) );
|
||||
fgcol = mix( fgcol, COL(72.,72.,72.), onRect( uvr, vec2( 4.2,-1.), vec2(6.15,4.2) ) );
|
||||
|
||||
fgcol *= (0.8+0.2*sin( uv.x*0.4+2.7 ));
|
||||
fgcol *= (0.8+0.2*clamp( 0.5*(uv.y-7.), 0., 1.));
|
||||
|
||||
// mix flag on background
|
||||
col = mix( col, fgcol, onRect( uv, flagcoords.xy, flagcoords.zw ) );
|
||||
}
|
||||
|
||||
// fake 8-bit color palette and dithering
|
||||
col = floor( (col+0.5*mod(uv.x+uv.y,2.)/32.)*32.)/32.;
|
||||
}
|
||||
bool getObjectColor( const int object, in vec2 uv, inout vec3 icol ) {
|
||||
uv = floor( mod(uv, vec2(64.)) );
|
||||
vec2 uvs = uv / 64.;
|
||||
vec3 col = vec3(20./255.);
|
||||
float d;
|
||||
|
||||
// only a lamp for now
|
||||
|
||||
// lamp top
|
||||
d = distance( uv*vec2(1.,2.), vec2(28.1, 5.8)*vec2(1.,2.) );
|
||||
col = mix( col, mix( COL(41.,250.,46.), COL(13.,99.,12.), clamp( d/8.-0.2, 0., 1.) ),
|
||||
onCircle(uv, vec2(31.,13.6), 11.7 )*step( uv.y, 6. ));
|
||||
col = mix( col, COL(9.,75.,6.), onCircleLine( uv, vec2(31.,14.), 11.6 ) *
|
||||
step( length(uv-vec2(31.,13.6)), 11.7 )*step( uv.y, 6. ) );
|
||||
col = mix( col, COL(100.,100.,100.), onLine( abs(uv.x-31.), 1. )*step( uv.y, 1. ) );
|
||||
col = mix( col, COL(140.,140.,140.), onLine( abs(uv.x-31.), 0.25 )*step( uv.y, 1. )*step( 1., uv.y ) );
|
||||
|
||||
// lamp bottom
|
||||
d = distance( uv*vec2(1.,2.), vec2(30.5, 6.5)*vec2(1.,2.) );
|
||||
col = mix( col, mix( COL(41.,250.,46.), COL(13.,99.,12.), clamp( abs(uv.x-31.)/4.-1.25, 0., 1. )), step( abs(uv.x-31.), 9. )*stepeq( uv.y, 7.) );
|
||||
col = mix( col, mix( COL(41.,250.,46.), COL(16.,123.,17.), clamp( abs(uv.x-31.)/4.-1.25, 0., 1. )), step( abs(uv.x-31.), 9. )*stepeq( uv.y, 8.) );
|
||||
col = mix( col, mix( COL(133.,250.,130.), COL(22.,150.,23.), clamp( abs(uv.x-31.)/4.-0.75, 0., 1. )), step( abs(uv.x-31.), 7. )*stepeq( uv.y, 9.) );
|
||||
|
||||
col = mix( col, mix( COL(255.,251.,187.), col, clamp( d/4.5-0.6, 0., 1.) ),
|
||||
onCircle(uv, vec2(31.,1.), 10.2 )*step( uv.y, 8. )*step( 7., uv.y ));
|
||||
col = mix( col, mix( COL(255.,255.,255.), col, clamp( d/4.-0.7, 0., 1.) ),
|
||||
onCircle(uv, vec2(31.,1.), 7.2 )*step( uv.y, 8. )*step( 7., uv.y ));
|
||||
|
||||
// floor
|
||||
d = distance( vec2(mod(uv.x, 32.),uv.y)*vec2(1.5,30./3.), vec2(16., 61.5)*vec2(1.5,30./3.) );
|
||||
col = mix( col, mix( COL(168.,168.,168.), COL(124.,124.,124.), clamp(d/15.-0.5, 0., 1.) ), step(d,24.5));
|
||||
col = mix( col, mix( COL(124.,124.,124.), COL(140.,140.,140.), clamp((uv.y-59.)/1., 0., 1.)), step(59.,uv.y)*step(uv.x, 57.)*step(7.,uv.x));
|
||||
col = mix( col, mix( COL(168.,168.,168.), COL(124.,124.,124.), clamp(abs(32.-uv.x)/10.-2., 0., 1.)), step(uv.y, 62.)*step(62.,uv.y)*step(uv.x, 61.)*step(3.,uv.x));
|
||||
col = mix( col, mix( COL(152.,152.,152.), COL(124.,124.,124.), clamp(abs(32.-uv.x)/10.-2.25, 0., 1.)), step(uv.y, 61.)*step(61.,uv.y)*step(uv.x, 59.)*step(5.,uv.x));
|
||||
|
||||
col = floor( (col)*32.)/32.;
|
||||
if( any(notEqual(col, vec3(floor((20./255.)*32.)/32.))) ) {
|
||||
icol = col;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Proocedural MAP functions
|
||||
|
||||
bool isWall( const vec2 vos ) {
|
||||
return vos.y<0.4*ROOM_SIZE || vos.y>2.75*ROOM_SIZE || any( equal( mod( vos, vec2( ROOM_SIZE ) ), vec2(0.,0.) ) );
|
||||
}
|
||||
bool isDoor( const vec2 vos ) {
|
||||
return isWall(vos) && ((hash(vos)>0.75 && any( equal( mod( vos, vec2( ROOM_SIZE*0.5 ) ), vec2(2.) ) ))
|
||||
|| any( equal( mod( vos, vec2( ROOM_SIZE ) ), vec2(ROOM_SIZE*0.5) ) ));
|
||||
}
|
||||
bool isObject( const vec2 vos ) {
|
||||
return hash( vos*10. ) > 0.95;
|
||||
}
|
||||
bool map( const vec2 vos ) {
|
||||
return isObject( vos ) || isWall( vos );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Render MAP functions
|
||||
|
||||
bool intersectSprite( const vec3 ro, const vec3 rd, const vec3 vos, const vec3 nor, out vec2 uv ) {
|
||||
float dist, u;
|
||||
vec2 a = vos.xz + nor.zx*vec2(-0.5,0.5) + vec2(0.5, 0.5);
|
||||
vec2 b = vos.xz - nor.zx*vec2(-0.5,0.5) + vec2(0.5, 0.5);
|
||||
if( intersectSegment( ro, rd, a, b, dist, u) ) {
|
||||
uv.x = u; uv.y = 1.-(ro+dist*rd).y;
|
||||
if( sign(nor.x)<0. ) uv.x = 1.-uv.x;
|
||||
return uv.y>0.&&uv.y<1.;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
int getMaterialId( const vec2 vos ) {
|
||||
return int( mod( 521.21 * hash( floor((vos-vec2(0.5))/ROOM_SIZE ) ), float(NUM_MATERIALS)) );
|
||||
}
|
||||
bool getColorForPosition( const vec3 ro, const vec3 rd, const vec3 vos, const vec3 pos, const vec3 nor, inout vec3 col ) {
|
||||
vec2 uv;
|
||||
|
||||
if( isWall( vos.xz ) ) {
|
||||
if( isDoor( vos.xz ) ) {
|
||||
if( intersectSprite( ro, rd, vos+nor*0.03, nor, uv ) ) {
|
||||
// open the door
|
||||
uv.x -= clamp( 2.-0.75*distance( ro.xz, vos.xz+vec2(0.5) ), 0., 1.);
|
||||
if( uv.x > 0. ) {
|
||||
getMaterialColor( MATERIAL_DOOR, uv*64., 0., col );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// a wall is hit
|
||||
if( pos.y <= 1. && pos.y >= 0. ) {
|
||||
vec2 mpos = vec2( dot(vec3(-nor.z,0.0,nor.x),pos), -pos.y );
|
||||
float sha = 0.6 + 0.4*abs(nor.z);
|
||||
getMaterialColor( isDoor( vos.xz+nor.xz )?MATERIAL_DOORWAY:getMaterialId(vos.xz), mpos*64., hash( vos.xz ), col );
|
||||
col *= sha;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if( isObject( vos.xz ) && !isWall( vos.xz+vec2(1.,0.) ) && !isWall( vos.xz+vec2(-1.,0.) )
|
||||
&& !isWall( vos.xz+vec2(0.,-1.) ) && !isWall( vos.xz+vec2(0.,1.) ) &&
|
||||
intersectSprite( ro, rd, vos, rdcenter, uv ) ) {
|
||||
return getObjectColor( 0, uv*64., col );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool castRay( const vec3 ro, const vec3 rd, inout vec3 col ) {
|
||||
vec3 pos = floor(ro);
|
||||
vec3 ri = 1.0/rd;
|
||||
vec3 rs = sign(rd);
|
||||
vec3 dis = (pos-ro + 0.5 + rs*0.5) * ri;
|
||||
|
||||
float res = 0.0;
|
||||
vec3 mm = vec3(0.0);
|
||||
bool hit = false;
|
||||
|
||||
for( int i=0; i<MAXSTEPS; i++ ) {
|
||||
if( hit ) continue;
|
||||
|
||||
mm = step(dis.xyz, dis.zyx);
|
||||
dis += mm * rs * ri;
|
||||
pos += mm * rs;
|
||||
|
||||
if( map(pos.xz) ) {
|
||||
vec3 mini = (pos-ro + 0.5 - 0.5*vec3(rs))*ri;
|
||||
float t = max ( mini.x, mini.z );
|
||||
hit = getColorForPosition( ro, rd, pos, ro+rd*t, -mm*sign(rd), col );
|
||||
}
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Some really ugly code
|
||||
|
||||
#define CCOS(a) cos(clamp(a,0.,1.)*1.57079632679)
|
||||
#define CSIN(a) sin(clamp(a,0.,1.)*1.57079632679)
|
||||
vec3 path( const float t ) {
|
||||
float tmod = mod( t/SECONDS_IN_ROOM, 8. );
|
||||
float tfloor = floor( tmod );
|
||||
|
||||
vec3 pos = vec3( 4.*ROOM_SIZE*floor(t/(SECONDS_IN_ROOM*8.))+0.5, 0.5, 0.5*ROOM_SIZE+0.5 );
|
||||
return pos + ROOM_SIZE*vec3(
|
||||
clamp(tmod,0.,1.)+clamp(tmod-4.,0.,1.)+0.5*(2.+CSIN(tmod-1.)-CCOS(tmod-3.)+CSIN(tmod-5.)-CCOS(tmod-7.)), 0.,
|
||||
clamp(tmod-2.,0.,1.)-clamp(tmod-6.,0.,1.)+0.5*(-CCOS(tmod-1.)+CSIN(tmod-3.)+CCOS(tmod-5.)-CSIN(tmod-7.)) );
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Main
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
|
||||
vec2 q = fragCoord.xy / iResolution.xy;
|
||||
vec2 p = -1.0 + 2.0*q;
|
||||
p.x *= iResolution.x/ iResolution.y;
|
||||
|
||||
vec3 ro = path( time );
|
||||
vec3 ta = path( time+0.1 );
|
||||
|
||||
rdcenter = rotate( normalize( ta - ro), 0.3*cos(time*0.75) );
|
||||
vec3 uu = normalize(cross( vec3(0.,1.,0.), rdcenter ));
|
||||
vec3 vv = normalize(cross(rdcenter,uu));
|
||||
vec3 rd = normalize( p.x*uu + p.y*vv + 2.5*rdcenter );
|
||||
|
||||
vec3 col = rd.y>0.?vec3(56./255.):vec3(112./255.);
|
||||
castRay( ro, rd, col );
|
||||
|
||||
fragColor = vec4( col, 1.0 );
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
// https://www.shadertoy.com/view/4tdSWr
|
||||
|
||||
const float cloudscale = 1.1;
|
||||
const float speed = 0.03;
|
||||
const float clouddark = 0.5;
|
||||
const float cloudlight = 0.3;
|
||||
const float cloudcover = 0.2;
|
||||
const float cloudalpha = 8.0;
|
||||
const float skytint = 0.5;
|
||||
const vec3 skycolour1 = vec3(0.2, 0.4, 0.6);
|
||||
const vec3 skycolour2 = vec3(0.4, 0.7, 1.0);
|
||||
|
||||
const mat2 m = mat2( 1.6, 1.2, -1.2, 1.6 );
|
||||
|
||||
vec2 hash( vec2 p ) {
|
||||
p = vec2(dot(p,vec2(127.1,311.7)), dot(p,vec2(269.5,183.3)));
|
||||
return -1.0 + 2.0*fract(sin(p)*43758.5453123);
|
||||
}
|
||||
|
||||
float noise( in vec2 p ) {
|
||||
const float K1 = 0.366025404; // (sqrt(3)-1)/2;
|
||||
const float K2 = 0.211324865; // (3-sqrt(3))/6;
|
||||
vec2 i = floor(p + (p.x+p.y)*K1);
|
||||
vec2 a = p - i + (i.x+i.y)*K2;
|
||||
vec2 o = (a.x>a.y) ? vec2(1.0,0.0) : vec2(0.0,1.0); //vec2 of = 0.5 + 0.5*vec2(sign(a.x-a.y), sign(a.y-a.x));
|
||||
vec2 b = a - o + K2;
|
||||
vec2 c = a - 1.0 + 2.0*K2;
|
||||
vec3 h = max(0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );
|
||||
vec3 n = h*h*h*h*vec3( dot(a,hash(i+0.0)), dot(b,hash(i+o)), dot(c,hash(i+1.0)));
|
||||
return dot(n, vec3(70.0));
|
||||
}
|
||||
|
||||
float fbm(vec2 n) {
|
||||
float total = 0.0, amplitude = 0.1;
|
||||
for (int i = 0; i < 7; i++) {
|
||||
total += noise(n) * amplitude;
|
||||
n = m * n;
|
||||
amplitude *= 0.4;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
// -----------------------------------------------
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
|
||||
vec2 p = fragCoord.xy / iResolution.xy;
|
||||
vec2 uv = p*vec2(iResolution.x/iResolution.y,1.0);
|
||||
float time = iGlobalTime * speed;
|
||||
float q = fbm(uv * cloudscale * 0.5);
|
||||
|
||||
//ridged noise shape
|
||||
float r = 0.0;
|
||||
uv *= cloudscale;
|
||||
uv -= q - time;
|
||||
float weight = 0.8;
|
||||
for (int i=0; i<8; i++){
|
||||
r += abs(weight*noise( uv ));
|
||||
uv = m*uv + time;
|
||||
weight *= 0.7;
|
||||
}
|
||||
|
||||
//noise shape
|
||||
float f = 0.0;
|
||||
uv = p*vec2(iResolution.x/iResolution.y,1.0);
|
||||
uv *= cloudscale;
|
||||
uv -= q - time;
|
||||
weight = 0.7;
|
||||
for (int i=0; i<8; i++){
|
||||
f += weight*noise( uv );
|
||||
uv = m*uv + time;
|
||||
weight *= 0.6;
|
||||
}
|
||||
|
||||
f *= r + f;
|
||||
|
||||
//noise colour
|
||||
float c = 0.0;
|
||||
time = iGlobalTime * speed * 2.0;
|
||||
uv = p*vec2(iResolution.x/iResolution.y,1.0);
|
||||
uv *= cloudscale*2.0;
|
||||
uv -= q - time;
|
||||
weight = 0.4;
|
||||
for (int i=0; i<7; i++){
|
||||
c += weight*noise( uv );
|
||||
uv = m*uv + time;
|
||||
weight *= 0.6;
|
||||
}
|
||||
|
||||
//noise ridge colour
|
||||
float c1 = 0.0;
|
||||
time = iGlobalTime * speed * 3.0;
|
||||
uv = p*vec2(iResolution.x/iResolution.y,1.0);
|
||||
uv *= cloudscale*3.0;
|
||||
uv -= q - time;
|
||||
weight = 0.4;
|
||||
for (int i=0; i<7; i++){
|
||||
c1 += abs(weight*noise( uv ));
|
||||
uv = m*uv + time;
|
||||
weight *= 0.6;
|
||||
}
|
||||
|
||||
c += c1;
|
||||
|
||||
vec3 skycolour = mix(skycolour2, skycolour1, p.y);
|
||||
vec3 cloudcolour = vec3(1.1, 1.1, 0.9) * clamp((clouddark + cloudlight*c), 0.0, 1.0);
|
||||
|
||||
f = cloudcover + cloudalpha*f*r;
|
||||
|
||||
vec3 result = mix(skycolour, clamp(skytint * skycolour + cloudcolour, 0.0, 1.0), clamp(f + c, 0.0, 1.0));
|
||||
|
||||
fragColor = vec4( result, 1.0 );
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
//Xyptonjtroz by nimitz (twitter: @stormoid)
|
||||
|
||||
//Audio by Dave_Hoskins
|
||||
|
||||
#define ITR 100
|
||||
#define FAR 30.
|
||||
#define time iGlobalTime
|
||||
|
||||
/*
|
||||
Believable animated volumetric dust storm in 7 samples,
|
||||
blending each layer in based on geometry distance allows to
|
||||
render it without visible seams. 3d Triangle noise is
|
||||
used for the dust volume.
|
||||
|
||||
Also included is procedural bump mapping and glow based on
|
||||
curvature*fresnel. (see: https://www.shadertoy.com/view/Xts3WM)
|
||||
|
||||
|
||||
Further explanation of the dust generation (per Dave's request):
|
||||
|
||||
The basic idea is to have layers of gradient shaded volumetric
|
||||
animated noise. The problem is when geometry is intersected
|
||||
before the ray reaches the far plane. A way to smoothly blend
|
||||
the low sampled noise is needed. So I am blending (smoothstep)
|
||||
each dust layer based on current ray distance and the solid
|
||||
interesction distance. I am also scaling the noise taps as a
|
||||
function of the current distance so that the distant dust doesn't
|
||||
appear too noisy and as a function of current height to get some
|
||||
"ground hugging" effect.
|
||||
|
||||
*/
|
||||
|
||||
mat2 mm2(in float a){float c = cos(a), s = sin(a);return mat2(c,s,-s,c);}
|
||||
|
||||
float height(in vec2 p)
|
||||
{
|
||||
p *= 0.2;
|
||||
return sin(p.y)*0.4 + sin(p.x)*0.4;
|
||||
}
|
||||
|
||||
//smooth min form iq
|
||||
float smin( float a, float b)
|
||||
{
|
||||
const float k = 0.7;
|
||||
float h = clamp( 0.5 + 0.5*(b-a)/k, 0.0, 1.0 );
|
||||
return mix( b, a, h ) - k*h*(1.0-h);
|
||||
}
|
||||
|
||||
//form Dave
|
||||
vec2 hash22(vec2 p)
|
||||
{
|
||||
p = fract(p * vec2(5.3983, 5.4427));
|
||||
p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));
|
||||
return fract(vec2(p.x * p.y * 95.4337, p.x * p.y * 97.597));
|
||||
}
|
||||
|
||||
float vine(vec3 p, in float c, in float h)
|
||||
{
|
||||
p.y += sin(p.z*0.2625)*2.5;
|
||||
p.x += cos(p.z*0.1575)*3.;
|
||||
vec2 q = vec2(mod(p.x, c)-c/2., p.y);
|
||||
return length(q) - h -sin(p.z*2.+sin(p.x*7.)*0.5+time*0.5)*0.13;
|
||||
}
|
||||
|
||||
float map(vec3 p)
|
||||
{
|
||||
p.y += height(p.zx);
|
||||
|
||||
vec3 bp = p;
|
||||
vec2 hs = hash22(floor(p.zx/4.));
|
||||
p.zx = mod(p.zx,4.)-2.;
|
||||
|
||||
float d = p.y+0.5;
|
||||
p.y -= hs.x*0.4-0.15;
|
||||
p.zx += hs*1.3;
|
||||
d = smin(d, length(p)-hs.x*0.4);
|
||||
|
||||
d = smin(d, vine(bp+vec3(1.8,0.,0),15.,.8) );
|
||||
d = smin(d, vine(bp.zyx+vec3(0.,0,17.),20.,0.75) );
|
||||
|
||||
return d*1.1;
|
||||
}
|
||||
|
||||
float march(in vec3 ro, in vec3 rd)
|
||||
{
|
||||
float precis = 0.002;
|
||||
float h=precis*2.0;
|
||||
float d = 0.;
|
||||
for( int i=0; i<ITR; i++ )
|
||||
{
|
||||
if( abs(h)<precis || d>FAR ) break;
|
||||
d += h;
|
||||
float res = map(ro+rd*d);
|
||||
h = res;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
float tri(in float x){return abs(fract(x)-.5);}
|
||||
vec3 tri3(in vec3 p){return vec3( tri(p.z+tri(p.y*1.)), tri(p.z+tri(p.x*1.)), tri(p.y+tri(p.x*1.)));}
|
||||
|
||||
mat2 m2 = mat2(0.970, 0.242, -0.242, 0.970);
|
||||
|
||||
float triNoise3d(in vec3 p, in float spd)
|
||||
{
|
||||
float z=1.4;
|
||||
float rz = 0.;
|
||||
vec3 bp = p;
|
||||
for (float i=0.; i<=3.; i++ )
|
||||
{
|
||||
vec3 dg = tri3(bp*2.);
|
||||
p += (dg+time*spd);
|
||||
|
||||
bp *= 1.8;
|
||||
z *= 1.5;
|
||||
p *= 1.2;
|
||||
//p.xz*= m2;
|
||||
|
||||
rz+= (tri(p.z+tri(p.x+tri(p.y))))/z;
|
||||
bp += 0.14;
|
||||
}
|
||||
return rz;
|
||||
}
|
||||
|
||||
float fogmap(in vec3 p, in float d)
|
||||
{
|
||||
p.x += time*1.5;
|
||||
p.z += sin(p.x*.5);
|
||||
return triNoise3d(p*2.2/(d+20.),0.2)*(1.-smoothstep(0.,.7,p.y));
|
||||
}
|
||||
|
||||
vec3 fog(in vec3 col, in vec3 ro, in vec3 rd, in float mt)
|
||||
{
|
||||
float d = .5;
|
||||
for(int i=0; i<7; i++)
|
||||
{
|
||||
vec3 pos = ro + rd*d;
|
||||
float rz = fogmap(pos, d);
|
||||
float grd = clamp((rz - fogmap(pos+.8-float(i)*0.1,d))*3., 0.1, 1. );
|
||||
vec3 col2 = (vec3(.1,0.8,.5)*.5 + .5*vec3(.5, .8, 1.)*(1.7-grd))*0.55;
|
||||
col = mix(col,col2,clamp(rz*smoothstep(d-0.4,d+2.+d*.75,mt),0.,1.) );
|
||||
d *= 1.5+0.3;
|
||||
if (d>mt)break;
|
||||
}
|
||||
return col;
|
||||
}
|
||||
|
||||
vec3 normal(in vec3 p)
|
||||
{
|
||||
vec2 e = vec2(-1., 1.)*0.005;
|
||||
return normalize(e.yxx*map(p + e.yxx) + e.xxy*map(p + e.xxy) +
|
||||
e.xyx*map(p + e.xyx) + e.yyy*map(p + e.yyy) );
|
||||
}
|
||||
|
||||
float bnoise(in vec3 p)
|
||||
{
|
||||
float n = sin(triNoise3d(p*.3,0.0)*11.)*0.6+0.4;
|
||||
n += sin(triNoise3d(p*1.,0.05)*40.)*0.1+0.9;
|
||||
return (n*n)*0.003;
|
||||
}
|
||||
|
||||
vec3 bump(in vec3 p, in vec3 n, in float ds)
|
||||
{
|
||||
vec2 e = vec2(.005,0);
|
||||
float n0 = bnoise(p);
|
||||
vec3 d = vec3(bnoise(p+e.xyy)-n0, bnoise(p+e.yxy)-n0, bnoise(p+e.yyx)-n0)/e.x;
|
||||
n = normalize(n-d*2.5/sqrt(ds));
|
||||
return n;
|
||||
}
|
||||
|
||||
float shadow(in vec3 ro, in vec3 rd, in float mint, in float tmax)
|
||||
{
|
||||
float res = 1.0;
|
||||
float t = mint;
|
||||
for( int i=0; i<10; i++ )
|
||||
{
|
||||
float h = map(ro + rd*t);
|
||||
res = min( res, 4.*h/t );
|
||||
t += clamp( h, 0.05, .5 );
|
||||
if(h<0.001 || t>tmax) break;
|
||||
}
|
||||
return clamp( res, 0.0, 1.0 );
|
||||
|
||||
}
|
||||
|
||||
float curv(in vec3 p, in float w)
|
||||
{
|
||||
vec2 e = vec2(-1., 1.)*w;
|
||||
|
||||
float t1 = map(p + e.yxx), t2 = map(p + e.xxy);
|
||||
float t3 = map(p + e.xyx), t4 = map(p + e.yyy);
|
||||
|
||||
return .125/(e.x*e.x) *(t1 + t2 + t3 + t4 - 4. * map(p));
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
vec2 p = fragCoord.xy/iResolution.xy-0.5;
|
||||
vec2 q = fragCoord.xy/iResolution.xy;
|
||||
p.x*=iResolution.x/iResolution.y;
|
||||
vec2 mo = iMouse.xy / iResolution.xy-.5;
|
||||
mo = (mo==vec2(-.5))?mo=vec2(-0.1,0.07):mo;
|
||||
mo.x *= iResolution.x/iResolution.y;
|
||||
|
||||
vec3 ro = vec3(smoothstep(0.,1.,tri(time*.45)*2.)*0.1, smoothstep(0.,1.,tri(time*0.9)*2.)*0.07, -time*0.6);
|
||||
ro.y -= height(ro.zx)+0.05;
|
||||
mo.x += smoothstep(0.6,1.,sin(time*.6)*0.5+0.5)-1.5;
|
||||
vec3 eyedir = normalize(vec3(cos(mo.x),mo.y*2.-0.2+sin(time*0.45*1.57)*0.1,sin(mo.x)));
|
||||
vec3 rightdir = normalize(vec3(cos(mo.x+1.5708),0.,sin(mo.x+1.5708)));
|
||||
vec3 updir = normalize(cross(rightdir,eyedir));
|
||||
vec3 rd=normalize((p.x*rightdir+p.y*updir)*1.+eyedir);
|
||||
|
||||
vec3 ligt = normalize( vec3(.5, .05, -.2) );
|
||||
vec3 ligt2 = normalize( vec3(.5, -.1, -.2) );
|
||||
|
||||
float rz = march(ro,rd);
|
||||
|
||||
vec3 fogb = mix(vec3(.7,.8,.8 )*0.3, vec3(1.,1.,.77)*.95, pow(dot(rd,ligt2)+1.2, 2.5)*.25);
|
||||
fogb *= clamp(rd.y*.5+.6, 0., 1.);
|
||||
vec3 col = fogb;
|
||||
|
||||
if ( rz < FAR )
|
||||
{
|
||||
vec3 pos = ro+rz*rd;
|
||||
vec3 nor= normal( pos );
|
||||
float d = distance(pos,ro);
|
||||
nor = bump(pos,nor,d);
|
||||
float crv = clamp(curv(pos, .4),.0,10.);
|
||||
float shd = shadow(pos,ligt,0.1,3.);
|
||||
float dif = clamp( dot( nor, ligt ), 0.0, 1.0 )*shd;
|
||||
float spe = pow(clamp( dot( reflect(rd,nor), ligt ), 0.0, 1.0 ),50.)*shd;
|
||||
float fre = pow( clamp(1.0+dot(nor,rd),0.0,1.0), 1.5 );
|
||||
vec3 brdf = vec3(0.10,0.11,0.13);
|
||||
brdf += 1.5*dif*vec3(1.00,0.90,0.7);
|
||||
col = mix(vec3(0.1,0.2,1),vec3(.3,.5,1),pos.y*.5)*0.2+.1;
|
||||
col *= (sin(bnoise(pos)*900.)*0.2+0.8);
|
||||
col = col*brdf + col*spe*.5 + fre*vec3(.7,1.,0.2)*.3*crv;
|
||||
}
|
||||
|
||||
//ordinary distance fog first
|
||||
col = mix(col, fogb, smoothstep(FAR-7.,FAR,rz));
|
||||
|
||||
//then volumetric fog
|
||||
col = fog(col, ro, rd, rz);
|
||||
|
||||
//post
|
||||
col = pow(col,vec3(0.8));
|
||||
col *= 1.-smoothstep(0.1,2.,length(p));
|
||||
|
||||
fragColor = vec4( col, 1.0 );
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
// london.jpg
|
||||
|
||||
// I started working a bit on the colors of Remix 2, ended up with something like this. :)
|
||||
// Remix 2 here: https://www.shadertoy.com/view/MtcGD7
|
||||
// Remix 1 here: https://www.shadertoy.com/view/llc3DM
|
||||
// Original here: https://www.shadertoy.com/view/XsXXRN
|
||||
|
||||
float rand(vec2 n) {
|
||||
return fract(sin(cos(dot(n, vec2(12.9898,12.1414)))) * 83758.5453);
|
||||
}
|
||||
|
||||
float noise(vec2 n) {
|
||||
const vec2 d = vec2(0.0, 1.0);
|
||||
vec2 b = floor(n), f = smoothstep(vec2(0.0), vec2(1.0), fract(n));
|
||||
return mix(mix(rand(b), rand(b + d.yx), f.x), mix(rand(b + d.xy), rand(b + d.yy), f.x), f.y);
|
||||
}
|
||||
|
||||
float fbm(vec2 n) {
|
||||
float total = 0.0, amplitude = 1.0;
|
||||
for (int i = 0; i <5; i++) {
|
||||
total += noise(n) * amplitude;
|
||||
n += n*1.7;
|
||||
amplitude *= 0.47;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
|
||||
|
||||
const vec3 c1 = vec3(0.5, 0.0, 0.1);
|
||||
const vec3 c2 = vec3(0.9, 0.1, 0.0);
|
||||
const vec3 c3 = vec3(0.2, 0.1, 0.7);
|
||||
const vec3 c4 = vec3(1.0, 0.9, 0.1);
|
||||
const vec3 c5 = vec3(0.1);
|
||||
const vec3 c6 = vec3(0.9);
|
||||
|
||||
vec2 speed = vec2(0.1, 0.9);
|
||||
float shift = 1.327+sin(iGlobalTime*2.0)/2.4;
|
||||
float alpha = 1.0;
|
||||
|
||||
float dist = 3.5-sin(iGlobalTime*0.4)/1.89;
|
||||
|
||||
vec2 uv = fragCoord.xy / iResolution.xy;
|
||||
vec2 p = fragCoord.xy * dist / iResolution.xx;
|
||||
p += sin(p.yx*4.0+vec2(.2,-.3)*iGlobalTime)*0.04;
|
||||
p += sin(p.yx*8.0+vec2(.6,+.1)*iGlobalTime)*0.01;
|
||||
|
||||
p.x -= iGlobalTime/1.1;
|
||||
float q = fbm(p - iGlobalTime * 0.3+1.0*sin(iGlobalTime+0.5)/2.0);
|
||||
float qb = fbm(p - iGlobalTime * 0.4+0.1*cos(iGlobalTime)/2.0);
|
||||
float q2 = fbm(p - iGlobalTime * 0.44 - 5.0*cos(iGlobalTime)/2.0) - 6.0;
|
||||
float q3 = fbm(p - iGlobalTime * 0.9 - 10.0*cos(iGlobalTime)/15.0)-4.0;
|
||||
float q4 = fbm(p - iGlobalTime * 1.4 - 20.0*sin(iGlobalTime)/14.0)+2.0;
|
||||
q = (q + qb - .4 * q2 -2.0*q3 + .6*q4)/3.8;
|
||||
vec2 r = vec2(fbm(p + q /2.0 + iGlobalTime * speed.x - p.x - p.y), fbm(p + q - iGlobalTime * speed.y));
|
||||
vec3 c = mix(c1, c2, fbm(p + r)) + mix(c3, c4, r.x) - mix(c5, c6, r.y);
|
||||
vec3 color = vec3(1.0/(pow(c+1.61,vec3(4.0))) * cos(shift * fragCoord.y / iResolution.y));
|
||||
|
||||
color=vec3(1.0,.2,.05)/(pow((r.y+r.y)* max(.0,p.y)+0.1, 4.0));;
|
||||
color += (texture(iChannel0,uv*0.6+vec2(.5,.1)).xyz*0.01*pow((r.y+r.y)*.65,5.0)+0.055)*mix( vec3(.9,.4,.3),vec3(.7,.5,.2), uv.y);
|
||||
color = color/(1.0+max(vec3(0),color));
|
||||
fragColor = vec4(color.x, color.y, color.z, alpha);
|
||||
}
|
|
@ -0,0 +1,309 @@
|
|||
//Somewhere in 1993 by nimitz (twitter: @stormoid)
|
||||
|
||||
#define PALETTE 6.8
|
||||
|
||||
//3 to 5 works best
|
||||
#define TERRAIN_COMPLEXITY 4.
|
||||
#define ITR 100
|
||||
#define FAR 700.
|
||||
#define time mod(iGlobalTime,500.)
|
||||
|
||||
mat2 mm2(in float a){float c = cos(a), s = sin(a);return mat2(c,-s,s,c);}
|
||||
float smoothfloor(const in float x, const in float w)
|
||||
{
|
||||
return floor(x)+smoothstep(w, 1.-w,fract(x));
|
||||
}
|
||||
|
||||
vec3 enpos()
|
||||
{
|
||||
return vec3(sin(time)*100.+50.,sin(time)*30.+30.,300.+sin(time*.9+sin(time*0.88+0.2))*100.);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
//---------------------------HUD--------------------------
|
||||
//--------------------------------------------------------
|
||||
|
||||
float square(in vec2 p){ return max(abs(p.x),abs(p.y));}
|
||||
float loz(in vec2 p){ return abs(p.x)+abs(p.y);}
|
||||
|
||||
//from Dave (https://www.shadertoy.com/view/4djSRW)
|
||||
vec2 hash2(float p)
|
||||
{
|
||||
vec2 p2 = fract(p * vec2(5.3983, 5.4427));
|
||||
p2 += dot(p2.yx, p2.xy + vec2(21.5351, 14.3137));
|
||||
return fract(vec2(p2.x * p2.y * 95.4337, p2.x * p2.y * 97.597));
|
||||
}
|
||||
|
||||
float line( in vec2 a, in vec2 b, in vec2 p )
|
||||
{
|
||||
vec2 pa = p - a, ba = b - a;
|
||||
float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
|
||||
return length( pa - ba*h );
|
||||
}
|
||||
|
||||
float crosshair(in vec2 p , in float tk, in float rt)
|
||||
{
|
||||
float d = abs(p.x)+abs(p.y);
|
||||
float a = atan(p.y,p.x);
|
||||
float rz = smoothstep(0.03*tk,.04*tk,abs(d-0.5));
|
||||
d = sin(a*3.+1.59-time*3.5-rt);
|
||||
rz += smoothstep(0.0,.07*tk,d);
|
||||
return rz;
|
||||
}
|
||||
|
||||
//inspired by otaviogood "runes" (https://www.shadertoy.com/view/MsXSRn)
|
||||
float text2(in vec2 p)
|
||||
{
|
||||
p = (p+vec2(1.75,-.8))*7.;
|
||||
p.x *= 1.5;
|
||||
float sd = floor(time*8.);
|
||||
vec2 p1 = vec2(0), p2 = hash2(sd);
|
||||
float d= 1.;
|
||||
vec2 fl = vec2(2.,2.);
|
||||
for(float i=0.;i<7.;i++)
|
||||
{
|
||||
if(hash2(sd+i+10.).x<0.3)continue;
|
||||
p1 = hash2(i+sd);
|
||||
p2 = hash2(i+sd+1.);
|
||||
p1 = (floor(p1*fl) + .5)/fl;
|
||||
p2 = (floor(p2*fl) + .5)/fl;
|
||||
if (p1 == p2) p2 = vec2(.5);
|
||||
d = min(line(p1, p2, p), d);
|
||||
p1 = p2;
|
||||
p2 = hash2(i+sd+3.);
|
||||
p2 = (floor(p2*fl) + .5)/fl;
|
||||
d = min(line(p1, p2, p), d);
|
||||
p1 = p2;
|
||||
p2 = hash2(i+sd+5.);
|
||||
p2 = (floor(p2*fl) + .5)/fl;
|
||||
if (p1 == p2)
|
||||
{
|
||||
p2 = hash2(i+sd+7.);
|
||||
p2 = (floor(p2*fl) + .5)/fl;
|
||||
}
|
||||
d = min(line(p1,p2,p),d);
|
||||
p.x -= .8;
|
||||
}
|
||||
|
||||
d = smoothstep(0.03, .08,d);
|
||||
return d;
|
||||
}
|
||||
|
||||
vec3 makeHud(in vec2 p, in float seek)
|
||||
{
|
||||
float sk1 = smoothstep(0.99, 1., seek);
|
||||
float sk2 = step(1.-sk1, .5);
|
||||
//lens deformation
|
||||
float ll = abs(p.x)+abs(p.y)*0.25;
|
||||
p *= ll * -.3+1.29;
|
||||
p *= 2.;
|
||||
vec3 col = vec3(0);
|
||||
float d= 1.;
|
||||
//crosshairs
|
||||
float rz = crosshair(p*1.1, .9,1.+sk1);
|
||||
rz = min(rz,crosshair(p*2.7,2., -time*6.5-1.1-sk1));
|
||||
//minimap (top right)
|
||||
float d2 = square(p+vec2(-1.45, -0.67))+0.02;
|
||||
d = smoothstep(0.3,0.31,d2);
|
||||
d = max(d,smoothstep(0.35,.55,min(sin(p.x*80.+1.9),sin(p.y*80.+time*15.))+1.4));
|
||||
d = min(d,smoothstep(0.002,0.009,abs(d2-0.3)));
|
||||
vec3 enp = enpos()/1000.;
|
||||
enp.z = 1.-enp.z;
|
||||
float en = smoothstep(0.025, 0.033, loz(enp.xz+p-vec2(1.47, 1.4))) ;
|
||||
en += mod(floor(time*2.5), 2.);
|
||||
d = min(d,en);
|
||||
rz = min(d,rz);
|
||||
//text (top left)
|
||||
rz= min(rz,text2(p));
|
||||
//altitude bars
|
||||
d = min(rz,sin(p.y*100.+sin(time)*20.)*3.+3.);
|
||||
d2 = max(d,(p.x+0.59)*200.);
|
||||
d2 = max(d2,-(p.x+0.66)*200.);
|
||||
float d3 = max(d,(p.x-0.66)*200.);
|
||||
d3 = max(d3,-(p.x-.59)*200.);
|
||||
d2 = min(d2,d3);
|
||||
d2 += smoothstep(0.59, .6, -p.y);
|
||||
d2 += smoothstep(0.59, .6, p.y);
|
||||
rz = min(rz,d2);
|
||||
//bottom left "status"
|
||||
float num = mod(floor(time*12.),12.);
|
||||
vec2 p2 = p+vec2(-1.32,.94);
|
||||
d = 1.;
|
||||
for(float i=0.;i<5.;i++)
|
||||
{
|
||||
d = min(d,length(p2)+float(num==i));
|
||||
p2.x -= 0.1;
|
||||
}
|
||||
d = smoothstep(0.023,.03,d);
|
||||
rz = min(d,rz);
|
||||
|
||||
vec3 hcol = (sin(vec3(0.35,0.4,0.48)*(3.35)*PALETTE)*0.5+.5);
|
||||
hcol.gb -= sk2;
|
||||
hcol.r += sk2;
|
||||
return hcol*(1.-rz);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
//--------------------------------------------------------
|
||||
//--------------------------------------------------------
|
||||
|
||||
float tri(in float x)
|
||||
{
|
||||
return abs(fract(x)-0.5);
|
||||
}
|
||||
|
||||
mat2 m2 = mat2( 0.80, 0.60, -0.60, 0.80 );
|
||||
float tnoise(in vec2 p)
|
||||
{
|
||||
p*=.008;
|
||||
float z=2.;
|
||||
float rz = 0.;
|
||||
for (float i= 1.;i < TERRAIN_COMPLEXITY;i++ )
|
||||
{
|
||||
rz+= tri(p.x+tri(p.y*1.))/z;
|
||||
z = z*2.;
|
||||
p = p*1.8;
|
||||
p*= m2;
|
||||
}
|
||||
return rz*9.;
|
||||
}
|
||||
|
||||
float oct(in vec3 p){ return dot(vec3(0.5773),abs(p));}
|
||||
vec2 ou( vec2 d1, vec2 d2 ){return (d1.x<d2.x) ? d1 : d2;}
|
||||
|
||||
vec3 roty(vec3 p, float a)
|
||||
{
|
||||
float s = sin(a), c = cos(a);
|
||||
return vec3(c*p.x + s*p.z, p.y, -s*p.x + c*p.z);
|
||||
}
|
||||
|
||||
vec2 map(vec3 p)
|
||||
{
|
||||
//terrain
|
||||
vec2 d = vec2(6.*tnoise(p.xz)+p.y+20.+(tri(p.z*0.001)-0.4)*22.,1.);
|
||||
//xlog(x) seems to work nicely for a valley
|
||||
d.x -= abs(p.x*0.5*log(abs(p.x)))*0.05-8.;
|
||||
//flat water
|
||||
d = ou(d,vec2(p.y+30., 2.));
|
||||
//"enemy"
|
||||
vec3 enp = enpos();
|
||||
enp.z += time*50.;
|
||||
d = ou(d,vec2((oct(roty(p-enp, time*2.5))-6.)*0.66,8.));
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
vec2 march(in vec3 ro, in vec3 rd)
|
||||
{
|
||||
float precis = .1;
|
||||
float h=precis*2.0;
|
||||
float d = 0.;
|
||||
float c = 1.;
|
||||
for( int i=0; i<ITR; i++ )
|
||||
{
|
||||
if( abs(h)<precis || d>FAR ) break;
|
||||
d += h;
|
||||
vec2 res = map(ro+rd*d);
|
||||
h = res.x*1.4;
|
||||
c = res.y;
|
||||
}
|
||||
return vec2(d,c);
|
||||
}
|
||||
|
||||
vec3 normal(const in vec3 p)
|
||||
{
|
||||
vec2 e = vec2(-1., 1.)*.1;
|
||||
return normalize(e.yxx*map(p + e.yxx).x + e.xxy*map(p + e.xxy).x +
|
||||
e.xyx*map(p + e.xyx).x + e.yyy*map(p + e.yyy).x );
|
||||
}
|
||||
|
||||
//(from eiffie, who thought it was from iq, dont know who actually wrote it)
|
||||
float segm(vec3 ro, vec3 rd, vec3 p1, vec3 p2)
|
||||
{
|
||||
vec3 p = p1-ro;
|
||||
vec3 di = p2-ro-p;
|
||||
float proj = dot(rd, di);
|
||||
float m = clamp((dot(rd,p)*proj-dot(p,di))/(dot(di,di)-proj*proj), 0., 1.);
|
||||
p += di*m;
|
||||
p = dot(p, rd)*rd-p;
|
||||
return smoothstep(0.9985,.999,1.-dot(p,p));
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
vec2 p = fragCoord.xy/iResolution.xy-0.5;
|
||||
vec2 bp = p+0.5;
|
||||
p.x*=iResolution.x/iResolution.y;
|
||||
vec2 um = vec2(0);
|
||||
um.x = 0.5+(smoothstep(-2.,2.,sin(time*.7-0.1))-0.5)*.1;
|
||||
um.y = sin(time+1.)*0.02;
|
||||
|
||||
//camera
|
||||
vec3 ro = vec3((smoothstep(-2., 2., sin(time*0.7+1.57))-0.5)*50., sin(time)*5.-1., time*50.);
|
||||
um.x *= 3.;
|
||||
vec3 eye = normalize(vec3(cos(um.x),um.y*5.,sin(um.x)));
|
||||
vec3 right = normalize(vec3(cos(um.x+1.5708),0.,sin(um.x+1.5708)));
|
||||
mat2 ori = mm2( smoothstep(-.5,.5,sin(time*0.7+0.78))-.5 + smoothfloor(time*0.04,.45)*6.28 );
|
||||
right.xy *= ori;
|
||||
vec3 up = normalize(cross(right,eye));
|
||||
vec3 rd=normalize((p.x*right+p.y*up)*.75+eye);
|
||||
|
||||
vec3 bg = sin(vec3(0.35,0.4,0.48)*11.3*PALETTE)*0.5+.5;
|
||||
vec3 col = bg*floor(-rd.y*50.+6.)*0.06;
|
||||
|
||||
//march
|
||||
vec2 rz = march(ro,rd);
|
||||
if ( rz.x < FAR )
|
||||
{
|
||||
vec3 pos = ro+rz.x*rd;
|
||||
vec3 nor = normal( pos );
|
||||
vec3 ligt = normalize(vec3(-.7,0.2, 0.1));
|
||||
float dif = clamp(dot(nor, ligt), 0., 1.);
|
||||
float fre = pow(clamp(1. + dot(nor, rd), 0., 1.), 2.);
|
||||
if (rz.y == 1.)
|
||||
{
|
||||
float mx = abs(pos.x*.1)-10.;
|
||||
mx = smoothstep(-20.,10.,mx);
|
||||
col = mix(vec3(0.,0.37,0),vec3(0.2,.17,0.15),mx);
|
||||
}
|
||||
else
|
||||
col = sin(vec3(0.35,0.4,0.48)*rz.y*PALETTE)*0.5+.55;
|
||||
col = col*dif + col*0.4 + .3*fre*col;
|
||||
}
|
||||
|
||||
//lasers
|
||||
vec3 enp =enpos();
|
||||
enp.z += time*50.;
|
||||
vec3 rn = enp - ro;
|
||||
float tgt = dot(eye, normalize(rn));
|
||||
if (tgt > .997)
|
||||
{
|
||||
vec3 ray1 = vec3(0.7, 1., -1);
|
||||
vec3 ray2 = vec3(-0.7, 1., -1);
|
||||
ray1.xy *= ori; ray2.xy *= ori;
|
||||
float lz = segm(ro,rd,ro-ray1,up*0.5+ro+(eye-ray1*0.01)*30.);
|
||||
lz += segm(ro,rd,ro-ray2,up*.5+ro+(eye-ray2*0.01)*30.);
|
||||
float sw = mod(floor(time*20.),2.);
|
||||
lz *= sw;
|
||||
col = col*(1.-smoothstep(0.0,1.,lz))+lz*vec3(1.,0.,0.);
|
||||
//hit (cant really have explosions since I don't have a function for hit times)
|
||||
if (tgt > .999)
|
||||
{
|
||||
vec2 d = hash2(time);
|
||||
rd.xy += d*0.03;
|
||||
rn.xy += d*10.;
|
||||
float s = sw*smoothstep(0.9998, .9999,dot(rd,normalize(rn)));
|
||||
col = col*(1.-smoothstep(0., 1., s))+s*vec3(1.-d.x, .0, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
//hud
|
||||
float lk = 0.;
|
||||
if (tgt > .99)lk = 4.;
|
||||
vec3 hud = makeHud(p,tgt);
|
||||
col = col*(1.-smoothstep(0., 1., hud.y+hud.x+hud.z))+hud;
|
||||
//scanlines
|
||||
col *= (sin(p.y*1.3*iResolution.x)*0.15)*(sin(p.y*10.+time*410.)*0.4)+1.;
|
||||
|
||||
fragColor = vec4( col, 1.0 );
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* "Seascape" by Alexander Alekseev aka TDM - 2014
|
||||
* License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
|
||||
* Contact: tdmaav@gmail.com
|
||||
*/
|
||||
|
||||
const int NUM_STEPS = 8;
|
||||
const float PI = 3.1415;
|
||||
const float EPSILON = 1e-3;
|
||||
#define EPSILON_NRM (0.1 / iResolution.x)
|
||||
|
||||
// sea
|
||||
const int ITER_GEOMETRY = 3;
|
||||
const int ITER_FRAGMENT = 5;
|
||||
const float SEA_HEIGHT = 0.6;
|
||||
const float SEA_CHOPPY = 4.0;
|
||||
const float SEA_SPEED = 0.8;
|
||||
const float SEA_FREQ = 0.16;
|
||||
const vec3 SEA_BASE = vec3(0.1,0.19,0.22);
|
||||
const vec3 SEA_WATER_COLOR = vec3(0.8,0.9,0.6);
|
||||
#define SEA_TIME (1.0 + iGlobalTime * SEA_SPEED)
|
||||
const mat2 octave_m = mat2(1.6,1.2,-1.2,1.6);
|
||||
|
||||
// math
|
||||
mat3 fromEuler(vec3 ang) {
|
||||
vec2 a1 = vec2(sin(ang.x),cos(ang.x));
|
||||
vec2 a2 = vec2(sin(ang.y),cos(ang.y));
|
||||
vec2 a3 = vec2(sin(ang.z),cos(ang.z));
|
||||
mat3 m;
|
||||
m[0] = vec3(a1.y*a3.y+a1.x*a2.x*a3.x,a1.y*a2.x*a3.x+a3.y*a1.x,-a2.y*a3.x);
|
||||
m[1] = vec3(-a2.y*a1.x,a1.y*a2.y,a2.x);
|
||||
m[2] = vec3(a3.y*a1.x*a2.x+a1.y*a3.x,a1.x*a3.x-a1.y*a3.y*a2.x,a2.y*a3.y);
|
||||
return m;
|
||||
}
|
||||
float hash( vec2 p ) {
|
||||
float h = dot(p,vec2(127.1,311.7));
|
||||
return fract(sin(h)*43758.5453123);
|
||||
}
|
||||
float noise( in vec2 p ) {
|
||||
vec2 i = floor( p );
|
||||
vec2 f = fract( p );
|
||||
vec2 u = f*f*(3.0-2.0*f);
|
||||
return -1.0+2.0*mix( mix( hash( i + vec2(0.0,0.0) ),
|
||||
hash( i + vec2(1.0,0.0) ), u.x),
|
||||
mix( hash( i + vec2(0.0,1.0) ),
|
||||
hash( i + vec2(1.0,1.0) ), u.x), u.y);
|
||||
}
|
||||
|
||||
// lighting
|
||||
float diffuse(vec3 n,vec3 l,float p) {
|
||||
return pow(dot(n,l) * 0.4 + 0.6,p);
|
||||
}
|
||||
float specular(vec3 n,vec3 l,vec3 e,float s) {
|
||||
float nrm = (s + 8.0) / (3.1415 * 8.0);
|
||||
return pow(max(dot(reflect(e,n),l),0.0),s) * nrm;
|
||||
}
|
||||
|
||||
// sky
|
||||
vec3 getSkyColor(vec3 e) {
|
||||
e.y = max(e.y,0.0);
|
||||
return vec3(pow(1.0-e.y,2.0), 1.0-e.y, 0.6+(1.0-e.y)*0.4);
|
||||
}
|
||||
|
||||
// sea
|
||||
float sea_octave(vec2 uv, float choppy) {
|
||||
uv += noise(uv);
|
||||
vec2 wv = 1.0-abs(sin(uv));
|
||||
vec2 swv = abs(cos(uv));
|
||||
wv = mix(wv,swv,wv);
|
||||
return pow(1.0-pow(wv.x * wv.y,0.65),choppy);
|
||||
}
|
||||
|
||||
float map(vec3 p) {
|
||||
float freq = SEA_FREQ;
|
||||
float amp = SEA_HEIGHT;
|
||||
float choppy = SEA_CHOPPY;
|
||||
vec2 uv = p.xz; uv.x *= 0.75;
|
||||
|
||||
float d, h = 0.0;
|
||||
for(int i = 0; i < ITER_GEOMETRY; i++) {
|
||||
d = sea_octave((uv+SEA_TIME)*freq,choppy);
|
||||
d += sea_octave((uv-SEA_TIME)*freq,choppy);
|
||||
h += d * amp;
|
||||
uv *= octave_m; freq *= 1.9; amp *= 0.22;
|
||||
choppy = mix(choppy,1.0,0.2);
|
||||
}
|
||||
return p.y - h;
|
||||
}
|
||||
|
||||
float map_detailed(vec3 p) {
|
||||
float freq = SEA_FREQ;
|
||||
float amp = SEA_HEIGHT;
|
||||
float choppy = SEA_CHOPPY;
|
||||
vec2 uv = p.xz; uv.x *= 0.75;
|
||||
|
||||
float d, h = 0.0;
|
||||
for(int i = 0; i < ITER_FRAGMENT; i++) {
|
||||
d = sea_octave((uv+SEA_TIME)*freq,choppy);
|
||||
d += sea_octave((uv-SEA_TIME)*freq,choppy);
|
||||
h += d * amp;
|
||||
uv *= octave_m; freq *= 1.9; amp *= 0.22;
|
||||
choppy = mix(choppy,1.0,0.2);
|
||||
}
|
||||
return p.y - h;
|
||||
}
|
||||
|
||||
vec3 getSeaColor(vec3 p, vec3 n, vec3 l, vec3 eye, vec3 dist) {
|
||||
float fresnel = clamp(1.0 - dot(n,-eye), 0.0, 1.0);
|
||||
fresnel = pow(fresnel,3.0) * 0.65;
|
||||
|
||||
vec3 reflected = getSkyColor(reflect(eye,n));
|
||||
vec3 refracted = SEA_BASE + diffuse(n,l,80.0) * SEA_WATER_COLOR * 0.12;
|
||||
|
||||
vec3 color = mix(refracted,reflected,fresnel);
|
||||
|
||||
float atten = max(1.0 - dot(dist,dist) * 0.001, 0.0);
|
||||
color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;
|
||||
|
||||
color += vec3(specular(n,l,eye,60.0));
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
// tracing
|
||||
vec3 getNormal(vec3 p, float eps) {
|
||||
vec3 n;
|
||||
n.y = map_detailed(p);
|
||||
n.x = map_detailed(vec3(p.x+eps,p.y,p.z)) - n.y;
|
||||
n.z = map_detailed(vec3(p.x,p.y,p.z+eps)) - n.y;
|
||||
n.y = eps;
|
||||
return normalize(n);
|
||||
}
|
||||
|
||||
float heightMapTracing(vec3 ori, vec3 dir, out vec3 p) {
|
||||
float tm = 0.0;
|
||||
float tx = 1000.0;
|
||||
float hx = map(ori + dir * tx);
|
||||
if(hx > 0.0) return tx;
|
||||
float hm = map(ori + dir * tm);
|
||||
float tmid = 0.0;
|
||||
for(int i = 0; i < NUM_STEPS; i++) {
|
||||
tmid = mix(tm,tx, hm/(hm-hx));
|
||||
p = ori + dir * tmid;
|
||||
float hmid = map(p);
|
||||
if(hmid < 0.0) {
|
||||
tx = tmid;
|
||||
hx = hmid;
|
||||
} else {
|
||||
tm = tmid;
|
||||
hm = hmid;
|
||||
}
|
||||
}
|
||||
return tmid;
|
||||
}
|
||||
|
||||
// main
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
|
||||
vec2 uv = fragCoord.xy / iResolution.xy;
|
||||
uv = uv * 2.0 - 1.0;
|
||||
uv.x *= iResolution.x / iResolution.y;
|
||||
float time = iGlobalTime * 0.3 + iMouse.x*0.01;
|
||||
|
||||
// ray
|
||||
vec3 ang = vec3(sin(time*3.0)*0.1,sin(time)*0.2+0.3,time);
|
||||
vec3 ori = vec3(0.0,3.5,time*5.0);
|
||||
vec3 dir = normalize(vec3(uv.xy,-2.0)); dir.z += length(uv) * 0.15;
|
||||
dir = normalize(dir) * fromEuler(ang);
|
||||
|
||||
// tracing
|
||||
vec3 p;
|
||||
heightMapTracing(ori,dir,p);
|
||||
vec3 dist = p - ori;
|
||||
vec3 n = getNormal(p, dot(dist,dist) * EPSILON_NRM);
|
||||
vec3 light = normalize(vec3(0.0,1.0,0.8));
|
||||
|
||||
// color
|
||||
vec3 color = mix(
|
||||
getSkyColor(dir),
|
||||
getSeaColor(p,n,light,dir,dist),
|
||||
pow(smoothstep(0.0,-0.05,dir.y),0.3));
|
||||
|
||||
// post
|
||||
fragColor = vec4(pow(color,vec3(0.75)), 1.0);
|
||||
}
|
|
@ -0,0 +1,393 @@
|
|||
// Mt2GWD
|
||||
// flyguy
|
||||
|
||||
#define DOWN_SCALE 1.0
|
||||
|
||||
#define MAX_INT_DIGITS 4
|
||||
|
||||
#define CHAR_SIZE vec2(8, 12)
|
||||
#define CHAR_SPACING vec2(8, 12)
|
||||
|
||||
#define STRWIDTH(c) (c * CHAR_SPACING.x)
|
||||
#define STRHEIGHT(c) (c * CHAR_SPACING.y)
|
||||
|
||||
#define NORMAL 0
|
||||
#define INVERT 1
|
||||
#define UNDERLINE 2
|
||||
|
||||
int TEXT_MODE = NORMAL;
|
||||
|
||||
/*
|
||||
--------
|
||||
-###----
|
||||
##-##---
|
||||
##-##---
|
||||
-###----
|
||||
#####-#-
|
||||
##-####-
|
||||
##--##--
|
||||
##-###--
|
||||
-###-##-
|
||||
--------
|
||||
--------
|
||||
|
||||
00000000
|
||||
01110000
|
||||
11011000
|
||||
11011000
|
||||
01110000
|
||||
11111010
|
||||
11011110
|
||||
11001100
|
||||
11011100
|
||||
01110110
|
||||
00000000
|
||||
00000000
|
||||
|
||||
//Broken up into 4 8x3 (24 bit) chunks for each component of the vec4.
|
||||
//Hexadecimal is being used to reduce clutter in the code but decimal still works.
|
||||
|
||||
00000000
|
||||
01110000 -> 00000000 01110000 11011000 -> 0x0070D8
|
||||
11011000
|
||||
|
||||
11011000
|
||||
01110000 -> 11011000 01110000 11111010 -> 0xD870FA
|
||||
11111010
|
||||
|
||||
11011110
|
||||
11001100 -> 11011110 11001100 11011100 -> 0xDECCDC
|
||||
11011100
|
||||
|
||||
01110110
|
||||
00000000 -> 01110110 00000000 00000000 -> 0x760000
|
||||
00000000
|
||||
|
||||
vec4(0x0070D8,0xD870FA,0xDECCDC,0x760000)
|
||||
*/
|
||||
|
||||
//Automatically generated from the 8x12 font sheet here:
|
||||
//http://www.massmind.org/techref/datafile/charset/extractor/charset_extractor.htm
|
||||
|
||||
vec4 ch_spc = vec4(0x000000,0x000000,0x000000,0x000000);
|
||||
vec4 ch_exc = vec4(0x003078,0x787830,0x300030,0x300000);
|
||||
vec4 ch_quo = vec4(0x006666,0x662400,0x000000,0x000000);
|
||||
vec4 ch_hsh = vec4(0x006C6C,0xFE6C6C,0x6CFE6C,0x6C0000);
|
||||
vec4 ch_dol = vec4(0x30307C,0xC0C078,0x0C0CF8,0x303000);
|
||||
vec4 ch_pct = vec4(0x000000,0xC4CC18,0x3060CC,0x8C0000);
|
||||
vec4 ch_amp = vec4(0x0070D8,0xD870FA,0xDECCDC,0x760000);
|
||||
vec4 ch_apo = vec4(0x003030,0x306000,0x000000,0x000000);
|
||||
vec4 ch_lbr = vec4(0x000C18,0x306060,0x603018,0x0C0000);
|
||||
vec4 ch_rbr = vec4(0x006030,0x180C0C,0x0C1830,0x600000);
|
||||
vec4 ch_ast = vec4(0x000000,0x663CFF,0x3C6600,0x000000);
|
||||
vec4 ch_crs = vec4(0x000000,0x18187E,0x181800,0x000000);
|
||||
vec4 ch_com = vec4(0x000000,0x000000,0x000038,0x386000);
|
||||
vec4 ch_dsh = vec4(0x000000,0x0000FE,0x000000,0x000000);
|
||||
vec4 ch_per = vec4(0x000000,0x000000,0x000038,0x380000);
|
||||
vec4 ch_lsl = vec4(0x000002,0x060C18,0x3060C0,0x800000);
|
||||
vec4 ch_0 = vec4(0x007CC6,0xD6D6D6,0xD6D6C6,0x7C0000);
|
||||
vec4 ch_1 = vec4(0x001030,0xF03030,0x303030,0xFC0000);
|
||||
vec4 ch_2 = vec4(0x0078CC,0xCC0C18,0x3060CC,0xFC0000);
|
||||
vec4 ch_3 = vec4(0x0078CC,0x0C0C38,0x0C0CCC,0x780000);
|
||||
vec4 ch_4 = vec4(0x000C1C,0x3C6CCC,0xFE0C0C,0x1E0000);
|
||||
vec4 ch_5 = vec4(0x00FCC0,0xC0C0F8,0x0C0CCC,0x780000);
|
||||
vec4 ch_6 = vec4(0x003860,0xC0C0F8,0xCCCCCC,0x780000);
|
||||
vec4 ch_7 = vec4(0x00FEC6,0xC6060C,0x183030,0x300000);
|
||||
vec4 ch_8 = vec4(0x0078CC,0xCCEC78,0xDCCCCC,0x780000);
|
||||
vec4 ch_9 = vec4(0x0078CC,0xCCCC7C,0x181830,0x700000);
|
||||
vec4 ch_col = vec4(0x000000,0x383800,0x003838,0x000000);
|
||||
vec4 ch_scl = vec4(0x000000,0x383800,0x003838,0x183000);
|
||||
vec4 ch_les = vec4(0x000C18,0x3060C0,0x603018,0x0C0000);
|
||||
vec4 ch_equ = vec4(0x000000,0x007E00,0x7E0000,0x000000);
|
||||
vec4 ch_grt = vec4(0x006030,0x180C06,0x0C1830,0x600000);
|
||||
vec4 ch_que = vec4(0x0078CC,0x0C1830,0x300030,0x300000);
|
||||
vec4 ch_ats = vec4(0x007CC6,0xC6DEDE,0xDEC0C0,0x7C0000);
|
||||
vec4 ch_A = vec4(0x003078,0xCCCCCC,0xFCCCCC,0xCC0000);
|
||||
vec4 ch_B = vec4(0x00FC66,0x66667C,0x666666,0xFC0000);
|
||||
vec4 ch_C = vec4(0x003C66,0xC6C0C0,0xC0C666,0x3C0000);
|
||||
vec4 ch_D = vec4(0x00F86C,0x666666,0x66666C,0xF80000);
|
||||
vec4 ch_E = vec4(0x00FE62,0x60647C,0x646062,0xFE0000);
|
||||
vec4 ch_F = vec4(0x00FE66,0x62647C,0x646060,0xF00000);
|
||||
vec4 ch_G = vec4(0x003C66,0xC6C0C0,0xCEC666,0x3E0000);
|
||||
vec4 ch_H = vec4(0x00CCCC,0xCCCCFC,0xCCCCCC,0xCC0000);
|
||||
vec4 ch_I = vec4(0x007830,0x303030,0x303030,0x780000);
|
||||
vec4 ch_J = vec4(0x001E0C,0x0C0C0C,0xCCCCCC,0x780000);
|
||||
vec4 ch_K = vec4(0x00E666,0x6C6C78,0x6C6C66,0xE60000);
|
||||
vec4 ch_L = vec4(0x00F060,0x606060,0x626666,0xFE0000);
|
||||
vec4 ch_M = vec4(0x00C6EE,0xFEFED6,0xC6C6C6,0xC60000);
|
||||
vec4 ch_N = vec4(0x00C6C6,0xE6F6FE,0xDECEC6,0xC60000);
|
||||
vec4 ch_O = vec4(0x00386C,0xC6C6C6,0xC6C66C,0x380000);
|
||||
vec4 ch_P = vec4(0x00FC66,0x66667C,0x606060,0xF00000);
|
||||
vec4 ch_Q = vec4(0x00386C,0xC6C6C6,0xCEDE7C,0x0C1E00);
|
||||
vec4 ch_R = vec4(0x00FC66,0x66667C,0x6C6666,0xE60000);
|
||||
vec4 ch_S = vec4(0x0078CC,0xCCC070,0x18CCCC,0x780000);
|
||||
vec4 ch_T = vec4(0x00FCB4,0x303030,0x303030,0x780000);
|
||||
vec4 ch_U = vec4(0x00CCCC,0xCCCCCC,0xCCCCCC,0x780000);
|
||||
vec4 ch_V = vec4(0x00CCCC,0xCCCCCC,0xCCCC78,0x300000);
|
||||
vec4 ch_W = vec4(0x00C6C6,0xC6C6D6,0xD66C6C,0x6C0000);
|
||||
vec4 ch_X = vec4(0x00CCCC,0xCC7830,0x78CCCC,0xCC0000);
|
||||
vec4 ch_Y = vec4(0x00CCCC,0xCCCC78,0x303030,0x780000);
|
||||
vec4 ch_Z = vec4(0x00FECE,0x981830,0x6062C6,0xFE0000);
|
||||
vec4 ch_lsb = vec4(0x003C30,0x303030,0x303030,0x3C0000);
|
||||
vec4 ch_rsl = vec4(0x000080,0xC06030,0x180C06,0x020000);
|
||||
vec4 ch_rsb = vec4(0x003C0C,0x0C0C0C,0x0C0C0C,0x3C0000);
|
||||
vec4 ch_pow = vec4(0x10386C,0xC60000,0x000000,0x000000);
|
||||
vec4 ch_usc = vec4(0x000000,0x000000,0x000000,0x00FF00);
|
||||
vec4 ch_a = vec4(0x000000,0x00780C,0x7CCCCC,0x760000);
|
||||
vec4 ch_b = vec4(0x00E060,0x607C66,0x666666,0xDC0000);
|
||||
vec4 ch_c = vec4(0x000000,0x0078CC,0xC0C0CC,0x780000);
|
||||
vec4 ch_d = vec4(0x001C0C,0x0C7CCC,0xCCCCCC,0x760000);
|
||||
vec4 ch_e = vec4(0x000000,0x0078CC,0xFCC0CC,0x780000);
|
||||
vec4 ch_f = vec4(0x00386C,0x6060F8,0x606060,0xF00000);
|
||||
vec4 ch_g = vec4(0x000000,0x0076CC,0xCCCC7C,0x0CCC78);
|
||||
vec4 ch_h = vec4(0x00E060,0x606C76,0x666666,0xE60000);
|
||||
vec4 ch_i = vec4(0x001818,0x007818,0x181818,0x7E0000);
|
||||
vec4 ch_j = vec4(0x000C0C,0x003C0C,0x0C0C0C,0xCCCC78);
|
||||
vec4 ch_k = vec4(0x00E060,0x60666C,0x786C66,0xE60000);
|
||||
vec4 ch_l = vec4(0x007818,0x181818,0x181818,0x7E0000);
|
||||
vec4 ch_m = vec4(0x000000,0x00FCD6,0xD6D6D6,0xC60000);
|
||||
vec4 ch_n = vec4(0x000000,0x00F8CC,0xCCCCCC,0xCC0000);
|
||||
vec4 ch_o = vec4(0x000000,0x0078CC,0xCCCCCC,0x780000);
|
||||
vec4 ch_p = vec4(0x000000,0x00DC66,0x666666,0x7C60F0);
|
||||
vec4 ch_q = vec4(0x000000,0x0076CC,0xCCCCCC,0x7C0C1E);
|
||||
vec4 ch_r = vec4(0x000000,0x00EC6E,0x766060,0xF00000);
|
||||
vec4 ch_s = vec4(0x000000,0x0078CC,0x6018CC,0x780000);
|
||||
vec4 ch_t = vec4(0x000020,0x60FC60,0x60606C,0x380000);
|
||||
vec4 ch_u = vec4(0x000000,0x00CCCC,0xCCCCCC,0x760000);
|
||||
vec4 ch_v = vec4(0x000000,0x00CCCC,0xCCCC78,0x300000);
|
||||
vec4 ch_w = vec4(0x000000,0x00C6C6,0xD6D66C,0x6C0000);
|
||||
vec4 ch_x = vec4(0x000000,0x00C66C,0x38386C,0xC60000);
|
||||
vec4 ch_y = vec4(0x000000,0x006666,0x66663C,0x0C18F0);
|
||||
vec4 ch_z = vec4(0x000000,0x00FC8C,0x1860C4,0xFC0000);
|
||||
vec4 ch_lpa = vec4(0x001C30,0x3060C0,0x603030,0x1C0000);
|
||||
vec4 ch_bar = vec4(0x001818,0x181800,0x181818,0x180000);
|
||||
vec4 ch_rpa = vec4(0x00E030,0x30180C,0x183030,0xE00000);
|
||||
vec4 ch_tid = vec4(0x0073DA,0xCE0000,0x000000,0x000000);
|
||||
vec4 ch_lar = vec4(0x000000,0x10386C,0xC6C6FE,0x000000);
|
||||
|
||||
vec2 res = vec2(0);
|
||||
vec2 print_pos = vec2(0);
|
||||
|
||||
//Extracts bit b from the given number.
|
||||
//Shifts bits right (num / 2^bit) then ANDs the result with 1 (mod(result,2.0)).
|
||||
float extract_bit(float n, float b)
|
||||
{
|
||||
b = clamp(b,-1.0,24.0);
|
||||
return floor(mod(floor(n / pow(2.0,floor(b))),2.0));
|
||||
}
|
||||
|
||||
//Returns the pixel at uv in the given bit-packed sprite.
|
||||
float sprite(vec4 spr, vec2 size, vec2 uv)
|
||||
{
|
||||
uv = floor(uv);
|
||||
|
||||
//Calculate the bit to extract (x + y * width) (flipped on x-axis)
|
||||
float bit = (size.x-uv.x-1.0) + uv.y * size.x;
|
||||
|
||||
//Clipping bound to remove garbage outside the sprite's boundaries.
|
||||
bool bounds = all(greaterThanEqual(uv,vec2(0))) && all(lessThan(uv,size));
|
||||
|
||||
float pixels = 0.0;
|
||||
pixels += extract_bit(spr.x, bit - 72.0);
|
||||
pixels += extract_bit(spr.y, bit - 48.0);
|
||||
pixels += extract_bit(spr.z, bit - 24.0);
|
||||
pixels += extract_bit(spr.w, bit - 00.0);
|
||||
|
||||
return bounds ? pixels : 0.0;
|
||||
}
|
||||
|
||||
//Prints a character and moves the print position forward by 1 character width.
|
||||
float char_(vec4 ch, vec2 uv)
|
||||
{
|
||||
if( TEXT_MODE == INVERT )
|
||||
{
|
||||
//Inverts all of the bits in the character.
|
||||
ch = pow(2.0,24.0)-1.0-ch;
|
||||
}
|
||||
if( TEXT_MODE == UNDERLINE )
|
||||
{
|
||||
//Makes the bottom 8 bits all 1.
|
||||
//Shifts the bottom chunk right 8 bits to drop the lowest 8 bits,
|
||||
//then shifts it left 8 bits and adds 255 (binary 11111111).
|
||||
ch.w = floor(ch.w/256.0)*256.0 + 255.0;
|
||||
}
|
||||
|
||||
float px = sprite(ch, CHAR_SIZE, uv - print_pos);
|
||||
print_pos.x += CHAR_SPACING.x;
|
||||
return px;
|
||||
}
|
||||
|
||||
|
||||
//Returns the digit sprite for the given number.
|
||||
vec4 get_digit(float d)
|
||||
{
|
||||
d = floor(d);
|
||||
|
||||
if(d == 0.0) return ch_0;
|
||||
if(d == 1.0) return ch_1;
|
||||
if(d == 2.0) return ch_2;
|
||||
if(d == 3.0) return ch_3;
|
||||
if(d == 4.0) return ch_4;
|
||||
if(d == 5.0) return ch_5;
|
||||
if(d == 6.0) return ch_6;
|
||||
if(d == 7.0) return ch_7;
|
||||
if(d == 8.0) return ch_8;
|
||||
if(d == 9.0) return ch_9;
|
||||
return vec4(0.0);
|
||||
}
|
||||
|
||||
//Prints out the given number starting at pos.
|
||||
float print_number(float number, vec2 uv)
|
||||
{
|
||||
float result = 0.0;
|
||||
|
||||
for(int i = 3;i >= -1;i--)
|
||||
{
|
||||
float digit = mod( number / pow(10.0, float(i)) , 10.0);
|
||||
|
||||
if(i == -1) //Add a decimal point.
|
||||
{
|
||||
result += char_(ch_per,uv);
|
||||
}
|
||||
|
||||
if(abs(number) > pow(10.0, float(i)) || i == 0) //Clip off leading zeros.
|
||||
{
|
||||
result += char_(get_digit(digit),uv);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
float print_integer(float number, int zeros, vec2 uv)
|
||||
{
|
||||
float result = 0.0;
|
||||
|
||||
for(int i = MAX_INT_DIGITS;i >= 0;i--)
|
||||
{
|
||||
float digit = mod( number / pow(10.0, float(i)) , 10.0);
|
||||
|
||||
if(abs(number) > pow(10.0, float(i)) || zeros > i || i == 0) //Clip off leading zeros.
|
||||
{
|
||||
result += char_(get_digit(digit),uv);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
float text(vec2 uv)
|
||||
{
|
||||
float col = 0.0;
|
||||
|
||||
vec2 center = res/2.0;
|
||||
|
||||
float hour = floor(iDate.w/60.0/60.0);
|
||||
float minute = floor(mod(iDate.w/60.0,60.0));
|
||||
float second = floor(mod(iDate.w,60.0));
|
||||
|
||||
//Greeting Text
|
||||
|
||||
print_pos = floor(center - vec2(STRWIDTH(17.0),STRHEIGHT(1.0))/2.0);
|
||||
|
||||
col += char_(ch_H,uv);
|
||||
col += char_(ch_e,uv);
|
||||
col += char_(ch_l,uv);
|
||||
col += char_(ch_l,uv);
|
||||
col += char_(ch_o,uv);
|
||||
col += char_(ch_com,uv);
|
||||
|
||||
col += char_(ch_spc,uv);
|
||||
|
||||
col += char_(ch_S,uv);
|
||||
col += char_(ch_h,uv);
|
||||
col += char_(ch_a,uv);
|
||||
col += char_(ch_d,uv);
|
||||
col += char_(ch_e,uv);
|
||||
col += char_(ch_r,uv);
|
||||
col += char_(ch_t,uv);
|
||||
col += char_(ch_o,uv);
|
||||
col += char_(ch_y,uv);
|
||||
col += char_(ch_exc,uv);
|
||||
|
||||
//Date Text
|
||||
|
||||
print_pos = vec2(2, 2.0 + STRHEIGHT(2.0));
|
||||
|
||||
TEXT_MODE = INVERT;
|
||||
col += char_(ch_D,uv);
|
||||
col += char_(ch_a,uv);
|
||||
col += char_(ch_t,uv);
|
||||
col += char_(ch_e,uv);
|
||||
|
||||
TEXT_MODE = NORMAL;
|
||||
col += char_(ch_col,uv);
|
||||
|
||||
TEXT_MODE = UNDERLINE;
|
||||
col += print_integer(iDate.z,2,uv);
|
||||
col += char_(ch_lsl,uv);
|
||||
col += print_integer(iDate.y+1.0,2,uv);
|
||||
col += char_(ch_lsl,uv);
|
||||
col += print_integer(iDate.x,4,uv);
|
||||
|
||||
//Time Text
|
||||
|
||||
print_pos = vec2(2, 2.0 + STRHEIGHT(1.0));
|
||||
|
||||
TEXT_MODE = INVERT;
|
||||
col += char_(ch_T, uv);
|
||||
col += char_(ch_i, uv);
|
||||
col += char_(ch_m, uv);
|
||||
col += char_(ch_e, uv);
|
||||
|
||||
TEXT_MODE = NORMAL;
|
||||
col += char_(ch_col, uv);
|
||||
|
||||
TEXT_MODE = UNDERLINE;
|
||||
|
||||
col += print_integer(hour,2, uv);
|
||||
col += char_(ch_col, uv);
|
||||
col += print_integer(minute,2, uv);
|
||||
col += char_(ch_col, uv);
|
||||
col += print_integer(second,2, uv);
|
||||
|
||||
//Resolution Text
|
||||
|
||||
print_pos = vec2(2, 2.0 + STRHEIGHT(0.0));
|
||||
|
||||
TEXT_MODE = INVERT;
|
||||
col += char_(ch_R,uv);
|
||||
col += char_(ch_e,uv);
|
||||
col += char_(ch_s,uv);
|
||||
col += char_(ch_o,uv);
|
||||
col += char_(ch_l,uv);
|
||||
col += char_(ch_u,uv);
|
||||
col += char_(ch_t,uv);
|
||||
col += char_(ch_i,uv);
|
||||
col += char_(ch_o,uv);
|
||||
col += char_(ch_n,uv);
|
||||
|
||||
TEXT_MODE = NORMAL;
|
||||
col += char_(ch_col,uv);
|
||||
|
||||
TEXT_MODE = UNDERLINE;
|
||||
col += print_integer(iResolution.x,0,uv);
|
||||
col += char_(ch_x,uv);
|
||||
col += print_integer(iResolution.y,0,uv);
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
res = iResolution.xy / DOWN_SCALE;
|
||||
vec2 uv = fragCoord.xy / DOWN_SCALE;
|
||||
vec2 duv = floor(fragCoord.xy / DOWN_SCALE);
|
||||
|
||||
float pixel = text(duv);
|
||||
|
||||
//Shading stuff
|
||||
vec3 col = vec3(1);
|
||||
col *= (1.-distance(mod(uv,vec2(1.0)),vec2(0.65)))*1.2;
|
||||
col *= mix(vec3(0.2),vec3(0,1,0),pixel);
|
||||
|
||||
fragColor = vec4(vec3(col), 1.0);
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
// cube02_0.jpg
|
||||
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
|
||||
// Created by S. Guillitte 2015
|
||||
|
||||
float zoom=1.;
|
||||
|
||||
vec2 cmul( vec2 a, vec2 b ) { return vec2( a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x ); }
|
||||
vec2 csqr( vec2 a ) { return vec2( a.x*a.x - a.y*a.y, 2.*a.x*a.y ); }
|
||||
|
||||
|
||||
mat2 rot(float a) {
|
||||
return mat2(cos(a),sin(a),-sin(a),cos(a));
|
||||
}
|
||||
|
||||
vec2 iSphere( in vec3 ro, in vec3 rd, in vec4 sph )//from iq
|
||||
{
|
||||
vec3 oc = ro - sph.xyz;
|
||||
float b = dot( oc, rd );
|
||||
float c = dot( oc, oc ) - sph.w*sph.w;
|
||||
float h = b*b - c;
|
||||
if( h<0.0 ) return vec2(-1.0);
|
||||
h = sqrt(h);
|
||||
return vec2(-b-h, -b+h );
|
||||
}
|
||||
|
||||
float map(in vec3 p) {
|
||||
|
||||
float res = 0.;
|
||||
|
||||
vec3 c = p;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
p =.7*abs(p)/dot(p,p) -.7;
|
||||
p.yz= csqr(p.yz);
|
||||
p=p.zxy;
|
||||
res += exp(-19. * abs(dot(p,c)));
|
||||
|
||||
}
|
||||
return res/2.;
|
||||
}
|
||||
|
||||
|
||||
|
||||
vec3 raymarch( in vec3 ro, vec3 rd, vec2 tminmax )
|
||||
{
|
||||
float t = tminmax.x;
|
||||
float dt = .02;
|
||||
//float dt = .2 - .195*cos(iGlobalTime*.05);//animated
|
||||
vec3 col= vec3(0.);
|
||||
float c = 0.;
|
||||
for( int i=0; i<64; i++ )
|
||||
{
|
||||
t+=dt*exp(-2.*c);
|
||||
if(t>tminmax.y)break;
|
||||
vec3 pos = ro+t*rd;
|
||||
|
||||
c = map(ro+t*rd);
|
||||
|
||||
col = .99*col+ .08*vec3(c*c, c, c*c*c);//green
|
||||
//col = .99*col+ .08*vec3(c*c*c, c*c, c);//blue
|
||||
}
|
||||
return col;
|
||||
}
|
||||
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
float time = iGlobalTime;
|
||||
vec2 q = fragCoord.xy / iResolution.xy;
|
||||
vec2 p = -1.0 + 2.0 * q;
|
||||
p.x *= iResolution.x/iResolution.y;
|
||||
vec2 m = vec2(0.);
|
||||
if( iMouse.z>0.0 )m = iMouse.xy/iResolution.xy*3.14;
|
||||
m-=.5;
|
||||
|
||||
// camera
|
||||
|
||||
vec3 ro = zoom*vec3(4.);
|
||||
ro.yz*=rot(m.y);
|
||||
ro.xz*=rot(m.x+ 0.1*time);
|
||||
vec3 ta = vec3( 0.0 , 0.0, 0.0 );
|
||||
vec3 ww = normalize( ta - ro );
|
||||
vec3 uu = normalize( cross(ww,vec3(0.0,1.0,0.0) ) );
|
||||
vec3 vv = normalize( cross(uu,ww));
|
||||
vec3 rd = normalize( p.x*uu + p.y*vv + 4.0*ww );
|
||||
|
||||
|
||||
vec2 tmm = iSphere( ro, rd, vec4(0.,0.,0.,2.) );
|
||||
|
||||
// raymarch
|
||||
vec3 col = raymarch(ro,rd,tmm);
|
||||
if (tmm.x<0.)col = texture(iChannel0, rd.rg).rgb;
|
||||
else {
|
||||
vec3 nor=(ro+tmm.x*rd)/2.;
|
||||
nor = reflect(rd, nor);
|
||||
float fre = pow(.5+ clamp(dot(nor,rd),0.0,1.0), 3. )*1.3;
|
||||
col += texture(iChannel0, nor.rg).rgb * fre;
|
||||
|
||||
}
|
||||
|
||||
// shade
|
||||
|
||||
col = .5 *(log(1.+col));
|
||||
col = clamp(col,0.,1.);
|
||||
fragColor = vec4( col, 1.0 );
|
||||
|
||||
}
|
|
@ -0,0 +1,396 @@
|
|||
// stone.jpg
|
||||
// Abandoned base. Created by Reinder Nijhoff 2014
|
||||
// @reindernijhoff
|
||||
//
|
||||
// https://www.shadertoy.com/view/XsSSRW
|
||||
//
|
||||
|
||||
// #define GOLD
|
||||
#define BUMPMAP
|
||||
#define MARCHSTEPS 128
|
||||
#define MARCHSTEPSREFLECTION 64
|
||||
#define SPHERE
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
const vec2 dropPosition = vec2(1.05,2.1);
|
||||
const vec3 backgroundColor = vec3(0.9,0.5,0.2);
|
||||
#define time iGlobalTime
|
||||
#define stime2 sin(time*2.)
|
||||
#define ctime2 cos(time*2.)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// noises
|
||||
|
||||
float hash( float n ) {
|
||||
return fract(sin(n)*43758.5453123);
|
||||
}
|
||||
|
||||
float noise( in vec2 x ) {
|
||||
vec2 p = floor(x);
|
||||
vec2 f = fract(x);
|
||||
f = f*f*(3.0-2.0*f);
|
||||
float n = p.x + p.y*157.0;
|
||||
return mix(mix( hash(n+ 0.0), hash(n+ 1.0),f.x),
|
||||
mix( hash(n+157.0), hash(n+158.0),f.x),f.y);
|
||||
}
|
||||
|
||||
const mat2 m2 = mat2( 0.80, -0.60, 0.60, 0.80 );
|
||||
|
||||
float fbm( vec2 p ) {
|
||||
float f = 0.0;
|
||||
f += 0.5000*noise( p ); p = m2*p*2.02;
|
||||
f += 0.2500*noise( p ); p = m2*p*2.03;
|
||||
f += 0.1250*noise( p ); p = m2*p*2.01;
|
||||
f += 0.0625*noise( p );
|
||||
|
||||
return f/0.9375;
|
||||
}
|
||||
|
||||
mat2 rot(const in float a) {
|
||||
return mat2(cos(a),sin(a),-sin(a),cos(a));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// distance primitives
|
||||
|
||||
float sdBox( in vec3 p, in vec3 b ) {
|
||||
vec3 d = abs(p) - b;
|
||||
return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));
|
||||
}
|
||||
|
||||
float sdSphere( in vec3 p, in float s ) {
|
||||
return length(p)-s;
|
||||
}
|
||||
|
||||
float sdCylinder( in vec3 p, in vec2 h ) {
|
||||
vec2 d = abs(vec2(length(p.xz),p.y)) - h;
|
||||
return min(max(d.x,d.y),0.0) + length(max(d,0.0));
|
||||
}
|
||||
|
||||
float sdPipe( in vec3 p, in vec3 h ) {
|
||||
return length(h.xy-p.xy) - h.z;
|
||||
}
|
||||
|
||||
float sdPPipe( in vec3 p, in vec3 h ) {
|
||||
return length(h.xy-p.xy) - h.z - 0.02*(max(sin(p.z*20.)-0.8,0.));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// distance operators
|
||||
|
||||
float opU( float d2, float d1 ) { return min( d1,d2); }
|
||||
float opS( float d2, float d1 ) { return max(-d1,d2); }
|
||||
vec2 opU( vec2 d2, vec2 d1 ) { return mix(d1,d2,step(d2.x,d1.x)); }//( d2.x<d1.x)? d2:d1; }
|
||||
vec2 opS( vec2 d2, vec2 d1 ) { return mix(-d1,d2,step(-d1.x,d2.x)); }//(-d1.x>d2.x)?-d1:d2; }
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Map functions
|
||||
|
||||
#ifdef SPHERE
|
||||
vec3 sP;
|
||||
#endif
|
||||
|
||||
float xoffset( float z) {
|
||||
return 2.1*sin(z*0.1);
|
||||
}
|
||||
|
||||
vec2 getSectorId( float z ) {
|
||||
float id = floor( (z+6.)/12.);
|
||||
return vec2( id, hash(id) );
|
||||
}
|
||||
|
||||
float map( vec3 p ) {
|
||||
float zorig = p.z;
|
||||
p = vec3( p.x+xoffset(p.z), p.y-2., mod( p.z + 6., 12. ) - 6.);
|
||||
|
||||
float x = p.x*2., y = p.y-0.8, z = p.z;
|
||||
float d = -sdBox( vec3((x+y)*0.7071, (y-x)*0.7071, z), vec3(3.8,3.8,20.) );
|
||||
|
||||
d = opS( d, sdBox( p, vec3( 2.5, 2., 5.75 ) ) );
|
||||
d = opU( d, sdPPipe( vec3(abs(p.x),p.y,p.z), vec3( 2.2, -1.7, 0.25 ) ) );
|
||||
d = opU( d, sdPipe( vec3(p.x,abs(p.y-0.2),p.z), vec3( 2.4, 1.5, 0.1 ) ) );
|
||||
d = opU( d, sdPipe( vec3(p.x,p.y+0.6*cos(p.z*3.1415926/12.),p.z), vec3( -2.4, 1.8, 0.12 ) ) );
|
||||
|
||||
d = opU( d, 2.2-p.y );
|
||||
float l = distance( p.xz, dropPosition );
|
||||
p.y += 0.003*sin(40.*l-6.*time)*exp(-4.*l);
|
||||
|
||||
d = opU( d, p.y+2.03 );
|
||||
d = opU( d, sdSphere( vec3( p.x, p.y-2.3, p.z*0.3), 0.2) );
|
||||
|
||||
if( getSectorId(zorig).y > 0.75 ) {
|
||||
d = opS( d, sdCylinder( vec3(p.x, p.y-9., p.z), vec2(1.5,10.) ) );
|
||||
|
||||
vec3 pr = vec3( stime2*p.x+ctime2*p.z, p.y-2.4, stime2*p.z-ctime2*p.x);
|
||||
d = opU( d, sdBox( pr, vec3(3.0,0.1,0.1) ) );
|
||||
d = opU( d, sdBox( pr, vec3(0.1,0.1,3.0) ) );
|
||||
}
|
||||
#ifdef SPHERE
|
||||
d = opU( d, sdSphere( vec3( p.x, p.y, zorig)-sP, 0.2) );
|
||||
#endif
|
||||
return d;
|
||||
}
|
||||
|
||||
float mapMaterial( vec3 p ) {
|
||||
float zorig = p.z;
|
||||
p = vec3( p.x+xoffset(p.z), p.y-2., mod( p.z + 6., 12. ) - 6.);
|
||||
|
||||
float x = p.x*2., y = p.y-0.8, z = p.z;
|
||||
vec2 d = vec2( -sdBox( vec3((x+y)*0.7071, (y-x)*0.7071, z), vec3(3.8,3.8,20.) ), 5.);
|
||||
|
||||
d = opS( d, vec2( sdBox( p, vec3( 2.5, 2., 5.75 ) ), 3. ) );
|
||||
d = opU( d, vec2( sdPPipe( vec3(abs(p.x),p.y,p.z), vec3( 2.2, -1.7, 0.25 ) ), 1. ) );
|
||||
d = opU( d, vec2( sdPipe( vec3(p.x,abs(p.y-0.2),p.z), vec3( 2.4, 1.5, 0.1 ) ), 4. ) );
|
||||
d = opU( d, vec2( sdPipe( vec3(p.x,p.y+0.6*cos(p.z*3.1415926/12.),p.z), vec3( -2.4, 1.8, 0.12 ) ), 4. ) );
|
||||
|
||||
|
||||
d = opU( d, vec2( 2.2-p.y, 5. ) );
|
||||
d = opU( d, vec2( p.y+2.03, 2. ) );
|
||||
d = opU( d, vec2( sdSphere( vec3( p.x, p.y-2.3, p.z*0.3), 0.2), 6.) );
|
||||
|
||||
if( getSectorId(zorig).y > 0.75 ) {
|
||||
d = opS( d, vec2( sdCylinder( vec3(p.x, p.y-4., p.z), vec2(1.5,2.) ), 5.) );
|
||||
|
||||
vec3 pr = vec3( stime2*p.x+ctime2*p.z, p.y-2.4, stime2*p.z-ctime2*p.x);
|
||||
d = opU( d, vec2( sdBox( pr, vec3(3.0,0.1,0.1) ), 4.) );
|
||||
d = opU( d, vec2( sdBox( pr, vec3(0.1,0.1,3.0) ), 4.) );
|
||||
}
|
||||
|
||||
#ifdef SPHERE
|
||||
d = opU( d, vec2( sdSphere( vec3( p.x, p.y, zorig)-sP, 0.2), 7.) );
|
||||
#endif
|
||||
|
||||
return abs(d.y);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
vec3 calcNormal( in vec3 pos ) {
|
||||
const vec2 e = vec2(1.0,-1.0)*0.005;
|
||||
|
||||
vec3 n = normalize( e.xyy*map( pos + e.xyy ) +
|
||||
e.yyx*map( pos + e.yyx ) +
|
||||
e.yxy*map( pos + e.yxy ) +
|
||||
e.xxx*map( pos + e.xxx ) );
|
||||
|
||||
#ifdef BUMPMAP
|
||||
vec3 p = pos * 20.;
|
||||
if( abs(pos.x+xoffset(pos.z))>2.48 )n = normalize( n + 0.1*vec3(0.,fbm(p.yz)-0.5,fbm(p.zy)-0.5));
|
||||
#endif
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
vec3 int1, int2;
|
||||
|
||||
float intersect( in vec3 ro, in vec3 rd ) {
|
||||
const float maxd = 60.0;
|
||||
const float precis = 0.001;
|
||||
float h = precis*2.0;
|
||||
float t = 0.;
|
||||
int1.z = -1.;
|
||||
|
||||
for( int i=0; i < MARCHSTEPS; i++ ) {
|
||||
if( h < precis ) {
|
||||
int1 = ro+rd*t;
|
||||
break;
|
||||
}
|
||||
h = map( ro+rd*t );
|
||||
t += h;
|
||||
}
|
||||
if( int1.z < 0. ) return -1.;
|
||||
|
||||
ro = ro + rd*t;
|
||||
vec3 nor = calcNormal(ro);
|
||||
rd = reflect( rd, nor );
|
||||
ro += 0.1 * nor;
|
||||
t = 0.0;
|
||||
h = precis*2.0;
|
||||
|
||||
for( int i=0; i < MARCHSTEPSREFLECTION; i++ ) {
|
||||
if( h < precis ) {
|
||||
int2 = ro+rd*t;
|
||||
return 1.;
|
||||
}
|
||||
h = map( ro+rd*t );
|
||||
t += h;
|
||||
}
|
||||
|
||||
return 0.;
|
||||
}
|
||||
|
||||
float softshadow( in vec3 ro, in vec3 rd, in float mint, in float maxt, in float k ) {
|
||||
float res = 1.0;
|
||||
float t = mint;
|
||||
for( int i=0; i<16; i++ ) {
|
||||
if( t>maxt ) break;
|
||||
float h = map( ro + rd*t );
|
||||
res = min( res, k*h/t );
|
||||
t += 0.03 + h;
|
||||
}
|
||||
return clamp( res, 0.0, 1.0 );
|
||||
|
||||
}
|
||||
|
||||
float calcOcc( in vec3 pos, in vec3 nor ) {
|
||||
float totao = 0.0;
|
||||
float sca = 1.0;
|
||||
for( int i=0; i<5; i++ )
|
||||
{
|
||||
float h = 0.02 + float(i)/4.0;
|
||||
float d = map( pos + h*nor );
|
||||
totao += clamp(h-d,0.0,1.0)*sca;
|
||||
sca *= 0.4;
|
||||
}
|
||||
return clamp( 1.0 - 2.0*totao, 0.0, 1.0 );
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// shade
|
||||
|
||||
vec4 texcube( sampler2D sam, in vec3 p, in vec3 n )
|
||||
{
|
||||
vec4 x = texture( sam, p.yz );
|
||||
vec4 y = texture( sam, p.zx );
|
||||
vec4 z = texture( sam, p.xy );
|
||||
return x*abs(n.x) + y*abs(n.y) + z*abs(n.z);
|
||||
}
|
||||
|
||||
float calcLightning( in vec3 pos, in vec3 light, in vec3 nor, in float maxDist, in bool shadow ) {
|
||||
float sh = 1.;
|
||||
vec3 lig = ( light-pos );
|
||||
float im = length( lig );
|
||||
lig /= im;
|
||||
if(shadow) sh = softshadow( pos, lig, 1.02, im, 32.0 );
|
||||
sh /= im;
|
||||
sh *= clamp(dot(nor,lig),0.,1.);
|
||||
return sh * (1.-smoothstep(0.,maxDist,im));
|
||||
}
|
||||
|
||||
vec3 shade( in vec3 ro, in vec3 pos, in bool shadow, in float m, in float r ) {
|
||||
vec3 light, col = vec3(0.);
|
||||
vec3 nor = calcNormal(pos);
|
||||
|
||||
vec2 id = getSectorId(pos.z);
|
||||
|
||||
float occ = calcOcc( pos, nor );
|
||||
float dist, sh = 1., xo = xoffset(pos.z);
|
||||
|
||||
float rc = hash(id.x+43.);
|
||||
float gc = hash(id.x+153.);
|
||||
vec3 lc = normalize(vec3( max(rc,gc), min(rc,gc), 0.1 ) );
|
||||
|
||||
if( id.y > 0.75 ) {
|
||||
light = vec3( -xo, 6.5, id*12. );
|
||||
light.xz += vec2( hash(id.x+56423.), hash(id.x+124.) ) - 0.5;
|
||||
sh = 8.;
|
||||
dist = 8.;
|
||||
} else {
|
||||
light = vec3( -xo, 3.9, id*12. );
|
||||
sh = 3.;
|
||||
dist = 5.3;
|
||||
if( hash(id.x+234.) < 0.15 ) lc *= 1.-clamp( 10.*(fbm( vec2(time*10., id.x) )-2.5*id.y), 0., 1.);
|
||||
if( pos.y > 4. ) sh*=0.5;
|
||||
}
|
||||
|
||||
sh *= calcLightning( pos, light, nor, dist, shadow );
|
||||
|
||||
|
||||
if( m < 6.5 ) col = texcube( iChannel0, pos*0.5, nor ).xyz;
|
||||
if( m == 1. ) col *= 0.05;
|
||||
if( m == 4. && pos.y > 2. ) col *= vec3(0.1,0.,0.);
|
||||
if( m == 4. && pos.y < 2. ) col *= vec3(0.1,0.4,1.2);
|
||||
|
||||
if( m == 5. ) col *= (1.+0.5*fbm(pos.yz*2.))*vec3(0.2,0.1,0.05);
|
||||
if( m == 2. ) col *= vec3(0.8,0.6,0.4);
|
||||
|
||||
col *= lc * occ * sh;
|
||||
|
||||
if( m == 6. ) col = mix( 0.1*col, col*fbm(pos.xz*10.) + 0.8*lc,
|
||||
(1.-smoothstep( 4.15, 4.2,pos.y)) *
|
||||
smoothstep( 0.01, 0.04,abs(mod(pos.z+0.15,0.3)-0.15)) *
|
||||
smoothstep( 0.01, 0.02,abs(pos.x+xo)));
|
||||
|
||||
col *= clamp(1.-2.*r, 0.65, 1.);
|
||||
|
||||
col = mix( 0.05*backgroundColor, col, exp( -0.04*distance(pos, ro) ) );
|
||||
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// main
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
|
||||
vec2 q = fragCoord.xy / iResolution.xy;
|
||||
vec2 p = -1.0 + 2.0*q;
|
||||
p.x *= iResolution.x / iResolution.y;
|
||||
|
||||
if (q.y < .12 || q.y >= .88) {
|
||||
fragColor=vec4(0.,0.,0.,1.);
|
||||
return;
|
||||
}
|
||||
|
||||
// camera
|
||||
float o = 0.2*noise(vec2(time,0.));
|
||||
float z = 2.*time+o;
|
||||
float x = -0.95*xoffset(z);
|
||||
vec3 ro = vec3(x,1.7+0.02*sin(time*1.13*2.*3.1415926+o), z-1.);
|
||||
vec3 ta = vec3(x,1.7, z+5.);
|
||||
|
||||
#ifdef SPHERE
|
||||
sP = vec3(sin(time), 1.6*cos(time*0.4), ro.z+9.+6.*sin(time*0.15) );
|
||||
// ta = mix(ta,sP+vec3(0.,2.,0.),0.2);
|
||||
#endif
|
||||
|
||||
if (iMouse.z>=1.) {
|
||||
ta.yz *= rot( -(0.5-iMouse.y/iResolution.y)*0.15 );
|
||||
ta.xz *= rot( -(0.5-iMouse.x/iResolution.x)*0.5 );
|
||||
}
|
||||
|
||||
vec3 ww = normalize( ta - ro );
|
||||
vec3 uu = normalize( cross(ww,vec3(0.0,1.0,0.0) ) );
|
||||
vec3 vv = normalize( cross(uu,ww));
|
||||
vec3 rd = normalize( -p.x*uu + p.y*vv + 2.2*ww );
|
||||
|
||||
vec3 col = 0.035*backgroundColor;
|
||||
|
||||
// raymarch
|
||||
float ints = intersect(ro ,rd );
|
||||
if( ints > -0.5 ) {
|
||||
float m = mapMaterial(int1);
|
||||
|
||||
#ifdef GOLD
|
||||
float r = .8;
|
||||
#else
|
||||
float xo = xoffset(int1.z);
|
||||
vec3 p = vec3( int1.x+xo, int1.y-2., mod( int1.z + 6., 12. ) - 6.);
|
||||
float l = m == 2.?exp(-2.*distance( p.xz, dropPosition )):0.;
|
||||
|
||||
float r = 0.6 * clamp(2.*(fbm( int1.xz )-0.6+l), 0.0125, 1.)*clamp(2.-int1.y, 0., 1.);
|
||||
if(m == 1.) r = 0.05+0.3 * fbm( int1.xz * 20. );
|
||||
if(m == 7.) r = .8;
|
||||
|
||||
if(abs(int1.x+xo) > 2.49) {
|
||||
r = fbm(int1.yz*0.5)*0.4*
|
||||
clamp(2.*(fbm( int1.yz*vec2(3.2,24.)+vec2(0.5*time,0.) )-0.5+l), 0.0, 1.)
|
||||
*clamp(0.5*int1.y, 0., 1.);
|
||||
}
|
||||
if(m == 4.) { r = 0.1; }
|
||||
#endif
|
||||
col = shade( ro, int1.xyz, true, m, r );
|
||||
|
||||
if( ints > 0.5 ) {
|
||||
col += r * shade( int1.xyz, int2.xyz, false, mapMaterial(int2), 0. );
|
||||
}
|
||||
}
|
||||
|
||||
// gamma
|
||||
col = pow( clamp(col*2.,0.0,1.0), vec3(0.4545) );
|
||||
col *= 1.2*vec3(1.,0.99,0.95);
|
||||
col = clamp(1.06*col-0.03, 0., 1.);
|
||||
|
||||
fragColor = vec4( col, 1.0 );
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
float time=iGlobalTime*1.0;
|
||||
vec2 uv = (fragCoord.xy / iResolution.xx-0.5)*8.0;
|
||||
vec2 uv0=uv;
|
||||
float i0=1.0;
|
||||
float i1=1.0;
|
||||
float i2=1.0;
|
||||
float i4=0.0;
|
||||
for(int s=0;s<7;s++)
|
||||
{
|
||||
vec2 r;
|
||||
r=vec2(cos(uv.y*i0-i4+time/i1),sin(uv.x*i0-i4+time/i1))/i2;
|
||||
r+=vec2(-r.y,r.x)*0.3;
|
||||
uv.xy+=r;
|
||||
|
||||
i0*=1.93;
|
||||
i1*=1.15;
|
||||
i2*=1.7;
|
||||
i4+=0.05+0.1*time*i1;
|
||||
}
|
||||
float r=sin(uv.x-time)*0.5+0.5;
|
||||
float b=sin(uv.y+time)*0.5+0.5;
|
||||
float g=sin((uv.x+uv.y+sin(time*0.5))*0.5)*0.5+0.5;
|
||||
fragColor = vec4(r,g,b,1.0);
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
//noise3.jpg
|
||||
//Plasma Globe by nimitz (twitter: @stormoid)
|
||||
|
||||
//looks best with around 25 rays
|
||||
#define NUM_RAYS 13.
|
||||
|
||||
#define VOLUMETRIC_STEPS 19
|
||||
|
||||
#define MAX_ITER 35
|
||||
#define FAR 6.
|
||||
|
||||
#define time iGlobalTime*1.1
|
||||
|
||||
|
||||
mat2 mm2(in float a){float c = cos(a), s = sin(a);return mat2(c,-s,s,c);}
|
||||
float noise( in float x ){return textureLod(iChannel0, vec2(x*.01,1.),0.0).x;}
|
||||
|
||||
float hash( float n ){return fract(sin(n)*43758.5453);}
|
||||
|
||||
//iq's ubiquitous 3d noise
|
||||
float noise(in vec3 p)
|
||||
{
|
||||
vec3 ip = floor(p);
|
||||
vec3 f = fract(p);
|
||||
f = f*f*(3.0-2.0*f);
|
||||
|
||||
vec2 uv = (ip.xy+vec2(37.0,17.0)*ip.z) + f.xy;
|
||||
vec2 rg = textureLod( iChannel0, (uv+ 0.5)/256.0, 0.0 ).yx;
|
||||
return mix(rg.x, rg.y, f.z);
|
||||
}
|
||||
|
||||
mat3 m3 = mat3( 0.00, 0.80, 0.60,
|
||||
-0.80, 0.36, -0.48,
|
||||
-0.60, -0.48, 0.64 );
|
||||
|
||||
|
||||
//See: https://www.shadertoy.com/view/XdfXRj
|
||||
float flow(in vec3 p, in float t)
|
||||
{
|
||||
float z=2.;
|
||||
float rz = 0.;
|
||||
vec3 bp = p;
|
||||
for (float i= 1.;i < 5.;i++ )
|
||||
{
|
||||
p += time*.1;
|
||||
rz+= (sin(noise(p+t*0.8)*6.)*0.5+0.5) /z;
|
||||
p = mix(bp,p,0.6);
|
||||
z *= 2.;
|
||||
p *= 2.01;
|
||||
p*= m3;
|
||||
}
|
||||
return rz;
|
||||
}
|
||||
|
||||
//could be improved
|
||||
float sins(in float x)
|
||||
{
|
||||
float rz = 0.;
|
||||
float z = 2.;
|
||||
for (float i= 0.;i < 3.;i++ )
|
||||
{
|
||||
rz += abs(fract(x*1.4)-0.5)/z;
|
||||
x *= 1.3;
|
||||
z *= 1.15;
|
||||
x -= time*.65*z;
|
||||
}
|
||||
return rz;
|
||||
}
|
||||
|
||||
float segm( vec3 p, vec3 a, vec3 b)
|
||||
{
|
||||
vec3 pa = p - a;
|
||||
vec3 ba = b - a;
|
||||
float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1. );
|
||||
return length( pa - ba*h )*.5;
|
||||
}
|
||||
|
||||
vec3 path(in float i, in float d)
|
||||
{
|
||||
vec3 en = vec3(0.,0.,1.);
|
||||
float sns2 = sins(d+i*0.5)*0.22;
|
||||
float sns = sins(d+i*.6)*0.21;
|
||||
en.xz *= mm2((hash(i*10.569)-.5)*6.2+sns2);
|
||||
en.xy *= mm2((hash(i*4.732)-.5)*6.2+sns);
|
||||
return en;
|
||||
}
|
||||
|
||||
vec2 map(vec3 p, float i)
|
||||
{
|
||||
float lp = length(p);
|
||||
vec3 bg = vec3(0.);
|
||||
vec3 en = path(i,lp);
|
||||
|
||||
float ins = smoothstep(0.11,.46,lp);
|
||||
float outs = .15+smoothstep(.0,.15,abs(lp-1.));
|
||||
p *= ins*outs;
|
||||
float id = ins*outs;
|
||||
|
||||
float rz = segm(p, bg, en)-0.011;
|
||||
return vec2(rz,id);
|
||||
}
|
||||
|
||||
float march(in vec3 ro, in vec3 rd, in float startf, in float maxd, in float j)
|
||||
{
|
||||
float precis = 0.001;
|
||||
float h=0.5;
|
||||
float d = startf;
|
||||
for( int i=0; i<MAX_ITER; i++ )
|
||||
{
|
||||
if( abs(h)<precis||d>maxd ) break;
|
||||
d += h*1.2;
|
||||
float res = map(ro+rd*d, j).x;
|
||||
h = res;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
//volumetric marching
|
||||
vec3 vmarch(in vec3 ro, in vec3 rd, in float j, in vec3 orig)
|
||||
{
|
||||
vec3 p = ro;
|
||||
vec2 r = vec2(0.);
|
||||
vec3 sum = vec3(0);
|
||||
float w = 0.;
|
||||
for( int i=0; i<VOLUMETRIC_STEPS; i++ )
|
||||
{
|
||||
r = map(p,j);
|
||||
p += rd*.03;
|
||||
float lp = length(p);
|
||||
|
||||
vec3 col = sin(vec3(1.05,2.5,1.52)*3.94+r.y)*.85+0.4;
|
||||
col.rgb *= smoothstep(.0,.015,-r.x);
|
||||
col *= smoothstep(0.04,.2,abs(lp-1.1));
|
||||
col *= smoothstep(0.1,.34,lp);
|
||||
sum += abs(col)*5. * (1.2-noise(lp*2.+j*13.+time*5.)*1.1) / (log(distance(p,orig)-2.)+.75);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
//returns both collision dists of unit sphere
|
||||
vec2 iSphere2(in vec3 ro, in vec3 rd)
|
||||
{
|
||||
vec3 oc = ro;
|
||||
float b = dot(oc, rd);
|
||||
float c = dot(oc,oc) - 1.;
|
||||
float h = b*b - c;
|
||||
if(h <0.0) return vec2(-1.);
|
||||
else return vec2((-b - sqrt(h)), (-b + sqrt(h)));
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
vec2 p = fragCoord.xy/iResolution.xy-0.5;
|
||||
p.x*=iResolution.x/iResolution.y;
|
||||
vec2 um = iMouse.xy / iResolution.xy-.5;
|
||||
|
||||
//camera
|
||||
vec3 ro = vec3(0.,0.,5.);
|
||||
vec3 rd = normalize(vec3(p*.7,-1.5));
|
||||
mat2 mx = mm2(time*.4+um.x*6.);
|
||||
mat2 my = mm2(time*0.3+um.y*6.);
|
||||
ro.xz *= mx;rd.xz *= mx;
|
||||
ro.xy *= my;rd.xy *= my;
|
||||
|
||||
vec3 bro = ro;
|
||||
vec3 brd = rd;
|
||||
|
||||
vec3 col = vec3(0.0125,0.,0.025);
|
||||
#if 1
|
||||
for (float j = 1.;j<NUM_RAYS+1.;j++)
|
||||
{
|
||||
ro = bro;
|
||||
rd = brd;
|
||||
mat2 mm = mm2((time*0.1+((j+1.)*5.1))*j*0.25);
|
||||
ro.xy *= mm;rd.xy *= mm;
|
||||
ro.xz *= mm;rd.xz *= mm;
|
||||
float rz = march(ro,rd,2.5,FAR,j);
|
||||
if ( rz >= FAR)continue;
|
||||
vec3 pos = ro+rz*rd;
|
||||
col = max(col,vmarch(pos,rd,j, bro));
|
||||
}
|
||||
#endif
|
||||
|
||||
ro = bro;
|
||||
rd = brd;
|
||||
vec2 sph = iSphere2(ro,rd);
|
||||
|
||||
if (sph.x > 0.)
|
||||
{
|
||||
vec3 pos = ro+rd*sph.x;
|
||||
vec3 pos2 = ro+rd*sph.y;
|
||||
vec3 rf = reflect( rd, pos );
|
||||
vec3 rf2 = reflect( rd, pos2 );
|
||||
float nz = (-log(abs(flow(rf*1.2,time)-.01)));
|
||||
float nz2 = (-log(abs(flow(rf2*1.2,-time)-.01)));
|
||||
col += (0.1*nz*nz* vec3(0.12,0.12,.5) + 0.05*nz2*nz2*vec3(0.55,0.2,.55))*0.8;
|
||||
}
|
||||
|
||||
fragColor = vec4(col*1.3, 1.0);
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
// Auroras by nimitz 2017 (twitter: @stormoid)
|
||||
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
|
||||
// Contact the author for other licensing options
|
||||
|
||||
/*
|
||||
|
||||
There are two main hurdles I encountered rendering this effect.
|
||||
First, the nature of the texture that needs to be generated to get a believable effect
|
||||
needs to be very specific, with large scale band-like structures, small scale non-smooth variations
|
||||
to create the trail-like effect, a method for animating said texture smoothly and finally doing all
|
||||
of this cheaply enough to be able to evaluate it several times per fragment/pixel.
|
||||
|
||||
The second obstacle is the need to render a large volume while keeping the computational cost low.
|
||||
Since the effect requires the trails to extend way up in the atmosphere to look good, this means
|
||||
that the evaluated volume cannot be as constrained as with cloud effects. My solution was to make
|
||||
the sample stride increase polynomially, which works very well as long as the trails are lower opcaity than
|
||||
the rest of the effect. Which is always the case for auroras.
|
||||
|
||||
After that, there were some issues with getting the correct emission curves and removing banding at lowered
|
||||
sample densities, this was fixed by a combination of sample number influenced dithering and slight sample blending.
|
||||
|
||||
N.B. the base setup is from an old shader and ideally the effect would take an arbitrary ray origin and
|
||||
direction. But this was not required for this demo and would be trivial to fix.
|
||||
*/
|
||||
|
||||
#define time iTime
|
||||
|
||||
mat2 mm2(in float a){float c = cos(a), s = sin(a);return mat2(c,s,-s,c);}
|
||||
mat2 m2 = mat2(0.95534, 0.29552, -0.29552, 0.95534);
|
||||
float tri(in float x){return clamp(abs(fract(x)-.5),0.01,0.49);}
|
||||
vec2 tri2(in vec2 p){return vec2(tri(p.x)+tri(p.y),tri(p.y+tri(p.x)));}
|
||||
|
||||
float triNoise2d(in vec2 p, float spd)
|
||||
{
|
||||
float z=1.8;
|
||||
float z2=2.5;
|
||||
float rz = 0.;
|
||||
p *= mm2(p.x*0.06);
|
||||
vec2 bp = p;
|
||||
for (float i=0.; i<5.; i++ )
|
||||
{
|
||||
vec2 dg = tri2(bp*1.85)*.75;
|
||||
dg *= mm2(time*spd);
|
||||
p -= dg/z2;
|
||||
|
||||
bp *= 1.3;
|
||||
z2 *= .45;
|
||||
z *= .42;
|
||||
p *= 1.21 + (rz-1.0)*.02;
|
||||
|
||||
rz += tri(p.x+tri(p.y))*z;
|
||||
p*= -m2;
|
||||
}
|
||||
return clamp(1./pow(rz*29., 1.3),0.,.55);
|
||||
}
|
||||
|
||||
float hash21(in vec2 n){ return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453); }
|
||||
vec4 aurora(vec3 ro, vec3 rd)
|
||||
{
|
||||
vec4 col = vec4(0);
|
||||
vec4 avgCol = vec4(0);
|
||||
|
||||
for(float i=0.;i<50.;i++)
|
||||
{
|
||||
float of = 0.006*hash21(gl_FragCoord.xy)*smoothstep(0.,15., i);
|
||||
float pt = ((.8+pow(i,1.4)*.002)-ro.y)/(rd.y*2.+0.4);
|
||||
pt -= of;
|
||||
vec3 bpos = ro + pt*rd;
|
||||
vec2 p = bpos.zx;
|
||||
float rzt = triNoise2d(p, 0.06);
|
||||
vec4 col2 = vec4(0,0,0, rzt);
|
||||
col2.rgb = (sin(1.-vec3(2.15,-.5, 1.2)+i*0.043)*0.5+0.5)*rzt;
|
||||
avgCol = mix(avgCol, col2, .5);
|
||||
col += avgCol*exp2(-i*0.065 - 2.5)*smoothstep(0.,5., i);
|
||||
|
||||
}
|
||||
|
||||
col *= (clamp(rd.y*15.+.4,0.,1.));
|
||||
|
||||
|
||||
//return clamp(pow(col,vec4(1.3))*1.5,0.,1.);
|
||||
//return clamp(pow(col,vec4(1.7))*2.,0.,1.);
|
||||
//return clamp(pow(col,vec4(1.5))*2.5,0.,1.);
|
||||
//return clamp(pow(col,vec4(1.8))*1.5,0.,1.);
|
||||
|
||||
//return smoothstep(0.,1.1,pow(col,vec4(1.))*1.5);
|
||||
return col*1.8;
|
||||
//return pow(col,vec4(1.))*2.
|
||||
}
|
||||
|
||||
|
||||
//-------------------Background and Stars--------------------
|
||||
|
||||
vec3 nmzHash33(vec3 q)
|
||||
{
|
||||
uvec3 p = uvec3(ivec3(q));
|
||||
p = p*uvec3(374761393U, 1103515245U, 668265263U) + p.zxy + p.yzx;
|
||||
p = p.yzx*(p.zxy^(p >> 3U));
|
||||
return vec3(p^(p >> 16U))*(1.0/vec3(0xffffffffU));
|
||||
}
|
||||
|
||||
vec3 stars(in vec3 p)
|
||||
{
|
||||
vec3 c = vec3(0.);
|
||||
float res = iResolution.x*1.;
|
||||
|
||||
for (float i=0.;i<4.;i++)
|
||||
{
|
||||
vec3 q = fract(p*(.15*res))-0.5;
|
||||
vec3 id = floor(p*(.15*res));
|
||||
vec2 rn = nmzHash33(id).xy;
|
||||
float c2 = 1.-smoothstep(0.,.6,length(q));
|
||||
c2 *= step(rn.x,.0005+i*i*0.001);
|
||||
c += c2*(mix(vec3(1.0,0.49,0.1),vec3(0.75,0.9,1.),rn.y)*0.1+0.9);
|
||||
p *= 1.3;
|
||||
}
|
||||
return c*c*.8;
|
||||
}
|
||||
|
||||
vec3 bg(in vec3 rd)
|
||||
{
|
||||
float sd = dot(normalize(vec3(-0.5, -0.6, 0.9)), rd)*0.5+0.5;
|
||||
sd = pow(sd, 5.);
|
||||
vec3 col = mix(vec3(0.05,0.1,0.2), vec3(0.1,0.05,0.2), sd);
|
||||
return col*.63;
|
||||
}
|
||||
//-----------------------------------------------------------
|
||||
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
vec2 q = fragCoord.xy / iResolution.xy;
|
||||
vec2 p = q - 0.5;
|
||||
p.x*=iResolution.x/iResolution.y;
|
||||
|
||||
vec3 ro = vec3(0,0,-6.7);
|
||||
vec3 rd = normalize(vec3(p,1.3));
|
||||
vec2 mo = iMouse.xy / iResolution.xy-.5;
|
||||
mo = (mo==vec2(-.5))?mo=vec2(-0.1,0.1):mo;
|
||||
mo.x *= iResolution.x/iResolution.y;
|
||||
rd.yz *= mm2(mo.y);
|
||||
rd.xz *= mm2(mo.x + sin(time*0.05)*0.2);
|
||||
|
||||
vec3 col = vec3(0.);
|
||||
vec3 brd = rd;
|
||||
float fade = smoothstep(0.,0.01,abs(brd.y))*0.1+0.9;
|
||||
|
||||
col = bg(rd)*fade;
|
||||
|
||||
if (rd.y > 0.){
|
||||
vec4 aur = smoothstep(0.,1.5,aurora(ro,rd))*fade;
|
||||
col += stars(rd);
|
||||
col = col*(1.-aur.a) + aur.rgb;
|
||||
}
|
||||
else //Reflections
|
||||
{
|
||||
rd.y = abs(rd.y);
|
||||
col = bg(rd)*fade*0.6;
|
||||
vec4 aur = smoothstep(0.0,2.5,aurora(ro,rd));
|
||||
col += stars(rd)*0.1;
|
||||
col = col*(1.-aur.a) + aur.rgb;
|
||||
vec3 pos = ro + ((0.5-ro.y)/rd.y)*rd;
|
||||
float nz2 = triNoise2d(pos.xz*vec2(.5,.7), 0.);
|
||||
col += mix(vec3(0.2,0.25,0.5)*0.08,vec3(0.3,0.3,0.5)*0.7, nz2*0.4);
|
||||
}
|
||||
|
||||
fragColor = vec4(col, 1.);
|
||||
}
|
|
@ -0,0 +1,348 @@
|
|||
// https://www.shadertoy.com/view/wsjBD3
|
||||
// License CC0: A battered alien planet
|
||||
// Been experimenting with space inspired shaders
|
||||
|
||||
#define PI 3.141592654
|
||||
#define TAU (2.0*PI)
|
||||
|
||||
#define TOLERANCE 0.00001
|
||||
#define MAX_ITER 65
|
||||
#define MIN_DISTANCE 0.01
|
||||
#define MAX_DISTANCE 9.0
|
||||
|
||||
const vec3 skyCol1 = vec3(0.35, 0.45, 0.6);
|
||||
const vec3 skyCol2 = vec3(0.4, 0.7, 1.0);
|
||||
const vec3 skyCol3 = pow(skyCol1, vec3(0.25));
|
||||
const vec3 sunCol1 = vec3(1.0,0.6,0.4);
|
||||
const vec3 sunCol2 = vec3(1.0,0.9,0.7);
|
||||
const vec3 smallSunCol1 = vec3(1.0,0.5,0.25)*0.5;
|
||||
const vec3 smallSunCol2 = vec3(1.0,0.5,0.25)*0.5;
|
||||
const vec3 mountainColor = 1.0*sqrt(vec3(0.95, 0.65, 0.45));
|
||||
const float cellWidth = 1.0;
|
||||
const vec4 planet = vec4(80.0, -20.0, 100.0, 50.0)*1000.0;
|
||||
|
||||
void rot(inout vec2 p, float a) {
|
||||
float c = cos(a);
|
||||
float s = sin(a);
|
||||
p = vec2(p.x*c + p.y*s, -p.x*s + p.y*c);
|
||||
}
|
||||
|
||||
vec2 mod2(inout vec2 p, vec2 size) {
|
||||
vec2 c = floor((p + size*0.5)/size);
|
||||
p = mod(p + size*0.5,size) - size*0.5;
|
||||
return c;
|
||||
}
|
||||
|
||||
float circle(vec2 p, float r) {
|
||||
return length(p) - r;
|
||||
}
|
||||
|
||||
float egg(vec2 p, float ra, float rb) {
|
||||
const float k = sqrt(3.0);
|
||||
p.x = abs(p.x);
|
||||
float r = ra - rb;
|
||||
return ((p.y<0.0) ? length(vec2(p.x, p.y )) - r :
|
||||
(k*(p.x+r)<p.y) ? length(vec2(p.x, p.y-k*r)) :
|
||||
length(vec2(p.x+r,p.y )) - 2.0*r) - rb;
|
||||
}
|
||||
|
||||
vec2 hash(vec2 p) {
|
||||
p = vec2(dot (p, vec2 (127.1, 311.7)), dot (p, vec2 (269.5, 183.3)));
|
||||
return -1. + 2.*fract (sin (p)*43758.5453123);
|
||||
}
|
||||
|
||||
vec2 raySphere(vec3 ro, vec3 rd, vec4 sphere) {
|
||||
vec3 center = sphere.xyz;
|
||||
float radius = sphere.w;
|
||||
vec3 m = ro - center.xyz;
|
||||
float b = dot(m, rd);
|
||||
float c = dot(m, m) - radius*radius;
|
||||
if(c > 0.0 && b > 0.0) return vec2(-1.0, -1.0);
|
||||
float discr = b * b - c;
|
||||
if(discr < 0.0) return vec2(-1.0);
|
||||
float normalMultiplier = 1.0;
|
||||
float s = sqrt(discr);
|
||||
float t0 = -b - s;
|
||||
float t1 = -b + s;;
|
||||
return vec2(t0, t1);
|
||||
}
|
||||
|
||||
float noise1(vec2 p) {
|
||||
vec2 n = mod2(p, vec2(cellWidth));
|
||||
vec2 hh = hash(sqrt(2.0)*(n+1000.0));
|
||||
hh.x *= hh.y;
|
||||
|
||||
float r = 0.225*cellWidth;
|
||||
|
||||
float d = circle(p, 2.0*r);
|
||||
|
||||
float h = hh.x*smoothstep(0.0, r, -d);
|
||||
|
||||
return h*0.25;
|
||||
}
|
||||
|
||||
float noise2_(vec2 p) {
|
||||
vec2 n = mod2(p, vec2(cellWidth));
|
||||
vec2 hh = hash(sqrt(2.0)*(n+1000.0));
|
||||
hh.x *= hh.y;
|
||||
|
||||
rot(p, TAU*hh.y);
|
||||
float r = 0.45*cellWidth;
|
||||
|
||||
// float d = circle(p, 1.0*r);
|
||||
float d = egg(p, 0.75*r, 0.5*r*abs(hh.y));
|
||||
|
||||
float h = (hh.x)*smoothstep(0.0, r, -2.0*d);
|
||||
|
||||
return h*0.275;
|
||||
}
|
||||
|
||||
|
||||
float height(vec2 p, float dd, int mx) {
|
||||
const float aa = 0.45;
|
||||
const float ff = 2.03;
|
||||
const float tt = 1.2;
|
||||
const float oo = 3.93;
|
||||
const float near = 0.25;
|
||||
const float far = 0.65;
|
||||
|
||||
float a = 1.0;
|
||||
float o = 0.2;
|
||||
float s = 0.0;
|
||||
float d = 0.0;
|
||||
|
||||
int i = 0;
|
||||
|
||||
for (; i < 4;++i) {
|
||||
float nn = a*noise2_(p);
|
||||
s += nn;
|
||||
d += abs(a);
|
||||
p += o;
|
||||
a *= aa;
|
||||
p *= ff;
|
||||
o *= oo;
|
||||
rot(p, tt);
|
||||
}
|
||||
|
||||
float lod = s/d;
|
||||
|
||||
float rdd = dd/MAX_DISTANCE;
|
||||
mx = int(mix(float(4), float(mx), step(rdd, far)));
|
||||
|
||||
for (; i < mx; ++i) {
|
||||
float nn = a*noise1(p);
|
||||
s += nn;
|
||||
d += abs(a);
|
||||
p += o;
|
||||
a *= aa;
|
||||
p *= ff;
|
||||
o *= oo;
|
||||
rot(p, tt);
|
||||
}
|
||||
|
||||
float hid = (s/d);
|
||||
|
||||
return mix(hid, lod, smoothstep(near, far, rdd));
|
||||
}
|
||||
|
||||
float loheight(vec2 p, float d) {
|
||||
return height(p, d, 0);
|
||||
}
|
||||
|
||||
float height(vec2 p, float d) {
|
||||
return height(p, d, 6);
|
||||
}
|
||||
|
||||
float hiheight(vec2 p, float d) {
|
||||
return height(p, d, 8);
|
||||
}
|
||||
|
||||
vec3 normal(vec2 p, float d) {
|
||||
vec2 eps = vec2(0.00125, 0.0);
|
||||
|
||||
vec3 n;
|
||||
|
||||
n.x = (hiheight(p - eps.xy, d) - hiheight(p + eps.xy, d));
|
||||
n.y = 2.0*eps.x;
|
||||
n.z = (hiheight(p - eps.yx, d) - hiheight(p + eps.yx, d));
|
||||
|
||||
return normalize(n);
|
||||
}
|
||||
|
||||
const float stepLength[] = float[](0.9, 0.25);
|
||||
|
||||
|
||||
float march(vec3 ro, vec3 rd, out int max_iter) {
|
||||
float dt = 0.1;
|
||||
float d = MIN_DISTANCE;
|
||||
int currentStep = 0;
|
||||
float lastd = d;
|
||||
for (int i = 0; i < MAX_ITER; ++i)
|
||||
{
|
||||
vec3 p = ro + d*rd;
|
||||
float h = height(p.xz, d);
|
||||
|
||||
if (d > MAX_DISTANCE) {
|
||||
max_iter = i;
|
||||
return MAX_DISTANCE;
|
||||
}
|
||||
|
||||
float hd = p.y - h;
|
||||
|
||||
if (hd < TOLERANCE) {
|
||||
++currentStep;
|
||||
if (currentStep >= stepLength.length()) {
|
||||
max_iter = i;
|
||||
return d;
|
||||
}
|
||||
|
||||
d = lastd;
|
||||
continue;
|
||||
}
|
||||
|
||||
float sl = stepLength[currentStep];
|
||||
|
||||
dt = max(hd, TOLERANCE)*sl + 0.0025*d;
|
||||
lastd = d;
|
||||
d += dt;
|
||||
}
|
||||
|
||||
max_iter = MAX_ITER;
|
||||
return MAX_DISTANCE;
|
||||
}
|
||||
|
||||
vec3 sunDirection() {
|
||||
return normalize(vec3(-0.5, 0.085, 1.0));
|
||||
}
|
||||
|
||||
vec3 smallSunDirection() {
|
||||
return normalize(vec3(-0.2, -0.05, 1.0));
|
||||
}
|
||||
|
||||
float psin(float f) {
|
||||
return 0.5 + 0.5*sin(f);
|
||||
}
|
||||
|
||||
vec3 skyColor(vec3 ro, vec3 rd) {
|
||||
vec3 sunDir = sunDirection();
|
||||
vec3 smallSunDir = smallSunDirection();
|
||||
|
||||
float sunDot = max(dot(rd, sunDir), 0.0);
|
||||
float smallSunDot = max(dot(rd, smallSunDir), 0.0);
|
||||
|
||||
float angle = atan(rd.y, length(rd.xz))*2.0/PI;
|
||||
|
||||
vec3 skyCol = mix(mix(skyCol1, skyCol2, max(0.0, angle)), skyCol3, clamp(-angle*2.0, 0.0, 1.0));
|
||||
|
||||
vec3 sunCol = 0.5*sunCol1*pow(sunDot, 20.0) + 8.0*sunCol2*pow(sunDot, 2000.0);
|
||||
vec3 smallSunCol = 0.5*smallSunCol1*pow(smallSunDot, 200.0) + 8.0*smallSunCol2*pow(smallSunDot, 20000.0);
|
||||
|
||||
vec3 dust = pow(sunCol2*mountainColor, vec3(1.75))*smoothstep(0.05, -0.1, rd.y)*0.5;
|
||||
|
||||
vec2 si = raySphere(ro, rd, planet);
|
||||
|
||||
vec3 planetSurface = ro + si.x*rd;
|
||||
vec3 planetNormal = normalize(planetSurface - planet.xyz);
|
||||
float planetDiff = max(dot(planetNormal, sunDir), 0.0);
|
||||
float planetBorder = max(dot(planetNormal, -rd), 0.0);
|
||||
float planetLat = (planetSurface.x+planetSurface.y)*0.0005;
|
||||
vec3 planetCol = mix(1.3*vec3(0.9, 0.8, 0.7), 0.3*vec3(0.9, 0.8, 0.7), pow(psin(planetLat+1.0)*psin(sqrt(2.0)*planetLat+2.0)*psin(sqrt(3.5)*planetLat+3.0), 0.5));
|
||||
|
||||
vec3 final = vec3(0.0);
|
||||
|
||||
final += step(0.0, si.x)*pow(planetDiff, 0.75)*planetCol*smoothstep(-0.075, 0.0, rd.y)*smoothstep(0.0, 0.1, planetBorder);
|
||||
|
||||
final += skyCol + sunCol + smallSunCol + dust;
|
||||
|
||||
|
||||
return final;
|
||||
}
|
||||
|
||||
vec3 getColor(vec3 ro, vec3 rd) {
|
||||
int max_iter = 0;
|
||||
vec3 skyCol = skyColor(ro, rd);
|
||||
vec3 col = vec3(0);
|
||||
|
||||
float d = march(ro, rd, max_iter);
|
||||
|
||||
if (d < MAX_DISTANCE) {
|
||||
vec3 sunDir = sunDirection();
|
||||
vec3 osunDir = sunDir*vec3(-1.0, .0, -1.0);
|
||||
vec3 p = ro + d*rd;
|
||||
|
||||
vec3 normal = normal(p.xz, d);
|
||||
|
||||
float amb = 0.2;
|
||||
|
||||
float dif1 = max(0.0, dot(sunDir, normal));
|
||||
vec3 shd1 = sunCol2*mix(amb, 1.0, pow(dif1, 0.75));
|
||||
|
||||
float dif2 = max(0.0, dot(osunDir, normal));
|
||||
vec3 shd2 = sunCol1*mix(amb, 1.0, pow(dif2, 0.75));
|
||||
|
||||
vec3 ref = reflect(rd, normal);
|
||||
vec3 rcol = skyColor(p, ref);
|
||||
|
||||
col = mountainColor*amb*skyCol3;
|
||||
col += mix(shd1, shd2, -0.5)*mountainColor;
|
||||
float fre = max(dot(normal, -rd), 0.0);
|
||||
fre = pow(1.0 - fre, 5.0);
|
||||
col += rcol*fre*0.5;
|
||||
col += (1.0*p.y);
|
||||
col = tanh(col);
|
||||
col = mix(col, skyCol, smoothstep(0.5*MAX_DISTANCE, 1.0*MAX_DISTANCE, d));
|
||||
|
||||
} else {
|
||||
col = skyCol;
|
||||
}
|
||||
|
||||
// col += vec3(1.1, 0.0, 0.0)* smoothstep(0.25, 1.0,(float(max_iter)/float(MAX_ITER)));
|
||||
return col;
|
||||
}
|
||||
|
||||
vec3 getSample1(vec2 p, float time) {
|
||||
float off = 0.5*iTime;
|
||||
|
||||
vec3 ro = vec3(0.5, 1.0-0.25, -2.0 + off);
|
||||
vec3 la = ro + vec3(0.0, -0.30, 2.0);
|
||||
|
||||
vec3 ww = normalize(la - ro);
|
||||
vec3 uu = normalize(cross(vec3(0.0,1.0,0.0), ww));
|
||||
vec3 vv = normalize(cross(ww, uu));
|
||||
vec3 rd = normalize(p.x*uu + p.y*vv + 2.0*ww);
|
||||
|
||||
vec3 col = getColor(ro, rd) ;
|
||||
|
||||
return col;
|
||||
|
||||
}
|
||||
|
||||
vec3 getSample2(vec2 p, float time) {
|
||||
p.y-=time*0.25;
|
||||
float h = height(p, 0.0);
|
||||
vec3 n = normal(p, 0.0);
|
||||
|
||||
vec3 lp = vec3(10.0, -1.2, 0.0);
|
||||
|
||||
vec3 ld = normalize(vec3(p.x, h, p.y)- lp);
|
||||
|
||||
float d = max(dot(ld, n), 0.0);
|
||||
|
||||
vec3 col = vec3(0.0);
|
||||
|
||||
col = vec3(1.0)*(h+0.1);
|
||||
col += vec3(1.5)*pow(d, 0.75);
|
||||
|
||||
return col;
|
||||
|
||||
}
|
||||
|
||||
void mainImage(out vec4 fragColor, vec2 fragCoord) {
|
||||
vec2 q = fragCoord.xy/iResolution.xy;
|
||||
vec2 p = -1.0 + 2.0*q;
|
||||
p.x *= iResolution.x/iResolution.y;
|
||||
|
||||
vec3 col = getSample1(p, iTime);
|
||||
|
||||
fragColor = vec4(col, 1.0);
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
|
||||
goblins.png
|
||||
size: 1024, 128
|
||||
filter: Linear, Linear
|
||||
pma: true
|
||||
dagger
|
||||
bounds: 2, 18, 26, 108
|
||||
goblin/eyes-closed
|
||||
bounds: 2, 4, 34, 12
|
||||
goblin/head
|
||||
bounds: 113, 23, 103, 66
|
||||
rotate: 90
|
||||
goblin/left-arm
|
||||
bounds: 937, 89, 37, 35
|
||||
rotate: 90
|
||||
goblin/left-foot
|
||||
bounds: 609, 61, 65, 31
|
||||
rotate: 90
|
||||
goblin/left-hand
|
||||
bounds: 840, 21, 36, 41
|
||||
goblin/left-lower-leg
|
||||
bounds: 504, 56, 33, 70
|
||||
goblin/left-shoulder
|
||||
bounds: 745, 17, 29, 44
|
||||
goblin/left-upper-leg
|
||||
bounds: 397, 53, 33, 73
|
||||
goblin/neck
|
||||
bounds: 862, 85, 36, 41
|
||||
goblin/pelvis
|
||||
bounds: 776, 18, 62, 43
|
||||
goblin/right-arm
|
||||
bounds: 181, 5, 23, 50
|
||||
rotate: 90
|
||||
goblin/right-foot
|
||||
bounds: 747, 63, 63, 33
|
||||
rotate: 90
|
||||
goblin/right-hand
|
||||
bounds: 878, 3, 36, 37
|
||||
goblin/right-lower-leg
|
||||
bounds: 321, 50, 36, 76
|
||||
goblin/right-shoulder
|
||||
bounds: 663, 14, 39, 45
|
||||
goblin/right-upper-leg
|
||||
bounds: 675, 63, 34, 63
|
||||
goblin/torso
|
||||
bounds: 181, 30, 68, 96
|
||||
goblin/undie-straps
|
||||
bounds: 38, 2, 55, 19
|
||||
goblin/undies
|
||||
bounds: 974, 97, 36, 29
|
||||
goblingirl/eyes-closed
|
||||
bounds: 397, 30, 37, 21
|
||||
goblingirl/head
|
||||
bounds: 30, 23, 103, 81
|
||||
rotate: 90
|
||||
goblingirl/left-arm
|
||||
bounds: 916, 8, 37, 35
|
||||
rotate: 90
|
||||
goblingirl/left-foot
|
||||
bounds: 642, 61, 65, 31
|
||||
rotate: 90
|
||||
goblingirl/left-hand
|
||||
bounds: 900, 86, 35, 40
|
||||
goblingirl/left-lower-leg
|
||||
bounds: 539, 56, 33, 70
|
||||
goblingirl/left-shoulder
|
||||
bounds: 633, 13, 28, 46
|
||||
goblingirl/left-upper-leg
|
||||
bounds: 574, 56, 33, 70
|
||||
goblingirl/neck
|
||||
bounds: 878, 42, 35, 41
|
||||
goblingirl/pelvis
|
||||
bounds: 817, 64, 62, 43
|
||||
rotate: 90
|
||||
goblingirl/right-arm
|
||||
bounds: 603, 4, 28, 50
|
||||
goblingirl/right-foot
|
||||
bounds: 782, 63, 63, 33
|
||||
rotate: 90
|
||||
goblingirl/right-hand
|
||||
bounds: 915, 47, 36, 37
|
||||
goblingirl/right-lower-leg
|
||||
bounds: 359, 50, 36, 76
|
||||
goblingirl/right-shoulder
|
||||
bounds: 704, 16, 39, 45
|
||||
goblingirl/right-upper-leg
|
||||
bounds: 711, 63, 34, 63
|
||||
goblingirl/torso
|
||||
bounds: 251, 30, 68, 96
|
||||
goblingirl/undie-straps
|
||||
bounds: 95, 2, 55, 19
|
||||
goblingirl/undies
|
||||
bounds: 974, 66, 36, 29
|
||||
shield
|
||||
bounds: 432, 54, 70, 72
|
||||
spear
|
||||
bounds: 233, 6, 22, 368
|
||||
rotate: 90
|
|
@ -0,0 +1,627 @@
|
|||
{
|
||||
"skeleton": {
|
||||
"hash": "djttFmlR6Co",
|
||||
"spine": "4.1.17",
|
||||
"x": -92.53,
|
||||
"y": -5.3,
|
||||
"width": 234.03,
|
||||
"height": 354.91,
|
||||
"images": "./images/",
|
||||
"audio": ""
|
||||
},
|
||||
"bones": [
|
||||
{ "name": "root" },
|
||||
{ "name": "hip", "parent": "root", "x": 0.65, "y": 114.41, "color": "ffd300ff" },
|
||||
{
|
||||
"name": "torso",
|
||||
"parent": "hip",
|
||||
"length": 85.83,
|
||||
"rotation": 93.93,
|
||||
"x": -6.42,
|
||||
"y": 1.98,
|
||||
"color": "ffd300ff"
|
||||
},
|
||||
{
|
||||
"name": "neck",
|
||||
"parent": "torso",
|
||||
"length": 18.38,
|
||||
"rotation": -1.52,
|
||||
"x": 81.68,
|
||||
"y": -6.35,
|
||||
"color": "ffd300ff"
|
||||
},
|
||||
{
|
||||
"name": "head",
|
||||
"parent": "neck",
|
||||
"length": 68.29,
|
||||
"rotation": -13.92,
|
||||
"x": 20.94,
|
||||
"y": 11.59,
|
||||
"color": "ffd300ff"
|
||||
},
|
||||
{
|
||||
"name": "left-shoulder",
|
||||
"parent": "torso",
|
||||
"length": 35.43,
|
||||
"rotation": -156.96,
|
||||
"x": 74.05,
|
||||
"y": -20.39,
|
||||
"color": "ff0000ff"
|
||||
},
|
||||
{
|
||||
"name": "left-arm",
|
||||
"parent": "left-shoulder",
|
||||
"length": 35.62,
|
||||
"rotation": 28.17,
|
||||
"x": 37.86,
|
||||
"y": -2.35,
|
||||
"color": "ff0000ff"
|
||||
},
|
||||
{
|
||||
"name": "left-upper-leg",
|
||||
"parent": "hip",
|
||||
"length": 50.4,
|
||||
"rotation": -89.1,
|
||||
"x": 14.45,
|
||||
"y": 2.81,
|
||||
"color": "ff0000ff"
|
||||
},
|
||||
{
|
||||
"name": "left-lower-leg",
|
||||
"parent": "left-upper-leg",
|
||||
"length": 49.9,
|
||||
"rotation": -16.66,
|
||||
"x": 56.34,
|
||||
"y": 0.99,
|
||||
"color": "ff0000ff"
|
||||
},
|
||||
{
|
||||
"name": "left-foot",
|
||||
"parent": "left-lower-leg",
|
||||
"length": 46.5,
|
||||
"rotation": 102.43,
|
||||
"x": 58.94,
|
||||
"y": -7.61,
|
||||
"color": "ff0000ff"
|
||||
},
|
||||
{
|
||||
"name": "left-hand",
|
||||
"parent": "left-arm",
|
||||
"length": 11.52,
|
||||
"rotation": 2.7,
|
||||
"x": 35.62,
|
||||
"y": 0.08,
|
||||
"color": "ff0000ff"
|
||||
},
|
||||
{ "name": "pelvis", "parent": "hip", "x": 1.41, "y": -6.58, "color": "ffd300ff" },
|
||||
{
|
||||
"name": "right-shoulder",
|
||||
"parent": "torso",
|
||||
"length": 37.25,
|
||||
"rotation": 133.89,
|
||||
"x": 76.02,
|
||||
"y": 18.15,
|
||||
"color": "54ff00ff"
|
||||
},
|
||||
{
|
||||
"name": "right-arm",
|
||||
"parent": "right-shoulder",
|
||||
"length": 36.75,
|
||||
"rotation": 36.33,
|
||||
"x": 37.61,
|
||||
"y": 0.31,
|
||||
"color": "54ff00ff"
|
||||
},
|
||||
{
|
||||
"name": "right-upper-leg",
|
||||
"parent": "hip",
|
||||
"length": 42.46,
|
||||
"rotation": -97.5,
|
||||
"x": -20.08,
|
||||
"y": -6.84,
|
||||
"color": "54ff00ff"
|
||||
},
|
||||
{
|
||||
"name": "right-lower-leg",
|
||||
"parent": "right-upper-leg",
|
||||
"length": 58.53,
|
||||
"rotation": -14.34,
|
||||
"x": 43,
|
||||
"y": -0.62,
|
||||
"color": "54ff00ff"
|
||||
},
|
||||
{
|
||||
"name": "right-foot",
|
||||
"parent": "right-lower-leg",
|
||||
"length": 45.46,
|
||||
"rotation": 110.31,
|
||||
"x": 64.89,
|
||||
"y": 0.04,
|
||||
"color": "54ff00ff"
|
||||
},
|
||||
{
|
||||
"name": "right-hand",
|
||||
"parent": "right-arm",
|
||||
"length": 15.32,
|
||||
"rotation": 2.36,
|
||||
"x": 36.9,
|
||||
"y": 0.35,
|
||||
"color": "54ff00ff"
|
||||
}
|
||||
],
|
||||
"slots": [
|
||||
{ "name": "left-shoulder", "bone": "left-shoulder", "attachment": "left-shoulder" },
|
||||
{ "name": "left-arm", "bone": "left-arm", "attachment": "left-arm" },
|
||||
{ "name": "left-hand-item", "bone": "left-hand", "attachment": "spear" },
|
||||
{ "name": "left-hand", "bone": "left-hand", "attachment": "left-hand" },
|
||||
{ "name": "left-foot", "bone": "left-foot", "attachment": "left-foot" },
|
||||
{ "name": "left-lower-leg", "bone": "left-lower-leg", "attachment": "left-lower-leg" },
|
||||
{ "name": "left-upper-leg", "bone": "left-upper-leg", "attachment": "left-upper-leg" },
|
||||
{ "name": "neck", "bone": "neck", "attachment": "neck" },
|
||||
{ "name": "torso", "bone": "torso", "attachment": "torso" },
|
||||
{ "name": "pelvis", "bone": "pelvis", "attachment": "pelvis" },
|
||||
{ "name": "right-foot", "bone": "right-foot", "attachment": "right-foot" },
|
||||
{ "name": "right-lower-leg", "bone": "right-lower-leg", "attachment": "right-lower-leg" },
|
||||
{ "name": "undie-straps", "bone": "pelvis", "attachment": "undie-straps" },
|
||||
{ "name": "undies", "bone": "pelvis", "attachment": "undies" },
|
||||
{ "name": "right-upper-leg", "bone": "right-upper-leg", "attachment": "right-upper-leg" },
|
||||
{ "name": "head", "bone": "head", "attachment": "head" },
|
||||
{ "name": "eyes", "bone": "head" },
|
||||
{ "name": "right-shoulder", "bone": "right-shoulder", "attachment": "right-shoulder" },
|
||||
{ "name": "right-arm", "bone": "right-arm", "attachment": "right-arm" },
|
||||
{ "name": "right-hand-item", "bone": "right-hand" },
|
||||
{ "name": "right-hand", "bone": "right-hand", "attachment": "right-hand" },
|
||||
{ "name": "right-hand-item-top", "bone": "right-hand", "attachment": "shield" }
|
||||
],
|
||||
"skins": [
|
||||
{
|
||||
"name": "default",
|
||||
"attachments": {
|
||||
"left-hand-item": {
|
||||
"dagger": { "x": 7.88, "y": -23.46, "rotation": 10.48, "width": 26, "height": 108 },
|
||||
"spear": { "x": -4.56, "y": 39.2, "rotation": 13.05, "width": 22, "height": 368 }
|
||||
},
|
||||
"right-hand-item": {
|
||||
"dagger": { "x": 6.52, "y": -24.16, "rotation": -8.06, "width": 26, "height": 108 }
|
||||
},
|
||||
"right-hand-item-top": {
|
||||
"shield": { "rotation": 93.5, "width": 70, "height": 72 }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "goblin",
|
||||
"attachments": {
|
||||
"eyes": {
|
||||
"eyes-closed": { "name": "goblin/eyes-closed", "x": 32.22, "y": -21.27, "rotation": -88.93, "width": 34, "height": 12 }
|
||||
},
|
||||
"head": {
|
||||
"head": { "name": "goblin/head", "x": 25.74, "y": 2.33, "rotation": -92.29, "width": 103, "height": 66 }
|
||||
},
|
||||
"left-arm": {
|
||||
"left-arm": {
|
||||
"name": "goblin/left-arm",
|
||||
"x": 16.7,
|
||||
"y": -1.69,
|
||||
"scaleX": 1.0573,
|
||||
"scaleY": 1.0573,
|
||||
"rotation": 33.85,
|
||||
"width": 37,
|
||||
"height": 35
|
||||
}
|
||||
},
|
||||
"left-foot": {
|
||||
"left-foot": { "name": "goblin/left-foot", "x": 24.85, "y": 8.75, "rotation": 3.32, "width": 65, "height": 31 }
|
||||
},
|
||||
"left-hand": {
|
||||
"left-hand": {
|
||||
"name": "goblin/left-hand",
|
||||
"x": 3.47,
|
||||
"y": 3.41,
|
||||
"scaleX": 0.8922,
|
||||
"scaleY": 0.8922,
|
||||
"rotation": 31.14,
|
||||
"width": 36,
|
||||
"height": 41
|
||||
}
|
||||
},
|
||||
"left-lower-leg": {
|
||||
"left-lower-leg": { "name": "goblin/left-lower-leg", "x": 23.59, "y": -2.07, "rotation": 105.76, "width": 33, "height": 70 }
|
||||
},
|
||||
"left-shoulder": {
|
||||
"left-shoulder": { "name": "goblin/left-shoulder", "x": 15.56, "y": -2.27, "rotation": 62.01, "width": 29, "height": 44 }
|
||||
},
|
||||
"left-upper-leg": {
|
||||
"left-upper-leg": { "name": "goblin/left-upper-leg", "x": 29.69, "y": -3.87, "rotation": 89.1, "width": 33, "height": 73 }
|
||||
},
|
||||
"neck": {
|
||||
"neck": { "name": "goblin/neck", "x": 10.1, "y": 0.42, "rotation": -93.7, "width": 36, "height": 41 }
|
||||
},
|
||||
"pelvis": {
|
||||
"pelvis": { "name": "goblin/pelvis", "x": -5.62, "y": 0.77, "width": 62, "height": 43 }
|
||||
},
|
||||
"right-arm": {
|
||||
"right-arm": { "name": "goblin/right-arm", "x": 16.44, "y": -1.04, "rotation": 94.32, "width": 23, "height": 50 }
|
||||
},
|
||||
"right-foot": {
|
||||
"right-foot": { "name": "goblin/right-foot", "x": 23.57, "y": 9.8, "rotation": 1.53, "width": 63, "height": 33 }
|
||||
},
|
||||
"right-hand": {
|
||||
"right-hand": { "name": "goblin/right-hand", "x": 7.89, "y": 2.78, "rotation": 91.96, "width": 36, "height": 37 }
|
||||
},
|
||||
"right-lower-leg": {
|
||||
"right-lower-leg": { "name": "goblin/right-lower-leg", "x": 25.68, "y": -3.16, "rotation": 111.84, "width": 36, "height": 76 }
|
||||
},
|
||||
"right-shoulder": {
|
||||
"right-shoulder": { "name": "goblin/right-shoulder", "x": 15.68, "y": -1.03, "rotation": 130.65, "width": 39, "height": 45 }
|
||||
},
|
||||
"right-upper-leg": {
|
||||
"right-upper-leg": { "name": "goblin/right-upper-leg", "x": 20.35, "y": 1.48, "rotation": 97.5, "width": 34, "height": 63 }
|
||||
},
|
||||
"torso": {
|
||||
"torso": { "name": "goblin/torso", "x": 38.1, "y": -3.87, "rotation": -94.95, "width": 68, "height": 96 }
|
||||
},
|
||||
"undie-straps": {
|
||||
"undie-straps": { "name": "goblin/undie-straps", "x": -3.88, "y": 13.11, "scaleX": 1.0896, "width": 55, "height": 19 }
|
||||
},
|
||||
"undies": {
|
||||
"undies": { "name": "goblin/undies", "x": 6.3, "y": 0.13, "rotation": 0.92, "width": 36, "height": 29 }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "goblingirl",
|
||||
"attachments": {
|
||||
"eyes": {
|
||||
"eyes-closed": { "name": "goblingirl/eyes-closed", "x": 28, "y": -25.55, "rotation": -87.05, "width": 37, "height": 21 }
|
||||
},
|
||||
"head": {
|
||||
"head": { "name": "goblingirl/head", "x": 27.72, "y": -4.32, "rotation": -85.58, "width": 103, "height": 81 }
|
||||
},
|
||||
"left-arm": {
|
||||
"left-arm": { "name": "goblingirl/left-arm", "x": 19.64, "y": -2.43, "rotation": 33.05, "width": 37, "height": 35 }
|
||||
},
|
||||
"left-foot": {
|
||||
"left-foot": { "name": "goblingirl/left-foot", "x": 25.18, "y": 7.92, "rotation": 3.32, "width": 65, "height": 31 }
|
||||
},
|
||||
"left-hand": {
|
||||
"left-hand": {
|
||||
"name": "goblingirl/left-hand",
|
||||
"x": 4.34,
|
||||
"y": 2.39,
|
||||
"scaleX": 0.8965,
|
||||
"scaleY": 0.8965,
|
||||
"rotation": 30.35,
|
||||
"width": 35,
|
||||
"height": 40
|
||||
}
|
||||
},
|
||||
"left-lower-leg": {
|
||||
"left-lower-leg": { "name": "goblingirl/left-lower-leg", "x": 25.02, "y": -0.61, "rotation": 105.76, "width": 33, "height": 70 }
|
||||
},
|
||||
"left-shoulder": {
|
||||
"left-shoulder": { "name": "goblingirl/left-shoulder", "x": 19.81, "y": -0.43, "rotation": 61.22, "width": 28, "height": 46 }
|
||||
},
|
||||
"left-upper-leg": {
|
||||
"left-upper-leg": { "name": "goblingirl/left-upper-leg", "x": 30.22, "y": -2.95, "rotation": 89.1, "width": 33, "height": 70 }
|
||||
},
|
||||
"neck": {
|
||||
"neck": { "name": "goblingirl/neck", "x": 6.16, "y": -3.15, "rotation": -98.86, "width": 35, "height": 41 }
|
||||
},
|
||||
"pelvis": {
|
||||
"pelvis": { "name": "goblingirl/pelvis", "x": -3.88, "y": 3.19, "width": 62, "height": 43 }
|
||||
},
|
||||
"right-arm": {
|
||||
"right-arm": { "name": "goblingirl/right-arm", "x": 16.85, "y": -0.66, "rotation": 93.53, "width": 28, "height": 50 }
|
||||
},
|
||||
"right-foot": {
|
||||
"right-foot": { "name": "goblingirl/right-foot", "x": 23.46, "y": 9.66, "rotation": 1.53, "width": 63, "height": 33 }
|
||||
},
|
||||
"right-hand": {
|
||||
"right-hand": { "name": "goblingirl/right-hand", "x": 7.22, "y": 3.44, "rotation": 91.17, "width": 36, "height": 37 }
|
||||
},
|
||||
"right-lower-leg": {
|
||||
"right-lower-leg": { "name": "goblingirl/right-lower-leg", "x": 26.15, "y": -3.28, "rotation": 111.84, "width": 36, "height": 76 }
|
||||
},
|
||||
"right-shoulder": {
|
||||
"right-shoulder": { "name": "goblingirl/right-shoulder", "x": 14.46, "y": 0.46, "rotation": 129.85, "width": 39, "height": 45 }
|
||||
},
|
||||
"right-upper-leg": {
|
||||
"right-upper-leg": { "name": "goblingirl/right-upper-leg", "x": 19.7, "y": 2.13, "rotation": 97.5, "width": 34, "height": 63 }
|
||||
},
|
||||
"torso": {
|
||||
"torso": { "name": "goblingirl/torso", "x": 36.28, "y": -5.14, "rotation": -95.75, "width": 68, "height": 96 }
|
||||
},
|
||||
"undie-straps": {
|
||||
"undie-straps": { "name": "goblingirl/undie-straps", "x": -1.52, "y": 14.19, "width": 55, "height": 19 }
|
||||
},
|
||||
"undies": {
|
||||
"undies": { "name": "goblingirl/undies", "x": 5.4, "y": 1.71, "width": 36, "height": 29 }
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"animations": {
|
||||
"walk": {
|
||||
"slots": {
|
||||
"eyes": {
|
||||
"attachment": [
|
||||
{ "time": 0.7, "name": "eyes-closed" },
|
||||
{ "time": 0.8 }
|
||||
]
|
||||
}
|
||||
},
|
||||
"bones": {
|
||||
"left-upper-leg": {
|
||||
"rotate": [
|
||||
{ "value": -26.56 },
|
||||
{ "time": 0.1333, "value": -8.79 },
|
||||
{ "time": 0.2333, "value": 9.51 },
|
||||
{ "time": 0.3667, "value": 30.74 },
|
||||
{ "time": 0.5, "value": 25.34 },
|
||||
{ "time": 0.6333, "value": 26.12 },
|
||||
{ "time": 0.7333, "value": -7.71 },
|
||||
{ "time": 0.8667, "value": -21.19 },
|
||||
{ "time": 1, "value": -26.56 }
|
||||
],
|
||||
"translate": [
|
||||
{ "x": -1.32, "y": 1.71 },
|
||||
{ "time": 0.3667, "x": -0.06, "y": 2.43 },
|
||||
{ "time": 1, "x": -1.32, "y": 1.71 }
|
||||
]
|
||||
},
|
||||
"right-upper-leg": {
|
||||
"rotate": [
|
||||
{ "value": 42.45 },
|
||||
{ "time": 0.1333, "value": 52.11 },
|
||||
{ "time": 0.2333, "value": 8.54 },
|
||||
{ "time": 0.5, "value": -16.94 },
|
||||
{ "time": 0.6333, "value": 1.9 },
|
||||
{
|
||||
"time": 0.7333,
|
||||
"value": 28.06,
|
||||
"curve": [ 0.795, 31.71, 0.867, 58.69 ]
|
||||
},
|
||||
{
|
||||
"time": 0.8667,
|
||||
"value": 58.69,
|
||||
"curve": [ 0.933, 58.35, 1, 42.45 ]
|
||||
},
|
||||
{ "time": 1, "value": 42.45 }
|
||||
],
|
||||
"translate": [
|
||||
{ "x": 6.24 },
|
||||
{ "time": 0.2333, "x": 2.14, "y": 2.4 },
|
||||
{ "time": 0.5, "x": 2.44, "y": 4.8 },
|
||||
{ "time": 1, "x": 6.24 }
|
||||
]
|
||||
},
|
||||
"left-lower-leg": {
|
||||
"rotate": [
|
||||
{ "value": -22.98 },
|
||||
{ "time": 0.1333, "value": -63.51 },
|
||||
{ "time": 0.2333, "value": -73.76 },
|
||||
{ "time": 0.5, "value": 5.12 },
|
||||
{ "time": 0.6333, "value": -28.3 },
|
||||
{ "time": 0.7333, "value": 4.08 },
|
||||
{ "time": 0.8667, "value": 3.53 },
|
||||
{ "time": 1, "value": -22.98 }
|
||||
],
|
||||
"translate": [
|
||||
{},
|
||||
{ "time": 0.2333, "x": 2.56, "y": -0.47 },
|
||||
{ "time": 0.5 }
|
||||
]
|
||||
},
|
||||
"left-foot": {
|
||||
"rotate": [
|
||||
{ "value": -3.69 },
|
||||
{ "time": 0.1333, "value": -10.42 },
|
||||
{ "time": 0.2333, "value": -5.01 },
|
||||
{ "time": 0.3667, "value": 3.87 },
|
||||
{ "time": 0.5, "value": -3.88 },
|
||||
{ "time": 0.6333, "value": 2.78 },
|
||||
{ "time": 0.7333, "value": 1.68 },
|
||||
{ "time": 0.8667, "value": -8.54 },
|
||||
{ "time": 1, "value": -3.69 }
|
||||
]
|
||||
},
|
||||
"right-shoulder": {
|
||||
"rotate": [
|
||||
{
|
||||
"value": 5.29,
|
||||
"curve": [ 0.167, 5.29, 0.475, 6.65 ]
|
||||
},
|
||||
{ "time": 0.6333, "value": 6.65 },
|
||||
{ "time": 1, "value": 5.29 }
|
||||
]
|
||||
},
|
||||
"right-arm": {
|
||||
"rotate": [
|
||||
{
|
||||
"value": -4.03,
|
||||
"curve": [ 0.169, -3.91, 0.51, 19.66 ]
|
||||
},
|
||||
{
|
||||
"time": 0.6333,
|
||||
"value": 19.79,
|
||||
"curve": [ 0.746, 19.75, 0.922, -3.91 ]
|
||||
},
|
||||
{ "time": 1, "value": -4.03 }
|
||||
]
|
||||
},
|
||||
"right-hand": {
|
||||
"rotate": [
|
||||
{ "value": 8.99 },
|
||||
{ "time": 0.6333, "value": 0.51 },
|
||||
{ "time": 1, "value": 8.99 }
|
||||
]
|
||||
},
|
||||
"left-shoulder": {
|
||||
"rotate": [
|
||||
{
|
||||
"value": 6.26,
|
||||
"curve": [ 0.17, 6.26, 0.342, -11.79 ]
|
||||
},
|
||||
{
|
||||
"time": 0.5,
|
||||
"value": -11.79,
|
||||
"curve": [ 0.641, -11.79, 0.843, 6.16 ]
|
||||
},
|
||||
{ "time": 1, "value": 6.26 }
|
||||
],
|
||||
"translate": [
|
||||
{ "x": 1.15, "y": 0.24 }
|
||||
]
|
||||
},
|
||||
"left-hand": {
|
||||
"rotate": [
|
||||
{
|
||||
"value": -21.24,
|
||||
"curve": [ 0.148, -21.24, 0.378, -27.21 ]
|
||||
},
|
||||
{
|
||||
"time": 0.5,
|
||||
"value": -27.28,
|
||||
"curve": [ 0.621, -27.28, 0.875, -21.4 ]
|
||||
},
|
||||
{ "time": 1, "value": -21.24 }
|
||||
]
|
||||
},
|
||||
"left-arm": {
|
||||
"rotate": [
|
||||
{
|
||||
"value": 28.38,
|
||||
"curve": [ 0.17, 28.38, 0.342, 60.09 ]
|
||||
},
|
||||
{
|
||||
"time": 0.5,
|
||||
"value": 60.09,
|
||||
"curve": [ 0.641, 60.09, 0.843, 28.54 ]
|
||||
},
|
||||
{ "time": 1, "value": 28.38 }
|
||||
]
|
||||
},
|
||||
"torso": {
|
||||
"rotate": [
|
||||
{ "value": -10.28 },
|
||||
{
|
||||
"time": 0.1333,
|
||||
"value": -15.39,
|
||||
"curve": [ 0.261, -15.36, 0.324, -9.78 ]
|
||||
},
|
||||
{
|
||||
"time": 0.3667,
|
||||
"value": -9.78,
|
||||
"curve": [ 0.521, -10.8, 0.545, -15.72 ]
|
||||
},
|
||||
{
|
||||
"time": 0.6333,
|
||||
"value": -15.75,
|
||||
"curve": [ 0.688, -15.66, 0.819, -7.07 ]
|
||||
},
|
||||
{
|
||||
"time": 0.8667,
|
||||
"value": -7.07,
|
||||
"curve": [ 0.895, -7.07, 0.975, -10.25 ]
|
||||
},
|
||||
{ "time": 1, "value": -10.28 }
|
||||
],
|
||||
"translate": [
|
||||
{ "x": -1.29, "y": 1.69 }
|
||||
]
|
||||
},
|
||||
"right-foot": {
|
||||
"rotate": [
|
||||
{ "value": -5.25 },
|
||||
{ "time": 0.2333, "value": -1.91 },
|
||||
{ "time": 0.3667, "value": -6.45 },
|
||||
{ "time": 0.5, "value": -5.4 },
|
||||
{ "time": 0.7333, "value": -11.69 },
|
||||
{ "time": 0.8667, "value": 0.46 },
|
||||
{ "time": 1, "value": -5.25 }
|
||||
]
|
||||
},
|
||||
"right-lower-leg": {
|
||||
"rotate": [
|
||||
{
|
||||
"value": -3.39,
|
||||
"curve": [ 0.042, -4.05, 0.099, -45.1 ]
|
||||
},
|
||||
{
|
||||
"time": 0.1333,
|
||||
"value": -45.53,
|
||||
"curve": [ 0.156, -45.53, 0.207, -5.89 ]
|
||||
},
|
||||
{ "time": 0.2333, "value": -4.83 },
|
||||
{ "time": 0.5, "value": -19.53 },
|
||||
{ "time": 0.6333, "value": -64.8 },
|
||||
{
|
||||
"time": 0.7333,
|
||||
"value": -82.56,
|
||||
"curve": [ 0.882, -68.28, 1, -3.39 ]
|
||||
},
|
||||
{ "time": 1, "value": -3.39 }
|
||||
],
|
||||
"translate": [
|
||||
{ "time": 0.5 },
|
||||
{ "time": 0.6333, "x": 2.19, "y": 0.21 },
|
||||
{ "time": 1 }
|
||||
]
|
||||
},
|
||||
"hip": {
|
||||
"translate": [
|
||||
{ "y": -4.16 },
|
||||
{
|
||||
"time": 0.1333,
|
||||
"y": -7.06,
|
||||
"curve": [ 0.217, 0, 0.284, 0, 0.217, -0.53, 0.284, 3.27 ]
|
||||
},
|
||||
{ "time": 0.3667, "y": 6.78 },
|
||||
{ "time": 0.5, "y": -6.14 },
|
||||
{
|
||||
"time": 0.6333,
|
||||
"y": -7.06,
|
||||
"curve": [ 0.717, 0, 0.784, 0, 0.717, -0.53, 0.784, 3.27 ]
|
||||
},
|
||||
{ "time": 0.8667, "y": 6.78 },
|
||||
{ "time": 1, "y": -4.16 }
|
||||
]
|
||||
},
|
||||
"neck": {
|
||||
"rotate": [
|
||||
{ "value": 3.6 },
|
||||
{ "time": 0.1333, "value": 17.5 },
|
||||
{ "time": 0.2333, "value": 6.11 },
|
||||
{ "time": 0.3667, "value": 3.46 },
|
||||
{ "time": 0.5, "value": 5.18 },
|
||||
{ "time": 0.6333, "value": 18.36 },
|
||||
{ "time": 0.7333, "value": 6.09 },
|
||||
{ "time": 0.8667, "value": 2.29 },
|
||||
{ "time": 1, "value": 3.6 }
|
||||
]
|
||||
},
|
||||
"head": {
|
||||
"rotate": [
|
||||
{
|
||||
"value": 3.6,
|
||||
"curve": [ 0, 3.6, 0.094, -0.89 ]
|
||||
},
|
||||
{ "time": 0.1333, "value": -0.21 },
|
||||
{ "time": 0.2333, "value": 6.11 },
|
||||
{ "time": 0.3667, "value": 3.46 },
|
||||
{
|
||||
"time": 0.5,
|
||||
"value": 5.18,
|
||||
"curve": [ 0.5, 5.18, 0.617, -1.4 ]
|
||||
},
|
||||
{ "time": 0.6667, "value": 1.11 },
|
||||
{ "time": 0.7333, "value": 6.09 },
|
||||
{ "time": 0.8667, "value": 2.29 },
|
||||
{ "time": 1, "value": 3.6 }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
Copyright (c) 2013, Esoteric Software
|
||||
|
||||
The images in this project may be redistributed as long as they are accompanied
|
||||
by this license file. The images may not be used for commercial use of any
|
||||
kind.
|
||||
|
||||
The project file is released into the public domain. It may be used as the basis
|
||||
for derivative work.
|
After Width: | Height: | Size: 140 KiB |