v4k initial commit

main
Dominik Madarász 2023-08-10 16:30:56 +02:00
parent 3b67efc1f5
commit 5f798d0d8d
345 changed files with 153350 additions and 804 deletions

7
.gitignore vendored 100644
View File

@ -0,0 +1,7 @@
.art*.zip
__pycache__
.vs
emsdk
demos/html5/*.data
demos/html5/*.js
demos/html5/*.html

213
MAKE.bat
View File

@ -13,14 +13,14 @@ cd `dirname $0`
# tidy environment
if [ "$1" = "tidy" ]; then
rm 0?-* 2> /dev/null
rm fwk.o 2> /dev/null
rm v4k.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 fwk_*.* 2> /dev/null
rm engine/bind/libv4k* 2> /dev/null
rm v4k_*.* 2> /dev/null
rm 3rd_*.* 2> /dev/null
rm libfwk* 2> /dev/null
rm libv4k* 2> /dev/null
rm -rf *.dSYM 2> /dev/null
rm *.png 2> /dev/null
rm *.mp4 2> /dev/null
@ -38,6 +38,11 @@ if [ "$1" = "join" ]; then
sh tools/join.bat
exit
fi
if [ "$1" = "prep" ]; then
sh MAKE.bat join
sh MAKE.bat amalgamation
exit
fi
# cook
if [ "$1" = "cook" ]; then
cc -o cook tools/cook.c -I.
@ -62,6 +67,8 @@ while [ $# -ge 1 ]; do
echo sh MAKE.bat [gcc,clang,tcc] [dbg,dev,rel] [dll,static]
echo sh MAKE.bat [tidy]
echo sh MAKE.bat [split,join]
echo sh MAKE.bat [amalgamation]
echo sh MAKE.bat [prep]
echo sh MAKE.bat [cook]
echo sh MAKE.bat [sln]
exit
@ -147,19 +154,19 @@ 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/
export import="libfwk.so -Wl,-rpath,./"
echo libv4k.so && $cc -o libv4k.so engine/v4k.c -shared -fPIC -w -lX11 -lm -ldl -lpthread $flags $args
cp libv4k.so engine/bind/
export import="libv4k.so -Wl,-rpath,./"
else
# framework (static)
echo fwk && $cc -c engine/fwk.c -w $flags $args
export import=fwk.o
echo v4k && $cc -c engine/v4k.c -w $flags $args
export import=v4k.o
fi
# editor
@ -202,19 +209,19 @@ 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
export import=libfwk.dylib
echo libv4k && cc -ObjC -dynamiclib -o libv4k.dylib engine/v4k.c -framework cocoa -framework iokit -framework audiotoolbox -w $flags $args
cp libv4k.dylib engine/bind
export import=libv4k.dylib
else
# framework
echo fwk && cc -c -ObjC engine/fwk.c -w $flags $args
export import=fwk.o
echo v4k && cc -c -ObjC engine/v4k.c -w $flags $args
export import=v4k.o
fi
# editor
@ -253,13 +260,17 @@ if "%1"=="help" (
echo %0 [docs] ; generate tools/docs/docs.html file
echo %0 [cook] ; cook .zipfiles with tools/cook.ini cookbook
echo %0 [sync] ; sync repo to latest
echo %0 [pull] ; pull changes from 'latest' upstream
echo %0 [git] ; prepare for commit
echo %0 [push] ; prepare for commit, stage changes and commit them
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 [bind] ; generate lua bindings
echo %0 [checkmem] ; check untracked allocators in V4K
echo %0 [split^|join] ; engine/v4k* ^>split^> engine/split/* or engine/split/* ^>join^> engine/v4k*
echo %0 [amalgamation] ; combine engine/v4k* into a single-header file
echo %0 [prep] ; combine split files into a single-header file, ready for use
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] [nov4k^|nodemos^|editor] [vis] [-- args]
echo cl \
echo tcc ^|
echo cc ^| select compiler. must be accessible in PATH
@ -269,11 +280,11 @@ if "%1"=="help" (
echo dbg \ debug build: [x] ASAN [x] poison [x] asserts [x] profiler [x] symbols [ ] zero optimizations
echo dev ^| develop build: [ ] ASAN [x] poison [x] asserts [x] profiler [x] symbols [*] some optimizations (default^)
echo rel / release build: [ ] ASAN [ ] poison [ ] asserts [ ] profiler [x] symbols (cl,clang-cl only^) [x] many optimizations
echo static \ link fwk as static library
echo dll / link fwk as dynamic library (dll^) (default^)
echo nofwk \ do not compile framework
echo static \ link v4k as static library
echo dll / link v4k as dynamic library (dll^) (default^)
echo nov4k \ do not compile framework
echo nodemos ^| do not compile demos
echo noeditor / do not compile editor
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.
@ -290,18 +301,18 @@ if "%1"=="sync" (
rem cook asset files
if "%1"=="cook" (
rem generate cooker twice: use multi-threaded version if available (cl). then cook.
rem call tools\tcc tools\cook.c -Iengine engine\fwk.c
rem cl tools\cook.c -Iengine engine\fwk.c
rem call tools\tcc tools\cook.c -Iengine engine\v4k.c
rem cl tools\cook.c -Iengine engine\v4k.c
rem cook
tools\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
tools\luajit tools\luajit_make_bindings.lua > v4k.lua
move /y v4k.lua engine\bind
exit /b
)
@ -318,45 +329,45 @@ if "%1"=="docs" (
set /p LAST_MODIFIED=<info.obj
rem ...and generate docs
cl tools\docs\docs.c engine\fwk.c -Iengine %2
docs engine\fwk.h --excluded=3rd_glad.h,fwk.h,fwk_compat.h, > fwk.html
move /y fwk.html engine\
cl tools\docs\docs.c engine\v4k.c -Iengine %2
docs engine\v4k.h --excluded=3rd_glad.h,v4k.h,v4k_compat.h, > v4k.html
move /y v4k.html engine\
exit /b
)
rem generate single-header distribution
if "%1"=="amalgamation" (
echo // This file is intended to be consumed by a compiler. Do not read. > fwk.h
echo // **Browse to any of the sources in engine/split/ folder instead** >> fwk.h
echo // ---------------------------------------------------------------- >> fwk.h
echo // #define FWK_IMPLEMENTATION early in **one** C file to unroll the >> fwk.h
echo // implementation. The symbol must be defined in a C (not C++^) file>> fwk.h
echo // ---------------------------------------------------------------- >> fwk.h
echo #pragma once >> fwk.h
type engine\split\3rd_font_md.h >> fwk.h
type engine\split\3rd_glad.h >> fwk.h
type engine\fwk.h >> fwk.h
echo #ifdef FWK_IMPLEMENTATION >> fwk.h
echo #define FWK_3RD >> fwk.h
type engine\fwk >> fwk.h
type engine\fwk.c >> fwk.h
echo #endif // FWK_IMPLEMENTATION >> fwk.h
move /y fwk.h engine\joint
echo // This file is intended to be consumed by a compiler. Do not read. > v4k.h
echo // **Browse to any of the sources in engine/split/ folder instead** >> v4k.h
echo // ---------------------------------------------------------------- >> v4k.h
echo // #define V4K_IMPLEMENTATION early in **one** C file to unroll the >> v4k.h
echo // implementation. The symbol must be defined in a C (not C++^) file>> v4k.h
echo // ---------------------------------------------------------------- >> v4k.h
echo #pragma once >> v4k.h
type engine\split\3rd_font_md.h >> v4k.h
type engine\split\3rd_glad.h >> v4k.h
type engine\v4k.h >> v4k.h
echo #ifdef V4K_IMPLEMENTATION >> v4k.h
echo #define V4K_3RD >> v4k.h
type engine\v4k >> v4k.h
type engine\v4k.c >> v4k.h
echo #endif // V4K_IMPLEMENTATION >> v4k.h
move /y v4k.h engine\joint
exit /b
)
rem generate prior files to a github release
if "%1"=="github" (
rem generate prior files to a git release
if "%1"=="git" (
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
rem rd /q /s engine\split
rem md engine\split
rem move /y fwk_*.? engine\split\
rem move /y v4k_*.? engine\split\
rem move /y 3rd_*.? engine\split\
call make.bat tidy
@ -364,6 +375,28 @@ rem move /y 3rd_*.? engine\split\
exit /b
)
if "%1"=="pull" (
git fetch v4k
git merge -Xrename-threshold=50 v4k/main
exit /b
)
if "%1"=="push" (
call make.bat tidy
git status
git add .
git commit
exit /b
)
if "%1"=="prep" (
call make.bat join
call make.bat amalgamation
exit /b
)
rem shortcuts for split & join amalgamation scripts
if "%1"=="split" (
call tools\split
@ -376,11 +409,19 @@ if "%1"=="join" (
rem check memory api calls
if "%1"=="checkmem" (
findstr /RNC:"[^_xv]realloc[(]" engine\fwk.c engine\split\fwk*
findstr /RNC:"[^_xv]malloc[(]" engine\fwk.c engine\split\fwk*
findstr /RNC:"[^_xv]free[(]" engine\fwk.c engine\split\fwk*
findstr /RNC:"[^_xv]calloc[(]" engine\fwk.c engine\split\fwk*
findstr /RNC:"[^_xv]strdup[(]" engine\fwk.c engine\split\fwk*
findstr /RNC:"[^_xv]realloc[(]" engine\v4k.c engine\split\v4k*
findstr /RNC:"[^_xv]xrealloc[(]" engine\v4k.c engine\split\v4k*
findstr /RNC:"[^_xv]malloc[(]" engine\v4k.c engine\split\v4k*
findstr /RNC:"[^_xv]free[(]" engine\v4k.c engine\split\v4k*
findstr /RNC:"[^_xv]calloc[(]" engine\v4k.c engine\split\v4k*
findstr /RNC:"[^_xv]strdup[(]" engine\v4k.c engine\split\v4k*
exit /b
)
if "%1"=="html5" (
pushd demos\html5
call make.bat %2
popd
exit /b
)
@ -391,7 +432,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\v4k.dll > nul 2> nul
del .temp*.* > nul 2> nul
del *.zip > nul 2> nul
del *.mem > nul 2> nul
@ -408,7 +449,7 @@ if "%1"=="tidy" (
del *.def > nul 2> nul
del *.dll > nul 2> nul
del 3rd_*.* > nul 2> nul
del fwk_*.* > nul 2> nul
del v4k_*.* > nul 2> nul
rem del ??-*.* > nul 2> nul
del temp_*.* > nul 2> nul
rd /q /s .vs > nul 2> nul
@ -426,9 +467,9 @@ set dll=dll
set build=dev
set args=-Iengine
set other=
set fwk=yes
set v4k=yes
set demos=yes
set editor=yes
set editor=no
set vis=no
set sln=no
set rc=0
@ -452,9 +493,10 @@ set rc=0
if "%1"=="vis" set "vis=yes" && goto loop
if "%1"=="nofwk" set "fwk=no" && goto loop
if "%1"=="nov4k" set "v4k=no" && goto loop
if "%1"=="nodemos" set "demos=no" && goto loop
if "%1"=="noeditor" set "editor=no" && goto loop
if "%1"=="editor" set "editor=yes" && goto loop
if "%1"=="tcc" set "cc=%1" && goto loop
if "%1"=="cl" set "cc=%1" && goto loop
@ -530,10 +572,10 @@ if "!cc!"=="cl" (
if "!dll!"=="static" (
set export=/c
set import=fwk.obj
set import=v4k.obj
) else (
set export=/DAPI=EXPORT /LD
set import=/DAPI=IMPORT fwk.lib
set import=/DAPI=IMPORT v4k.lib
)
if "!build!"=="rel" (
@ -554,15 +596,15 @@ if "!cc!"=="cl" (
if "!dll!"=="static" (
set export=/c
set import=fwk.obj
set import=v4k.obj
) else (
set export=/DAPI=EXPORT /LD
set import=/DAPI=IMPORT fwk.lib
set import=/DAPI=IMPORT v4k.lib
)
set warnings_fwkc=-Wno-deprecated-declarations -Wno-tautological-constant-out-of-range-compare
set warnings_v4kc=-Wno-deprecated-declarations -Wno-tautological-constant-out-of-range-compare
set warnings_demos=-Wno-empty-body -Wno-format-security -Wno-pointer-sign
set warnings=!warnings_fwkc! !warnings_demos!
set warnings=!warnings_v4kc! !warnings_demos!
if "!build!"=="rel" (
set args=!warnings! /nologo /Zi /MT /openmp /DNDEBUG !args! /Os /Ox /O2 /Oy /GF /Gw /arch:AVX2
@ -581,10 +623,10 @@ if "!cc!"=="cl" (
if "!dll!"=="static" (
set export=-c
set import=fwk.o
set import=v4k.o
) else (
set export=-DAPI=EXPORT -shared
set import=-DAPI=IMPORT fwk.def
set import=-DAPI=IMPORT v4k.def
)
if "!build!"=="rel" (
@ -606,10 +648,10 @@ if "!cc!"=="cl" (
if "!dll!"=="static" (
set export=-c
set import=fwk.o !libs! -Wl,--allow-multiple-definition
set import=v4k.o !libs! -Wl,--allow-multiple-definition
) else (
set export=-DAPI=EXPORT -shared -o fwk.dll !libs! -Wl,--out-implib,fwk.a
set import=-DAPI=IMPORT fwk.a
set export=-DAPI=EXPORT -shared -o v4k.dll !libs! -Wl,--out-implib,v4k.a
set import=-DAPI=IMPORT v4k.a
)
set args=-Wno-implicit-function-declaration !args!
@ -635,31 +677,34 @@ echo import=!import!, export=!export!
if "!cc!"=="tcc" set "cc=call tools\tcc"
rem detect wether user-defined sources use single-header distro
rem if so, remove API=IMPORT flags and also do not produce fwk.dll by default
rem if so, remove API=IMPORT flags and also do not produce v4k.dll by default
if not "!other!"=="" (
>nul find "FWK_IMPLEMENTATION" !other! && (
>nul find "V4K_IMPLEMENTATION" !other! && (
set import=
set fwk=no
set v4k=no
)
)
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 "!v4k!"=="yes" (
if "!vis!"=="yes" echo !cc! engine\v4k.c !export! !args! ^&^& if "!dll!"=="dll" copy /y v4k.dll engine\bind ^> nul
!echo! v4k && !cc! engine\v4k.c !export! !args! && if "!dll!"=="dll" copy /y v4k.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! hello && !cc! !o! hello.exe hello.c !args! || set rc=1
!echo! hello && !cc! !o! hello.exe hello.c !args! || set rc=1
!echo! 99-syncdemo && !cc! !o! 99-syncdemo.exe demos\99-syncdemo.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-material && !cc! !o! 99-material.exe demos\99-material.c !import! !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

237
README.md
View File

@ -1,19 +1,11 @@
<h1 align="center"><a href="https://bit.ly/-f-w-k-">F·W·K</a></h1>
<h1 align="center">V·4·K</h1>
<p align="center">
3D game framework in C.<br/>
</p>
<p align="center">
<img src="https://i.imgur.com/sInbRoA.gif"/><br/>
3D game engine/framework in C, with Luajit and Python bindings.<br/>
</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).
@ -38,7 +30,7 @@
- [x] Audio: WAV/FLAC, OGG/MP1/MP3, FUR, MOD/XM/S3M/IT, SFXR and MID+SF2/SF3.
- [x] Video: MP4, MPG, OGV, MKV, WMV and AVI. Also, MP4 recording with MPEG-1 fallback.
- [x] Model: IQM/E, GLTF/2, GLB, FBX, OBJ, DAE, BLEND, MD3/5, MS3D, SMD, X, 3DS, BVH, DXF, LWO.
- [x] Render: PBR (metallic-roughness) workflow. <!-- @todo: merge demo_pbr.c rendering code into fwk_render.c -->
- [x] Render: PBR (metallic-roughness) workflow. <!-- @todo: merge demo_pbr.c rendering code into v4k_render.c -->
- [x] Render: Cubemaps, panoramas and spherical harmonics. Rayleigh/Mie scattering.
- [x] Render: Post-effects (SSAO,FXAA1/3,CRT,Contrast,Grain,Outline,Vignette...).
- [x] Render: 3D Anims, skeletal anims, hardware skinning and instanced rendering.
@ -52,25 +44,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/v4k2023).
## 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.
@ -79,7 +82,7 @@ Nice to have/extend (engine dependant):
- Animation pass: playlists, additive, blend/shapes, ik/bones, animgraph/controllers.
// 6) anims, I (playlist: ~~forward/backwards/loop/rewind)~~, II (~~blend~~/shapes), III (ik/bone), IV (graph/controller)
// ~~blend anims~~, animtracks+animevents, additive anims,
// fwk_data: quantization: ~~half, quant, microfloat~~.
// v4k_data: quantization: ~~half, quant, microfloat~~.
// anim; ~~keyframes[] { frame+delay,frame+delay,... }, anim duration, anim flip,~~
// anim tracks / anim events
- Audio pass: 3D audio, HRTF, FFT, filtering and sound occlusion.
@ -129,8 +132,8 @@ Engine types:
Nice to have:
- [ ] fix leaks and todos
- [ ] fwk_app: cpu usage, orientation
- [ ] fwk_input: mouse clip, mouse wrap,
- [ ] v4k_app: cpu usage, orientation
- [ ] v4k_input: mouse clip, mouse wrap,
- [ ] zip0 seek-vfs optimization. zip_append_file is suboptimal, and requires tons of contiguous memory for giant files.
Almost done:
@ -172,37 +175,31 @@ Almost done:
-->
## Hello FWK
## Hello V4K
```C
#include "fwk.h" // Minimal C sample
#include "v4k.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!");
puts("hello V4K from C!");
}
}
```
```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
while fwk.window_swap() and fwk.input(fwk.KEY_ESC) == 0 do -- game loop
print("hello FWK from Lua!")
local v4k = require("v4k") -- Minimal Lua sample
v4k.window_create(75.0,0) -- 75% size, no extra flags
while v4k.window_swap() and v4k.input(v4k.KEY_ESC) == 0 do -- game loop
print("hello V4K from Lua!")
end
```
## Quickstart
- Double-click `MAKE.bat` (Win) or `sh MAKE.bat` (Linux/OSX) to compile everything.
- `MAKE.bat sln` (Win) or `sh MAKE.bat sln` (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 +212,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 V4K.
- 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/v4k.h, v4k.c and v4k` 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)"),
[Nuulbee](https://sketchfab.com/3d-models/kgirls01-d2f946f58a8040ae993cda70c97b302c "for kgirls01 3D model (CC BY-NC-ND 4.0)"),
[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)"),
[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)"),
[Vassvik](https://github.com/vassvik/mv_easy_font "for mv_easy_font (Unlicense)"),
[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)")
- [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)")
- [ID Software, David St-Louis](https://github.com/Daivuk/PureDOOM "for PureDOOM (Doom License)")
- [Miloslav Číž](https://codeberg.org/drummyfish/Anarch "for Anarch (CC0)")
- [Quaternius](https://www.patreon.com/quaternius "for the lovely 3D robots (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/V4K/issues"><img alt="Issues" src="https://img.shields.io/github/issues-raw/r-lyeh/V4K.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>

View File

@ -0,0 +1,30 @@
#include <stdio.h>
#include <inttypes.h>
/*
https://www.tastyfish.cz/lrs/bytebeat.html
Outputting the variable i creates a periodical saw-shaped beat, multiplication/division decreases/increases the speed, addition/subtraction shifts the phase backward/forward.
Squaring (and other powers) create a wah-wah effect.
Crazier patterns can be achieved by using the variable in places of numerical constants, e.g. i << ((i / 512) % 8) (shifting by a value that depends on the variable).
Modulo (%) increases the frequency and decreases volume (limits the wave peak).
So called Sierpinski harmonies are often used melodic expressions of the form i*N & i >> M.
Bitwise and (&) can add distortion (create steps in the wave).
A macro structure of the song (silent/louds parts, verse/chorus, ...) can be achieved by combining multiple patterns with some low-frequency pattern, e.g. this alternates a slower and faster beat: int cond = (i & 0x8000) == 0;, cond * (i / 16) + !cond * (i / 32)
Extra variables can add more complexity (e.g. precompute some variable a which will subsequently be used multiple times in the final formula).
*/
int main(void) {
for (int t = 0;; ++t) {
putchar(
t|(t<<((t/920)%16))|(t/3*t&(t<<13)*t)|(t%16386?123:t&203?148:3)&(t/920)
// (t/8)>>(t>>9)*t/((t>>14&3)+4)
// ((1-(((t+10)>>((t>>9)&((t>>14))))&(t>>4&-2)))*2)*(((t>>10)^((t+((t>>6)&127))>>10))&1)*32+128
// t*((0xbadbea75>>((t>>12)&30)&3)*0.25*(0x5afe5>>((t>>16)&28)&3))
// ((t>>4)*(13&(0x8898a989>>(t>>11&30)))&255)+((((t>>9|(t>>2)|t>>8)*10+4*((t>>2)&t>>15|t>>8))&255)>>1)
// t*((t>>12|t>>8)&63&t>>4)
// ((0x47 >> ((t >> 9) % 32)) & (t >> (t % 32))) | (0x57 >> ((t >> 7) % 32)) | (0x06 >> ((t >> ((((t * 11) >> 14) & 0x0e) % 32)) % 32))
);
}
return 0;
}

View File

@ -0,0 +1,65 @@
// @todo: object_print(obj, "");
#include "v4k.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( "bjork-all-is-full-of-love.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 );
}
}

128
demos/99-net_rpc.c 100644
View File

@ -0,0 +1,128 @@
// core for remote procedure calls
// - rlyeh, public domain.
//
// format:
// - query: id method [args.....] ('subject' is alias for arg[0]; and 'object' can be any arg[1..])
// - answer: id error [values...]
//
// todo:
// - [ ] promote rpc_function to (int argc, void **args) ?
#define V4K_IMPLEMENTATION
#include "engine/joint/v4k.h"
#ifndef RPC_H
#define RPC_H
void rpc_insert(const char *signature, void * function );
char *rpc(const char *cmdline); // for debugging purposes
char* rpc_quick(unsigned query_number, const char* cmdline);
char *rpc_full(unsigned id, const char* method, unsigned num_args, char *args[]);
#endif
// -----------------------------------------------------------------------------
#define RPC_C
#ifdef RPC_C
#pragma once
typedef void* (*rpc_function)();
typedef struct rpc_call {
char *method;
rpc_function function;
uint64_t function_hash;
} rpc_call;
#define RPC_SIGNATURE_i_iii UINT64_C(0x9830e90d3327e74b) // HASH_STR("int(int,int,int)")
#define RPC_SIGNATURE_i_ii UINT64_C(0xa7fcab437d38c750) // HASH_STR("int(int,int)")
#define RPC_SIGNATURE_s_s UINT64_C(0xc4db3d7818162463) // HASH_STR("char*(char*)")
#define RPC_SIGNATURE_s_v UINT64_C(0x8857a7c1cd20bd7b) // HASH_STR("char*(void)")
rpc_call rpc_new_call(const char *signature, rpc_function function) {
if( signature && function ) {
array(char*)tokens = strsplit(signature, "(,)"); array_pop(tokens);
if( array_count(tokens) >= 1 ) {
char *method = strrchr(tokens[0], ' ')+1;
char *rettype = va("%.*s", (int)(method - tokens[0] - 1), tokens[0]);
int num_args = array_count(tokens) - 1;
uint64_t hash = hash_str(va("%s(%s)", rettype, num_args ? strjoin(num_args, &tokens[1], ",") : "void" ));
method = va("%s%d", method, num_args );
#ifdef _DEBUG
printf("%p %p %s %s(", function, (void*)hash, rettype, method); for(int i = 1, end = array_count(tokens); i < end; ++i) printf("%s%s", tokens[i], i == (end-1)? "":", "); puts(");");
#endif
return (rpc_call) { strdup(method), function, hash }; // LEAK
}
}
return (rpc_call) {0};
}
static map(char*, rpc_call) rpc_calls = 0;
void rpc_insert(const char *signature, void *function ) {
rpc_call call = rpc_new_call(signature, function);
if( call.method ) {
if( !rpc_calls ) map_init(rpc_calls, less_str, hash_str);
if( map_find(rpc_calls, call.method)) {
map_erase(rpc_calls, call.method);
}
map_insert(rpc_calls, call.method, call);
}
}
char *rpc_full(unsigned id, const char* method, unsigned num_args, char *args[]) {
#ifdef _DEBUG
printf("id:%x method:%s args:", id, method );
for( int i = 0; i < num_args; ++i ) printf("%s", args[i]); puts("");
#endif
method = va("%s%d", method, num_args);
rpc_call *found = map_find(rpc_calls, (char*)method);
if( found ) {
switch(found->function_hash) {
default:
case RPC_SIGNATURE_i_iii: return va("%d \"%d %s\" %d", id, errno, strerror(errno), (int)(uintptr_t)found->function(atoi(args[0]), atoi(args[1]), atoi(args[2])) );
case RPC_SIGNATURE_i_ii: return va("%d \"%d %s\" %d", id, errno, strerror(errno), (int)(uintptr_t)found->function(atoi(args[0]), atoi(args[1])) );
case RPC_SIGNATURE_s_s: return va("%d \"%d %s\" %s", id, errno, strerror(errno), (char*)found->function(args[0]) );
case RPC_SIGNATURE_s_v: return va("%d \"%d %s\" %s", id, errno, strerror(errno), (char*)found->function() );
}
}
return va("%d \"0\" ?", id);
}
char* rpc_quick(unsigned query_number, const char* cmdline) {
array(char*) args = os_argparse(cmdline, false);
int num_args = array_count(args);
char *ret = num_args ? rpc_full(query_number, args[0], num_args - 1, &args[1]) : rpc_full(query_number, "", 0, NULL);
array_free(args);
return ret;
}
char *rpc(const char *cmdline) { // for debugging purposes
char *rc = rpc_quick(0, cmdline);
puts(rc);
return rc;
}
// -----------------------------------------------------------------------------
int rpc_add2(int num1, int num2) {
return num1+num2;
}
int rpc_add3(int num1, int num2, int num3) {
return num1+num2+num3;
}
char *rpc_echo(char *text) {
return text;
}
int main() {
rpc_insert("int add(int,int)", rpc_add2);
rpc_insert("int add(int,int,int)", rpc_add3);
rpc_insert("char* echo(char*)", rpc_echo);
rpc("add 1 2"); // -> 3
rpc("add 100 3 -3"); // -> 100
rpc("echo \"hello world\""); // -> hello world
}
#endif // RPC_C

View File

@ -0,0 +1,43 @@
// shadertoy viewer
// - rlyeh, public domain
#include "v4k.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() && !input(KEY_ESC)) {
// 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("V4K - %s", browser[selector]));
sh = shadertoy( browser[selector], 0 );
}
// draw
shadertoy_render(&sh, window_delta());
// UI
if( ui_panel("Shadertoy", 0)) {
if( ui_list("In use", (const char**)browser, browser_count, &selector) ) {
reload = 1;
}
ui_panel_end();
}
}
}

108
demos/99-syncdemo.c 100644
View File

@ -0,0 +1,108 @@
#include "v4k.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};
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 */);
};
}
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;
}
// 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_grid(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, stringf("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, stringf("npc #%d", id));
}
// stats
char title[64];
sprintf(title, "player #%lld", self_id);
window_title(title);
}
}

Binary file not shown.

View File

@ -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

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

View File

@ -0,0 +1,40 @@
# Blender v2.64 (sub 0) OBJ File: ''
# www.blender.org
mtllib data/cube.mtl
o Cube
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -0.999999
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vt 0.666667 0.500000
vt 0.666667 1.000000
vt 0.333333 1.000000
vt 1.000000 0.500000
vt 1.000000 1.000000
vt 0.998981 0.000000
vt 0.666667 0.001019
vt 0.333333 0.500000
vt 0.333333 0.001020
vt 0.000000 1.000000
vt 0.333333 0.000000
vt 0.000000 0.500000
vt 0.665647 0.000000
vt 0.000000 0.001020
usemtl Material
s off
f 1/1 2/2 3/3
f 5/4 8/5 6/1
f 1/6 5/4 2/7
f 2/8 6/9 3/1
f 3/8 7/3 8/10
f 5/11 1/8 4/12
f 4/8 1/1 3/3
f 8/5 7/2 6/1
f 5/4 6/1 2/7
f 6/9 7/13 3/1
f 4/12 3/8 8/10
f 8/14 5/11 4/12

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,6 @@
Kristof Lovas
https://kristoflovas.gumroad.com/l/FWVNShaderBall
This is a much lower poly shader ball mesh than the regular ones available on the internet, its made from 10.000 triangles, and it uses face weighted normals, to achieve smooth shading. Its ideal for non tessellated material presentation, or to be used in a material showcasing scene, where a lot of them would appear on the screen at the same time.
To get the best shading, make sure you the vertex normals from the fbx, so the face weighted normals works!

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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);
}

View File

@ -0,0 +1,165 @@
// Protean clouds by nimitz (twitter: @stormoid)
// https://www.shadertoy.com/view/3l23Rh
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// Contact the author for other licensing options
/*
Technical details:
The main volume noise is generated from a deformed periodic grid, which can produce
a large range of noise-like patterns at very cheap evalutation cost. Allowing for multiple
fetches of volume gradient computation for improved lighting.
To further accelerate marching, since the volume is smooth, more than half the the density
information isn't used to rendering or shading but only as an underlying volume distance to
determine dynamic step size, by carefully selecting an equation (polynomial for speed) to
step as a function of overall density (not necessarialy rendered) the visual results can be
the same as a naive implementation with ~40% increase in rendering performance.
Since the dynamic marching step size is even less uniform due to steps not being rendered at all
the fog is evaluated as the difference of the fog integral at each rendered step.
*/
mat3 rot_x(float a){float sa = sin(a); float ca = cos(a); return mat3(1.,.0,.0, .0,ca,sa, .0,-sa,ca);}
mat3 rot_y(float a){float sa = sin(a); float ca = cos(a); return mat3(ca,.0,sa, .0,1.,.0, -sa,.0,ca);}
mat3 rot_z(float a){float sa = sin(a); float ca = cos(a); return mat3(ca,sa,.0, -sa,ca,.0, .0,.0,1.);}
mat2 rot(in float a){float c = cos(a), s = sin(a);return mat2(c,s,-s,c);}
const float fov = 1.5;
const mat3 m3 = mat3(0.33338, 0.56034, -0.71817, -0.87887, 0.32651, -0.15323, 0.15162, 0.69596, 0.61339)*1.93;
float mag2(vec2 p){return dot(p,p);}
float mag2(vec3 p){return dot(p,p);}
float linstep(in float mn, in float mx, in float x){ return clamp((x - mn)/(mx - mn), 0., 1.); }
vec2 disp(float t){ return vec2(sin(t*0.22)*1., cos(t*0.175)*1.)*2.; }
float prm1 = 0.;
vec2 bsMo = vec2(0);
float colVar = 0.;
float shapeVar = 0.;
float mg2(vec2 p){return dot(p,p);}
vec2 map(vec3 p)
{
vec3 p2 = p;
p2.xy -= disp(p.z).xy;
p.xy *= rot(sin(p.z+iTime)*0.15 + iTime*0.09);
float cl = mag2(p2.xy);
float d = 0.;
p *= .61;
float z = 1.;
float trk = 1.;
for(int i = 0; i < 5; i++)
{
p += sin(p.zxy*0.75*trk + iTime*trk*.8)*(0.1 + prm1*0.2);
d -= abs(dot(cos(p), sin(p.yzx))*z);
z *= 0.57;
trk *= 1.4;
p = p*m3;
}
d = abs(d + prm1*3.)+ prm1*.3 - 2.5 + bsMo.y;
return vec2(d + cl*.2 + 0.25, cl);
}
vec4 render( in vec3 ro, in vec3 rd, float time )
{
vec4 rez = vec4(0);
const float ldst = 8.;
vec3 lpos = vec3(disp(time + ldst)*0.5, time + ldst);
float t = 1.5;
float fogT = 0.;
for(int i=0; i<130; i++)
{
if(rez.a > 0.99)break;
vec3 pos = ro + t*rd;
vec2 mpv = map(pos);
float den = clamp(mpv.x-0.3,0.,1.)*1.12;
float dn = clamp((mpv.x + 2.),0.,3.);
vec4 col = vec4(0);
if (mpv.x > 0.6)
{
col = vec4(sin(vec3(5.,0.4,0.2) + mpv.y*0.1 +sin(pos.z*0.4)*0.5 + 1.8)*0.5 + 0.5,0.08);
col *= den*den*den;
col.rgb *= linstep(4.,-2.5, mpv.x)*2.3;
float dif = clamp((den - map(pos+.8).x)/9., 0.001, 1. );
dif += clamp((den - map(pos+.35).x)/2.5, 0.001, 1. );
col.xyz *= den*(vec3(0.005,.045,.075) + 1.5*vec3(0.033,0.07,0.03)*dif);
}
float fogC = exp(t*0.2 - 2.2);
col.rgba += vec4(0.06,0.11,0.11, 0.1)*clamp(fogC-fogT, 0., 1.);
fogT = fogC;
rez = rez + col*(1. - rez.a);
t += clamp(0.5 - dn*dn*.05, 0.09, 0.3);
}
return clamp(rez, 0.0, 1.0);
}
float getsat(vec3 c)
{
float mi = min(min(c.x, c.y), c.z);
float ma = max(max(c.x, c.y), c.z);
return (ma - mi)/(ma+ 1e-7);
}
//from my "Will it blend" shader (https://www.shadertoy.com/view/lsdGzN)
vec3 iLerp(in vec3 a, in vec3 b, in float x)
{
vec3 ic = mix(a, b, x) + vec3(1e-6,0.,0.);
float sd = abs(getsat(ic) - mix(getsat(a), getsat(b), x));
vec3 dir = normalize(vec3(2.*ic.x - ic.y - ic.z, 2.*ic.y - ic.x - ic.z, 2.*ic.z - ic.y - ic.x));
float lgt = dot(vec3(1.0), ic);
float ff = dot(dir, normalize(ic));
ic += 1.5*dir*sd*ff*lgt;
return clamp(ic,0.,1.);
}
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;
vec2 mous = iMouse.xy/iResolution.xy;
vec2 mo = mous - 0.5;
bsMo = mo;
mo = (mo==vec2(-0.5))?mo=vec2(0.12, 0.15):mo;
mo.x *= iResolution.x/iResolution.y;
mo*= 4.14;
mo.y = clamp(mo.y*0.6-.5,-4. ,.15 );
float time = iTime*3.;
vec3 ro = vec3(0,0,time);
ro += vec3(sin(iTime)*0.5,sin(iTime*1.)*0.,0);
float dspAmp = .85;
ro.xy += disp(ro.z)*dspAmp;
float tgtDst = 3.5;
vec3 target = normalize(ro - vec3(disp(time + tgtDst)*dspAmp, time + tgtDst));
ro.x -= bsMo.x*2.;
vec3 rightdir = normalize(cross(target, vec3(0,1,0)));
vec3 updir = normalize(cross(rightdir, target));
rightdir = normalize(cross(updir, target));
vec3 rd=normalize((p.x*rightdir + p.y*updir)*1. - target);
rd.xy *= rot(-disp(time + 3.5).x*0.2 + bsMo.x);
prm1 = smoothstep(-0.4, 0.4,sin(iTime*0.3));
vec4 scn = render(ro, rd, time);
vec3 col = scn.rgb;
col = iLerp(col.bgr, col.rgb, clamp(1.-prm1,0.05,1.));
col = pow(col, vec3(.55,0.65,0.6))*vec3(1.,.97,.9);
col *= pow( 16.0*q.x*q.y*(1.0-q.x)*(1.0-q.y), 0.12)*0.7+0.3; //Vign
fragColor = vec4( col, 1.0 );
}

View File

@ -0,0 +1,313 @@
//bio.jpg, hill.jpg, check.jpg
//Raymarch settings
#define MIN_DIST 0.001
#define MAX_DIST 32.0
#define MAX_STEPS 96
#define STEP_MULT 0.9
#define NORMAL_OFFS 0.01
#define FOCAL_LENGTH 0.8
//Scene settings
//#define SHOW_RAY_COST
//Colors
#define SKY_COLOR_1 vec3(0.60,0.00,0.00)
#define SKY_COLOR_2 vec3(1.00,0.50,0.00)
#define SUN_COLOR_1 vec3(1.00, 0.00, 0.00)
#define SUN_COLOR_2 vec3(1.00, 1.00, 0.00)
#define GRID_COLOR_1 vec3(0.00, 0.05, 0.20)
#define GRID_COLOR_2 vec3(1.00, 0.20, 0.60)
#define WATER_COLOR vec3(0.50, 1.00, 2.90)
//Parameters
#define GRID_SIZE 0.20
#define GRID_LINE_SIZE 1.25
#define WATER_LEVEL 0.20
#define WATER_FOG_SIZE 0.05
#define SUN_DIRECTION vec3( 0.10,-1.00,-0.03)
#define CLOUD_SCROLL vec2(0.002, 0.001)
#define CLOUD_BLUR 2.0
#define CLOUD_SCALE vec2(0.04, 0.10)
#define MOUNTAIN_SCALE 6.0
#define MOUNTAIN_SHIFT 5.3
//Color modes
//vec3(#,#,#) Number of bits per channel
//24 bit color
#define RGB888 vec3(8,8,8)
//16 bit color
#define RGB565 vec3(5,6,5)
#define RGB664 vec3(6,6,4)
//8 bit color
#define RGB332 vec3(3,3,2)
#define RGB242 vec3(2,4,2)
#define RGB222 vec3(2,2,2) //+2 unused
//#define DITHER_ENABLE
#define COLOR_MODE RGB242
//Object IDs
#define SKYDOME 0.
#define FLOOR 1.
#define RIVER 2.
float pi = atan(1.0) * 4.0;
float tau = atan(1.0) * 8.0;
vec3 dither(vec3 color, vec3 bits, vec2 pixel)
{
vec3 cmax = exp2(bits)-1.0;
vec3 dithfactor = mod(color, 1.0 / cmax) * cmax;
float dithlevel = texture(iChannel2,pixel / iChannelResolution[2].xy).r;
vec3 cl = floor(color * cmax)/cmax;
vec3 ch = ceil(color * cmax)/cmax;
return mix(cl, ch, step(dithlevel, dithfactor));
}
struct MarchResult
{
vec3 position;
vec3 normal;
float dist;
float steps;
float id;
};
//Returns a rotation matrix for the given angles around the X,Y,Z axes.
mat3 Rotate(vec3 angles)
{
vec3 c = cos(angles);
vec3 s = sin(angles);
mat3 rotX = mat3( 1.0, 0.0, 0.0, 0.0,c.x,s.x, 0.0,-s.x, c.x);
mat3 rotY = mat3( c.y, 0.0,-s.y, 0.0,1.0,0.0, s.y, 0.0, c.y);
mat3 rotZ = mat3( c.z, s.z, 0.0,-s.z,c.z,0.0, 0.0, 0.0, 1.0);
return rotX * rotY * rotZ;
}
//==== Distance field operators/functions by iq. ====
vec2 opU(vec2 d1, vec2 d2)
{
return (d1.x < d2.x) ? d1 : d2;
}
vec2 opS(vec2 d1, vec2 d2)
{
return (-d1.x > d2.x) ? d1*vec2(-1,1) : d2;
}
vec2 sdSphere(vec3 p, float s, float id)
{
return vec2(length(p) - s, id);
}
vec2 sdPlane(vec3 p, vec4 n, float id)
{
// n must be normalized
return vec2(dot(p,n.xyz) + n.w, id);
}
vec2 sdColumn(vec3 p, float r, float id)
{
return vec2(((abs(p.x)+abs(p.y))-r)/sqrt(2.0), id);
}
vec2 dfRiver(vec3 p, float id)
{
float offs = sin(p.y)*0.15 + sin(p.y * 0.2);
return sdColumn(p.xzy + vec3(offs,0,0), 0.4, id);
}
//Distance to the scene
vec2 Scene(vec3 p)
{
vec2 d = vec2(MAX_DIST, SKYDOME);
d = opU(sdPlane(p, vec4(0, 0,-1, 0), FLOOR), d);
d = opS(dfRiver(p, RIVER), d);
return d;
}
//Surface normal at the current position
vec3 Normal(vec3 p)
{
vec3 off = vec3(NORMAL_OFFS, 0, 0);
return normalize
(
vec3
(
Scene(p + off.xyz).x - Scene(p - off.xyz).x,
Scene(p + off.zxy).x - Scene(p - off.zxy).x,
Scene(p + off.yzx).x - Scene(p - off.yzx).x
)
);
}
//Raymarch the scene with the given ray
MarchResult MarchRay(vec3 orig,vec3 dir)
{
float steps = 0.0;
float dist = 0.0;
float id = 0.0;
for(int i = 0;i < MAX_STEPS;i++)
{
vec2 object = Scene(orig + dir * dist);
//Add the sky dome and have it follow the camera.
object = opU(object, -sdSphere(dir * dist, MAX_DIST, SKYDOME));
dist += object.x * STEP_MULT;
id = object.y;
steps++;
if(abs(object.x) < MIN_DIST * dist)
{
break;
}
}
MarchResult result;
result.position = orig + dir * dist;
result.normal = Normal(result.position);
result.dist = dist;
result.steps = steps;
result.id = id;
return result;
}
//Scene texturing/shading
vec3 Shade(MarchResult hit, vec3 direction, vec3 camera)
{
vec3 color = vec3(0.0);
if(hit.id == FLOOR)
{
vec2 uv = abs(mod(hit.position.xy + GRID_SIZE/2.0, GRID_SIZE) - GRID_SIZE/2.0);
uv /= fwidth(hit.position.xy);
float riverEdge = dfRiver(hit.position, 0.0).x / fwidth(hit.position.xy).x;
float gln = min(min(uv.x, uv.y), riverEdge) / GRID_SIZE;
color = mix(GRID_COLOR_1, GRID_COLOR_2, 1.0 - smoothstep(0.0, GRID_LINE_SIZE / GRID_SIZE, gln));
}
if(hit.id == RIVER)
{
vec2 uv = vec2(hit.position.z, abs(mod(hit.position.y + GRID_SIZE/2.0, GRID_SIZE) - GRID_SIZE/2.0));
uv /= fwidth(hit.position.xy);
float gln = min(uv.x, uv.y) / GRID_SIZE;
color = mix(GRID_COLOR_1, GRID_COLOR_2, 1.0 - smoothstep(0.0, GRID_LINE_SIZE / GRID_SIZE, gln));
}
//Distance fog
color *= 1.0 - smoothstep(0.0, MAX_DIST*0.9, hit.dist);
//Water
float waterMix = smoothstep(WATER_LEVEL - WATER_FOG_SIZE, WATER_LEVEL + WATER_FOG_SIZE, hit.position.z);
color = mix(color, WATER_COLOR, waterMix);
if(hit.id == SKYDOME)
{
//Sky gradient
//Causes weird position-colored artefacts around the horizon (AMD R9 270)
//color = mix(SKY_COLOR_1, SKY_COLOR_2, -hit.position.z/16.0);
color += mix(SKY_COLOR_1, SKY_COLOR_2, -hit.position.z/16.0);
//Sun
vec3 sunDir = normalize(SUN_DIRECTION);
float sun = smoothstep(0.950, 0.952, dot(direction, sunDir));
vec3 sunCol = mix(SUN_COLOR_1, SUN_COLOR_2, -hit.position.z/16.0);
color = mix(color, sunCol, sun);
//Clouds
vec2 cloudUV = CLOUD_SCALE * direction.xy / dot(direction, vec3(0, 0,-1));
cloudUV += CLOUD_SCROLL * iGlobalTime;
color *= smoothstep(0.5, 0.3, texture(iChannel1, cloudUV, CLOUD_BLUR).r) * 0.5 + 0.5;
//Mountains
float a = atan(hit.position.y, hit.position.x)/tau + 0.5;
a -= 3.28;
float mountains = MOUNTAIN_SCALE * texture(iChannel0, vec2(a, 0.1),-99.0).r - hit.position.z - MOUNTAIN_SHIFT;
color = mix(color, vec3(0.0), 1.0 - smoothstep(0.6, 0.7, mountains));
}
return color;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 res = iResolution.xy / iResolution.y;
vec2 uv = fragCoord.xy / iResolution.y;
//Camera stuff
vec3 angles = vec3(0);
//Auto mode
if(iMouse.xy == vec2(0,0))
{
angles.y = tau * (1.8 / 8.0);
angles.x = tau * (3.9 / 8.0) + sin(iGlobalTime * 0.1) * 0.3;
}
else
{
angles = vec3((iMouse.xy / iResolution.xy) * pi, 0);
angles.xy *= vec2(2.0, 1.0);
}
angles.y = clamp(angles.y, 0.0, 15.5 * tau / 64.0);
mat3 rotate = Rotate(angles.yzx);
vec3 orig = vec3(0, 0,-2) * rotate;
vec3 dir = normalize(vec3(uv - res / 2.0, FOCAL_LENGTH)) * rotate;
//Ray marching
MarchResult hit = MarchRay(orig, dir);
//Shading
vec3 color = Shade(hit, dir, orig);
#ifdef SHOW_RAY_COST
color = mix(vec3(0,1,0), vec3(1,0,0), hit.steps / float(MAX_STEPS));
#endif
#ifdef DITHER_ENABLE
color = dither(color, COLOR_MODE, fragCoord);
#endif
fragColor = vec4(color, 1.0);
}

View File

@ -0,0 +1,718 @@
#define line1 H_ e_ l_ l_ o_ _ BOLD S_ h_ a_ d_ e_ r_ t_ o_ y_ BOLD _ t_ h_ i_ s_ _ i_ s_ _ m_ y_
#define line2 BLUE p_ r_ o_ p_ o_ r_ t_ i_ o_ n_ a_ l_ BLUE _ f_ o_ n_ t_ _dot _ I_ _ h_ o_ p_ e_ _ y_ o_ u_
#define line3 GREEN l_ i_ k_ e_ GREEN _ i_ t_ _comma _ RED f_ e_ e_ l_ RED _ ITAL f_ r_ e_ e_ ITAL _ t_ o_ _ u_ s_ e_ _ i_ t_ _dot
#define line4 a_ b_ c_ d_ e_ f_ g_ h_ i_ j_ k_ l_ m_ n_ o_ p_ q_ r_ s_ t_ u_ v_ w_ x_ y_ z_
#define line5 A_ B_ C_ D_ E_ F_ G_ H_ I_ J_ K_ L_ M_ N_ O_ P_ Q_ R_ S_ T_ U_ V_ W_ X_ Y_ Z_
#define line6 _1 _2 _3 _4 _5 _6 _7 _8 _9 _0 _dot _comma _exclam _question _open1 _close1 _dotdot _dotcomma _equal _add _sub _mul _div _lt _gt _hash _and _or _und _open2 _close2 _open3 _close3
// line function, used in k, v, w, x, y, z, 1, 2, 4, 7 and ,
// rest is drawn using (stretched) circle(g)
// todo: distance fields of s,S, J { and }
// todo before we can show shaders :)
//
float line(vec2 p, vec2 a, vec2 b)
{
vec2 pa = p - a;
vec2 ba = b - a;
float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
return length(pa - ba * h);
}
//These functions are re-used by multiple letters
float _u(vec2 uv, float w, float v) {
return length(vec2(
abs(length(vec2(uv.x,
max(0.0,-(.4-v)-uv.y) ))-w)
,max(0.,uv.y-.4)));
}
float _i(vec2 uv) {
return length(vec2(uv.x,max(0.,abs(uv.y)-.4)));
}
float _j(vec2 uv) {
uv.x+=.2;
uv.y+=.55;
float x = uv.x>0.&&uv.y<0.?
abs(length(uv)-.25)
:min(length(uv+vec2(0.,.25)),
length(vec2(uv.x-.25,max(0.,abs(uv.y-.475)-.475))));
return x;
}
float _l(vec2 uv) {
uv.y -= .2;
return length(vec2(uv.x,max(0.,abs(uv.y)-.6)));
}
float _o(vec2 uv) {
return abs(length(vec2(uv.x,max(0.,abs(uv.y)-.15)))-.25);
}
// Here is the alphabet
float aa(vec2 uv) {
uv = -uv;
float x = abs(length(vec2(max(0.,abs(uv.x)-.05),uv.y-.2))-.2);
x = min(x,length(vec2(uv.x+.25,max(0.,abs(uv.y-.2)-.2))));
return min(x,(uv.x<0.?uv.y<0.:atan(uv.x,uv.y+0.15)>2.)?_o(uv):length(vec2(uv.x-.22734,uv.y+.254)));
}
float bb(vec2 uv) {
float x = _o(uv);
uv.x += .25;
return min(x,_l(uv));
}
float cc(vec2 uv) {
float x = _o(uv);
uv.y= abs(uv.y);
return uv.x<0.||atan(uv.x,uv.y-0.15)<1.14?x:
min(length(vec2(uv.x+.25,max(0.0,abs(uv.y)-.15))),//makes df right
length(uv+vec2(-.22734,-.254)));
}
float dd(vec2 uv) {
uv.x *= -1.;
return bb(uv);
}
float ee(vec2 uv) {
float x = _o(uv);
return min(uv.x<0.||uv.y>.05||atan(uv.x,uv.y+0.15)>2.?x:length(vec2(uv.x-.22734,uv.y+.254)),
length(vec2(max(0.,abs(uv.x)-.25),uv.y-.05)));
}
float ff(vec2 uv) {
uv.x *= -1.;
uv.x += .05;
float x = _j(vec2(uv.x,-uv.y));
uv.y -= .4;
x = min(x,length(vec2(max(0.,abs(uv.x-.05)-.25),uv.y)));
return x;
}
float gg(vec2 uv) {
float x = _o(uv);
return min(x,uv.x>0.||atan(uv.x,uv.y+.6)<-2.?
_u(uv,0.25,-0.2):
length(uv+vec2(.23,.7)));
}
float hh(vec2 uv) {
uv.y *= -1.;
float x = _u(uv,.25,.25);
uv.x += .25;
uv.y *= -1.;
return min(x,_l(uv));
}
float ii(vec2 uv) {
return min(_i(uv),length(vec2(uv.x,uv.y-.6)));
}
float jj(vec2 uv) {
uv.x+=.05;
return min(_j(uv),length(vec2(uv.x-.05,uv.y-.6)));
}
float kk(vec2 uv) {
float x = line(uv,vec2(-.25,-.1), vec2(0.25,0.4));
x = min(x,line(uv,vec2(-.15,.0), vec2(0.25,-0.4)));
uv.x+=.25;
return min(x,_l(uv));
}
float ll(vec2 uv) {
return _l(uv);
}
float mm(vec2 uv) {
//uv.x *= 1.4;
uv.y *= -1.;
uv.x-=.175;
float x = _u(uv,.175,.175);
uv.x+=.35;
x = min(x,_u(uv,.175,.175));
uv.x+=.175;
return min(x,_i(uv));
}
float nn(vec2 uv) {
uv.y *= -1.;
float x = _u(uv,.25,.25);
uv.x+=.25;
return min(x,_i(uv));
}
float oo(vec2 uv) {
return _o(uv);
}
float pp(vec2 uv) {
float x = _o(uv);
uv.x += .25;
uv.y += .4;
return min(x,_l(uv));
}
float qq(vec2 uv) {
uv.x = -uv.x;
return pp(uv);
}
float rr(vec2 uv) {
uv.x -= .05;
float x =atan(uv.x,uv.y-0.15)<1.14&&uv.y>0.?_o(uv):length(vec2(uv.x-.22734,uv.y-.254));
//)?_o(uv):length(vec2(uv.x-.22734,uv.y+.254))+.4);
uv.x+=.25;
return min(x,_i(uv));
}
float ss(vec2 uv) {
if (uv.y <.225-uv.x*.5 && uv.x>0. || uv.y<-.225-uv.x*.5)
uv = -uv;
float a = abs(length(vec2(max(0.,abs(uv.x)-.05),uv.y-.2))-.2);
float b = length(vec2(uv.x-.231505,uv.y-.284));
float x = atan(uv.x-.05,uv.y-0.2)<1.14?a:b;
return x;
}
float tt(vec2 uv) {
uv.x *= -1.;
uv.y -= .4;
uv.x += .05;
float x = min(_j(uv),length(vec2(max(0.,abs(uv.x-.05)-.25),uv.y)));
return x;
}
float uu(vec2 uv) {
return _u(uv,.25,.25);
}
float vv(vec2 uv) {
uv.x=abs(uv.x);
return line(uv,vec2(0.25,0.4), vec2(0.,-0.4));
}
float ww(vec2 uv) {
uv.x=abs(uv.x);
return min(line(uv,vec2(0.3,0.4), vec2(.2,-0.4)),
line(uv,vec2(0.2,-0.4), vec2(0.,0.1)));
}
float xx(vec2 uv) {
uv=abs(uv);
return line(uv,vec2(0.,0.), vec2(.3,0.4));
}
float yy(vec2 uv) {
return min(line(uv,vec2(.0,-.2), vec2(-.3,0.4)),
line(uv,vec2(.3,.4), vec2(-.3,-0.8)));
}
float zz(vec2 uv) {
float l = line(uv,vec2(0.25,0.4), vec2(-0.25,-0.4));
uv.y=abs(uv.y);
float x = length(vec2(max(0.,abs(uv.x)-.25),uv.y-.4));
return min(x,l);
}
// Capitals
float AA(vec2 uv) {
float x = length(vec2(
abs(length(vec2(uv.x,
max(0.0,uv.y-.35) ))-0.25)
,min(0.,uv.y+.4)));
return min(x,length(vec2(max(0.,abs(uv.x)-.25),uv.y-.1) ));
}
float BB(vec2 uv) {
uv.y -=.1;
uv.y = abs(uv.y);
float x = length(vec2(
abs(length(vec2(max(0.0,uv.x),
uv.y-.25))-0.25)
,min(0.,uv.x+.25)));
return min(x,length(vec2(uv.x+.25,max(0.,abs(uv.y)-.5)) ));
}
float CC(vec2 uv) {
float x = abs(length(vec2(uv.x,max(0.,abs(uv.y-.1)-.25)))-.25);
uv.y -= .1;
uv.y= abs(uv.y);
return uv.x<0.||atan(uv.x,uv.y-0.25)<1.14?x:
min(length(vec2(uv.x+.25,max(0.0,abs(uv.y)-.25))),//makes df right
length(uv+vec2(-.22734,-.354)));
}
float DD(vec2 uv) {
uv.y -=.1;
//uv.y = abs(uv.y);
float x = length(vec2(
abs(length(vec2(max(0.0,uv.x),
max(0.0,abs(uv.y)-.25)))-0.25)
,min(0.,uv.x+.25)));
return min(x,length(vec2(uv.x+.25,max(0.,abs(uv.y)-.5)) ));
}
float EE(vec2 uv) {
uv.y -=.1;
uv.y = abs(uv.y);
float x = min(length(vec2(max(0.,abs(uv.x)-.25),uv.y)),
length(vec2(max(0.,abs(uv.x)-.25),uv.y-.5)));
return min(x,length(vec2(uv.x+.25,max(0.,abs(uv.y)-.5))));
}
float FF(vec2 uv) {
uv.y -=.1;
float x = min(length(vec2(max(0.,abs(uv.x)-.25),uv.y)),
length(vec2(max(0.,abs(uv.x)-.25),uv.y-.5)));
return min(x,length(vec2(uv.x+.25,max(0.,abs(uv.y)-.5))));
}
float GG(vec2 uv) {
float x = abs(length(vec2(uv.x,max(0.,abs(uv.y-.1)-.25)))-.25);
uv.y -= .1;
float a = atan(uv.x,max(0.,abs(uv.y)-0.25));
x = uv.x<0.||a<1.14 || a>3.?x:
min(length(vec2(uv.x+.25,max(0.0,abs(uv.y)-.25))),//makes df right
length(uv+vec2(-.22734,-.354)));
x = min(x,line(uv,vec2(.22734,-.1),vec2(.22734,-.354)));
return min(x,line(uv,vec2(.22734,-.1),vec2(.05,-.1)));
}
float HH(vec2 uv) {
uv.y -=.1;
uv.x = abs(uv.x);
float x = length(vec2(max(0.,abs(uv.x)-.25),uv.y));
return min(x,length(vec2(uv.x-.25,max(0.,abs(uv.y)-.5))));
}
float II(vec2 uv) {
uv.y -= .1;
float x = length(vec2(uv.x,max(0.,abs(uv.y)-.5)));
uv.y = abs(uv.y);
return min(x,length(vec2(max(0.,abs(uv.x)-.1),uv.y-.5)));
}
float JJ(vec2 uv) {
uv.x += .125;
float x = length(vec2(
abs(length(vec2(uv.x,
min(0.0,uv.y+.15) ))-0.25)
,max(0.,max(-uv.x,uv.y-.6))));
return min(x,length(vec2(max(0.,abs(uv.x-.125)-.125),uv.y-.6)));
}
float KK(vec2 uv) {
float x = line(uv,vec2(-.25,-.1), vec2(0.25,0.6));
x = min(x,line(uv,vec2(-.1, .1), vec2(0.25,-0.4)));
// uv.x+=.25;
return min(x,length(vec2(uv.x+.25,max(0.,abs(uv.y-.1)-.5))));
}
float LL(vec2 uv) {
uv.y -=.1;
float x = length(vec2(max(0.,abs(uv.x)-.2),uv.y+.5));
return min(x,length(vec2(uv.x+.2,max(0.,abs(uv.y)-.5))));
}
float MM(vec2 uv) {
uv.y-=.1;
float x = min(length(vec2(uv.x-.35,max(0.,abs(uv.y)-.5))),
line(uv,vec2(-.35,.5),vec2(.0,-.1)));
x = min(x,line(uv,vec2(.0,-.1),vec2(.35,.5)));
return min(x,length(vec2(uv.x+.35,max(0.,abs(uv.y)-.5))));
}
float NN(vec2 uv) {
uv.y-=.1;
float x = min(length(vec2(uv.x-.25,max(0.,abs(uv.y)-.5))),
line(uv,vec2(-.25,.5),vec2(.25,-.5)));
return min(x,length(vec2(uv.x+.25,max(0.,abs(uv.y)-.5))));
}
float OO(vec2 uv) {
return abs(length(vec2(uv.x,max(0.,abs(uv.y-.1)-.25)))-.25);
}
float PP(vec2 uv) {
float x = length(vec2(
abs(length(vec2(max(0.0,uv.x),
uv.y-.35))-0.25)
,min(0.,uv.x+.25)));
return min(x,length(vec2(uv.x+.25,max(0.,abs(uv.y-.1)-.5)) ));
}
float QQ(vec2 uv) {
float x = abs(length(vec2(uv.x,max(0.,abs(uv.y-.1)-.25)))-.25);
uv.y += .3;
uv.x -= .2;
return min(x,length(vec2(abs(uv.x+uv.y),max(0.,abs(uv.x-uv.y)-.2)))/sqrt(2.));
}
float RR(vec2 uv) {
float x = length(vec2(
abs(length(vec2(max(0.0,uv.x),
uv.y-.35))-0.25)
,min(0.,uv.x+.25)));
x = min(x,length(vec2(uv.x+.25,max(0.,abs(uv.y-.1)-.5)) ));
return min(x,line(uv,vec2(0.0,0.1),vec2(0.25,-0.4)));
}
float SS(vec2 uv) {
uv.y -= .1;
if (uv.y <.275-uv.x*.5 && uv.x>0. || uv.y<-.275-uv.x*.5)
uv = -uv;
float a = abs(length(vec2(max(0.,abs(uv.x)),uv.y-.25))-.25);
float b = length(vec2(uv.x-.236,uv.y-.332));
float x = atan(uv.x-.05,uv.y-0.25)<1.14?a:b;
return x;
}
float TT(vec2 uv) {
uv.y -= .1;
float x = length(vec2(uv.x,max(0.,abs(uv.y)-.5)));
return min(x,length(vec2(max(0.,abs(uv.x)-.25),uv.y-.5)));
}
float UU(vec2 uv) {
float x = length(vec2(
abs(length(vec2(uv.x,
min(0.0,uv.y+.15) ))-0.25)
,max(0.,uv.y-.6)));
return x;
}
float VV(vec2 uv) {
uv.x=abs(uv.x);
return line(uv,vec2(0.25,0.6), vec2(0.,-0.4));
}
float WW(vec2 uv) {
uv.x=abs(uv.x);
return min(line(uv,vec2(0.3,0.6), vec2(.2,-0.4)),
line(uv,vec2(0.2,-0.4), vec2(0.,0.2)));
}
float XX(vec2 uv) {
uv.y -= .1;
uv=abs(uv);
return line(uv,vec2(0.,0.), vec2(.3,0.5));
}
float YY(vec2 uv) {
return min(min(line(uv,vec2(.0, .1), vec2(-.3, 0.6)),
line(uv,vec2(.0, .1), vec2( .3, 0.6))),
length(vec2(uv.x,max(0.,abs(uv.y+.15)-.25))));
}
float ZZ(vec2 uv) {
float l = line(uv,vec2(0.25,0.6), vec2(-0.25,-0.4));
uv.y-=.1;
uv.y=abs(uv.y);
float x = length(vec2(max(0.,abs(uv.x)-.25),uv.y-.5));
return min(x,l);
}
//Numbers
float _11(vec2 uv) {
return min(min(
line(uv,vec2(-0.2,0.45),vec2(0.,0.6)),
length(vec2(uv.x,max(0.,abs(uv.y-.1)-.5)))),
length(vec2(max(0.,abs(uv.x)-.2),uv.y+.4)));
}
float _22(vec2 uv) {
float x = min(line(uv,vec2(0.185,0.17),vec2(-.25,-.4)),
length(vec2(max(0.,abs(uv.x)-.25),uv.y+.4)));
uv.y-=.35;
uv.x += 0.025;
return min(x,abs(atan(uv.x,uv.y)-0.63)<1.64?abs(length(uv)-.275):
length(uv+vec2(.23,-.15)));
}
float _33(vec2 uv) {
uv.y-=.1;
uv.y = abs(uv.y);
uv.y-=.25;
return atan(uv.x,uv.y)>-1.?abs(length(uv)-.25):
min(length(uv+vec2(.211,-.134)),length(uv+vec2(.0,.25)));
}
float _44(vec2 uv) {
float x = min(length(vec2(uv.x-.15,max(0.,abs(uv.y-.1)-.5))),
line(uv,vec2(0.15,0.6),vec2(-.25,-.1)));
return min(x,length(vec2(max(0.,abs(uv.x)-.25),uv.y+.1)));
}
float _55(vec2 uv) {
float b = min(length(vec2(max(0.,abs(uv.x)-.25),uv.y-.6)),
length(vec2(uv.x+.25,max(0.,abs(uv.y-.36)-.236))));
uv.y += 0.1;
uv.x += 0.05;
float c = abs(length(vec2(uv.x,max(0.,abs(uv.y)-.0)))-.3);
return min(b,abs(atan(uv.x,uv.y)+1.57)<.86 && uv.x<0.?
length(uv+vec2(.2,.224))
:c);
}
float _66(vec2 uv) {
uv.y-=.075;
uv = -uv;
float b = abs(length(vec2(uv.x,max(0.,abs(uv.y)-.275)))-.25);
uv.y-=.175;
float c = abs(length(vec2(uv.x,max(0.,abs(uv.y)-.05)))-.25);
return min(c,cos(atan(uv.x,uv.y+.45)+0.65)<0.||(uv.x>0.&& uv.y<0.)?b:
length(uv+vec2(0.2,0.6)));
}
float _77(vec2 uv) {
return min(length(vec2(max(0.,abs(uv.x)-.25),uv.y-.6)),
line(uv,vec2(-0.25,-0.39),vec2(0.25,0.6)));
}
float _88(vec2 uv) {
float l = length(vec2(max(0.,abs(uv.x)-.08),uv.y-.1+uv.x*.07));
uv.y-=.1;
uv.y = abs(uv.y);
uv.y-=.245;
return min(abs(length(uv)-.255),l);
}
float _99(vec2 uv) {
uv.y-=.125;
float b = abs(length(vec2(uv.x,max(0.,abs(uv.y)-.275)))-.25);
uv.y-=.175;
float c = abs(length(vec2(uv.x,max(0.,abs(uv.y)-.05)))-.25);
return min(c,cos(atan(uv.x,uv.y+.45)+0.65)<0.||(uv.x>0.&& uv.y<0.)?b:
length(uv+vec2(0.2,0.6)));
}
float _00(vec2 uv) {
uv.y-=.1;
return abs(length(vec2(uv.x,max(0.,abs(uv.y)-.25)))-.25);
}
//Symbols
float ddot(vec2 uv) {
uv.y+=.4;
return length(uv)*0.97;//-.03;
}
float comma(vec2 uv) {
return min(ddot(uv),line(uv,vec2(.031,-.405),vec2(-.029,-.52)));
}
float exclam(vec2 uv) {
return min(ddot(uv),length(vec2(uv.x,max(0.,abs(uv.y-.2)-.4)))-uv.y*.06);
}
float question(vec2 uv) {
float x = min(ddot(uv),length(vec2(uv.x,max(0.,abs(uv.y+.035)-.1125))));
uv.y-=.35;
uv.x += 0.025;
return min(x,abs(atan(uv.x,uv.y)-1.05)<2.?abs(length(uv)-.275):
length(uv+vec2(.225,-.16))-.0);
}
float open1(vec2 uv) {
uv.x-=.62;
return abs(atan(uv.x,uv.y)+1.57)<1.?
abs(length(uv)-.8)
:length(vec2(uv.x+.435,abs(uv.y)-.672));
}
float close1(vec2 uv) {
uv.x = -uv.x;
return open1(uv);
}
float dotdot(vec2 uv) {
uv.y -= .1;
uv.y = abs(uv.y);
uv.y-=.25;
return length(uv);
}
float dotcomma(vec2 uv) {
uv.y -= .1;
float x = line(uv,vec2(.0,-.28),vec2(-.029,-.32));
uv.y = abs(uv.y);
uv.y-=.25;
return min(length(uv),x);
}
float eequal(vec2 uv) {
uv.y -= .1;
uv.y = abs(uv.y);
return length(vec2(max(0.,abs(uv.x)-.25),uv.y-.15));
}
float aadd(vec2 uv) {
uv.y -= .1;
return min(length(vec2(max(0.,abs(uv.x)-.25),uv.y)),
length(vec2(uv.x,max(0.,abs(uv.y)-.25))));
}
float ssub(vec2 uv) {
return length(vec2(max(0.,abs(uv.x)-.25),uv.y-.1));
}
float mmul(vec2 uv) {
uv.y -= .1;
uv = abs(uv);
return min(line(uv,vec2(0.866*.25,0.5*.25),vec2(0.))
,length(vec2(uv.x,max(0.,abs(uv.y)-.25))));
}
float ddiv(vec2 uv) {
return line(uv,vec2(-0.25,-0.4),vec2(0.25,0.6));
}
float lt(vec2 uv) {
uv.y-=.1;
uv.y = abs(uv.y);
return line(uv,vec2(0.25,0.25),vec2(-0.25,0.));
}
float gt(vec2 uv) {
uv.x=-uv.x;
return lt(uv);
}
float hash(vec2 uv) {
uv.y-=.1;
uv.x -= uv.y*.1;
uv = abs(uv);
return min(length(vec2(uv.x-.125,max(0.,abs(uv.y)-.3))),
length(vec2(max(0.,abs(uv.x)-.25),uv.y-.125)));
}
float and(vec2 uv) {
uv.y-=.44;
uv.x+=.05;
float x = abs(atan(uv.x,uv.y))<2.356?abs(length(uv)-.15):1.0;
x = min(x,line(uv,vec2(-0.106,-0.106),vec2(0.4,-0.712)));
x = min(x,line(uv,vec2( 0.106,-0.106),vec2(-0.116,-0.397)));
uv.x-=.025;
uv.y+=.54;
x = min(x,abs(atan(uv.x,uv.y)-.785)>1.57?abs(length(uv)-.2):1.0);
return min(x,line(uv,vec2( 0.141,-0.141),vec2( 0.377,0.177)));
}
float or(vec2 uv) {
uv.y -= .1;
return length(vec2(uv.x,max(0.,abs(uv.y)-.5)));
}
float und(vec2 uv) {
return length(vec2(max(0.,abs(uv.x)-.25),uv.y+.4));
}
float open2(vec2 uv) {
uv.y -= .1;
uv.y = abs(uv.y);
return min(length(vec2(uv.x+.125,max(0.,abs(uv.y)-.5))),
length(vec2(max(0.,abs(uv.x)-.125),uv.y-.5)));
}
float close2(vec2 uv) {
uv.x=-uv.x;
return open2(uv);
}
float open3(vec2 uv) {
uv.y -= .1;
uv.y = abs(uv.y);
float x = length(vec2(
abs(length(vec2((uv.x*sign(uv.y-.25)-.2),
max(0.0,abs(uv.y-.25)-.05) ))-0.2)
,max(0.,abs(uv.x)-.2)));
return x;
}
float close3(vec2 uv) {
uv.x=-uv.x;
return open3(uv);
}
vec2 clc(vec2 uv, float cp, float w, float ital) {
return uv-vec2(cp-(w*.5)+uv.y*ital,0.);
}
bool hit(vec2 uv,inout float cp,float w, float px) {
return abs((cp+=w)-uv.x)<w+.2;
}
//Render char if it's up
#define ch(l,w) if (hit(uv,cp,w,px)) { x=min(x,l(clc(uv,cp,w,ital))); us=cur;}
//Render char always (no effects anymore)
//#define ch(l,w) x = min(x,l(clc(uv,cp+=w,w,ital)));
//Make it a bit easier to type text
#define a_ ch(aa,0.7);
#define b_ ch(bb,0.7);
#define c_ ch(cc,0.7);
#define d_ ch(dd,0.7);
#define e_ ch(ee,0.7);
#define f_ ch(ff,0.6);
#define g_ ch(gg,0.7);
#define h_ ch(hh,0.7);
#define i_ ch(ii,0.3);
#define j_ ch(jj,0.3);
#define k_ ch(kk,0.7);
#define l_ ch(ll,0.3);
#define m_ ch(mm,0.9);
#define n_ ch(nn,0.7);
#define o_ ch(oo,0.7);
#define p_ ch(pp,0.7);
#define q_ ch(qq,0.7);
#define r_ ch(rr,0.7);
#define s_ ch(ss,0.7);
#define t_ ch(tt,0.7);
#define u_ ch(uu,0.7);
#define v_ ch(vv,0.7);
#define w_ ch(ww,0.9);
#define x_ ch(xx,0.8);
#define y_ ch(yy,0.8);
#define z_ ch(zz,0.7);
#define A_ ch(AA,0.7);
#define B_ ch(BB,0.7);
#define C_ ch(CC,0.7);
#define D_ ch(DD,0.7);
#define E_ ch(EE,0.7);
#define F_ ch(FF,0.7);
#define G_ ch(GG,0.7);
#define H_ ch(HH,0.7);
#define I_ ch(II,0.5);
#define J_ ch(JJ,0.5);
#define K_ ch(KK,0.7);
#define L_ ch(LL,0.5);
#define M_ ch(MM,0.9);
#define N_ ch(NN,0.7);
#define O_ ch(OO,0.7);
#define P_ ch(PP,0.7);
#define Q_ ch(QQ,0.7);
#define R_ ch(RR,0.7);
#define S_ ch(SS,0.7);
#define T_ ch(TT,0.7);
#define U_ ch(UU,0.7);
#define V_ ch(VV,0.7);
#define W_ ch(WW,0.9);
#define X_ ch(XX,0.8);
#define Y_ ch(YY,0.8);
#define Z_ ch(ZZ,0.7);
#define _1 ch(_11,0.7);
#define _2 ch(_22,0.7);
#define _3 ch(_33,0.7);
#define _4 ch(_44,0.7);
#define _5 ch(_55,0.7);
#define _6 ch(_66,0.7);
#define _7 ch(_77,0.7);
#define _8 ch(_88,0.7);
#define _9 ch(_99,0.7);
#define _0 ch(_00,0.7);
#define _dot ch(ddot,0.3);
#define _comma ch(comma,0.3);
#define _exclam ch(exclam,0.3);
#define _question ch(question,0.8);
#define _open1 ch(open1,0.7);
#define _close1 ch(close1,0.7);
#define _dotdot ch(dotdot,0.3);
#define _dotcomma ch(dotcomma,0.3);
#define _equal ch(eequal,0.7);
#define _add ch(aadd,0.7);
#define _sub ch(ssub,0.7);
#define _mul ch(mmul,0.7);
#define _div ch(ddiv,0.7);
#define _lt ch(lt,0.7);
#define _gt ch(gt,0.7);
#define _hash ch(hash,0.7);
#define _and ch(and,0.9);
#define _or ch(or,0.3);
#define _und ch(und,0.7);
#define _open2 ch(open2,0.6);
#define _close2 ch(close2,0.6);
#define _open3 ch(open3,0.7);
#define _close3 ch(close3,0.7);
//Space
#define _ cp+=.5;
//Markup
#define BOLD cur.w = 1.5-cur.w;
#define ITAL ital = 0.15-ital;
#define RED cur.r = 0.8-cur.r;
#define GREEN cur.g = 0.6-cur.g;
#define BLUE cur.b = 1.0-cur.b;
//Next line
#define crlf uv.y += 2.0; cp = 0.;
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
float ms = float(iMouse.w>0.);
float scale = 1.1-ms;// 2.0-cos(iGlobalTime*.1);
vec2 mouseOffs = ms*(iMouse.xy-.5*iResolution.xy)/scale;
vec2 uv = (fragCoord+mouseOffs-.5*iResolution.xy) / iResolution.x * 22.0 * scale;
//float ofs = floor(uv.x)+8.;
//uv.x = mod(uv.x,1.0)-.5;
float px = 22.0/iResolution.x*scale;
float x = 100.;
float cp = 0.;
vec4 cur = vec4(0.,0.,0.,0.5);
vec4 us = cur;
float ital = 0.0;
//uv+= .03*cos(uv*7.+iGlobalTime);
//uv.y += 2.;
uv.x += 10.1;
//uv.y -= 3.;
//uv.x += 5.;
int lnr = 2-int(floor(uv.y/2.));
uv.y = mod(uv.y,2.0)-1.0;
if (lnr==0) {line1}
if (lnr==1) {line2}
if (lnr==2) {line3}
if (lnr==3) {line4}
if (lnr==4) {line5}
if (lnr==5) {line6}
vec3 clr = vec3(0.0);
// Wobbly font
//float weight = 0.05+sin(length(-10.0+uv*3.9-10.0*sin(.09*iGlobalTime)))/50.;
float weight = 0.01+us.w*min(iGlobalTime*.02-.05,0.03);//+.03*length(sin(uv*6.+.3*iGlobalTime));//+0.02-0.06*cos(iGlobalTime*.4+1.);
if (ms>0.) {
fragColor = vec4(mix(us.rgb+0.5-0.5*smoothstep(0.,2.*px, abs(mod(x,.1)-.05)),vec3(1.0), sqrt(x)),1.0);
} else
fragColor = vec4(mix(us.rgb,vec3(1.0),smoothstep(weight-px,weight+px, x)),1.0);
}

View File

@ -0,0 +1,155 @@
// Smaller Number Printing - @P_Malin
// Creative Commons CC0 1.0 Universal (CC-0)
// Feel free to modify, distribute or use in commercial code, just don't hold me liable for anything bad that happens!
// If you use this code and want to give credit, that would be nice but you don't have to.
// I first made this number printing code in https://www.shadertoy.com/view/4sf3RN
// It started as a silly way of representing digits with rectangles.
// As people started actually using this in a number of places I thought I would try to condense the
// useful function a little so that it can be dropped into other shaders more easily,
// just snip between the perforations below.
// Also, the licence on the previous shader was a bit restrictive for utility code.
//
// Disclaimer: The values printed may not be accurate!
// Accuracy improvement for fractional values taken from TimoKinnunen https://www.shadertoy.com/view/lt3GRj
// ---- 8< ---- GLSL Number Printing - @P_Malin ---- 8< ----
// Creative Commons CC0 1.0 Universal (CC-0)
// https://www.shadertoy.com/view/4sBSWW
float DigitBin( const int x )
{
return x==0?480599.0:x==1?139810.0:x==2?476951.0:x==3?476999.0:x==4?350020.0:x==5?464711.0:x==6?464727.0:x==7?476228.0:x==8?481111.0:x==9?481095.0:0.0;
}
float PrintValue( vec2 vStringCoords, float fValue, float fMaxDigits, float fDecimalPlaces )
{
if ((vStringCoords.y < 0.0) || (vStringCoords.y >= 1.0)) return 0.0;
bool bNeg = ( fValue < 0.0 );
fValue = abs(fValue);
float fLog10Value = log2(abs(fValue)) / log2(10.0);
float fBiggestIndex = max(floor(fLog10Value), 0.0);
float fDigitIndex = fMaxDigits - floor(vStringCoords.x);
float fCharBin = 0.0;
if(fDigitIndex > (-fDecimalPlaces - 1.01)) {
if(fDigitIndex > fBiggestIndex) {
if((bNeg) && (fDigitIndex < (fBiggestIndex+1.5))) fCharBin = 1792.0;
} else {
if(fDigitIndex == -1.0) {
if(fDecimalPlaces > 0.0) fCharBin = 2.0;
} else {
float fReducedRangeValue = fValue;
if(fDigitIndex < 0.0) { fReducedRangeValue = fract( fValue ); fDigitIndex += 1.0; }
float fDigitValue = (abs(fReducedRangeValue / (pow(10.0, fDigitIndex))));
fCharBin = DigitBin(int(floor(mod(fDigitValue, 10.0))));
}
}
}
return floor(mod((fCharBin / pow(2.0, floor(fract(vStringCoords.x) * 4.0) + (floor(vStringCoords.y * 5.0) * 4.0))), 2.0));
}
// ---- 8< -------- 8< -------- 8< -------- 8< ----
// Original interface
float PrintValue(const in vec2 fragCoord, const in vec2 vPixelCoords, const in vec2 vFontSize, const in float fValue, const in float fMaxDigits, const in float fDecimalPlaces)
{
vec2 vStringCharCoords = (fragCoord.xy - vPixelCoords) / vFontSize;
return PrintValue( vStringCharCoords, fValue, fMaxDigits, fDecimalPlaces );
}
float GetCurve(float x)
{
return sin( x * 3.14159 * 4.0 );
}
float GetCurveDeriv(float x)
{
return 3.14159 * 4.0 * cos( x * 3.14159 * 4.0 );
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec3 vColour = vec3(0.0);
// Multiples of 4x5 work best
vec2 vFontSize = vec2(8.0, 15.0);
// Draw Horizontal Line
if(abs(fragCoord.y - iResolution.y * 0.5) < 1.0)
{
vColour = vec3(0.25);
}
// Draw Sin Wave
// See the comment from iq or this page
// http://www.iquilezles.org/www/articles/distance/distance.htm
float fCurveX = fragCoord.x / iResolution.x;
float fSinY = (GetCurve(fCurveX) * 0.25 + 0.5) * iResolution.y;
float fSinYdX = (GetCurveDeriv(fCurveX) * 0.25) * iResolution.y / iResolution.x;
float fDistanceToCurve = abs(fSinY - fragCoord.y) / sqrt(1.0+fSinYdX*fSinYdX);
float fSetPixel = fDistanceToCurve - 1.0; // Add more thickness
vColour = mix(vec3(1.0, 0.0, 0.0), vColour, clamp(fSetPixel, 0.0, 1.0));
// Draw Sin Value
float fValue4 = GetCurve(iMouse.x / iResolution.x);
float fPixelYCoord = (fValue4 * 0.25 + 0.5) * iResolution.y;
// Plot Point on Sin Wave
float fDistToPointA = length( vec2(iMouse.x, fPixelYCoord) - fragCoord.xy) - 4.0;
vColour = mix(vColour, vec3(0.0, 0.0, 1.0), (1.0 - clamp(fDistToPointA, 0.0, 1.0)));
// Plot Mouse Pos
float fDistToPointB = length( vec2(iMouse.x, iMouse.y) - fragCoord.xy) - 4.0;
vColour = mix(vColour, vec3(0.0, 1.0, 0.0), (1.0 - clamp(fDistToPointB, 0.0, 1.0)));
// Print Sin Value
vec2 vPixelCoord4 = vec2(iMouse.x, fPixelYCoord) + vec2(4.0, 4.0);
float fDigits = 1.0;
float fDecimalPlaces = 2.0;
float fIsDigit4 = PrintValue( (fragCoord - vPixelCoord4) / vFontSize, fValue4, fDigits, fDecimalPlaces);
vColour = mix( vColour, vec3(0.0, 0.0, 1.0), fIsDigit4);
// Print Shader Time
vec2 vPixelCoord1 = vec2(96.0, 5.0);
float fValue1 = iTime;
fDigits = 6.0;
float fIsDigit1 = PrintValue( (fragCoord - vPixelCoord1) / vFontSize, fValue1, fDigits, fDecimalPlaces);
vColour = mix( vColour, vec3(0.0, 1.0, 1.0), fIsDigit1);
// Print Date
vColour = mix( vColour, vec3(1.0, 1.0, 0.0), PrintValue( (fragCoord - vec2(0.0, 5.0)) / vFontSize, iDate.x, 4.0, 0.0));
vColour = mix( vColour, vec3(1.0, 1.0, 0.0), PrintValue( (fragCoord - vec2(0.0 + 48.0, 5.0)) / vFontSize, iDate.y + 1.0, 2.0, 0.0));
vColour = mix( vColour, vec3(1.0, 1.0, 0.0), PrintValue( (fragCoord - vec2(0.0 + 72.0, 5.0)) / vFontSize, iDate.z, 2.0, 0.0));
// Draw Time
vColour = mix( vColour, vec3(1.0, 0.0, 1.0), PrintValue( (fragCoord - vec2(184.0, 5.0)) / vFontSize, mod(iDate.w / (60.0 * 60.0), 12.0), 2.0, 0.0));
vColour = mix( vColour, vec3(1.0, 0.0, 1.0), PrintValue( (fragCoord - vec2(184.0 + 24.0, 5.0)) / vFontSize, mod(iDate.w / 60.0, 60.0), 2.0, 0.0));
vColour = mix( vColour, vec3(1.0, 0.0, 1.0), PrintValue( (fragCoord - vec2(184.0 + 48.0, 5.0)) / vFontSize, mod(iDate.w, 60.0), 2.0, 0.0));
if(iMouse.x > 0.0)
{
// Print Mouse X
vec2 vPixelCoord2 = iMouse.xy + vec2(-52.0, 6.0);
float fValue2 = iMouse.x / iResolution.x;
fDigits = 1.0;
fDecimalPlaces = 3.0;
float fIsDigit2 = PrintValue( (fragCoord - vPixelCoord2) / vFontSize, fValue2, fDigits, fDecimalPlaces);
vColour = mix( vColour, vec3(0.0, 1.0, 0.0), fIsDigit2);
// Print Mouse Y
vec2 vPixelCoord3 = iMouse.xy + vec2(0.0, 6.0);
float fValue3 = iMouse.y / iResolution.y;
fDigits = 1.0;
float fIsDigit3 = PrintValue( (fragCoord - vPixelCoord3) / vFontSize, fValue3, fDigits, fDecimalPlaces);
vColour = mix( vColour, vec3(0.0, 1.0, 0.0), fIsDigit3);
}
fragColor = vec4(vColour,1.0);
}

View File

@ -0,0 +1,201 @@
// Created by anatole duprat - XT95/2015
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
//More details here http://www.aduprat.com/portfolio/?page=articles/hemisphericalSDFAO
const float PI = 3.14159265359;
vec3 raymarche( in vec3 ro, in vec3 rd, in vec2 nfplane );
vec3 normal( in vec3 p );
float box( in vec3 p, in vec3 data );
float map( in vec3 p );
mat3 lookat( in vec3 fw, in vec3 up );
mat3 rotate( in vec3 v, in float angle);
//Random number [0:1] without sine
#define HASHSCALE1 .1031
float hash(float p)
{
vec3 p3 = fract(vec3(p) * HASHSCALE1);
p3 += dot(p3, p3.yzx + 19.19);
return fract((p3.x + p3.y) * p3.z);
}
vec3 randomSphereDir(vec2 rnd)
{
float s = rnd.x*PI*2.;
float t = rnd.y*2.-1.;
return vec3(sin(s), cos(s), t) / sqrt(1.0 + t * t);
}
vec3 randomHemisphereDir(vec3 dir, float i)
{
vec3 v = randomSphereDir( vec2(hash(i+1.), hash(i+2.)) );
return v * sign(dot(v, dir));
}
float ambientOcclusion( in vec3 p, in vec3 n, in float maxDist, in float falloff )
{
const int nbIte = 32;
const float nbIteInv = 1./float(nbIte);
const float rad = 1.-1.*nbIteInv; //Hemispherical factor (self occlusion correction)
float ao = 0.0;
for( int i=0; i<nbIte; i++ )
{
float l = hash(float(i))*maxDist;
vec3 rd = normalize(n+randomHemisphereDir(n, l )*rad)*l; // mix direction with the normal
// for self occlusion problems!
ao += (l - max(map( p + rd ),0.)) / maxDist * falloff;
}
return clamp( 1.-ao*nbIteInv, 0., 1.);
}
float classicAmbientOcclusion( in vec3 p, in vec3 n, in float maxDist, in float falloff )
{
float ao = 0.0;
const int nbIte = 6;
for( int i=0; i<nbIte; i++ )
{
float l = hash(float(i))*maxDist;
vec3 rd = n*l;
ao += (l - max(map( p + rd ),0.)) / maxDist * falloff;
}
return clamp( 1.-ao/float(nbIte), 0., 1.);
}
//Shading
vec3 shade( in vec3 p, in vec3 n, in vec3 org, in vec3 dir, vec2 v )
{
vec3 col = vec3(1.);
float a = ambientOcclusion(p,n, 4., 2.);
float b = classicAmbientOcclusion(p,n, 4., 1.2);
if( iMouse.z > .5 )
{
if( v.x-iMouse.x/iResolution.x >0. )
col *= a;
else
col *= b;
}
else
{
if( v.x > 0.5 )
col *= a;
else
col *= b;
}
return col;
}
//Main
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
//screen coords
vec2 q = fragCoord.xy/iResolution.xy;
vec2 v = -1.0+2.0*q;
v.x *= iResolution.x/iResolution.y;
//camera ray
float ctime = (iGlobalTime)*.25;
vec3 ro = vec3( cos(ctime)*5.,10.+cos(ctime*.5)*3.,-13.+sin(ctime) );
vec3 rd = normalize( vec3(v.x, v.y, 1.5) );
rd = lookat( -ro + vec3(0., 5., 0.), vec3(0., 1., 0.) ) * rd;
//classic raymarching by distance field
vec3 p = raymarche(ro, rd, vec2(1., 30.) );
vec3 n = normal(p.xyz);
vec3 col = shade(p, n, ro, rd, q);
//Gamma correction
col = pow(col, vec3(1./2.2));
if( iMouse.z > .5 )
{
if( abs(q.x-iMouse.x/iResolution.x) < 1./iResolution.x )
col = vec3(0.);
}
else if( abs(q.x-.5) < 1./iResolution.x)
col = vec3(0.);
fragColor = vec4( col, 1. );
}
float map( in vec3 p )
{
float d = -box(p-vec3(0.,10.,0.),vec3(10.));
d = min(d, box(rotate(vec3(0.,1.,0.), 1.)*(p-vec3(4.,5.,6.)), vec3(3.,5.,3.)) );
d = min(d, box(rotate(vec3(0.,1.,0.),-1.)*(p-vec3(-4.,2.,0.)), vec3(2.)) );
d = max(d, -p.z-9.);
return d;
}
vec3 raymarche( in vec3 ro, in vec3 rd, in vec2 nfplane )
{
vec3 p = ro+rd*nfplane.x;
float t = 0.;
for(int i=0; i<64; i++)
{
float d = map(p);
t += d;
p += rd*d;
if( d < 0.001 || t > nfplane.y )
break;
}
return p;
}
vec3 normal( in vec3 p )
{
vec3 eps = vec3(0.001, 0.0, 0.0);
return normalize( vec3(
map(p+eps.xyy)-map(p-eps.xyy),
map(p+eps.yxy)-map(p-eps.yxy),
map(p+eps.yyx)-map(p-eps.yyx)
) );
}
float box( in vec3 p, in vec3 data )
{
return max(max(abs(p.x)-data.x,abs(p.y)-data.y),abs(p.z)-data.z);
}
mat3 lookat( in vec3 fw, in vec3 up )
{
fw = normalize(fw);
vec3 rt = normalize( cross(fw, normalize(up)) );
return mat3( rt, cross(rt, fw), fw );
}
mat3 rotate( in vec3 v, in float angle)
{
float c = cos(angle);
float s = sin(angle);
return mat3(c + (1.0 - c) * v.x * v.x, (1.0 - c) * v.x * v.y - s * v.z, (1.0 - c) * v.x * v.z + s * v.y,
(1.0 - c) * v.x * v.y + s * v.z, c + (1.0 - c) * v.y * v.y, (1.0 - c) * v.y * v.z - s * v.x,
(1.0 - c) * v.x * v.z - s * v.y, (1.0 - c) * v.y * v.z + s * v.x, c + (1.0 - c) * v.z * v.z
);
}

View File

@ -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 );
}

View File

@ -0,0 +1,167 @@
/*--------------------------------------------------------------------------------------
License CC0 - http://creativecommons.org/publicdomain/zero/1.0/
To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
----------------------------------------------------------------------------------------
^ This means do ANYTHING YOU WANT with this code. Because we are programmers, not lawyers.
-Otavio Good
**************** Glorious Line Algorithm ****************
This is an attempt to solve everything anyone could want from a line in one function.
Glorious features:
- antialiasing
- rectangles, squares, lines, circles, rounded rectangles
- square or rounded endpoints
- outline shapes (might have some bugs still)
- dashed, animated lines
- resolution dependent or independent - some functions work in pixel units, some in UV coordinates.
- efficient
*/
// Clamp [0..1] range
vec3 saturate(vec3 a) { return clamp(a, 0.0, 1.0); }
vec2 saturate(vec2 a) { return clamp(a, 0.0, 1.0); }
float saturate(float a) { return clamp(a, 0.0, 1.0); }
// Basically a triangle wave
float repeat(float x) { return abs(fract(x*0.5+0.5)-0.5)*2.0; }
// This is it... what you have been waiting for... _The_ Glorious Line Algorithm.
// This function will make a signed distance field that says how far you are from the edge
// of the line at any point U,V.
// Pass it UVs, line end points, line thickness (x is along the line and y is perpendicular),
// How rounded the end points should be (0.0 is rectangluar, setting rounded to thick.y will be circular),
// dashOn is just 1.0 or 0.0 to turn on the dashed lines.
float LineDistField(vec2 uv, vec2 pA, vec2 pB, vec2 thick, float rounded, float dashOn) {
// Don't let it get more round than circular.
rounded = min(thick.y, rounded);
// midpoint
vec2 mid = (pB + pA) * 0.5;
// vector from point A to B
vec2 delta = pB - pA;
// Distance between endpoints
float lenD = length(delta);
// unit vector pointing in the line's direction
vec2 unit = delta / lenD;
// Check for when line endpoints are the same
if (lenD < 0.0001) unit = vec2(1.0, 0.0); // if pA and pB are same
// Perpendicular vector to unit - also length 1.0
vec2 perp = unit.yx * vec2(-1.0, 1.0);
// position along line from midpoint
float dpx = dot(unit, uv - mid);
// distance away from line at a right angle
float dpy = dot(perp, uv - mid);
// Make a distance function that is 0 at the transition from black to white
float disty = abs(dpy) - thick.y + rounded;
float distx = abs(dpx) - lenD * 0.5 - thick.x + rounded;
// Too tired to remember what this does. Something like rounded endpoints for distance function.
float dist = length(vec2(max(0.0, distx), max(0.0,disty))) - rounded;
dist = min(dist, max(distx, disty));
// This is for animated dashed lines. Delete if you don't like dashes.
float dashScale = 2.0*thick.y;
// Make a distance function for the dashes
float dash = (repeat(dpx/dashScale + iGlobalTime)-0.5)*dashScale;
// Combine this distance function with the line's.
dist = max(dist, dash-(1.0-dashOn*1.0)*10000.0);
return dist;
}
// This makes a filled line in pixel units. A 1.0 thick line will be 1 pixel thick.
float FillLinePix(vec2 uv, vec2 pA, vec2 pB, vec2 thick, float rounded) {
float scale = dFdy(uv).y;
thick = (thick * 0.5 - 0.5) * scale;
float df = LineDistField(uv, pA, pB, vec2(thick), rounded, 0.0);
return saturate(df / scale);
}
// This makes an outlined line in pixel units. A 1.0 thick outline will be 1 pixel thick.
float DrawOutlinePix(vec2 uv, vec2 pA, vec2 pB, vec2 thick, float rounded, float outlineThick) {
float scale = dFdy(uv).y;
thick = (thick * 0.5 - 0.5) * scale;
rounded = (rounded * 0.5 - 0.5) * scale;
outlineThick = (outlineThick * 0.5 - 0.5) * scale;
float df = LineDistField(uv, pA, pB, vec2(thick), rounded, 0.0);
return saturate((abs(df + outlineThick) - outlineThick) / scale);
}
// This makes a line in UV units. A 1.0 thick line will span a whole 0..1 in UV space.
float FillLine(vec2 uv, vec2 pA, vec2 pB, vec2 thick, float rounded) {
float df = LineDistField(uv, pA, pB, vec2(thick), rounded, 0.0);
return saturate(df / dFdy(uv).y);
}
// This makes a dashed line in UV units. A 1.0 thick line will span a whole 0..1 in UV space.
float FillLineDash(vec2 uv, vec2 pA, vec2 pB, vec2 thick, float rounded) {
float df = LineDistField(uv, pA, pB, vec2(thick), rounded, 1.0);
return saturate(df / dFdy(uv).y);
}
// This makes an outlined line in UV units. A 1.0 thick outline will span 0..1 in UV space.
float DrawOutline(vec2 uv, vec2 pA, vec2 pB, vec2 thick, float rounded, float outlineThick) {
float df = LineDistField(uv, pA, pB, vec2(thick), rounded, 0.0);
return saturate((abs(df + outlineThick) - outlineThick) / dFdy(uv).y);
}
// This just draws a point for debugging using a different technique that is less glorious.
void DrawPoint(vec2 uv, vec2 p, inout vec3 col) {
col = mix(col, vec3(1.0, 0.25, 0.25), saturate(dFdy(uv).y*8.0/distance(uv, p)-4.0));
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// Adjust UV space so it's a nice size and square.
vec2 uv = fragCoord.xy / iResolution.xy;
uv -= 0.5;
uv.x *= iResolution.x / iResolution.y;
uv *= 16.0;
// Make things that rotate with time.
vec2 rotA = vec2(cos(iGlobalTime*0.82), sin(iGlobalTime*0.82));
vec2 rotB = vec2(sin(iGlobalTime*0.82), -cos(iGlobalTime*0.82));
// Make a bunch of line endpoints to use.
vec2 pA = vec2(-4.0, 0.0) - rotA;
vec2 pB = vec2(4.0, 0.0) + rotA;
vec2 pC = pA + vec2(0.0, 4.0);
vec2 pD = pB + vec2(0.0, 4.0);
// Debugging code
//float df = LineDistField(uv, pA, pB, vec2(28.0 * dFdy(uv).y), 0.1, 0.0);
//float df = DistField(uv, pA, pB, 25.000625 * dFdx(uv).x, 0.5);
//vec3 finalColor = vec3(df*1.0, -df*1.0, 0.0);
//finalColor = vec3(1.0) * saturate(df / dFdy(uv).y);
//finalColor = vec3(1.0) * saturate((abs(df+0.009)-0.009) / dFdy(uv).y);
// Clear to white.
vec3 finalColor = vec3(1.0);
// Lots of sample lines
// 1 pixel thick regardless of screen scale.
finalColor *= FillLinePix(uv, pA, pB, vec2(0.0, 1.0), 0.0);
// Rounded rectangle outline, 1 pixel thick
finalColor *= DrawOutlinePix(uv, pA, pB, vec2(32.0), 16.0, 1.0);
// square-cornered rectangle outline, 1 pixel thick
finalColor *= DrawOutlinePix(uv, pA, pB, vec2(64.0), 0.0, 1.0);
// Fully rounded endpoint with outline 8 pixels thick
finalColor *= DrawOutlinePix(uv, pA, pB, vec2(128.0), 128.0, 8.0);
// Dashed line with rectangular endpoints that touch pC and pD, 0.5 radius thickness in UV units
finalColor *= FillLineDash(uv, pC, pD, vec2(0.0, 0.5), 0.0);
// Rounded endpoint dashed line with radius 0.125 in UV units
finalColor *= FillLineDash(uv, pC + vec2(0.0, 2.0), pD + vec2(0.0, 2.0), vec2(0.125), 1.0);
finalColor *= DrawOutline(uv, (pA + pB) * 0.5 + vec2(0.0, -4.5), (pA + pB) * 0.5 + vec2(0.0, -4.5), vec2(2.0, 2.0), 2.0, 0.8);
finalColor *= FillLine(uv, pA - vec2(4.0, 0.0), pC - vec2(4.0, 0.0)+rotA, vec2(0.125), 1.0);
finalColor *= FillLine(uv, pB + vec2(4.0, 0.0), pD + vec2(4.0, 0.0)-rotA, vec2(0.125), 1.0);
DrawPoint(uv, pA, finalColor);
DrawPoint(uv, pB, finalColor);
DrawPoint(uv, pC, finalColor);
DrawPoint(uv, pD, finalColor);
// Blue grid lines
finalColor -= vec3(1.0, 1.0, 0.2) * saturate(repeat(uv.x*2.0) - 0.92)*4.0;
finalColor -= vec3(1.0, 1.0, 0.2) * saturate(repeat(uv.y*2.0) - 0.92)*4.0;
//finalColor *= saturate(mod(fragCoord.y + 0.5, 2.0) + mod(fragCoord.x + 0.5, 2.0));
fragColor = vec4(sqrt(saturate(finalColor)), 1.0);
}

View File

@ -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 );
}

File diff suppressed because it is too large Load Diff

View File

@ -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 );
}

View File

@ -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);
}

View File

@ -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 );
}

View File

@ -0,0 +1,94 @@
// bwvideo.mp4
float sat( float t ) {
return clamp( t, 0.0, 1.0 );
}
vec2 sat( vec2 t ) {
return clamp( t, 0.0, 1.0 );
}
// vec3 sat( vec3 v ) {
// return clamp( v, 0.0f, 1.0f );
// }
//remaps inteval [a;b] to [0;1]
float remap( float t, float a, float b ) {
return sat( (t - a) / (b - a) );
}
//note: /\ t=[0;0.5;1], y=[0;1;0]
float linterp( float t ) {
return sat( 1.0 - abs( 2.0*t - 1.0 ) );
}
//note: [0;1]
float rand( vec2 n ) {
return fract(sin(dot(n.xy, vec2(12.9898, 78.233)))* 43758.5453);
}
//note: [-1;1]
float srand( vec2 n ) {
return rand(n) * 2.0 - 1.0;
}
float mytrunc( float x, float num_levels )
{
return floor(x*num_levels) / num_levels;
}
vec2 mytrunc( vec2 x, vec2 num_levels )
{
return floor(x*num_levels) / num_levels;
}
vec3 rgb2yuv( vec3 rgb )
{
vec3 yuv;
yuv.x = dot( rgb, vec3(0.299,0.587,0.114) );
yuv.y = dot( rgb, vec3(-0.14713, -0.28886, 0.436) );
yuv.z = dot( rgb, vec3(0.615, -0.51499, -0.10001) );
return yuv;
}
vec3 yuv2rgb( vec3 yuv )
{
vec3 rgb;
rgb.r = yuv.x + yuv.z * 1.13983;
rgb.g = yuv.x + dot( vec2(-0.39465, -0.58060), yuv.yz );
rgb.b = yuv.x + yuv.y * 2.03211;
return rgb;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
float THRESHOLD = 0.1 + iMouse.x / iResolution.x;
float time_s = mod( iGlobalTime, 32.0 );
float glitch_threshold = 1.0 - THRESHOLD;
const float max_ofs_siz = 0.1; //TOOD: input
const float yuv_threshold = 0.5; //TODO: input, >1.0f == no distort
const float time_frq = 16.0;
vec2 uv = fragCoord.xy / iResolution.xy;
uv.y = 1.0 - uv.y;
const float min_change_frq = 4.0;
float ct = mytrunc( time_s, min_change_frq );
float change_rnd = rand( mytrunc(uv.yy,vec2(16)) + 150.0 * ct );
float tf = time_frq*change_rnd;
float t = 5.0 * mytrunc( time_s, tf );
float vt_rnd = 0.5*rand( mytrunc(uv.yy + t, vec2(11)) );
vt_rnd += 0.5 * rand(mytrunc(uv.yy + t, vec2(7)));
vt_rnd = vt_rnd*2.0 - 1.0;
vt_rnd = sign(vt_rnd) * sat( ( abs(vt_rnd) - glitch_threshold) / (1.0-glitch_threshold) );
vec2 uv_nm = uv;
uv_nm = sat( uv_nm + vec2(max_ofs_siz*vt_rnd, 0) );
float rnd = rand( vec2( mytrunc( time_s, 8.0 )) );
uv_nm.y = (rnd>mix(1.0, 0.975, sat(THRESHOLD))) ? 1.0-uv_nm.y : uv_nm.y;
vec4 smpl = texture( iChannel0, uv_nm, -10.0 );
vec3 smpl_yuv = rgb2yuv( smpl.rgb );
smpl_yuv.y /= 1.0-3.0*abs(vt_rnd) * sat( yuv_threshold - vt_rnd );
smpl_yuv.z += 0.125 * vt_rnd * sat( vt_rnd - yuv_threshold );
fragColor = vec4( yuv2rgb(smpl_yuv), smpl.a );
}

View File

@ -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);
}

View File

@ -0,0 +1,219 @@
/*by mu6k, Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
I have no idea how I ended up here, but it demosceneish enough to publish.
You can use the mouse to rotate the camera around the 'object'.
If you can't see the shadows, increase occlusion_quality.
If it doesn't compile anymore decrease object_count and render_steps.
15/06/2013:
- published
16/06/2013:
- modified for better performance and compatibility
muuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuusk!*/
#define occlusion_enabled
#define occlusion_quality 4
//#define occlusion_preview
#define noise_use_smoothstep
#define light_color vec3(0.1,0.4,0.6)
#define light_direction normalize(vec3(.2,1.0,-0.2))
#define light_speed_modifier 1.0
#define object_color vec3(0.9,0.1,0.1)
#define object_count 9
#define object_speed_modifier 1.0
#define render_steps 33
float hash(float x)
{
return fract(sin(x*.0127863)*17143.321);
}
float hash(vec2 x)
{
return fract(cos(dot(x.xy,vec2(2.31,53.21))*124.123)*412.0);
}
vec3 cc(vec3 color, float factor,float factor2) //a wierd color modifier
{
float w = color.x+color.y+color.z;
return mix(color,vec3(w)*factor,w*factor2);
}
float hashmix(float x0, float x1, float interp)
{
x0 = hash(x0);
x1 = hash(x1);
#ifdef noise_use_smoothstep
interp = smoothstep(0.0,1.0,interp);
#endif
return mix(x0,x1,interp);
}
float noise(float p) // 1D noise
{
float pm = mod(p,1.0);
float pd = p-pm;
return hashmix(pd,pd+1.0,pm);
}
vec3 rotate_y(vec3 v, float angle)
{
float ca = cos(angle); float sa = sin(angle);
return v*mat3(
+ca, +.0, -sa,
+.0,+1.0, +.0,
+sa, +.0, +ca);
}
vec3 rotate_x(vec3 v, float angle)
{
float ca = cos(angle); float sa = sin(angle);
return v*mat3(
+1.0, +.0, +.0,
+.0, +ca, -sa,
+.0, +sa, +ca);
}
float max3(float a, float b, float c)//returns the maximum of 3 values
{
return max(a,max(b,c));
}
vec3 bpos[object_count];//position for each metaball
float dist(vec3 p)//distance function
{
float d=1024.0;
float nd;
for (int i=0 ;i<object_count; i++)
{
vec3 np = p+bpos[i];
float shape0 = max3(abs(np.x),abs(np.y),abs(np.z))-1.0;
float shape1 = length(np)-1.0;
nd = shape0+(shape1-shape0)*2.0;
d = mix(d,nd,smoothstep(-1.0,+1.0,d-nd));
}
return d;
}
vec3 normal(vec3 p,float e) //returns the normal, uses the distance function
{
float d=dist(p);
return normalize(vec3(dist(p+vec3(e,0,0))-d,dist(p+vec3(0,e,0))-d,dist(p+vec3(0,0,e))-d));
}
vec3 light = light_direction; //global variable that holds light direction
vec3 background(vec3 d)//render background
{
float t=iGlobalTime*0.5*light_speed_modifier;
float qq = dot(d,light)*.5+.5;
float bgl = qq;
float q = (bgl+noise(bgl*6.0+t)*.85+noise(bgl*12.0+t)*.85);
q+= pow(qq,32.0)*2.0;
vec3 sky = vec3(0.1,0.4,0.6)*q;
return sky;
}
float occlusion(vec3 p, vec3 d)//returns how much a point is visible from a given direction
{
float occ = 1.0;
p=p+d;
for (int i=0; i<occlusion_quality; i++)
{
float dd = dist(p);
p+=d*dd;
occ = min(occ,dd);
}
return max(.0,occ);
}
vec3 object_material(vec3 p, vec3 d)
{
vec3 color = normalize(object_color*light_color);
vec3 n = normal(p,0.1);
vec3 r = reflect(d,n);
float reflectance = dot(d,r)*.5+.5;reflectance=pow(reflectance,2.0);
float diffuse = dot(light,n)*.5+.5; diffuse = max(.0,diffuse);
#ifdef occlusion_enabled
float oa = occlusion(p,n)*.4+.6;
float od = occlusion(p,light)*.95+.05;
float os = occlusion(p,r)*.95+.05;
#else
float oa=1.0;
float ob=1.0;
float oc=1.0;
#endif
#ifndef occlusion_preview
color =
color*oa*.2 + //ambient
color*diffuse*od*.7 + //diffuse
background(r)*os*reflectance*.7; //reflection
#else
color=vec3((oa+od+os)*.3);
#endif
return color;
}
#define offset1 4.7
#define offset2 4.6
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord.xy / iResolution.xy - 0.5;
uv.x *= iResolution.x/iResolution.y; //fix aspect ratio
vec3 mouse = vec3(iMouse.xy/iResolution.xy - 0.5,iMouse.z-.5);
float t = iGlobalTime*.5*object_speed_modifier + 2.0;
for (int i=0 ;i<object_count; i++) //position for each metaball
{
bpos[i] = 1.3*vec3(
sin(t*0.967+float(i)*42.0),
sin(t*.423+float(i)*152.0),
sin(t*.76321+float(i)));
}
//setup the camera
vec3 p = vec3(.0,0.0,-4.0);
p = rotate_x(p,mouse.y*9.0+offset1);
p = rotate_y(p,mouse.x*9.0+offset2);
vec3 d = vec3(uv,1.0);
d.z -= length(d)*.5; //lens distort
d = normalize(d);
d = rotate_x(d,mouse.y*9.0+offset1);
d = rotate_y(d,mouse.x*9.0+offset2);
//and action!
float dd;
vec3 color;
for (int i=0; i<render_steps; i++) //raymarch
{
dd = dist(p);
p+=d*dd*.7;
if (dd<.04 || dd>4.0) break;
}
if (dd<0.5) //close enough
color = object_material(p,d);
else
color = background(d);
//post procesing
color *=.85;
color = mix(color,color*color,0.3);
color -= hash(color.xy+uv.xy)*.015;
color -= length(uv)*.1;
color =cc(color,.5,.6);
fragColor = vec4(color,1.0);
}

View File

@ -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);
}

View File

@ -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 );
}

View File

@ -0,0 +1,465 @@
// https://www.shadertoy.com/view/WtXyW4
// License CC0: Alien Waterworld
// Been working on space themed shaders
// Code "borrowed" from the usual suspects
#define PI 3.141592654
#define TAU (2.0*PI)
#define TOLERANCE 0.00001
#define MAX_ITER 55
#define MAX_DISTANCE 31.0
#define PERIOD 45.0
#define TIME mod(iTime, PERIOD)
const vec3 skyCol1 = vec3(0.35, 0.45, 0.6);
const vec3 skyCol2 = skyCol1*skyCol1*skyCol1*3.0;
const vec3 sunCol1 = vec3(1.0,0.9,0.8);
const vec3 sunCol2 = vec3(1.0,0.9,0.8);
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 ringColor = sqrt(vec3(0.95, 0.65, 0.45));
const vec4 planet = vec4(80.0, -20.0, 100.0, 50.0)*1000.0;
const vec3 planetCol = sqrt(vec3(0.9, 0.8, 0.7));
const vec3 ringsNormal = normalize(vec3(1.0, 1.25, 0.0));
const vec4 rings = vec4(ringsNormal, -dot(ringsNormal, planet.xyz));
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);
}
float psin(float f) {
return 0.5 + 0.5*sin(f);
}
vec2 toRect(vec2 p) {
return p.x*vec2(cos(p.y), sin(p.y));
}
vec2 toPolar(vec2 p) {
return vec2(length(p), atan(p.y, p.x));
}
float mod1(inout float p, float size) {
float halfsize = size*0.5;
float c = floor((p + halfsize)/size);
p = mod(p + halfsize, size) - halfsize;
return c;
}
float circle(vec2 p, float r) {
return length(p) - r;
}
float rayPlane(vec3 ro, vec3 rd, vec4 p) {
return -(dot(ro,p.xyz)+p.w)/dot(rd,p.xyz);
}
vec2 raySphere(vec3 ro, vec3 rd, vec4 sphere)
{
vec3 ce = sphere.xyz;
float ra = sphere.w;
vec3 oc = ro - ce;
float b = dot( oc, rd );
float c = dot( oc, oc ) - ra*ra;
float h = b*b - c;
if( h<0.0 ) return vec2(-1.0); // no intersection
h = sqrt( h );
return vec2( -b-h, -b+h );
}
float hash(in vec2 co) {
return fract(sin(dot(co.xy ,vec2(12.9898,58.233))) * 13758.5453);
}
float noise2(vec2 x) {
vec2 i = floor(x);
vec2 w = fract(x);
#if 1
// quintic interpolation
vec2 u = w*w*w*(w*(w*6.0-15.0)+10.0);
#else
// cubic interpolation
vec2 u = w*w*(3.0-2.0*w);
#endif
float a = hash(i+vec2(0.0,0.0));
float b = hash(i+vec2(1.0,0.0));
float c = hash(i+vec2(0.0,1.0));
float d = hash(i+vec2(1.0,1.0));
float k0 = a;
float k1 = b - a;
float k2 = c - a;
float k3 = d - c + a - b;
return k0 + k1*u.x + k2*u.y + k3*u.x*u.y;
}
float smoother(float d, float s) {
return s*tanh(d/s);
}
float heightMod(vec2 p) {
vec2 pp = toPolar(p);
pp.y += -pp.x*0.2;
p = toRect(pp);
return pow((psin(1.0*p.x)*psin(1.0*p.y)), max(0.25, pp.x*0.20))*0.8;
}
float loheight(vec2 p, float d) {
const float aa = 0.5;
const float ff = 2.03;
const float tt = 1.3;
const float oo = 0.93;
float hm = heightMod(p);
vec2 s = vec2(0.0);
float a = 1.0;
float o = 0.2;
for (int i = 0; i < 3; ++i) {
float nn = a*(noise2(2.0*p));
s.x += nn;
s.y += abs(a);
p += o;
a *= aa;
p *= ff;
o *= oo;
rot(p, tt);
}
s.x /= s.y;
s.x -= 1.0;
s.x += 0.7*hm;
s.x = smoother(s.x, 0.125);
return max(s.x+0.125, 0.0)*0.5;
}
float height(vec2 p, float d) {
const float aa = 0.5;
const float ff = 2.03;
const float tt = 1.3;
const float oo = 0.93;
float hm = heightMod(p);
vec2 s = vec2(0.0);
float a = 1.0;
float o = 0.2;
for (int i = 0; i < 5; ++i) {
float nn = a*(noise2(2.0*p));
s.x += nn;
s.y += abs(a);
p += o;
a *= aa;
p *= ff;
o *= oo;
rot(p, tt);
}
s.x /= s.y;
s.x -= 1.0;
s.x += 0.7*hm;
s.x = smoother(s.x, 0.125);
return max(s.x+0.125, 0.0)*0.5;
}
float hiheight(vec2 p, float d) {
const float aa = 0.5;
const float ff = 2.03;
const float tt = 1.3;
const float oo = 0.93;
float hm = heightMod(p);
vec2 s = vec2(0.0);
float a = 1.0;
float o = 0.2;
for (int i = 0; i < 6; ++i) {
float nn = a*(noise2(2.0*p));
s.x += nn;
s.y += abs(a);
p += o;
a *= aa;
p *= ff;
o *= oo;
rot(p, tt);
}
s.x /= s.y;
s.x -= 1.0;
s.x += 0.7*hm;
s.x = smoother(s.x, 0.125);
return max(s.x+0.125, 0.0)*0.5;
}
vec3 normal(vec2 p, float d) {
vec2 eps = vec2(0.000125, 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);
}
float march(vec3 ro, vec3 rd, float id, out int max_iter) {
float dt = 0.1;
float d = id;
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) {
return d;
}
float sl = 0.9;
dt = max(hd*sl, TOLERANCE+0.0005*d);
lastd = d;
d += dt;
}
max_iter = MAX_ITER;
return MAX_DISTANCE;
}
vec3 sunDirection() {
return normalize(vec3(-0.5, 0.2, 1.0));
}
vec3 smallSunDirection() {
return normalize(vec3(-0.2, -0.05, 1.0));
}
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 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);
vec2 si = raySphere(ro, rd, planet);
float pi = rayPlane(ro, rd, rings);
float dustTransparency = smoothstep(-0.15, 0.075, rd.y);
vec3 skyCol = mix(skyCol1, skyCol2, sqrt(dustTransparency));
skyCol *= (1.0-dustTransparency);
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*planetCol, 0.3*planetCol, pow(psin(planetLat+1.0)*psin(sqrt(2.0)*planetLat+2.0)*psin(sqrt(3.5)*planetLat+3.0), 0.5));
vec3 ringsSurface = ro + pi*rd;
float borderTransparency = smoothstep(0.0, 0.1, planetBorder);
float ringsDist = length(ringsSurface - planet.xyz)*1.0;
float ringsPeriod = ringsDist*0.001;
const float ringsMax = 150000.0*0.655;
const float ringsMin = 100000.0*0.666;
float ringsMul = pow(psin(ringsPeriod+1.0)*psin(sqrt(0.5)*ringsPeriod+2.0)*psin(sqrt(0.45)*ringsPeriod+4.0)*psin(sqrt(0.35)*ringsPeriod+5.0), 0.25);
float ringsMix = psin(ringsPeriod*10.0)*psin(ringsPeriod*10.0*sqrt(2.0))*(1.0 - smoothstep(50000.0, 200000.0, pi));
vec3 ringsCol = mix(vec3(0.125), 0.75*ringColor, ringsMix)*step(-pi, 0.0)*step(ringsDist, ringsMax)*step(-ringsDist, -ringsMin)*ringsMul;
vec3 final = vec3(0.0);
final += ringsCol*(step(pi, si.x) + step(si.x, 0.0));
final += step(0.0, si.x)*pow(planetDiff, 0.75)*mix(planetCol, ringsCol, 0.0)*dustTransparency*borderTransparency + ringsCol*(1.0 - borderTransparency);
final += skyCol + sunCol + smallSunCol;
return final;
}
vec3 shipColor(vec2 p) {
vec2 pp = toPolar(p);
pp.y += pp.x*0.05;
p = toRect(pp);
float n = mod1(p.x, 0.15);
p.y += 3.0-TIME*0.5+0.05*abs(n*n);
float td = abs(p.x) - (0.005-p.y*0.002);
td = abs(td) - (0.02*pow(-p.y, 0.25));
float sd = circle(p, 0.05);
vec3 trailCol = vec3(0.5)*smoothstep(-5.0, 0.0, p.y)*step(p.y, 0.0)*smoothstep(0.0, 0.025, -td);
vec3 shipCol = vec3(0.5+smoothstep(-1.0, 1.0, sin(TIME*15.0*TAU+n)))*smoothstep(0.0, 0.075, -sd);
vec3 col = trailCol;
col += shipCol;
float sm = step(abs(n), 2.0);
return col*sm;
}
vec3 getColor(vec3 ro, vec3 rd) {
int max_iter = 0;
vec3 skyCol = skyColor(ro, rd);
vec3 col = vec3(0);
const float shipHeight = 1.0;
const float seaHeight = 0.0;
const float cloudHeight = 0.2;
const float upperCloudHeight = 0.5;
float id = (cloudHeight - ro.y)/rd.y;
if (id > 0.0) {
float d = march(ro, rd, id, max_iter);
vec3 sunDir = sunDirection();
vec3 osunDir = sunDir*vec3(-1.0, 1.0, -1.0);
vec3 p = ro + d*rd;
float loh = loheight(p.xz, d);
float loh2 = loheight(p.xz+sunDir.xz*0.05, d);
float hih = hiheight(p.xz, d);
vec3 normal = normal(p.xz, d);
float ud = (upperCloudHeight - 4.0*loh - ro.y)/rd.y;
float sd = (seaHeight - ro.y)/rd.y;
vec3 sp = ro + sd*rd;
float scd = (cloudHeight - sp.y)/sunDir.y;
vec3 scp = sp + sunDir*scd;
float sloh = loheight(scp.xz, d);
float cshd = exp(-15.0*sloh);
float amb = 0.3;
vec3 seaNormal = normalize(vec3(0.0, 1.0, 0.0));
vec3 seaRef = reflect(rd, seaNormal);
vec3 seaCol = .25*skyColor(p, seaRef);
seaCol += pow(max(dot(seaNormal, sunDir), 0.0), 2.0);
seaCol *= cshd;
seaCol += 0.075*pow(vec3(0.1, 1.3, 4.0), vec3(max(dot(seaNormal, seaRef), 0.0)));
float spe = pow(max(dot(sunDir, reflect(rd, normal)), 0.0), 3.0);
float fre = pow(1.0-dot(normal, -rd), 2.0);
col = seaCol;
const float level = 0.00;
const float level2 = 0.3;
// REALLY fake shadows and lighting
vec3 scol = sunCol1*(smoothstep(level, level2, hih) - smoothstep(level, level2, loh2));
col = mix(vec3(1.0), col, exp(-17.0*(hih-0.25*loh)));
col = mix(vec3(.75), col, exp(-10.0*loh*(max(d-ud, 0.0))));
col += scol;
col += vec3(0.5)*spe*fre;
float ssd = (shipHeight - ro.y)/rd.y;
col += shipColor((ro + rd*ssd).xz);
col = mix(col, skyCol, smoothstep(0.5*MAX_DISTANCE, 1.*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 postProcess(in vec3 col, in vec2 q)
{
//col = saturate(col);
col=pow(clamp(col,0.0,1.0),vec3(0.75));
col=col*0.6+0.4*col*col*(3.0-2.0*col); // contrast
col=mix(col, vec3(dot(col, vec3(0.33))), -0.4); // satuation
col*=0.5+0.5*pow(19.0*q.x*q.y*(1.0-q.x)*(1.0-q.y),0.7); // vigneting
return col;
}
vec3 getSample1(vec2 p, float time) {
vec3 ro = vec3(0.5, 5.5, -2.0);
vec3 la = ro + vec3(0.0, -1.+0.9*TIME/PERIOD, 1.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, TIME);
col = postProcess(col, q);
col *= smoothstep(0.0, 2.0, TIME);
col *= 1.0-smoothstep(PERIOD-2.0, PERIOD, TIME);
fragColor = vec4(col, 1.0);
}

View File

@ -0,0 +1,461 @@
// noise3.jpg, stars.jpg
// Ben Quantock 2014
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
// parameters
const float SSradius = 200.0; // Okay, it's actually a lot smaller than the Stanford Torus, but it's a cool name.
const float SSthickness = 16.0;
const float angularSpeed = .221; // g = r*w^2, e.g. w = sqrt(9.81/200) = .221
vec3 SunDir = vec3(1,1,-1.5);
const float tau = 6.28318530717958647692;
vec2 Noise( in vec3 x )
{
vec3 p = floor(x), f = fract(x);
f = f*f*(3.0-2.0*f);
vec2 uv = (p.xy+vec2(37.0,17.0)*p.z) + f.xy;
vec4 rg = textureLod( iChannel0, (uv+0.5)/256.0, 0.0 );
return mix( rg.yw, rg.xz, f.z );
}
#define MAX 1000.0
float Foliage( vec3 pos )
{
return
max(
abs(pos.z)-SSthickness,
abs(length(pos.xy)-SSradius-2.0 + Noise(pos/16.0).x*2.0 + 2.0*abs(pos.z)/SSthickness - 1.0)-1.0
);
// todo: leafiness
}
float Water( vec3 pos )
{
return max( abs(pos.z)-SSthickness, abs(length(pos.xy)-SSradius-1.0)-1.0 );
}
float Building( vec3 pos, float seed )
{
if ( seed < .1 )
return length(vec3(pos.x,max(abs(pos.y)-2.0,0.0),pos.z))-2.0;
vec3 p = pos;
p.y += (seed-.5)*p.z;
p = abs(p)-vec3(2,3,2);
vec3 p2 = abs(pos+vec3(0,1.67,0))-vec3(1,.67,1);
return max(max(max(p.x,p.y),p.z),-max(p2.z,p2.y));
}
float Solid( vec3 pos )
{
float r = length(pos.xy);
vec2 polar = vec2(atan(pos.x,-pos.y),length(pos.xy));
vec3 spokep = pos;
const float spokeangle = tau/5.0;
float spokea = (fract(polar.x/spokeangle)-.5)*spokeangle;
spokep.xy = polar.y*vec2(sin(spokea),-cos(spokea));
return
min(min(
// ring
max(max(
// outer torus
abs( length(vec2(pos.z, r-SSradius))-SSthickness-.5 )-.5,
// window-gap
5.0-abs(r-(SSradius-6.0))),
// top gap
min(
6.0-abs(pos.z), //todo: close bottom
SSradius-r
)
),
// buildings
//length( vec3((fract(polar.x*40.0)-.5)*polar.y/40.0,polar.y+1.0-SSradius,pos.z+30.0*(fract(pow(floor(polar.x*40.0)*.777,2.0))-.5) ) ) - .5
//length( vec3((fract(polar.x*20.0)-.5)*polar.y/20.0,polar.y-SSradius,pos.z+30.0*(fract(pow(floor(polar.x*20.0)*.444,2.0))-.5) ) ) - 2.0
Building( vec3((fract(polar.x*20.0)-.5)*polar.y/20.0,polar.y-SSradius,pos.z+30.0*(fract(pow((floor(polar.x*20.0)+5.0)*.444,2.0))-.5) ), fract(pow(floor(polar.x*20.0)*.777,2.0)) )
// could do roads connecting them, by drawing 2 for every position
),
max(
min( min(
// spokes
max(
-SSradius-spokep.y,
length(spokep.xz)-2.0
),
// hub
max(
r-20.0,
abs(pos.z)-7.0
)),
max(
r-17.0,
abs(pos.z)-9.0
)
),
// dock
min(
8.0-abs(pos.x),
3.0-abs(pos.y)
)
)
);
}
// smooth min, to prevent hard edges when I use union of lights
bool domin;
float smin ( float a, float b )
{
/*const float s = 1.0;
return -log2(exp2(-a/s)+exp2(-b/s))*s;*/
if ( domin )
{
return min( a, b );
}
else
{
return 1.0/(1.0/a+1.0/b);
}
}
float Lights( vec3 pos )
{
return
smin(smin(//smin(
// ring light
sqrt( pow(length(vec2(pos.z, length(pos.xy)-188.0)),2.0) + pow(max(.0,dot(pos.xy,vec2(sin(iGlobalTime*.3),cos(iGlobalTime*.3)))),2.0) )-.5,
// landing lights
//length( vec3( abs(pos.x)-8.0, max(vec2(0),abs(pos.yz)-vec2(3,8.5)) ) )-.1),
// moving lights to test fake lighting/shadows
length(pos-vec3(-sin(iGlobalTime*.2)*20.0+8.0,-197,12.0*sin(iGlobalTime)))-.3),
length(pos-vec3(-sin(iGlobalTime*.22)*30.0,-197.0+4.0*sin(iGlobalTime*.7),12.0*sin(iGlobalTime*.87)))-2.0
);
}
vec4 SampleLights( vec3 pos )
{
domin = false;
// like then Normal calc
float r = .1;
vec2 d = vec2(-1,1) * r;
vec3 p0 = pos+d.xxx; // tetrahedral offsets
vec3 p1 = pos+d.xyy;
vec3 p2 = pos+d.yxy;
vec3 p3 = pos+d.yyx;
float f0 = Lights(p0);
float f1 = Lights(p1);
float f2 = Lights(p2);
float f3 = Lights(p3);
// this direction is completely innaccurrate for hard-edged intersections!
// it gets one or other surface normal, rather than a smoothed result
// so, build smooth light shapes
return vec4(
-normalize( p0*f0+p1*f1+p2*f2+p3*f3 - pos*(f0+f1+f2+f3) ),// /r, should be possible to use non-normalized value, for more realistic effect
(f0+f1+f2+f3)/4.0
);
}
float DistanceField( vec3 pos )
{
domin = true;
return min( min( min(
Foliage( pos ),
Water( pos ) ),
Solid( pos ) ),
Lights( pos )
);
}
float DistanceFieldNoLights( vec3 pos )
{
return min( min(
Foliage( pos ),
Water( pos ) ),
Solid( pos )
);
}
struct ShadeData { vec3 pos, ray, normal; float shadow; float t; };
ShadeData SetShadeData( vec3 pos, vec3 ray, vec3 normal, float shadow, float t )
{
ShadeData s;
s.pos = pos;
s.ray = ray;
s.normal = normal;
s.shadow = shadow;
s.t = t;
return s;
}
vec3 DiffuseLight( ShadeData s )
{
// sunlight
vec3 sun = vec3(1)*2.0*max(.0,dot(s.normal,SunDir))*s.shadow;
// local soft light sources
// Actually sample the lights!!
vec4 sl = SampleLights( s.pos );
// float fade = 1.0/sl.w; // point lights should be 1/(w*w), line lights are 1/w, infinite area lights are 1
//vec3 local = vec3(.4,.7,1)*5.0*(dot(sl.xyz,s.normal)*.5+.5)*fade;
vec3 local = vec3(.4,.7,1)*2.0*(dot(sl.xyz,s.normal)+1.0)/sl.w;
// like ambient occlusion, but towards the light
vec3 l = normalize(sl.xyz);
float d = 2.0;//s.t/20.0;
//shadow strength should depend on strength of SH vector
local *= .3+.7*min( 1.0, max( 0.0, (DistanceFieldNoLights(s.pos+l*d)/d)) );// /max(.001,dot(s.normal,l)) );
// ambient
vec3 ambient = vec3(0) + local;
// this ambient occlusion trick works ridiculously well
// sample the distance field at a point in front of the surface
// if there's a nearby concave surface the value will be less than the distance to the sample point
float aoRange = s.t/20.0;
float occlusion = max( 0.0, 1.0 - DistanceFieldNoLights( s.pos + s.normal*aoRange )/aoRange ); // can be > 1.0
ambient *= exp2( -2.0*pow(occlusion,2.0) ); // tweak the curve
return ambient;//+sun;
}
vec3 ShadeFoliage( ShadeData s )
{
vec3 albedo = mix( vec3(.05,.02,.01), vec3(.1,.5,.0), Noise(s.pos*20.0).x*.3+.7 );
return albedo*DiffuseLight(s);
}
vec3 ShadeWater( ShadeData s )
{
const float albedoScale = 4.0;
float rad = (SSradius+1.0)/albedoScale;
rad = floor( rad*tau+.5 )/tau; // round it so we get a whole number of texture repeats
vec2 uv = vec2(s.pos.z/albedoScale,atan(s.pos.x,s.pos.y)*rad);
vec3 base = vec3(.05,.1,.2)*DiffuseLight(s);
// normal map
vec2 noise = (Noise( s.pos*2.0+iGlobalTime*vec3(-4,4,0) )*2.0-1.0)*.1;
vec3 tangent = normalize(vec3(s.pos.y,-s.pos.x,0));
vec3 binormal = vec3(0,0,1);
vec3 normal = s.normal + tangent*noise.x + binormal*noise.y;
float fresnel = dot(normal,s.ray);
vec3 reflection = s.ray-2.0*fresnel*normal;
fresnel = pow( 1.0-abs(fresnel), 5.0 );
float up = dot( reflection, normal );
float across = dot( reflection, binormal );
vec3 refcol = vec3(.4,.7,1)*1.0*pow(1.0-abs(across),40.0);
return mix( base, refcol, fresnel );
}
vec3 ShadeSolid( ShadeData s )
{
return vec3(.8) * DiffuseLight(s);
}
vec3 ShadeLights( ShadeData s )
{
return vec3(.4,.7,1)*8.0*abs(dot(s.ray,s.normal)); // draw the lightbulb
}
vec3 Shade( ShadeData s )
{
float foliage = Foliage(s.pos);
float water = Water(s.pos);
float solid = Solid(s.pos);
float lights = Lights(s.pos);
float dist = min(min(min(foliage, water),solid),lights);
if ( lights == dist )
return ShadeLights(s);
#if (1) // test lighting
return DiffuseLight(s)*.8;
#else
else if ( foliage == dist )
return ShadeFoliage(s);
else if ( water == dist )
return ShadeWater(s);
else
return ShadeSolid(s);
#endif
}
//Compute the surface normal
vec3 Normal( vec3 pos )
{
// in theory we should be able to get a good gradient using just 4 points
vec2 d = vec2(-1,1) * .01;
vec3 p0 = pos+d.xxx; // tetrahedral offsets
vec3 p1 = pos+d.xyy;
vec3 p2 = pos+d.yxy;
vec3 p3 = pos+d.yyx;
float f0 = DistanceField(p0);
float f1 = DistanceField(p1);
float f2 = DistanceField(p2);
float f3 = DistanceField(p3);
return normalize( p0*f0+p1*f1+p2*f2+p3*f3 - pos*(f0+f1+f2+f3) );
}
struct Camera { vec3 pos, target, up; float zoom; };
Camera SetCam( vec3 pos, vec3 target, vec3 up, float zoom )
{
Camera cam;
cam.pos = pos;
cam.target = target;
cam.up = up;
cam.zoom = zoom;
return cam;
}
Camera MixCam( Camera a, Camera b, float c )
{
Camera cam;
cam.pos = mix( a.pos, b.pos, c );
cam.target = mix( a.target, b.target, c );
cam.up = mix( a.up, b.up, c );
cam.zoom = mix( a.zoom, b.zoom, c );
return cam;
}
vec3 BGRot( in vec3 v, in vec3 cs )
{
return vec3(v.xy*cs.x + v.yx*cs.yz, v.z);
}
vec2 Trace( vec3 pos, vec3 ray, vec2 interval )
{
float t = interval.x;
float h;
for( int i=0; i<200; i++ )
{
h = DistanceField( pos + t*ray );
if ( h < .01 || t > interval.y )
break;
t += h;
}
return vec2(t,h);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// rotate background
float a = iGlobalTime*angularSpeed; // radians per second
vec3 cs = vec3( cos(a), sin(a)*vec2(1,-1) );
SunDir = normalize( BGRot( SunDir, cs ) );
// todo: animate camera between pairs of keyframes
Camera camKeys[8];
camKeys[0] = SetCam( vec3(-400,-300,-300), vec3(0,0,0), vec3(0,.5,-1), .8 );
camKeys[1] = SetCam( vec3(-20,3.0-SSradius,-16), vec3(SSradius,-130,0), vec3(0,1,1), .7 );
camKeys[2] = SetCam( vec3(-10,2.0-SSradius,16), vec3(0,-SSradius,0), vec3(0,1,0), .8 );
camKeys[3] = SetCam( vec3(30,2.5-SSradius,5), vec3(-SSradius,40.0-SSradius,-50), vec3(0,1,0), .8 );
camKeys[4] = SetCam( vec3(30,2.5-SSradius,5), vec3(-SSradius,40.0-SSradius,-50), vec3(0,1,0), .8 );
camKeys[5] = SetCam( vec3(-10,2.5-SSradius,2), vec3(0,SSradius,0), vec3(.5,3,1), 1.2 );
camKeys[6] = SetCam( vec3(200,-150,400), vec3(0,0,0), vec3(0,.5,1), .8 );
camKeys[7] = SetCam( vec3(0,0,50), vec3(0,0,0), vec3(cs.y,-cs.x,0), .8 );
// pick a pair of cameras using time
// todo: could manually pick cam using all combinations of "iop", shown on screen when auto-cycling (cam: io)
// mouse moves cam along path, and target up/down (by up*length(target-pos))
float T = fract(iGlobalTime/52.0)*4.0;
Camera cam1, cam2;
bool rotCam = false;
if ( T < 1.0 ) { cam1 = camKeys[0]; cam2 = camKeys[1]; rotCam = true; }
else if ( T < 2.0 ) { cam1 = camKeys[2]; cam2 = camKeys[3]; }
else if ( T < 3.0 ) { cam1 = camKeys[4]; cam2 = camKeys[5]; }
else { cam1 = camKeys[6]; cam2 = camKeys[7]; rotCam = true; }
// mix between them
//T = smoothstep( .15, .85, fract(T) );
T = fract(T);
float T2 = T*T;
T = (6.0*T2 - 15.0*T + 10.0)*T2*T;
Camera cam = MixCam( cam1, cam2, T );
//rotCam = true; cam = camKeys[1];
rotCam = false; cam = camKeys[3];
//Camera cam = SetCam( vec3(500.0*(iMouse.xy/iResolution.xy-.5),0)+vec3(0,-300,-300), vec3(0,-100,0), vec3(0,1,0), .7 );
// fire a ray from the camera
vec3 pos = cam.pos;
vec3 forward = normalize(cam.target-cam.pos);
vec3 right = normalize(cross(cam.up,forward));
vec3 up = normalize(cross(forward,right));
vec3 ray = normalize(vec3( fragCoord.xy-iResolution.xy*.5, iResolution.x*cam.zoom ));
ray = right*ray.x + up*ray.y + forward*ray.z;
if ( rotCam )
{
pos = BGRot( pos, cs );
ray = BGRot( ray, cs );
}
// intersect that ray with isosurface bounding volume
vec2 interval = vec2(0,1000);
// march isosurface
vec2 th = Trace( pos, ray, interval );
// shading
vec3 col;
if ( th.y < 1.0 ) // shade some near misses to reduce artefacts
{
vec3 p = pos + th.x*ray;
vec3 n = Normal(p);
float shadowBias = mix ( 1.0, .1, abs(dot( n, SunDir )) );
float shadow = Trace( p, SunDir, vec2(shadowBias, 1000.0) ).y;
shadow = smoothstep( .01, 4.0, shadow );
col = Shade( SetShadeData(p,ray,n,shadow,th.x) );
}
else
{
// draw background
ray = BGRot( ray, cs.xzy );
float s = 1.3;
vec3 X = texture( iChannel1, ray.yz*s ).rgb;
vec3 Y = texture( iChannel1, ray.xz*s ).rgb;
vec3 Z = texture( iChannel1, ray.xy*s ).rgb;
col = mix( X, Y, smoothstep(-.3,.3,abs(ray.y)-abs(ray.x)) );
col = mix( col, Z, smoothstep(-.3,.3,abs(ray.z)-max(abs(ray.x),abs(ray.y))) );
col = pow(col,vec3(7,5,3))*.1;
col = vec3(0);
}
fragColor = vec4(pow(col,vec3(1.0/2.2)),1.0);
}

View File

@ -0,0 +1,423 @@
// noise3.jpg,
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
const float tau = 6.28318530717958647692;
// Gamma correction
#define GAMMA (2.2)
vec3 ToLinear( in vec3 col )
{
// simulate a monitor, converting colour values into light values
return pow( col, vec3(GAMMA) );
}
vec3 ToGamma( in vec3 col )
{
// convert back into colour values, so the correct light will come out of the monitor
return pow( col, vec3(1.0/GAMMA) );
}
vec3 localRay;
// Set up a camera looking at the scene.
// origin - camera is positioned relative to, and looking at, this point
// distance - how far camera is from origin
// rotation - about x & y axes, by left-hand screw rule, relative to camera looking along +z
// zoom - the relative length of the lens
void CamPolar( out vec3 pos, out vec3 ray, in vec3 origin, in vec2 rotation, in float distance, in float zoom, in vec2 fragCoord )
{
// get rotation coefficients
vec2 c = vec2(cos(rotation.x),cos(rotation.y));
vec4 s;
s.xy = vec2(sin(rotation.x),sin(rotation.y)); // worth testing if this is faster as sin or sqrt(1.0-cos);
s.zw = -s.xy;
// ray in view space
ray.xy = fragCoord.xy - iResolution.xy*.5;
ray.z = iResolution.y*zoom;
ray = normalize(ray);
localRay = ray;
// rotate ray
ray.yz = ray.yz*c.xx + ray.zy*s.zx;
ray.xz = ray.xz*c.yy + ray.zx*s.yw;
// position camera
pos = origin - distance*vec3(c.x*s.y,s.z,c.x*c.y);
}
// Noise functions, distinguished by variable types
vec2 Noise( in vec3 x )
{
vec3 p = floor(x);
vec3 f = fract(x);
f = f*f*(3.0-2.0*f);
// vec3 f2 = f*f; f = f*f2*(10.0-15.0*f+6.0*f2);
vec2 uv = (p.xy+vec2(37.0,17.0)*p.z);
vec4 rg = textureLod( iChannel0, (uv+f.xy+0.5)/256.0, 0.0 );
return mix( rg.yw, rg.xz, f.z );
}
vec2 NoisePrecise( in vec3 x )
{
vec3 p = floor(x);
vec3 f = fract(x);
f = f*f*(3.0-2.0*f);
// vec3 f2 = f*f; f = f*f2*(10.0-15.0*f+6.0*f2);
vec2 uv = (p.xy+vec2(37.0,17.0)*p.z);
vec4 rg = mix( mix(
textureLod( iChannel0, (uv+0.5)/256.0, 0.0 ),
textureLod( iChannel0, (uv+vec2(1,0)+0.5)/256.0, 0.0 ),
f.x ),
mix(
textureLod( iChannel0, (uv+vec2(0,1)+0.5)/256.0, 0.0 ),
textureLod( iChannel0, (uv+1.5)/256.0, 0.0 ),
f.x ),
f.y );
return mix( rg.yw, rg.xz, f.z );
}
vec4 Noise( in vec2 x )
{
vec2 p = floor(x.xy);
vec2 f = fract(x.xy);
f = f*f*(3.0-2.0*f);
// vec3 f2 = f*f; f = f*f2*(10.0-15.0*f+6.0*f2);
vec2 uv = p.xy + f.xy;
return textureLod( iChannel0, (uv+0.5)/256.0, 0.0 );
}
vec4 Noise( in ivec2 x )
{
return textureLod( iChannel0, (vec2(x)+0.5)/256.0, 0.0 );
}
vec2 Noise( in ivec3 x )
{
vec2 uv = vec2(x.xy)+vec2(37.0,17.0)*float(x.z);
return textureLod( iChannel0, (uv+0.5)/256.0, 0.0 ).xz;
}
float Waves( vec3 pos )
{
pos *= .2*vec3(1,1,1);
const int octaves = 5;
float f = 0.0;
// need to do the octaves from large to small, otherwise things don't line up
// (because I rotate by 45 degrees on each octave)
pos += iGlobalTime*vec3(0,.1,.1);
for ( int i=0; i < octaves; i++ )
{
pos = (pos.yzx + pos.zyx*vec3(1,-1,1))/sqrt(2.0);
f = f*2.0+abs(Noise(pos).x-.5)*2.0;
pos *= 2.0;
}
f /= exp2(float(octaves));
return (.5-f)*1.0;
}
float WavesDetail( vec3 pos )
{
pos *= .2*vec3(1,1,1);
const int octaves = 8;
float f = 0.0;
// need to do the octaves from large to small, otherwise things don't line up
// (because I rotate by 45 degrees on each octave)
pos += iGlobalTime*vec3(0,.1,.1);
for ( int i=0; i < octaves; i++ )
{
pos = (pos.yzx + pos.zyx*vec3(1,-1,1))/sqrt(2.0);
f = f*2.0+abs(NoisePrecise(pos).x-.5)*2.0;
pos *= 2.0;
}
f /= exp2(float(octaves));
return (.5-f)*1.0;
}
float WavesSmooth( vec3 pos )
{
pos *= .2*vec3(1,1,1);
const int octaves = 2;
float f = 0.0;
// need to do the octaves from large to small, otherwise things don't line up
// (because I rotate by 45 degrees on each octave)
pos += iGlobalTime*vec3(0,.1,.1);
for ( int i=0; i < octaves; i++ )
{
pos = (pos.yzx + pos.zyx*vec3(1,-1,1))/sqrt(2.0);
//f = f*2.0+abs(Noise(pos).x-.5)*2.0;
f = f*2.0+sqrt(pow(NoisePrecise(pos).x-.5,2.0)+.01)*2.0;
pos *= 2.0;
}
f /= exp2(float(octaves));
return (.5-f)*1.0;
}
float WaveCrests( vec3 ipos, in vec2 fragCoord )
{
vec3 pos = ipos;
pos *= .2*vec3(1,1,1);
const int octaves1 = 6;
const int octaves2 = 16;
float f = 0.0;
// need to do the octaves from large to small, otherwise things don't line up
// (because I rotate by 45 degrees on each octave)
pos += iGlobalTime*vec3(0,.1,.1);
vec3 pos2 = pos;
for ( int i=0; i < octaves1; i++ )
{
pos = (pos.yzx + pos.zyx*vec3(1,-1,1))/sqrt(2.0);
f = f*1.5+abs(Noise(pos).x-.5)*2.0;
pos *= 2.0;
}
pos = pos2 * exp2(float(octaves1));
pos.y = -.05*iGlobalTime;
for ( int i=octaves1; i < octaves2; i++ )
{
pos = (pos.yzx + pos.zyx*vec3(1,-1,1))/sqrt(2.0);
f = f*1.5+pow(abs(Noise(pos).x-.5)*2.0,1.0);
pos *= 2.0;
}
f /= 1500.0;
f -= Noise(ivec2(fragCoord.xy)).x*.01;
return pow(smoothstep(.4,-.1,f),6.0);
}
vec3 Sky( vec3 ray )
{
return vec3(.4,.45,.5);
}
vec3 boatRight, boatUp, boatForward;
vec3 boatPosition;
void ComputeBoatTransform( void )
{
vec3 samples[5];
samples[0] = vec3(0,0, 0);
samples[1] = vec3(0,0, .5);
samples[2] = vec3(0,0,-.5);
samples[3] = vec3( .5,0,0);
samples[4] = vec3(-.5,0,0);
samples[0].y = WavesSmooth(samples[0]);
samples[1].y = WavesSmooth(samples[1]);
samples[2].y = WavesSmooth(samples[2]);
samples[3].y = WavesSmooth(samples[3]);
samples[4].y = WavesSmooth(samples[4]);
boatPosition = (samples[0]+samples[1]+samples[2]+samples[3]+samples[4])/5.0;
boatRight = samples[3]-samples[4];
boatForward = samples[1]-samples[2];
boatUp = normalize(cross(boatForward,boatRight));
boatRight = normalize(cross(boatUp,boatForward));
boatForward = normalize(boatForward);
boatPosition += .0*boatUp;
}
vec3 BoatToWorld( vec3 dir )
{
return dir.x*boatRight+dir.x*boatUp+dir.x*boatForward;
}
vec3 WorldToBoat( vec3 dir )
{
return vec3( dot(dir,boatRight), dot(dir,boatUp), dot(dir,boatForward) );
}
float TraceBoat( vec3 pos, vec3 ray )
{
vec3 c = boatPosition;
float r = 1.0;
c -= pos;
float t = dot(c,ray);
float p = length(c-t*ray);
if ( p > r )
return 0.0;
return t-sqrt(r*r-p*p);
}
vec3 ShadeBoat( vec3 pos, vec3 ray )
{
pos -= boatPosition;
vec3 norm = normalize(pos);
pos = WorldToBoat(pos);
vec3 lightDir = normalize(vec3(-2,3,1));
float ndotl = dot(norm,lightDir);
// allow some light bleed, as if it's subsurface scattering through plastic
vec3 light = smoothstep(-.1,1.0,ndotl)*vec3(1.0,.9,.8)+vec3(.06,.1,.1);
// anti-alias the albedo
float aa = 4.0/iResolution.x;
//vec3 albedo = ((fract(pos.x)-.5)*(fract(pos.y)-.5)*(fract(pos.z)-.5) < 0.0) ? vec3(0) : vec3(1);
vec3 albedo = vec3(1,.01,0);
albedo = mix( vec3(.04), albedo, smoothstep( .25-aa, .25, abs(pos.y) ) );
albedo = mix( mix( vec3(1), vec3(.04), smoothstep(-aa*4.0,aa*4.0,cos(atan(pos.x,pos.z)*6.0)) ), albedo, smoothstep( .2-aa*1.5, .2, abs(pos.y) ) );
albedo = mix( vec3(.04), albedo, smoothstep( .05-aa*1.0, .05, abs(abs(pos.y)-.6) ) );
albedo = mix( vec3(1,.8,.08), albedo, smoothstep( .05-aa*1.0, .05, abs(abs(pos.y)-.65) ) );
vec3 col = albedo*light;
// specular
vec3 h = normalize(lightDir-ray);
float s = pow(max(0.0,dot(norm,h)),100.0)*100.0/32.0;
vec3 specular = s*vec3(1,1,1);
vec3 rr = reflect(ray,norm);
specular += mix( vec3(0,.04,.04), Sky(rr), smoothstep( -.1, .1, rr.y ) );
float ndotr = dot(norm,ray);
float fresnel = pow(1.0-abs(ndotr),5.0);
fresnel = mix( .001, 1.0, fresnel );
col = mix( col, specular, fresnel );
return col;
}
float OceanDistanceField( vec3 pos )
{
return pos.y - Waves(pos);
}
float OceanDistanceFieldDetail( vec3 pos )
{
return pos.y - WavesDetail(pos);
}
vec3 OceanNormal( vec3 pos )
{
vec3 norm;
vec2 d = vec2(.01*length(pos),0);
norm.x = OceanDistanceFieldDetail( pos+d.xyy )-OceanDistanceFieldDetail( pos-d.xyy );
norm.y = OceanDistanceFieldDetail( pos+d.yxy )-OceanDistanceFieldDetail( pos-d.yxy );
norm.z = OceanDistanceFieldDetail( pos+d.yyx )-OceanDistanceFieldDetail( pos-d.yyx );
return normalize(norm);
}
float TraceOcean( vec3 pos, vec3 ray )
{
float h = 1.0;
float t = 0.0;
for ( int i=0; i < 100; i++ )
{
if ( h < .01 || t > 100.0 )
break;
h = OceanDistanceField( pos+t*ray );
t += h;
}
if ( h > .1 )
return 0.0;
return t;
}
vec3 ShadeOcean( vec3 pos, vec3 ray, in vec2 fragCoord )
{
vec3 norm = OceanNormal(pos);
float ndotr = dot(ray,norm);
float fresnel = pow(1.0-abs(ndotr),5.0);
vec3 reflectedRay = ray-2.0*norm*ndotr;
vec3 refractedRay = ray+(-cos(1.33*acos(-ndotr))-ndotr)*norm;
refractedRay = normalize(refractedRay);
const float crackFudge = .0;
// reflection
vec3 reflection = Sky(reflectedRay);
float t=TraceBoat( pos-crackFudge*reflectedRay, reflectedRay );
if ( t > 0.0 )
{
reflection = ShadeBoat( pos+(t-crackFudge)*reflectedRay, reflectedRay );
}
// refraction
t=TraceBoat( pos-crackFudge*refractedRay, refractedRay );
vec3 col = vec3(0,.04,.04); // under-sea colour
if ( t > 0.0 )
{
col = mix( col, ShadeBoat( pos+(t-crackFudge)*refractedRay, refractedRay ), exp(-t) );
}
col = mix( col, reflection, fresnel );
// foam
col = mix( col, vec3(1), WaveCrests(pos,fragCoord) );
return col;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
ComputeBoatTransform();
vec2 camRot = vec2(.5,.5)+vec2(-.35,4.5)*(iMouse.yx/iResolution.yx);
vec3 pos, ray;
CamPolar( pos, ray, vec3(0), camRot, 3.0, 1.0, fragCoord );
float to = TraceOcean( pos, ray );
float tb = TraceBoat( pos, ray );
vec3 result;
if ( to > 0.0 && ( to < tb || tb == 0.0 ) )
result = ShadeOcean( pos+ray*to, ray, fragCoord );
else if ( tb > 0.0 )
result = ShadeBoat( pos+ray*tb, ray );
else
result = Sky( ray );
// vignette effect
result *= 1.1*smoothstep( .35, 1.0, localRay.z );
fragColor = vec4(ToGamma(result),1.0);
}

View File

@ -0,0 +1,954 @@
// river.jpg
// Where the River Goes
// @P_Malin
// What started as a hacked flow and advection experiment turned into something nice.
// Placeholder audio https://www.youtube.com/watch?v=gmar4gh5nIw suggested by @qthund on twitter
//#define ENABLE_ULTRA_QUALITY
#define ENABLE_WATER
#define ENABLE_FOAM
#define ENABLE_WATER_RECEIVE_SHADOW
#define ENABLE_CONE_STEPPING
// Textureless version
//#define ENABLE_NIMITZ_TRIANGLE_NOISE
//#define ENABLE_LANDSCAPE_RECEIVE_SHADOW
//#define ENABLE_SCREENSHOT_MODE
const float k_screenshotTime = 13.0;
#if defined(ENABLE_SCREENSHOT_MODE) || defined(ENABLE_ULTRA_QUALITY)
#define ENABLE_SUPERSAMPLE_MODE
#endif
#ifndef ENABLE_SCREENSHOT_MODE
#ifdef ENABLE_ULTRA_QUALITY
const int k_raymarchSteps = 96;
const int k_fmbSteps = 6;
const int k_superSampleCount = 6;
#else
const int k_raymarchSteps = 64;
const int k_fmbSteps = 3;
#endif
#else
const int k_raymarchSteps = 96;
const int k_fmbSteps = 5;
const int k_superSampleCount = 10;
#endif
const int k_fmbWaterSteps = 4;
#define OBJ_ID_SKY 0.0
#define OBJ_ID_GROUND 1.0
float g_fTime;
const vec3 g_vSunDir = vec3( -1.0, 0.7, 0.25 );
vec3 GetSunDir() { return normalize( g_vSunDir ); }
const vec3 g_sunColour = vec3( 1.0, 0.85, 0.5 ) * 5.0;
const vec3 g_skyColour = vec3( 0.1, 0.5, 1.0 ) * 1.0;
const vec3 k_bgSkyColourUp = g_skyColour * 4.0;
const vec3 k_bgSkyColourDown = g_skyColour * 6.0;
const vec3 k_envFloorColor = vec3(0.3, 0.2, 0.2);
const vec3 k_vFogExt = vec3(0.01, 0.015, 0.015) * 3.0;
const vec3 k_vFogIn = vec3(1.0, 0.9, 0.8) * 0.015;
const float k_fFarClip = 20.0;
#define MOD2 vec2(4.438975,3.972973)
float Hash( float p )
{
// https://www.shadertoy.com/view/4djSRW - Dave Hoskins
vec2 p2 = fract(vec2(p) * MOD2);
p2 += dot(p2.yx, p2.xy+19.19);
return fract(p2.x * p2.y);
//return fract(sin(n)*43758.5453);
}
float SmoothNoise(in vec2 o)
{
vec2 p = floor(o);
vec2 f = fract(o);
float n = p.x + p.y*57.0;
float a = Hash(n+ 0.0);
float b = Hash(n+ 1.0);
float c = Hash(n+ 57.0);
float d = Hash(n+ 58.0);
vec2 f2 = f * f;
vec2 f3 = f2 * f;
vec2 t = 3.0 * f2 - 2.0 * f3;
float u = t.x;
float v = t.y;
float res = a + (b-a)*u +(c-a)*v + (a-b+d-c)*u*v;
return res;
}
float FBM( vec2 p, float ps ) {
float f = 0.0;
float tot = 0.0;
float a = 1.0;
for( int i=0; i<k_fmbSteps; i++)
{
f += SmoothNoise( p ) * a;
p *= 2.0;
tot += a;
a *= ps;
}
return f / tot;
}
float FBM_Simple( vec2 p, float ps ) {
float f = 0.0;
float tot = 0.0;
float a = 1.0;
for( int i=0; i<3; i++)
{
f += SmoothNoise( p ) * a;
p *= 2.0;
tot += a;
a *= ps;
}
return f / tot;
}
vec3 SmoothNoise_DXY(in vec2 o)
{
vec2 p = floor(o);
vec2 f = fract(o);
float n = p.x + p.y*57.0;
float a = Hash(n+ 0.0);
float b = Hash(n+ 1.0);
float c = Hash(n+ 57.0);
float d = Hash(n+ 58.0);
vec2 f2 = f * f;
vec2 f3 = f2 * f;
vec2 t = 3.0 * f2 - 2.0 * f3;
vec2 dt = 6.0 * f - 6.0 * f2;
float u = t.x;
float v = t.y;
float du = dt.x;
float dv = dt.y;
float res = a + (b-a)*u +(c-a)*v + (a-b+d-c)*u*v;
float dx = (b-a)*du + (a-b+d-c)*du*v;
float dy = (c-a)*dv + (a-b+d-c)*u*dv;
return vec3(dx, dy, res);
}
vec3 FBM_DXY( vec2 p, vec2 flow, float ps, float df ) {
vec3 f = vec3(0.0);
float tot = 0.0;
float a = 1.0;
//flow *= 0.6;
for( int i=0; i<k_fmbWaterSteps; i++)
{
p += flow;
flow *= -0.75; // modify flow for each octave - negating this is fun
vec3 v = SmoothNoise_DXY( p );
f += v * a;
p += v.xy * df;
p *= 2.0;
tot += a;
a *= ps;
}
return f / tot;
}
float GetRiverMeander( const float x )
{
return sin(x * 0.3) * 1.5;
}
float GetRiverMeanderDx( const float x )
{
return cos(x * 0.3) * 1.5 * 0.3;
}
float GetRiverBedOffset( const vec3 vPos )
{
float fRiverBedDepth = 0.3 + (0.5 + 0.5 * sin( vPos.x * 0.001 + 3.0)) * 0.4;
float fRiverBedWidth = 2.0 + cos( vPos.x * 0.1 ) * 1.0;;
float fRiverBedAmount = smoothstep( fRiverBedWidth, fRiverBedWidth * 0.5, abs(vPos.z - GetRiverMeander(vPos.x)) );
return fRiverBedAmount * fRiverBedDepth;
}
float GetTerrainHeight( const vec3 vPos )
{
float fbm = FBM( vPos.xz * vec2(0.5, 1.0), 0.5 );
float fTerrainHeight = fbm * fbm;
fTerrainHeight -= GetRiverBedOffset(vPos);
return fTerrainHeight;
}
float GetTerrainHeightSimple( const vec3 vPos )
{
float fbm = FBM_Simple( vPos.xz * vec2(0.5, 1.0), 0.5 );
float fTerrainHeight = fbm * fbm;
fTerrainHeight -= GetRiverBedOffset(vPos);
return fTerrainHeight;
}
float GetSceneDistance( const vec3 vPos )
{
return vPos.y - GetTerrainHeight( vPos );
}
float GetFlowDistance( const vec2 vPos )
{
return -GetTerrainHeightSimple( vec3( vPos.x, 0.0, vPos.y ) );
}
vec2 GetBaseFlow( const vec2 vPos )
{
return vec2( 1.0, GetRiverMeanderDx(vPos.x) );
}
vec2 GetGradient( const vec2 vPos )
{
vec2 vDelta = vec2(0.01, 0.00);
float dx = GetFlowDistance( vPos + vDelta.xy ) - GetFlowDistance( vPos - vDelta.xy );
float dy = GetFlowDistance( vPos + vDelta.yx ) - GetFlowDistance( vPos - vDelta.yx );
return vec2( dx, dy );
}
vec3 GetFlowRate( const vec2 vPos )
{
vec2 vBaseFlow = GetBaseFlow( vPos );
vec2 vFlow = vBaseFlow;
float fFoam = 0.0;
float fDepth = -GetTerrainHeightSimple( vec3(vPos.x, 0.0, vPos.y) );
float fDist = GetFlowDistance( vPos );
vec2 vGradient = GetGradient( vPos );
vFlow += -vGradient * 40.0 / (1.0 + fDist * 1.5);
vFlow *= 1.0 / (1.0 + fDist * 0.5);
#if 1
float fBehindObstacle = 0.5 - dot( normalize(vGradient), -normalize(vFlow)) * 0.5;
float fSlowDist = clamp( fDepth * 5.0, 0.0, 1.0);
fSlowDist = mix(fSlowDist * 0.9 + 0.1, 1.0, fBehindObstacle * 0.9);
//vFlow += vGradient * 10.0 * (1.0 - fSlowDist);
fSlowDist = 0.5 + fSlowDist * 0.5;
vFlow *= fSlowDist;
#endif
float fFoamScale1 =0.5;
float fFoamCutoff = 0.4;
float fFoamScale2 = 0.35;
fFoam = abs(length( vFlow )) * fFoamScale1;// - length( vBaseFlow ));
fFoam += clamp( fFoam - fFoamCutoff, 0.0, 1.0 );
//fFoam = fFoam* fFoam;
fFoam = 1.0 - pow( fDist, fFoam * fFoamScale2 );
//fFoam = fFoam / fDist;
return vec3( vFlow * 0.6, fFoam );
}
vec4 SampleWaterNormal( vec2 vUV, vec2 vFlowOffset, float fMag, float fFoam )
{
vec2 vFilterWidth = max(abs(dFdx(vUV)), abs(dFdy(vUV)));
float fFilterWidth= max(vFilterWidth.x, vFilterWidth.y);
float fScale = (1.0 / (1.0 + fFilterWidth * fFilterWidth * 2000.0));
float fGradientAscent = 0.25 + (fFoam * -1.5);
vec3 dxy = FBM_DXY(vUV * 20.0, vFlowOffset * 20.0, 0.75 + fFoam * 0.25, fGradientAscent);
fScale *= max(0.25, 1.0 - fFoam * 5.0); // flatten normal in foam
vec3 vBlended = mix( vec3(0.0, 1.0, 0.0), normalize( vec3(dxy.x, fMag, dxy.y) ), fScale );
return vec4( normalize( vBlended ), dxy.z * fScale );
}
float SampleWaterFoam( vec2 vUV, vec2 vFlowOffset, float fFoam )
{
float f = FBM_DXY(vUV * 30.0, vFlowOffset * 50.0, 0.8, -0.5 ).z;
float fAmount = 0.2;
f = max( 0.0, (f - fAmount) / fAmount );
return pow( 0.5, f );
}
vec4 SampleFlowingNormal( const vec2 vUV, const vec2 vFlowRate, const float fFoam, const float time, out float fOutFoamTex )
{
float fMag = 2.5 / (1.0 + dot( vFlowRate, vFlowRate ) * 5.0);
float t0 = fract( time );
float t1 = fract( time + 0.5 );
float o0 = t0 - 0.5;
float o1 = t1 - 0.5;
vec4 sample0 = SampleWaterNormal( vUV, vFlowRate * o0, fMag, fFoam );
vec4 sample1 = SampleWaterNormal( vUV, vFlowRate * o1, fMag, fFoam );
float weight = abs( t0 - 0.5 ) * 2.0;
//weight = smoothstep( 0.0, 1.0, weight );
float foam0 = SampleWaterFoam( vUV, vFlowRate * o0 * 0.25, fFoam );
float foam1 = SampleWaterFoam( vUV, vFlowRate * o1 * 0.25, fFoam );
vec4 result= mix( sample0, sample1, weight );
result.xyz = normalize(result.xyz);
fOutFoamTex = mix( foam0, foam1, weight );
return result;
}
vec2 GetWindowCoord( const in vec2 vUV )
{
vec2 vWindow = vUV * 2.0 - 1.0;
vWindow.x *= iResolution.x / iResolution.y;
return vWindow;
}
vec3 GetCameraRayDir( const in vec2 vWindow, const in vec3 vCameraPos, const in vec3 vCameraTarget )
{
vec3 vForward = normalize(vCameraTarget - vCameraPos);
vec3 vRight = normalize(cross(vec3(0.0, 1.0, 0.0), vForward));
vec3 vUp = normalize(cross(vForward, vRight));
vec3 vDir = normalize(vWindow.x * vRight + vWindow.y * vUp + vForward * 2.0);
return vDir;
}
vec3 ApplyVignetting( const in vec2 vUV, const in vec3 vInput )
{
vec2 vOffset = (vUV - 0.5) * sqrt(2.0);
float fDist = dot(vOffset, vOffset);
const float kStrength = 0.8;
float fShade = mix( 1.0, 1.0 - kStrength, fDist );
return vInput * fShade;
}
vec3 Tonemap( vec3 x )
{
float a = 0.010;
float b = 0.132;
float c = 0.010;
float d = 0.163;
float e = 0.101;
return ( x * ( a * x + b ) ) / ( x * ( c * x + d ) + e );
}
struct Intersection
{
float m_dist;
float m_objId;
vec3 m_pos;
};
void RaymarchScene( vec3 vRayOrigin, vec3 vRayDir, out Intersection intersection )
{
float stepScale = 1.0;
#ifdef ENABLE_CONE_STEPPING
vec2 vRayProfile = vec2( sqrt(dot(vRayDir.xz, vRayDir.xz) ), vRayDir.y );
vec2 vGradVec = normalize( vec2( 1.0, 2.0 ) ); // represents the biggest gradient in our heightfield
vec2 vGradPerp = vec2( vGradVec.y, -vGradVec.x );
float fRdotG = dot( vRayProfile, vGradPerp );
float fOdotG = dot( vec2(0.0, 1.0), vGradPerp );
stepScale = -fOdotG / fRdotG;
if ( stepScale < 0.0 )
{
intersection.m_objId = OBJ_ID_SKY;
intersection.m_dist = k_fFarClip;
return;
}
#endif
intersection.m_dist = 0.01;
intersection.m_objId = OBJ_ID_SKY;
float fSceneDist = 0.0;
float oldT = 0.01;
for( int iter = 0; iter < k_raymarchSteps; iter++ )
{
vec3 vPos = vRayOrigin + vRayDir * intersection.m_dist;
// into sky - early out
if ( vRayDir.y > 0.0 )
{
if( vPos.y > 1.0 )
{
intersection.m_objId = OBJ_ID_SKY;
intersection.m_dist = k_fFarClip;
break;
}
}
fSceneDist = GetSceneDistance( vPos );
oldT = intersection.m_dist;
intersection.m_dist += fSceneDist * stepScale;
intersection.m_objId = OBJ_ID_GROUND;
if ( fSceneDist <= 0.01 )
{
break;
}
if ( intersection.m_dist > k_fFarClip )
{
intersection.m_objId = OBJ_ID_SKY;
intersection.m_dist = k_fFarClip;
break;
}
}
intersection.m_pos = vRayOrigin + vRayDir * intersection.m_dist;
}
vec3 GetSceneNormal(const in vec3 vPos)
{
const float fDelta = 0.001;
vec3 vDir1 = vec3( 1.0, 0.0, -1.0);
vec3 vDir2 = vec3(-1.0, 0.0, 1.0);
vec3 vDir3 = vec3(-1.0, 0.0, -1.0);
vec3 vOffset1 = vDir1 * fDelta;
vec3 vOffset2 = vDir2 * fDelta;
vec3 vOffset3 = vDir3 * fDelta;
vec3 vPos1 = vPos + vOffset1;
vec3 vPos2 = vPos + vOffset2;
vec3 vPos3 = vPos + vOffset3;
float f1 = GetSceneDistance( vPos1 );
float f2 = GetSceneDistance( vPos2 );
float f3 = GetSceneDistance( vPos3 );
vPos1.y -= f1;
vPos2.y -= f2;
vPos3.y -= f3;
vec3 vNormal = cross( vPos1 - vPos2, vPos3 - vPos2 );
return normalize( vNormal );
}
void TraceWater( vec3 vRayOrigin, vec3 vRayDir, out Intersection intersection )
{
intersection.m_dist = k_fFarClip;
float t = -vRayOrigin.y / vRayDir.y;
if ( t > 0.0 )
{
intersection.m_dist = t;
}
intersection.m_pos = vRayOrigin + vRayDir * intersection.m_dist;
}
struct Surface
{
vec3 m_pos;
vec3 m_normal;
vec3 m_albedo;
vec3 m_specR0;
float m_gloss;
float m_specScale;
};
#ifdef ENABLE_NIMITZ_TRIANGLE_NOISE
// https://www.shadertoy.com/view/4ts3z2
float tri(in float x){return abs(fract(x)-.5);}
vec3 tri3(in vec3 p){return vec3( tri(p.z+tri(p.y)), tri(p.z+tri(p.x)), tri(p.y+tri(p.x)));}
float triNoise(in vec3 p)
{
float z=1.4;
float rz = 0.;
vec3 bp = p;
for (float i=0.; i<=4.; i++ )
{
vec3 dg = tri3(bp*2.);
p += dg;
bp *= 1.8;
z *= 1.5;
p *= 1.2;
rz+= (tri(p.z+tri(p.x+tri(p.y))))/z;
bp += 0.14;
}
return rz;
}
#endif
void GetSurfaceInfo( Intersection intersection, out Surface surface )
{
surface.m_pos = intersection.m_pos;
surface.m_normal = GetSceneNormal(intersection.m_pos);
#ifdef ENABLE_NIMITZ_TRIANGLE_NOISE
vec3 vNoisePos = surface.m_pos * vec3(0.4, 0.3, 1.0);
surface.m_normal = normalize(surface.m_normal +triNoise(vNoisePos));
float fNoise = triNoise(vNoisePos);
fNoise = pow( fNoise, 0.15);
surface.m_albedo = mix(vec3(.7,.8,.95), vec3(.1, .1,.05), fNoise );
#else
#if 0
surface.m_albedo = texture( iChannel0, intersection.m_pos.xz ).rgb;
surface.m_albedo = surface.m_albedo * surface.m_albedo;
#else
vec3 vWeights = surface.m_normal * surface.m_normal;
vec3 col = vec3(0.0);
vec3 _sample;
_sample = texture( iChannel0, intersection.m_pos.xz ).rgb;
col += _sample * _sample * vWeights.y;
_sample = texture( iChannel0, intersection.m_pos.xy ).rgb;
col += _sample * _sample * vWeights.z;
_sample = texture( iChannel0, intersection.m_pos.yz ).rgb;
col += _sample * _sample * vWeights.x;
col /= vWeights.x + vWeights.y + vWeights.z;
surface.m_albedo = col;
#endif
#endif
surface.m_specR0 = vec3(0.001);
surface.m_gloss = 0.0;
surface.m_specScale = 1.0;
}
float GIV( float dotNV, float k)
{
return 1.0 / ((dotNV + 0.0001) * (1.0 - k)+k);
}
float GetSunShadow( const vec3 vPos )
{
vec3 vSunDir = GetSunDir();
Intersection shadowInt;
float k_fShadowDist = 2.0;
RaymarchScene( vPos + vSunDir * k_fShadowDist, -vSunDir, shadowInt );
float fShadowFactor = 1.0;
if( shadowInt.m_dist < (k_fShadowDist - 0.1) )
{
fShadowFactor = 0.0;
}
return fShadowFactor;
}
void AddSunLight( Surface surf, const vec3 vViewDir, const float fShadowFactor, inout vec3 vDiffuse, inout vec3 vSpecular )
{
vec3 vSunDir = GetSunDir();
vec3 vH = normalize( vViewDir + vSunDir );
float fNdotL = clamp(dot(GetSunDir(), surf.m_normal), 0.0, 1.0);
float fNdotV = clamp(dot(vViewDir, surf.m_normal), 0.0, 1.0);
float fNdotH = clamp(dot(surf.m_normal, vH), 0.0, 1.0);
float diffuseIntensity = fNdotL;
vDiffuse += g_sunColour * diffuseIntensity * fShadowFactor;
//vDiffuse = fShadowFactor * vec3(100.0);
float alpha = 1.0 - surf.m_gloss;
// D
float alphaSqr = alpha * alpha;
float pi = 3.14159;
float denom = fNdotH * fNdotH * (alphaSqr - 1.0) + 1.0;
float d = alphaSqr / (pi * denom * denom);
float k = alpha / 2.0;
float vis = GIV(fNdotL, k) * GIV(fNdotV, k);
float fSpecularIntensity = d * vis * fNdotL;
vSpecular += g_sunColour * fSpecularIntensity * fShadowFactor;
}
void AddSkyLight( Surface surf, inout vec3 vDiffuse, inout vec3 vSpecular )
{
float skyIntensity = max( 0.0, surf.m_normal.y * 0.3 + 0.7 );
vDiffuse += g_skyColour * skyIntensity;
}
vec3 GetFresnel( vec3 vView, vec3 vNormal, vec3 vR0, float fGloss )
{
float NdotV = max( 0.0, dot( vView, vNormal ) );
return vR0 + (vec3(1.0) - vR0) * pow( 1.0 - NdotV, 5.0 ) * pow( fGloss, 20.0 );
}
vec3 GetWaterExtinction( float dist )
{
float fOpticalDepth = dist * 6.0;
vec3 vExtinctCol = 1.0 - vec3(0.5, 0.4, 0.1);
vec3 vExtinction = exp2( -fOpticalDepth * vExtinctCol );
return vExtinction;
}
vec3 GetSkyColour( vec3 vRayDir )
{
vec3 vSkyColour = mix( k_bgSkyColourDown, k_bgSkyColourUp, clamp( vRayDir.y, 0.0, 1.0 ) );
float fSunDotV = dot(GetSunDir(), vRayDir);
float fDirDot = clamp(fSunDotV * 0.5 + 0.5, 0.0, 1.0);
vSkyColour += g_sunColour * (1.0 - exp2(fDirDot * -0.5)) * 2.0;
return vSkyColour;
}
vec3 GetEnvColour( vec3 vRayDir, float fGloss )
{
return mix( k_envFloorColor, k_bgSkyColourUp, clamp( vRayDir.y * (1.0 - fGloss * 0.5) * 0.5 + 0.5, 0.0, 1.0 ) );
}
vec3 GetRayColour( const in vec3 vRayOrigin, const in vec3 vRayDir, out Intersection intersection )
{
RaymarchScene( vRayOrigin, vRayDir, intersection );
if ( intersection.m_objId == OBJ_ID_SKY )
{
return GetSkyColour( vRayDir );
}
Surface surface;
GetSurfaceInfo( intersection, surface );
vec3 vIgnore = vec3(0.0);
vec3 vResult = vec3(0.0);
float fSunShadow = 1.0;
AddSunLight( surface, -vRayDir, fSunShadow, vResult, vIgnore );
AddSkyLight( surface, vResult, vIgnore);
return vResult * surface.m_albedo;
}
vec3 GetRayColour( const in vec3 vRayOrigin, const in vec3 vRayDir )
{
Intersection intersection;
return GetRayColour( vRayOrigin, vRayDir, intersection );
}
vec3 GetSceneColour( const in vec3 vRayOrigin, const in vec3 vRayDir )
{
Intersection primaryInt;
RaymarchScene( vRayOrigin, vRayDir, primaryInt );
float fFogDistance = 0.0;
vec3 vResult = vec3( 0.0 );
float fSunDotV = dot(GetSunDir(), vRayDir);
if ( primaryInt.m_objId == OBJ_ID_SKY )
{
vResult = GetSkyColour( vRayDir );
fFogDistance = k_fFarClip;
}
else
{
Intersection waterInt;
TraceWater( vRayOrigin, vRayDir, waterInt );
vec3 vReflectRayOrigin;
vec3 vSpecNormal;
vec3 vTransmitLight;
Surface specSurface;
vec3 vSpecularLight = vec3(0.0);
#ifdef ENABLE_WATER
vec3 vFlowRateAndFoam = GetFlowRate( waterInt.m_pos.xz );
vec2 vFlowRate = vFlowRateAndFoam.xy;
#ifdef ENABLE_FOAM
float fFoam = vFlowRateAndFoam.z;
float fFoamScale = 1.5;
float fFoamOffset = 0.2;
fFoam = clamp( (fFoam - fFoamOffset) * fFoamScale, 0.0, 1.0 );
fFoam = fFoam * fFoam * 0.5;
#else
float fFoam = 0.0;
#endif
float fWaterFoamTex = 1.0;
vec4 vWaterNormalAndHeight = SampleFlowingNormal( waterInt.m_pos.xz, vFlowRate, fFoam, g_fTime, fWaterFoamTex );
if( vRayDir.y < -0.01 )
{
// lie about the water intersection depth
waterInt.m_dist -= (0.04 * (1.0 - vWaterNormalAndHeight.w) / vRayDir.y);
}
if( waterInt.m_dist < primaryInt.m_dist )
{
fFogDistance = waterInt.m_dist;
vec3 vWaterNormal = vWaterNormalAndHeight.xyz;
vReflectRayOrigin = waterInt.m_pos;
vSpecNormal = vWaterNormal;
vec3 vRefractRayOrigin = waterInt.m_pos;
vec3 vRefractRayDir = refract( vRayDir, vWaterNormal, 1.0 / 1.3333 );
Intersection refractInt;
vec3 vRefractLight = GetRayColour( vRefractRayOrigin, vRefractRayDir, refractInt ); // note : dont need sky
float fEdgeAlpha = clamp( (1.0 + vWaterNormalAndHeight.w * 0.25) - refractInt.m_dist * 10.0, 0.0, 1.0 );
fFoam *= 1.0 - fEdgeAlpha;
// add extra extinction for the light travelling to the point underwater
vec3 vExtinction = GetWaterExtinction( refractInt.m_dist + abs( refractInt.m_pos.y ) );
specSurface.m_pos = waterInt.m_pos;
specSurface.m_normal = normalize( vWaterNormal + GetSunDir() * fFoam ); // would rather have SSS for foam
specSurface.m_albedo = vec3(1.0);
specSurface.m_specR0 = vec3( 0.01, 0.01, 0.01 );
vec2 vFilterWidth = max(abs(dFdx(waterInt.m_pos.xz)), abs(dFdy(waterInt.m_pos.xz)));
float fFilterWidth= max(vFilterWidth.x, vFilterWidth.y);
float fGlossFactor = exp2( -fFilterWidth * 0.3 );
specSurface.m_gloss = 0.99 * fGlossFactor;
specSurface.m_specScale = 1.0;
vec3 vSurfaceDiffuse = vec3(0.0);
float fSunShadow = 1.0;
#ifdef ENABLE_WATER_RECEIVE_SHADOW
fSunShadow = GetSunShadow( waterInt.m_pos );
#endif
AddSunLight( specSurface, -vRayDir, fSunShadow, vSurfaceDiffuse, vSpecularLight);
AddSkyLight( specSurface, vSurfaceDiffuse, vSpecularLight);
vec3 vInscatter = vSurfaceDiffuse * (1.0 - exp( -refractInt.m_dist * 0.1 )) * (1.0 + fSunDotV);
vTransmitLight = vRefractLight.rgb;
vTransmitLight += vInscatter;
vTransmitLight *= vExtinction;
#ifdef ENABLE_FOAM
float fFoamBlend = 1.0 - pow( fWaterFoamTex, fFoam * 5.0);// * (1.0 - fWaterFoamTex));
vTransmitLight = mix(vTransmitLight, vSurfaceDiffuse * 0.8, fFoamBlend );
specSurface.m_specScale = clamp(1.0 - fFoamBlend * 4.0, 0.0, 1.0);
#endif
}
else
#endif // #ifdef ENABLE_WATER
{
fFogDistance = primaryInt.m_dist;
Surface primarySurface;
GetSurfaceInfo( primaryInt, primarySurface );
vSpecNormal = primarySurface.m_normal;
vReflectRayOrigin = primaryInt.m_pos;
float fWetness = 1.0 - clamp( (vReflectRayOrigin.y + 0.025) * 5.0, 0.0, 1.0);
primarySurface.m_gloss = mix( primarySurface.m_albedo.r, 1.0, fWetness );
primarySurface.m_albedo = mix( primarySurface.m_albedo, primarySurface.m_albedo * 0.8, fWetness );
vTransmitLight = vec3(0.0);
float fSunShadow = 1.0;
#ifdef ENABLE_LANDSCAPE_RECEIVE_SHADOW
fSunShadow = GetSunShadow( primaryInt.m_pos );
#endif
AddSunLight( primarySurface, -vRayDir, fSunShadow, vTransmitLight, vSpecularLight);
AddSkyLight( primarySurface, vTransmitLight, vSpecularLight);
vTransmitLight *= primarySurface.m_albedo;
specSurface = primarySurface;
}
vec3 vReflectRayDir = reflect( vRayDir, vSpecNormal );
vec3 vReflectLight = GetRayColour( vReflectRayOrigin, vReflectRayDir );
vReflectLight = mix( GetEnvColour(vReflectRayDir, specSurface.m_gloss), vReflectLight, pow( specSurface.m_gloss, 40.0) );
vec3 vFresnel = GetFresnel( -vRayDir, vSpecNormal, specSurface.m_specR0, specSurface.m_gloss );
vSpecularLight += vReflectLight;
vResult = mix(vTransmitLight, vSpecularLight, vFresnel * specSurface.m_specScale );
}
if ( fFogDistance >= k_fFarClip )
{
fFogDistance = 100.0;
vResult = smoothstep( 0.9995, 0.9999, fSunDotV ) * g_sunColour * 200.0;
}
vec3 vFogColour = GetSkyColour(vRayDir);
vec3 vFogExtCol = exp2( k_vFogExt * -fFogDistance );
vec3 vFogInCol = exp2( k_vFogIn * -fFogDistance );
vResult = vResult*(vFogExtCol) + vFogColour*(1.0-vFogInCol);
return vResult;
}
// Code from https://www.shadertoy.com/view/ltlSWf
void BlockRender(in vec2 fragCoord)
{
const float blockRate = 15.0;
const float blockSize = 64.0;
float frame = floor(iGlobalTime * blockRate);
vec2 blockRes = floor(iResolution.xy / blockSize) + vec2(1.0);
float blockX = fract(frame / blockRes.x) * blockRes.x;
float blockY = fract(floor(frame / blockRes.x) / blockRes.y) * blockRes.y;
// Don't draw anything outside the current block.
if ((fragCoord.x - blockX * blockSize >= blockSize) ||
(fragCoord.x - (blockX - 1.0) * blockSize < blockSize) ||
(fragCoord.y - blockY * blockSize >= blockSize) ||
(fragCoord.y - (blockY - 1.0) * blockSize < blockSize))
{
discard;
}
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
g_fTime = iGlobalTime;
#ifdef ENABLE_SCREENSHOT_MODE
BlockRender( fragCoord.xy );
float fBaseTime = k_screenshotTime;
#else
float fBaseTime = iGlobalTime;
#endif
g_fTime = fBaseTime;
float fCameraTime = g_fTime;
// Static camera locations
//fCameraTime = 146.0; // some rocks
vec2 vUV = fragCoord.xy / iResolution.xy;
vec3 vCameraTarget = vec3(0.0, -0.5, 0.0);
vCameraTarget.x -= fCameraTime * 0.5;
vec3 vCameraPos = vCameraTarget + vec3(0.0, 0.0, 0.0);
float fHeading = fCameraTime * 0.1;
float fDist = 1.5 - cos(fCameraTime * 0.1 + 2.0) * 0.8;
if( iMouse.z > 0.0 )
{
fHeading = iMouse.x * 10.0 / iResolution.x;
fDist = 5.0 - iMouse.y * 5.0 / iResolution.y;
}
vCameraPos.y += 1.0 + fDist * fDist * 0.01;
vCameraPos.x += sin( fHeading ) * fDist;
vCameraPos.z += cos( fHeading ) * fDist;
vCameraTarget.z += GetRiverMeander( vCameraTarget.x );
vCameraPos.z += GetRiverMeander( vCameraPos.x );
vCameraPos.y = max( vCameraPos.y, GetTerrainHeightSimple( vCameraPos ) + 0.2 );
vec3 vRayOrigin = vCameraPos;
vec3 vRayDir = GetCameraRayDir( GetWindowCoord(vUV), vCameraPos, vCameraTarget );
#ifndef ENABLE_SUPERSAMPLE_MODE
vec3 vResult = GetSceneColour(vRayOrigin, vRayDir);
#else
vec3 vResult = vec3(0.0);
float fTot = 0.0;
for(int i=0; i<k_superSampleCount; i++)
{
g_fTime = fBaseTime + (fTot / 10.0) / 30.0;
vec3 vCurrRayDir = vRayDir;
vec3 vRandom = vec3( SmoothNoise( fragCoord.xy + fTot ),
SmoothNoise( fragCoord.yx + fTot + 42.0 ),
SmoothNoise( fragCoord.xx + fragCoord.yy + fTot + 42.0 ) ) * 2.0 - 1.0;
vRandom = normalize( vRandom );
vCurrRayDir += vRandom * 0.001;
vCurrRayDir = normalize(vCurrRayDir);
vResult += GetSceneColour(vRayOrigin, vCurrRayDir);
fTot += 1.0;
}
vResult /= fTot;
#endif
vResult = ApplyVignetting( vUV, vResult );
vec3 vFinal = Tonemap(vResult * 3.0);
vFinal = vFinal * 1.1 - 0.1;
fragColor = vec4(vFinal, 1.0);
}
void mainVR( out vec4 fragColor, in vec2 fragCoord, in vec3 fragRayOri, in vec3 fragRayDir )
{
g_fTime = iGlobalTime;
fragRayOri = fragRayOri.zyx;
fragRayDir = fragRayDir.zyx;
fragRayOri.z *= -1.0;
fragRayDir.z *= -1.0;
fragRayOri *= 0.1;
fragRayOri.y += 0.2;
fragRayOri.x -= g_fTime * 0.1;
fragRayOri.z += GetRiverMeander( fragRayOri.x );
vec3 vResult = GetSceneColour(fragRayOri, fragRayDir);
vec3 vFinal = Tonemap(vResult * 3.0);
vFinal = vFinal * 1.1 - 0.1;
fragColor = vec4(vFinal, 1.0);
}

View File

@ -0,0 +1,105 @@
//noise3.jpg
//Magnetismic by nimitz (twitter: @stormoid)
//Getting 60fps here at high quality
#define HIGH_QUALITY
#ifdef HIGH_QUALITY
#define STEPS 100
#define ALPHA_WEIGHT 0.025
#define BASE_STEP 0.05
#else
#define STEPS 50
#define ALPHA_WEIGHT 0.05
#define BASE_STEP 0.1
#endif
#define time iGlobalTime
vec2 mo;
vec2 rot(in vec2 p, in float a){float c = cos(a), s = sin(a);return p*mat2(c,s,-s,c);}
float hash21(in vec2 n){ return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453); }
float noise(in vec3 p) //iq's ubiquitous 3d noise
{
vec3 ip = floor(p), f = fract(p);
#ifdef HIGH_QUALITY
f = f*f*f*(f*(f*6. - 15.) + 10.); //Quintic smoothing
#else
f = f*f*(3.0-2.0*f); //Cubic smoothing
#endif
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);
}
float fbm(in vec3 p, in float sr)
{
p *= 3.5;
float rz = 0., z = 1.;
for(int i=0;i<4;i++)
{
float n = noise(p-time*.6);
rz += (sin(n*4.4)-.45)*z;
z *= .47;
p *= 3.5;
}
return rz;
}
vec4 map(in vec3 p)
{
float dtp = dot(p,p);
p = .5*p/(dtp + .2);
p.xz = rot(p.xz, p.y*2.5);
p.xy = rot(p.xz, p.y*2.);
float dtp2 = dot(p, p);
p = (mo.y + .6)*3.*p/(dtp2 - 5.);
float r = clamp(fbm(p, dtp*0.1)*1.5-dtp*(.35-sin(time*0.3)*0.15), 0. ,1.);
vec4 col = vec4(.5,1.7,.5,.96)*r;
float grd = clamp((dtp+.7)*0.4,0.,1.);
col.b += grd*.6;
col.r -= grd*.5;
vec3 lv = mix(p,vec3(0.3),2.);
grd = clamp((col.w - fbm(p+lv*.05,1.))*2., 0.01, 1.5 );
col.rgb *= vec3(.5, 0.4, .6)*grd + vec3(4.,0.,.4);
col.a *= clamp(dtp*2.-1.,0.,1.)*0.07+0.93;
return col;
}
vec4 vmarch(in vec3 ro, in vec3 rd)
{
vec4 rz = vec4(0);
float t = 2.5;
t += 0.03*hash21(gl_FragCoord.xy);
for(int i=0; i<STEPS; i++)
{
if(rz.a > 0.99 || t > 6.)break;
vec3 pos = ro + t*rd;
vec4 col = map(pos);
float den = col.a;
col.a *= ALPHA_WEIGHT;
col.rgb *= col.a*1.7;
rz += col*(1. - rz.a);
t += BASE_STEP - den*(BASE_STEP-BASE_STEP*0.015);
}
return rz;
}
void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
vec2 p = fragCoord.xy/iResolution.xy*2. - 1.;
p.x *= iResolution.x/iResolution.y*0.95;
mo = 2.0*iMouse.xy/iResolution.xy;
mo = (mo==vec2(.0))?mo=vec2(0.5,1.):mo;
vec3 ro = 4.*normalize(vec3(cos(2.75-2.0*(mo.x+time*0.05)), sin(time*0.22)*0.2, sin(2.75-2.0*(mo.x+time*0.05))));
vec3 eye = normalize(vec3(0) - ro);
vec3 rgt = normalize(cross(vec3(0,1,0), eye));
vec3 up = cross(eye,rgt);
vec3 rd = normalize(p.x*rgt + p.y*up + (3.3-sin(time*0.3)*.7)*eye);
vec4 col = vmarch(ro, rd);
fragColor = vec4(col.rgb, 1.0);
}

View File

@ -0,0 +1,499 @@
// https://www.shadertoy.com/view/XsBSDm
float g_cw = 15.; // char width in normalized units
float g_ch = 30.; // char height in normalized units
float g_cwb = .6; // character width buffer as a percentage of char width
float g_chb = .5; // line buffer as a percentage of char height
// vertical segment with the bottom of the segment being s
// and having length d
float vd( vec2 s, float d, vec2 uv )
{
float t = (d * (uv.y - s.y)) / (d*d);
t = clamp(t, 0., 1.);
return .1 * length((s + t * vec2(0., d)) - uv);
}
// horizontal segment with the left of the segment being s
// and having length d
float hd( vec2 s, float d, vec2 uv )
{
float t = (d * (uv.x - s.x)) / (d*d);
t = clamp(t, 0., 1.);
return .1 * length((s + t * vec2(d, 0.)) - uv);
}
// divide the experience into cells.
vec2 mod_uv(vec2 uv)
{
return vec2(mod(uv.x, g_cw * (1. + g_cwb)),
mod(uv.y, g_ch * (1. + g_chb)));
}
// ---------------------------------------------
// ALPHABET
float a(vec2 uv)
{
float r = vd(vec2(0.), g_ch * .9, uv);
r = min(r, hd(vec2(g_cw * .1, g_ch), g_cw * .8, uv));
r = min(r, vd(vec2(g_cw, 0.), g_ch * .9, uv));
r = min(r, hd(vec2(0., g_ch * .6), g_cw, uv));
return r;
}
float b(vec2 uv)
{
float r = vd(vec2(0.), g_ch, uv);
r = min(r, hd(vec2(.0, g_ch), g_cw, uv));
r = min(r, vd(vec2(g_cw, g_ch * .7), g_ch * .3, uv));
r = min(r, hd(vec2(0., g_ch * .6), g_cw * .8, uv));
r = min(r, vd(vec2(g_cw, 0.), g_ch * .5, uv));
r = min(r, hd(vec2(0.), g_cw, uv));
return r;
}
float c(vec2 uv)
{
float r = vd(vec2(0., g_ch * .1), g_ch * .8, uv);
r = min(r, hd(vec2(g_cw * .1, 0.), g_cw * .9, uv));
r = min(r, hd(vec2(g_cw * .1, g_ch), g_cw * .9, uv));
return r;
}
float d(vec2 uv)
{
float r = vd(vec2(0.), g_ch, uv);
r = min(r, vd(vec2(g_cw, g_ch * .1), g_ch * .8, uv));
r = min(r, hd(vec2(0.), g_cw * .9, uv));
r = min(r, hd(vec2(.0, g_ch), g_cw * .9, uv));
return r;
}
float e(vec2 uv)
{
float r = hd(vec2(.0, g_ch), g_cw, uv);
r = min(r, vd(vec2(0.), g_ch, uv));
r = min(r, hd(vec2(0.), g_cw, uv));
r = min(r, hd(vec2(0., g_ch * .6), g_cw * .8, uv));
return r;
}
float f(vec2 uv)
{
float r = hd(vec2(0., g_ch), g_cw, uv);
r = min(r, vd(vec2(0.), g_ch, uv));
r = min(r, hd(vec2(0., g_ch * .6), g_cw * .8, uv));
return r;
}
float g(vec2 uv)
{
float r = hd(vec2(g_cw * .1, g_ch), g_cw * .8, uv);
r = min(r, vd(vec2(0., g_ch * .1), g_ch * .8, uv));
r = min(r, hd(vec2(g_cw * .1, 0.), g_cw * .8, uv));
r = min(r, vd(vec2(g_cw, .1 * g_ch), g_ch * .4, uv));
r = min(r, hd(vec2(g_cw * .5, g_ch * .6), g_cw * .4, uv));
return r;
}
float h(vec2 uv)
{
float r = vd(vec2(0.), g_ch, uv);
r = min(r, vd(vec2(g_cw, 0.), g_ch, uv));
r = min(r, hd(vec2(.0, g_ch * .6), g_cw, uv));
return r;
}
float i(vec2 uv)
{
float r = hd(vec2(0.), g_cw, uv);
r = min(r, vd(vec2(g_cw * .5, 0.), g_ch, uv));
r = min(r, hd(vec2(0., g_ch), g_cw, uv));
return r;
}
float j(vec2 uv)
{
float r = vd(vec2(g_cw, g_ch * .1), g_ch * .9, uv);
r = min(r, hd(vec2(g_cw * .1, 0.), g_cw * .8, uv));
r = min(r, vd(vec2(0., g_ch * .1), g_ch * .2, uv));
return r;
}
float k(vec2 uv)
{
float r = vd(vec2(0.), g_ch, uv);
r = min(r, vd(vec2(g_cw, g_ch*.7), g_ch * .3, uv));
r = min(r, vd(vec2(g_cw, 0.), g_ch * .5, uv));
r = min(r, hd(vec2(0., g_ch * .6), g_cw * .8, uv));
return r;
}
float l(vec2 uv)
{
float r = vd(vec2(0.), g_ch, uv);
r = min(r, hd(vec2(0.), g_cw, uv));
return r;
}
float m(vec2 uv)
{
float r = vd(vec2(0.), g_ch, uv);
r = min(r, vd(vec2(g_cw, 0.), g_ch, uv));
r = min(r, hd(vec2(0., g_ch), g_cw * .3, uv));
r = min(r, vd(vec2(g_cw * .5, g_ch * .6), .3 * g_ch, uv));
r = min(r, hd(vec2(g_cw * .7, g_ch), g_cw * .3, uv));
return r;
}
float n(vec2 uv)
{
float r = vd(vec2(0.), g_ch, uv);
r = min(r, vd(vec2(g_cw, 0.), g_ch, uv));
r = min(r, vd(vec2(g_cw * .1, g_ch * .9), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .3, g_ch * .7), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .5, g_ch * .5), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .7, g_ch * .3), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .9, 0.), g_ch * .2, uv));
return r;
}
float o(vec2 uv)
{
float r = vd(vec2(0., g_ch * .1), g_ch * .8, uv);
r = min(r, hd(vec2(g_cw * .1, g_ch), g_cw * .8, uv));
r = min(r, vd(vec2(g_cw, g_ch * .1), g_ch * .8, uv));
r = min(r, hd(vec2(g_cw * .1, 0.), g_cw * .8, uv));
return r;
}
float p(vec2 uv)
{
float r = vd(vec2(0.), g_ch, uv);
r = min(r, hd(vec2(0., g_ch), g_cw, uv));
r = min(r, vd(vec2(g_cw, g_ch * .7), g_ch * .3, uv));
r = min(r, hd(vec2(0., g_ch * .6), g_cw * .8, uv));
return r;
}
float q(vec2 uv)
{
float r = vd(vec2(0., g_ch * .1), g_ch * .8, uv);
r = min(r, hd(vec2(g_cw * .1, g_ch), g_cw * .8, uv));
r = min(r, vd(vec2(g_cw, g_ch * .1), g_ch * .8, uv));
r = min(r, hd(vec2(g_cw * .1, 0.), g_cw * .8, uv));
r = min(r, vd(vec2(g_cw * .7, g_ch * -.05), g_cw * .4, uv));
return r;
}
float r(vec2 uv)
{
float r = vd(vec2(0.), g_ch, uv);
r = min(r, hd(vec2(.0, g_ch), g_cw, uv));
r = min(r, vd(vec2(g_cw, g_ch * .7), g_ch * .3, uv));
r = min(r, hd(vec2(0., g_ch * .6), g_cw * .8, uv));
r = min(r, vd(vec2(g_cw, 0.), g_ch * .5, uv));
return r;
}
float s(vec2 uv)
{
float r = hd(vec2(0.), g_cw * .9, uv);
r = min(r, vd(vec2(g_cw, g_ch * .1), g_ch * .4, uv));
r = min(r, hd(vec2(g_cw * .2, g_ch * .6), g_cw * .7, uv));
r = min(r, vd(vec2(0., g_ch * .7), g_ch * .2, uv));
r = min(r, hd(vec2(g_cw * .2, g_ch), g_cw * .8, uv));
return r;
}
float t(vec2 uv)
{
float r = hd(vec2(0., g_ch), g_cw, uv);
r = min(r, vd(vec2(g_cw * .5, 0.), g_ch, uv));
return r;
}
float u(vec2 uv)
{
float r = vd(vec2(0., g_ch * .1), g_ch * .9, uv);
r = min(r, hd(vec2(g_cw * .1, 0.), g_cw * .8, uv));
r = min(r, vd(vec2(g_cw, g_ch * .1), g_ch * .9, uv));
return r;
}
float v(vec2 uv)
{
float r = vd(vec2(0., g_ch * .5), g_ch * .5, uv);
r = min(r, vd(vec2(g_cw, g_ch * .5), g_ch * .5, uv));
r = min(r, vd(vec2(g_cw * .2, g_ch * .2), g_ch * .2, uv));
r = min(r, vd(vec2(g_cw * .8, g_ch * .2), g_ch * .2, uv));
r = min(r, vd(vec2(g_cw * .5, 0.), g_ch * .1, uv));
return r;
}
float w(vec2 uv)
{
float r = vd(vec2(0.), g_ch, uv);
r = min(r, vd(vec2(g_cw, 0.), g_ch, uv));
r = min(r, vd(vec2(g_cw * .5, g_ch * .1), g_ch * .3, uv));
r = min(r, hd(vec2(0.), g_cw * .3, uv));
r = min(r, hd(vec2(g_cw * .7, 0.), g_cw * .3, uv));
return r;
}
float x(vec2 uv)
{
float r = vd(vec2(0., g_ch * .9), g_ch * .1, uv);
r = min(r, vd(vec2(g_cw * .2, g_ch * .7), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .5, g_ch * .5), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .8, g_ch * .3), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw, 0.), g_ch * .2, uv));
r = min(r, vd(vec2(g_cw, g_ch * .9), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .8, g_ch * .7), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .2, g_ch * .3), g_ch * .1, uv));
r = min(r, vd(vec2(0.), g_ch * .2, uv));
return r;
}
float y(vec2 uv)
{
float r = vd(vec2(0., g_ch * .8), g_ch * .2, uv);
r = min(r, vd(vec2(g_cw * .2, g_ch * .6), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .8, g_ch * .6), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw, g_ch * .8), g_ch * .2, uv));
r = min(r, vd(vec2(g_cw * .5, 0.), g_ch * .5, uv));
return r;
}
float z(vec2 uv)
{
float r = hd(vec2(0., g_ch), g_cw, uv);
r = min(r, vd(vec2(g_cw * .9, g_ch * .9), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .7, g_ch * .7), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .5, g_ch * .5), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .3, g_ch * .3), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .1, g_ch * .1), g_ch * .1, uv));
r = min(r, hd(vec2(0.), g_cw, uv));
return r;
}
// ---------------------------------------------
// NUMBERS
float n1(vec2 uv)
{
float r = hd(vec2(g_cw * .3, g_ch), g_cw * .2, uv);
r = min(r, vd(vec2(g_cw * .5, 0.) , g_ch, uv));
return r;
}
float n2(vec2 uv)
{
float r = hd(vec2(0., g_ch), .9 * g_cw, uv);
r = min(r, vd(vec2(g_cw, g_ch*.7), g_ch * .2, uv));
r = min(r, hd(vec2(g_cw * .2, g_ch * .6), g_cw * .7, uv));
r = min(r, vd(vec2(0.), g_ch * .5, uv));
r = min(r, hd(vec2(0.), g_cw * .9, uv));
return r;
}
float n3(vec2 uv)
{
float r = hd(vec2(0., g_ch), .9 * g_cw, uv);
r = min(r, vd(vec2(g_cw, g_ch * .1), g_ch * .4, uv));
r = min(r, hd(vec2(g_cw * .2, g_ch * .6), g_cw * .7, uv));
r = min(r, vd(vec2(g_cw, g_ch * .7), g_ch * .2, uv));
r = min(r, hd(vec2(0.), g_cw * .9, uv));
return r;
}
float n4(vec2 uv)
{
float r = vd(vec2(0., g_ch * .6), g_ch * .4, uv);
r = min(r, hd(vec2(.0, g_ch * .6), g_cw, uv));
r = min(r, vd(vec2(g_cw, 0.), g_ch, uv));
return r;
}
float n5(vec2 uv)
{
float r = hd(vec2(0., g_ch), g_cw, uv);
r = min(r, vd(vec2(0., g_ch*.6), g_ch * .4, uv));
r = min(r, hd(vec2(g_cw * .1, g_ch * .6), g_cw * .8, uv));
r = min(r, vd(vec2(g_cw, g_ch * .1), g_ch * .4, uv));
r = min(r, hd(vec2(0.), g_cw * .9, uv));
return r;
}
float n6(vec2 uv)
{
float r = hd(vec2(g_cw * .1, g_ch), g_cw * .9, uv);
r = min(r, vd(vec2(0., g_ch * .1), g_ch * .8, uv));
r = min(r, hd(vec2(g_cw * .1, 0.), g_cw * .8, uv));
r = min(r, vd(vec2(g_cw, g_ch * .1), g_ch * .4, uv));
r = min(r, hd(vec2(g_cw * .2, g_ch * .6), g_cw * .7, uv));
return r;
}
float n7(vec2 uv)
{
float r = hd(vec2(0., g_ch), g_cw, uv);
r = min(r, vd(vec2(g_cw * .9, g_ch * .9), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .7, g_ch * .7), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .5, g_ch * .5), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .3, g_ch * .3), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .1, 0.), g_ch * .2, uv));
return r;
}
float n8(vec2 uv)
{
float r = hd(vec2(g_cw * .1, 0.), g_cw * .8, uv);
r = min(r, vd(vec2(g_cw, g_ch * .1), g_ch * .4, uv));
r = min(r, hd(vec2(g_cw * .2, g_ch * .6), g_cw * .7, uv));
r = min(r, vd(vec2(0., g_ch * .1), g_ch * .4, uv));
r = min(r, hd(vec2(g_cw * .1, g_ch), .8 * g_cw, uv));
r = min(r, vd(vec2(0., g_ch * .7), g_ch * .2, uv));
r = min(r, vd(vec2(g_cw, g_ch * .7), g_ch * .2, uv));
return r;
}
float n9(vec2 uv)
{
float r = hd(vec2(g_cw * .1, 0.), g_cw * .8, uv);
r = min(r, vd(vec2(g_cw, g_ch * .1), g_ch * .8, uv));
r = min(r, hd(vec2(g_cw * .2, g_ch * .6), g_cw * .6, uv));
r = min(r, hd(vec2(g_cw * .1, g_ch), g_cw * .8, uv));
r = min(r, vd(vec2(0., g_ch * .7), g_ch * .2, uv));
return r;
}
float n0(vec2 uv)
{
float r = vd(vec2(0., g_ch * .1), g_ch * .8, uv);
r = min(r, hd(vec2(g_cw * .1, g_ch), g_cw * .8, uv));
r = min(r, vd(vec2(g_cw, g_ch * .1), g_ch * .8, uv));
r = min(r, hd(vec2(g_cw * .1, 0.), g_cw * .8, uv));
r = min(r, vd(vec2(g_cw * .9, g_ch * .9), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .7, g_ch * .7), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .5, g_ch * .5), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .3, g_ch * .3), g_ch * .1, uv));
r = min(r, vd(vec2(g_cw * .1, g_ch * .1), g_ch * .1, uv));
return r;
}
// ---------------------------------------------
// SPECIAL CHARACTERS
float pe(vec2 uv) // period
{
float r = vd(vec2(0.), g_ch * .02, uv);
return r;
}
// ---------------------------------------------
// MACROS
#define A if (cs == idx) { tx = min(tx, a(uv)); } idx++;
#define B if (cs == idx) { tx = min(tx, b(uv)); } idx++;
#define C if (cs == idx) { tx = min(tx, c(uv)); } idx++;
#define D if (cs == idx) { tx = min(tx, d(uv)); } idx++;
#define E if (cs == idx) { tx = min(tx, e(uv)); } idx++;
#define F if (cs == idx) { tx = min(tx, f(uv)); } idx++;
#define G if (cs == idx) { tx = min(tx, g(uv)); } idx++;
#define H if (cs == idx) { tx = min(tx, h(uv)); } idx++;
#define I if (cs == idx) { tx = min(tx, i(uv)); } idx++;
#define J if (cs == idx) { tx = min(tx, j(uv)); } idx++;
#define K if (cs == idx) { tx = min(tx, k(uv)); } idx++;
#define L if (cs == idx) { tx = min(tx, l(uv)); } idx++;
#define M if (cs == idx) { tx = min(tx, m(uv)); } idx++;
#define N if (cs == idx) { tx = min(tx, n(uv)); } idx++;
#define O if (cs == idx) { tx = min(tx, o(uv)); } idx++;
#define P if (cs == idx) { tx = min(tx, p(uv)); } idx++;
#define Q if (cs == idx) { tx = min(tx, q(uv)); } idx++;
#define R if (cs == idx) { tx = min(tx, r(uv)); } idx++;
#define S if (cs == idx) { tx = min(tx, s(uv)); } idx++;
#define T if (cs == idx) { tx = min(tx, t(uv)); } idx++;
#define U if (cs == idx) { tx = min(tx, u(uv)); } idx++;
#define V if (cs == idx) { tx = min(tx, v(uv)); } idx++;
#define W if (cs == idx) { tx = min(tx, w(uv)); } idx++;
#define X if (cs == idx) { tx = min(tx, x(uv)); } idx++;
#define Y if (cs == idx) { tx = min(tx, y(uv)); } idx++;
#define Z if (cs == idx) { tx = min(tx, z(uv)); } idx++;
#define N1 if (cs == idx) { tx = min(tx, n1(uv)); } idx++;
#define N2 if (cs == idx) { tx = min(tx, n2(uv)); } idx++;
#define N3 if (cs == idx) { tx = min(tx, n3(uv)); } idx++;
#define N4 if (cs == idx) { tx = min(tx, n4(uv)); } idx++;
#define N5 if (cs == idx) { tx = min(tx, n5(uv)); } idx++;
#define N6 if (cs == idx) { tx = min(tx, n6(uv)); } idx++;
#define N7 if (cs == idx) { tx = min(tx, n7(uv)); } idx++;
#define N8 if (cs == idx) { tx = min(tx, n8(uv)); } idx++;
#define N9 if (cs == idx) { tx = min(tx, n9(uv)); } idx++;
#define N0 if (cs == idx) { tx = min(tx, n0(uv)); } idx++;
#define PE if (cs == idx) { tx = min(tx, pe(uv)); } idx++;
#define SP idx++;
#define NL idx+=int(cc - mod(float(idx), cc));
// ---------------------------------------------
// Periodic saw tooth function that repeats with a period of
// 4 and ranges from [-1, 1].
// The function starts out at 0 for x=0,
// raises to 1 for x=1,
// drops to 0 for x=2,
// continues to -1 for x=3,
// and then rises back to 0 for x=4
// to complete the period
float sawtooth( float x )
{
float xmod = mod(x+3.0, 4.);
return abs(xmod-2.0) - 1.;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
float display_width = 1010.;
float cc = floor(display_width / (g_cw * (1. + g_cwb))); // character count per line
vec2 uv = (fragCoord.xy) / iResolution.xx;
uv.y = iResolution.y/iResolution.x - uv.y; // type from top to bottom, left to right
uv *= display_width;
int cs = int(floor(uv.x / (g_cw * (1. + g_cwb))) + cc * floor(uv.y/(g_ch * (1. + g_chb))));
uv = mod_uv(uv);
uv.y = g_ch * (1. + g_chb) - uv.y; // paint the character from the bottom left corner
vec3 ccol = .35 * vec3(.1, .3, .2) * max(smoothstep(3., 0., uv.x), smoothstep(5., 0., uv.y));
uv -= vec2(g_cw * g_cwb * .5, g_ch * g_chb * .5);
float tx = 10000.;
int idx = 0;
//A B C D E F G H I J K L M N O P Q R S T U V W X Y Z N1 N2 N3 N4 N5 N6 N7 N8 N9 N0 PE NL
NL
NL
SP I N SP T H E SP N O T SP T O O SP D I S T A N T SP F U T U R E NL
SP W A Y SP D O W N SP I N SP D E E P SP N1 N3 NL
SP D R PE SP F O R R E S T E R SP A N D SP T V S SP F R A N K NL
SP W E R E SP H A T C H I N G SP A N SP E V I L SP S C H E M E PE NL
SP T H E Y SP H I R E D SP A SP T E M P SP B Y SP T H E SP N A M E SP O F SP M I K E NL
SP J U S T SP A SP R E G U L A R SP J O E SP T H E Y SP D I D N T SP L I K E PE NL
SP T H E I R SP E X P E R I M E N T SP N E E D E D SP A SP G O O D SP T E S T SP C A S E NL
SP S O SP T H E Y SP C O N K E D SP H I M SP O N SP T H E SP N O G G I N NL
SP A N D SP T H E Y SP S H O T SP H I M SP I N T O SP S P A C E SP PE PE PE
float throb = .4 + .2 * (.5 * sin(4. * iGlobalTime - .05 * float(cs)) + .5);
vec3 tcol = vec3(.7, 1., .8) * smoothstep(.2, .0, tx);
vec3 tglow = vec3(.7, 1., .8) * (.3 * throb + .7 * mix(.6, 1., throb) * smoothstep(throb, .1, tx));
vec3 terminal_color = ccol + tcol + tglow;
vec3 simple_color = vec3(max(0., 1. - tx));
float trans = smoothstep(-.1, .1, sawtooth(.3 * iGlobalTime - 1.));
fragColor = vec4(mix(terminal_color, simple_color, trans), 1.0);
}

View File

@ -0,0 +1,161 @@
#define NUM_LIGHTS 6
#define WALL_COLOR vec3(1.0, 0.5, 0.1)
#define FLOOR_COLOR vec3(0.4, 0.4, 0.4)
#define AMBIENT_LIGHT vec3(0.1, 0.1, 0.1)
//#define SHOW_SHADOWMAP
#define INF 1e8
#define EPS 1e-3
float tau = atan(1.0)*8.0;
//Globals
vec2 res = vec2(0); //Y-Normalized resolution
vec2 mouse = vec2(0); //Mouse coords (form center)
float psz = 0.0; //Pixel size
vec2 hpo = vec2(0); //Half pixel offset
// Shapes
float sdCircle(float r, vec2 uv)
{
return length(uv) - r;
}
float sdRing(float ir, float or, vec2 uv)
{
return abs(length(uv) - (ir+or)/2.0) - (or - ir);
}
float sdBox(float s, vec2 uv)
{
return max(abs(uv.x), abs(uv.y)) - s;
}
float sdRect(vec2 s, vec2 uv)
{
uv = abs(uv) - s;
return max(uv.x, uv.y);
}
float sdPlane(vec2 dir, vec2 uv)
{
return dot(normalize(dir), uv);
}
// Operations
float opU(float a, float b)
{
return min(a, b);
}
float opI(float a, float b)
{
return max(a, b);
}
float opS(float a, float b)
{
return max(-a, b);
}
//Domain modifiers
mat2 Rotate(float a)
{
return mat2(cos(a), sin(a),-sin(a), cos(a));
}
vec2 Rep1(vec2 uv, float r)
{
uv.x = mod(uv.x, r) - r/2.0;
return uv;
}
vec2 Rep2(vec2 uv, vec2 r)
{
return mod(uv, r) - r/2.0;
}
// Scene function (must be changed in both tabs)
float Scene(vec2 uv)
{
float d = -sdRect(res/2.0 - 0.05, uv);
vec2 rp = Rep2(uv, vec2(0.2));
d = opU(sdCircle(0.02, rp), d);
rp = Rep1(uv, 0.2);
d = opU(sdRect(vec2(0.005,0.1), rp), d);
d = opS(sdBox(0.2, uv), d);
d = opU(sdRing(0.08, 0.09, uv), d);
d = opS(sdRect(vec2(0.11,0.03), uv * Rotate(iGlobalTime)), d);
return d;
}
vec2 LightOrigin(int id)
{
return texture(iChannel0,vec2(0, float(id))/iResolution.xy + hpo).yz;
}
vec3 LightColor(int id)
{
return texture(iChannel0,vec2(1, float(id))/iResolution.xy + hpo).yzw;
}
float SampleShadow(int id, vec2 uv)
{
float a = atan(uv.y, uv.x)/tau + 0.5;
float r = length(uv);
float idn = float(id)/iResolution.y;
float s = texture(iChannel0, vec2(a, idn) + hpo).x;
return 1.0-smoothstep(s, s+0.02, length(uv));
}
//Reads lights from light buffer and combines them.
vec3 MixLights(vec2 uv)
{
vec3 b = AMBIENT_LIGHT;
for(int i = 0;i < NUM_LIGHTS;i++)
{
vec2 o = LightOrigin(i);
vec3 c = LightColor(i);
float l = 0.01 / pow(length(vec3(uv - o, 0.1)), 2.0);
l *= SampleShadow(i, uv-o);
b += c * l;
}
return b;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
hpo = 0.5 / iResolution.xy;
res = iResolution.xy / iResolution.y;
psz = 1.0 / iResolution.y;
vec2 uv = fragCoord.xy / iResolution.y - res/2.0;
mouse = iMouse.xy / iResolution.y - res/2.0;
vec3 col = vec3(0);
float d = Scene(uv);
col = mix(FLOOR_COLOR, WALL_COLOR, smoothstep(psz, 0.0, d));
col *= MixLights(uv);
#ifdef SHOW_SHADOWMAP
col = texture(iChannel0, fragCoord/iResolution.xy).rgb;
#endif
fragColor = vec4(col, 1.0);
}

View File

@ -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 );
}

View File

@ -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);
}

View File

@ -0,0 +1,594 @@
// Ben Weston - 15/08/2013
/*
Eye ball effects:
Ray-marched shape
Ray-traced iris refraction
Fake photon mapping on iris
Subsurface scattering on sclera
HDR reflections with fresnel
Eyelid reflection occlusion
Eyelid ambient occlusion
Procedural textures
Procedural animation
*/
// KEY CONTROLS - (click on eye to give keyboard focus)
const int Key_M = 77; // mouse controls camera / eye direction
const int Key_E = 69; // refraction on/off
const int Key_P = 80; // photon mapping on/off
const int Key_L = 76; // change photon mapping technique (both fake, but one is imitating reality and the other is prettier)
const int Key_S = 83; // subsurface scattering on/off
const int Key_A = 65; // ambient occlusion on/off
const int Key_R = 82; // reflection on/off
const int Key_O = 79; // reflection eyelid occlusion on/off
const int Key_C = 67; // iris colour
const int Key_N = 78; // iris normal
// Lights
#if (1)
// High-contrast light edge-on
const vec3 lightDir = vec3(-2,2,.5);
const vec3 lightColour = vec3(1.0);
const vec3 fillLightDir = vec3(0,1,0);
const vec3 fillLightColour = vec3(.65,.7,.8)*.7;//vec3(.15,.2,.25);
#else
// more neutral "good" lighting (doesn't show off the effects)
const vec3 lightDir = vec3(-2,2,-1);
const vec3 lightColour = vec3(.83,.8,.78);
const vec3 fillLightDir = vec3(0,1,0);
const vec3 fillLightColour = vec3(.65,.7,.8);
#endif
// Constants
const float tau = 6.28318530717958647692;
// Forward declarations
float Noise( in vec3 x );
vec2 Noise2( in vec3 x );
// Gamma correction
#define GAMMA (2.2)
vec3 ToLinear( in vec3 col )
{
// simulate a monitor, converting colour values into light values
return pow( col, vec3(GAMMA) );
}
vec3 ToGamma( in vec3 col )
{
// convert back into colour values, so the correct light will come out of the monitor
return pow( col, vec3(1.0/GAMMA) );
}
// key is javascript keycode: http://www.webonweboff.com/tips/js/event_key_codes.aspx
bool ReadKey( int key, bool toggle )
{
float keyVal = texture( iChannel3, vec2( (float(key)+.5)/256.0, toggle?.75:.25 ) ).x;
return (keyVal>.5)?true:false;
}
// ------- EDIT THESE THINGS! -------
// Camera (also rotated by mouse)
const vec3 CamPos = vec3(0,0.0,-250.0);
const vec3 CamLook = vec3(0,0,0);
const float CamZoom = 10.0;
const float NearPlane = 0.0; // actually not needed
const float drawDistance = 1000.0;
const vec3 SkyColour = vec3(.4,.25,.2);//fillLightColour*.5;//vec3(.1,.3,.5);
vec3 SkyDome( vec3 rd )
{
//the cube maps have lines in, and aren't HDR, so make our own shapes
// random variation
vec3 result = ToLinear(SkyColour)*2.0*Noise(rd);
// square sky-light
result = mix( result, vec3(8), smoothstep(.8,1.0,rd.y/max((rd.x+1.0),abs(rd.z))) );
return result;
}
// Eye params
const float IrisAng = tau/12.0;
const float PupilAng = (1.6*IrisAng/5.0);
const float EyeRadius = 10.0;
const float BulgeRadius = 6.0; // used for photon trace, must be bigger than EyeRadius*sin(IrisAng)
vec4 ComputeEyeRotation()
{
vec2 rot;
if ( !ReadKey( Key_M, true ) && iMouse.w > .00001 )
rot = .25*vec2(1.0,1.0)*tau*(iMouse.xy-iResolution.xy*.5)/iResolution.x;
else
{
float time = iGlobalTime/2.0;
time += Noise(vec3(0,time,0)); // add noise to time (this adds SO MUCH character!)
float flick = floor(time)+smoothstep(0.0,0.05,fract(time));
rot = vec2(.2,.1)*tau*(texture( iChannel0, vec2((flick+.5)/256.0,.5), -100.0 ).rb-.5);
}
return vec4(cos(rot.x),sin(rot.x),cos(rot.y),sin(rot.y));
}
vec3 ApplyEyeRotation( vec3 pos, vec4 rotation )
{
pos.yz = rotation.z*pos.yz + rotation.w*pos.zy*vec2(1,-1);
pos.xz = rotation.x*pos.xz + rotation.y*pos.zx*vec2(1,-1);
return pos;
}
// Shape
// This should return continuous positive values when outside and negative values inside,
// which roughly indicate the distance of the nearest surface.
float Isosurface( vec3 pos, vec4 eyeRotation )
{
pos = ApplyEyeRotation(pos,eyeRotation);
/* float f = length(pos)-EyeRadius;
// f += Noise(pos*3.0)*.008;
// cornea bulge
float o = EyeRadius*cos(IrisAng)-sqrt(BulgeRadius*BulgeRadius-EyeRadius*EyeRadius*pow(sin(IrisAng),2.0));
float g = length(pos-vec3(0,0,-o))-BulgeRadius;
//g += Noise(pos/2.0)*.5;
return min(f,g);
//return -log(exp(-g*2.0)+exp(-f*2.0))/2.0;*/
vec2 slice = vec2(length(pos.xy),pos.z);
float aa = atan(slice.x,-slice.y);
float bulge = cos(tau*.2*aa/IrisAng);
bulge = bulge*.8-.8;
bulge *= smoothstep(tau*.25,0.0,aa);
// sharp-edged bulge
// if ( aa < IrisAng )
// bulge += cos(tau*.25*aa/IrisAng)*.5;
bulge += cos(tau*.25*aa/IrisAng)*.5 * smoothstep(-.02,.1,IrisAng-aa); // slightly softer
return length(slice) - EyeRadius - bulge;
}
float GetEyelidMask( vec3 pos, vec4 eyeRotation )
{
vec3 eyelidPos = pos;
float eyelidTilt = -.05;
eyelidPos.xy = cos(eyelidTilt)*pos.xy + sin(eyelidTilt)*pos.yx*vec2(1,-1);
float highLid = tan(max(tau*.05,asin(eyeRotation.w)+IrisAng+.05));
float lowLid = tan(tau*.1);
float blink = smoothstep(.0,.02,abs(Noise(vec3(iGlobalTime*.2,0,0))-.5 ));
highLid *= blink;
lowLid *= blink;
return min(
(-eyelidPos.z-2.0) - (-eyelidPos.y/lowLid),
(-eyelidPos.z-2.0) - (eyelidPos.y/highLid)
);
}
float GetIrisPattern( vec2 uv )
{
return Noise( vec3( 10.0*uv/pow(length(uv),.7), 0 ) );
}
// Colour
vec3 Shading( vec3 worldPos, vec3 norm, float shadow, vec3 rd, vec4 eyeRotation )
{
vec3 view = normalize(-rd);
// eyelids - just match BG colour
float eyelidMask = GetEyelidMask(worldPos, eyeRotation);
if ( eyelidMask < 0.0 || (-worldPos.z-3.0) < (worldPos.x/tan(tau*.23)) )
{
return ToLinear(SkyColour);
}
vec3 pos = ApplyEyeRotation(worldPos,eyeRotation);
float lenposxy = length(pos.xy);
float ang = atan(lenposxy/(-pos.z));
if ( ang < 0.0 )
ang += tau/2.0;
// refract ray
vec3 irisRay = ApplyEyeRotation(-view,eyeRotation);
vec3 localNorm = ApplyEyeRotation(norm,eyeRotation);
float a = dot(irisRay,localNorm);
float b = cos(acos(a)*1.33);
if ( !ReadKey( Key_E, true ) )
irisRay += localNorm*(b-a);
irisRay = normalize(irisRay);
// intersect with plane
float planeDist = -cos(IrisAng)*EyeRadius;
float t = (planeDist-pos.z)/irisRay.z;
vec3 ppos = t*irisRay+pos;
// polar coord map
float rad = length(ppos.xy);
float pupilr = EyeRadius*sin(PupilAng);
float irisr = EyeRadius*sin(IrisAng);
float irisPattern = GetIrisPattern(ppos.xy); // reduce contrast of this now we have actual lighting!
/* vec3 iris = mix( mix( vec3(.3,.1,.1)*.5+.5*vec3(.6,.4,.1), vec3(.6,.4,.1), irisPattern ), // hazel
mix( vec3(.2,.2,.2)*.5+.5*vec3(.5,.45,.2), vec3(.5,.45,.2), irisPattern ),*/
/* vec3 iris = mix( mix( vec3(.1,.1,.4), vec3(.7,.9,1), irisPattern ), // blue
mix( vec3(.1,.1,.4), vec3(.3,.4,.7), irisPattern ),*/
// smoothstep(pupilr*2.0,irisr,rad));
vec3 iris = ToLinear( mix( pow( vec3(.65,.82,.85), 2.0*vec3(1.2-sqrt(irisPattern)) ),
vec3(1,.5,.2), .7*pow( mix( smoothstep(pupilr,irisr,rad), Noise(ppos), .7), 2.0) ));
if ( ReadKey( Key_C, true ) )
iris = vec3(1);
// darken outer
iris *= pow( smoothstep( irisr+1.0, irisr-1.5, rad ), GAMMA );
vec3 irisNorm;
irisNorm.x = GetIrisPattern(ppos.xy+vec2(-.001,0)) - GetIrisPattern(ppos.xy+vec2(.001,0));
irisNorm.y = GetIrisPattern(ppos.xy+vec2(0,-.001)) - GetIrisPattern(ppos.xy+vec2(0,.001));
// add a radial lump
irisNorm.xy += -.01*normalize(ppos.xy)*sin(1.*tau*rad/irisr);
irisNorm.z = -.15; // adjust severity of bumps
irisNorm = normalize(irisNorm);
if ( ReadKey( Key_N, true ) )
irisNorm = vec3(0,0,-1);
// lighting
// fake photon mapping by crudely sampling the photon density
// apply lighting with this modified normal
vec3 lightDirN = normalize(lightDir);
vec3 localLightDir = ApplyEyeRotation(lightDirN,eyeRotation);
vec3 fillLightDirN = normalize(fillLightDir);
vec3 localFillLightDir = ApplyEyeRotation(fillLightDirN,eyeRotation);
// Bend the light, imitating results of offline photon-mapping
// Jimenez's paper makes this seem very complex, because their mapping used a non-flat receiver
// but the self-shadowing was negligible, so the main effect was just like premultiplying by a normal
// where we'd get better results by using the actual normal.
float photonsL, photonsFL;
if ( !ReadKey( Key_P, true ) )
{
if ( !ReadKey( Key_L, true ) )
{
// Nice retro-reflective effect, but not correct
vec3 nn = normalize(vec3( ppos.xy, -sqrt(max(0.0,BulgeRadius*BulgeRadius-rad*rad)) ));
vec3 irisLDir = localLightDir;
vec3 irisFLDir = localFillLightDir;
// irisLDir.z = -cos(acos(-irisLDir.z)/1.33); // experiments showed it cuts out at 120 degrees, i.e. 1.33*the usual 90 degree cutoff
// irisFLDir.z = -cos(acos(-irisFLDir.z)/1.33); // experiments showed it cuts out at 120 degrees, i.e. 1.33*the usual 90 degree cutoff
float d = dot(nn,irisLDir);
irisLDir += nn*(cos(acos(d)/1.33) - d);
d = dot(nn,irisFLDir);
irisFLDir += nn*(cos(acos(d)/1.33) - d);
irisLDir = normalize(irisLDir);
irisFLDir = normalize(irisFLDir);
photonsL = smoothstep(0.0,1.0,dot(irisNorm,irisLDir)); //soften terminator
photonsFL = (dot(irisNorm,irisFLDir)*.5+.5);
//Seriously, this^ looks really nice, but not like reality. Bah!
/* reverse it, to make it look a lot like the accurate version - meh
vec3 nn = normalize(vec3( -ppos.xy, -sqrt(max(0.0,BulgeRadius*BulgeRadius-rad*rad)) ));
vec3 irisLDir = localLightDir;
vec3 irisFLDir = localFillLightDir;
float d = dot(nn,irisLDir);
irisLDir += nn*(cos(acos(d)/1.33) - d);
d = dot(nn,irisFLDir);
irisFLDir += nn*(cos(acos(d)/1.33) - d);
irisLDir = normalize(irisLDir);
irisFLDir = normalize(irisFLDir);
float photonsL = smoothstep(0.0,1.0,dot(irisNorm,irisLDir)); // soften the terminator
float photonsFL = (dot(irisNorm,irisFLDir)*.5+.5);
*/
}
else
{
//this is a reasonable match to the dark crescent effect seen in photos and offline photon mapping, but it looks wrong to me.
vec3 irisLDir = localLightDir;
vec3 irisFLDir = localFillLightDir;
irisLDir.z = -cos(acos(-irisLDir.z)/1.5); // experiments showed it cuts out at 120 degrees, i.e. 1.33*the usual 90 degree cutoff
irisFLDir.z = -cos(acos(-irisFLDir.z)/1.5); // experiments showed it cuts out at 120 degrees, i.e. 1.33*the usual 90 degree cutoff
irisLDir = normalize(irisLDir);
irisFLDir = normalize(irisFLDir);
photonsL = smoothstep(0.0,1.0,dot(irisNorm,irisLDir)); // soften the terminator
photonsFL = (dot(irisNorm,irisFLDir)*.5+.5);
// dark caustic ring
photonsL *= .3+.7*smoothstep( 1.2, .9, length(ppos.xy/irisr+.2*irisLDir.xy/(irisLDir.z-.05)) );
// photonsFL *= ...;
}
}
else
{
// no photons
photonsL = max( 0.0, dot(irisNorm,localLightDir) );
photonsFL = .5+.5*dot(irisNorm,localLightDir);
}
vec3 l = ToLinear(lightColour)*photonsL;
vec3 fl = ToLinear(fillLightColour)*photonsFL;
vec3 ambientOcclusion = vec3(1);
vec3 eyelidShadow = vec3(1);
if ( !ReadKey( Key_A, true ) )
{
// ambient occlusion on fill light
ambientOcclusion = mix( vec3(1), ToLinear(vec3(.8,.7,.68)), pow(smoothstep( 5.0, 0.0, eyelidMask ),1.0) );
// shadow on actual light
eyelidShadow = mix( vec3(1), ToLinear(vec3(.8,.7,.68)), smoothstep( 2.0, -2.0, GetEyelidMask( worldPos+lightDir*1.0, eyeRotation ) ) );
}
fl *= ambientOcclusion;
l *= eyelidShadow;
iris *= l+fl;
// darken pupil
iris *= smoothstep( pupilr-.01, pupilr+.5, rad );
// veins
float theta = atan(pos.x,pos.y);
theta += Noise(pos*1.0)*tau*.03;
float veins = (sin(theta*60.0)*.5+.5);
veins *= veins;
veins *= (sin(theta*13.0)*.5+.5);
veins *= smoothstep( IrisAng, tau*.2, ang );
veins *= veins;
veins *= .5;
vec3 sclera = mix( ToLinear(vec3(1,.98,.96)), ToLinear(vec3(.9,.1,0)), veins );
float ndotl = dot(norm,lightDirN);
// subsurface scattering
// float subsurface = max(0.0,-2.0*ndotl*EyeRadius);
// l = pow(ToLinear(vec3(.5,.3,.25)),vec3(subsurface*.2)); // more intense the further light had to travel
// fake, because that^ approximation gives a hard terminator
l = pow(ToLinear(vec3(.5,.3,.25)), vec3(mix( 3.0, 0.0, smoothstep(-1.0,.2,ndotl) )) );
if ( ReadKey( Key_S, true ) )
// l = mix( l, vec3(max(0.0,ndotl)), 0.5 );
// else
l = vec3(max(0.0,ndotl));
l *= ToLinear(lightColour);
fl = ToLinear(fillLightColour)*(dot(norm,fillLightDirN)*.5+.5);
fl *= ambientOcclusion;
l *= eyelidShadow;
sclera *= l+fl;
// blend between them
float blend = smoothstep(-.1,.1,ang-IrisAng);
vec3 result = mix(iris,sclera,blend);
// eyelid ambient occlusion/radiosity
// if ( !ReadKey( Key_A, true ) )
//result *= mix( vec3(1), ToLinear(vec3(.65,.55,.55)), exp2(-eyelidMask*2.0) );
// result *= mix( vec3(1), ToLinear(vec3(.8,.7,.68)), pow(smoothstep( 5.0, 0.0, eyelidMask ),1.0) );
// bumps - in specular only to help sub-surface scattering look smooth
vec3 bumps;
bumps.xy = .7*Noise2( pos*3.0 );
bumps.z = sqrt(1.0-dot(bumps.xy,bumps.xy));
bumps = mix( vec3(0,0,1), bumps, blend );
norm.xy += bumps.xy*.1;
norm = normalize(norm);
float glossiness = mix(.7,1.0,bumps.z);
// reflection map
float ndoti = dot( view, norm );
vec3 rr = -view+2.0*ndoti*norm;
vec3 reflection = SkyDome( rr );
// specular
vec3 h = normalize(view+lightDir);
float specular = pow(max(0.0,dot(h,norm)),2000.0);
// should fresnel affect specular? or should it just be added?
reflection += specular*32.0*glossiness*ToLinear(lightColour);
// reflection of eyelids
//float eyelidReflection = smoothstep( 1.8, 2.0, eyelidMask );
// apply some parallax (subtle improvement when looking up/down at eye)
float eyelidReflection = smoothstep( .8, 1.0, GetEyelidMask( normalize(worldPos + rd*2.0)*EyeRadius, eyeRotation ) );
if ( !ReadKey( Key_O, true ) )
reflection *= eyelidReflection;
// fresnel
float fresnel = mix(.04*glossiness,1.0,pow(1.0-ndoti,5.0));
if ( !ReadKey( Key_R, true ) )
result = mix ( result, reflection, fresnel );
//anti-alias the edge
float mask2 = min( eyelidMask, (-worldPos.z-3.0) - (worldPos.x/tan(tau*.23)) );
result = mix( ToLinear(SkyColour), result, smoothstep(.0,.3,mask2) );
return result;
}
// Precision controls
const float epsilon = .003;
const float normalPrecision = .1;
const float shadowOffset = .1;
const int traceDepth = 100; // takes time
// ------- BACK-END CODE -------
vec2 Noise2( in vec3 x )
{
vec3 p = floor(x.xzy);
vec3 f = fract(x.xzy);
f = f*f*(3.0-2.0*f);
// vec3 f2 = f*f; f = f*f2*(10.0-15.0*f+6.0*f2);
vec2 uv = (p.xy+vec2(37.0,17.0)*p.z) + f.xy;
vec4 rg = textureLod( iChannel0, (uv+0.5)/256.0, 0.0 );
return mix( rg.yw, rg.xz, f.z );
}
float Noise( in vec3 x )
{
return Noise2(x).x;
}
float Trace( vec3 ro, vec3 rd, vec4 eyeRotation )
{
float t = 0.0;
float dist = 1.0;
for ( int i=0; i < traceDepth; i++ )
{
if ( abs(dist) < epsilon || t > drawDistance || t < 0.0 )
continue;
dist = Isosurface( ro+rd*t, eyeRotation );
t = t+dist;
}
return t;//vec4(ro+rd*t,dist);
}
// get normal
vec3 GetNormal( vec3 pos, vec4 eyeRotation )
{
const vec2 delta = vec2(normalPrecision, 0);
vec3 n;
// it's important this is centred on the pos, it fixes a lot of errors
n.x = Isosurface( pos + delta.xyy, eyeRotation ) - Isosurface( pos - delta.xyy, eyeRotation );
n.y = Isosurface( pos + delta.yxy, eyeRotation ) - Isosurface( pos - delta.yxy, eyeRotation );
n.z = Isosurface( pos + delta.yyx, eyeRotation ) - Isosurface( pos - delta.yyx, eyeRotation );
return normalize(n);
}
// camera function by TekF
// compute ray from camera parameters
vec3 GetRay( vec3 dir, float zoom, vec2 uv )
{
uv = uv - .5;
uv.x *= iResolution.x/iResolution.y;
dir = zoom*normalize(dir);
vec3 right = normalize(cross(vec3(0,1,0),dir));
vec3 up = normalize(cross(dir,right));
return dir + right*uv.x + up*uv.y;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord.xy / iResolution.xy;
vec3 camPos = CamPos;
vec3 camLook = CamLook;
vec2 camRot = .5*tau*(iMouse.xy-iResolution.xy*.5)/iResolution.x;
if ( !ReadKey( Key_M, true ) )
camRot = vec2(0,0);
camPos.yz = cos(camRot.y)*camPos.yz + sin(camRot.y)*camPos.zy*vec2(1,-1);
camPos.xz = cos(camRot.x)*camPos.xz + sin(camRot.x)*camPos.zx*vec2(1,-1);
vec4 eyeRotation = ComputeEyeRotation();
if ( Isosurface(camPos, eyeRotation) <= 0.0 )
{
// camera inside ground
fragColor = vec4(0,0,0,0);
return;
}
vec3 ro = camPos;
vec3 rd;
rd = GetRay( camLook-camPos, CamZoom, uv );
ro += rd*(NearPlane/CamZoom);
rd = normalize(rd);
float t = Trace(ro,rd,eyeRotation);
vec3 result = ToLinear(SkyColour);
if ( t > 0.0 && t < drawDistance )
{
vec3 pos = ro+t*rd;
vec3 norm = GetNormal(pos,eyeRotation);
// shadow test
float shadow = 1.0;
if ( Trace( pos+lightDir*shadowOffset, lightDir, eyeRotation ) < drawDistance )
shadow = 0.0;
result = Shading( pos, norm, shadow, rd, eyeRotation );
// fog
// result = mix ( SkyColour, result, exp(-t*t*.0002) );
}
fragColor = vec4( ToGamma( result ), 1.0 );
}

View File

@ -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);
}

View File

@ -0,0 +1,145 @@
// noise3.jpg
// Created by inigo quilez - iq/2013
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
// Volumetric clouds. It performs level of detail (LOD) for faster rendering
float noise( in vec3 x )
{
vec3 p = floor(x);
vec3 f = fract(x);
f = f*f*(3.0-2.0*f);
#if 1
vec2 uv = (p.xy+vec2(37.0,17.0)*p.z) + f.xy;
vec2 rg = textureLod( iChannel0, (uv+ 0.5)/256.0, 0. ).yx;
#else
ivec3 q = ivec3(p);
ivec2 uv = q.xy + ivec2(37,17)*q.z;
vec2 rg = mix( mix( texelFetch( iChannel0, (uv )&255, 0 ),
texelFetch( iChannel0, (uv+ivec2(1,0))&255, 0 ), f.x ),
mix( texelFetch( iChannel0, (uv+ivec2(0,1))&255, 0 ),
texelFetch( iChannel0, (uv+ivec2(1,1))&255, 0 ), f.x ), f.y ).yx;
#endif
return -1.0+2.0*mix( rg.x, rg.y, f.z );
}
float map5( in vec3 p )
{
vec3 q = p - vec3(0.0,0.1,1.0)*iGlobalTime;
float f;
f = 0.50000*noise( q ); q = q*2.02;
f += 0.25000*noise( q ); q = q*2.03;
f += 0.12500*noise( q ); q = q*2.01;
f += 0.06250*noise( q ); q = q*2.02;
f += 0.03125*noise( q );
return clamp( 1.5 - p.y - 2.0 + 1.75*f, 0.0, 1.0 );
}
float map4( in vec3 p )
{
vec3 q = p - vec3(0.0,0.1,1.0)*iGlobalTime;
float f;
f = 0.50000*noise( q ); q = q*2.02;
f += 0.25000*noise( q ); q = q*2.03;
f += 0.12500*noise( q ); q = q*2.01;
f += 0.06250*noise( q );
return clamp( 1.5 - p.y - 2.0 + 1.75*f, 0.0, 1.0 );
}
float map3( in vec3 p )
{
vec3 q = p - vec3(0.0,0.1,1.0)*iGlobalTime;
float f;
f = 0.50000*noise( q ); q = q*2.02;
f += 0.25000*noise( q ); q = q*2.03;
f += 0.12500*noise( q );
return clamp( 1.5 - p.y - 2.0 + 1.75*f, 0.0, 1.0 );
}
float map2( in vec3 p )
{
vec3 q = p - vec3(0.0,0.1,1.0)*iGlobalTime;
float f;
f = 0.50000*noise( q ); q = q*2.02;
f += 0.25000*noise( q );;
return clamp( 1.5 - p.y - 2.0 + 1.75*f, 0.0, 1.0 );
}
vec3 sundir = normalize( vec3(-1.0,0.0,-1.0) );
vec4 integrate( in vec4 sum, in float dif, in float den, in vec3 bgcol, in float t )
{
// lighting
vec3 lin = vec3(0.65,0.7,0.75)*1.4 + vec3(1.0, 0.6, 0.3)*dif;
vec4 col = vec4( mix( vec3(1.0,0.95,0.8), vec3(0.25,0.3,0.35), den ), den );
col.xyz *= lin;
col.xyz = mix( col.xyz, bgcol, 1.0-exp(-0.003*t*t) );
// front to back blending
col.a *= 0.4;
col.rgb *= col.a;
return sum + col*(1.0-sum.a);
}
#define MARCH(STEPS,MAPLOD) for(int i=0; i<STEPS; i++) { vec3 pos = ro + t*rd; if( pos.y<-3.0 || pos.y>2.0 || sum.a > 0.99 ) break; float den = MAPLOD( pos ); if( den>0.01 ) { float dif = clamp((den - MAPLOD(pos+0.3*sundir))/0.6, 0.0, 1.0 ); sum = integrate( sum, dif, den, bgcol, t ); } t += max(0.05,0.02*t); }
vec4 raymarch( in vec3 ro, in vec3 rd, in vec3 bgcol, in ivec2 px )
{
vec4 sum = vec4(0.0);
float t = 0.05*texelFetch( iChannel0, px&255, 0 ).x;
MARCH(30,map5);
MARCH(30,map4);
MARCH(30,map3);
MARCH(30,map2);
return clamp( sum, 0.0, 1.0 );
}
mat3 setCamera( in vec3 ro, in vec3 ta, float cr )
{
vec3 cw = normalize(ta-ro);
vec3 cp = vec3(sin(cr), cos(cr),0.0);
vec3 cu = normalize( cross(cw,cp) );
vec3 cv = normalize( cross(cu,cw) );
return mat3( cu, cv, cw );
}
vec4 render( in vec3 ro, in vec3 rd, in ivec2 px )
{
// background sky
float sun = clamp( dot(sundir,rd), 0.0, 1.0 );
vec3 col = vec3(0.6,0.71,0.75) - rd.y*0.2*vec3(1.0,0.5,1.0) + 0.15*0.5;
col += 0.2*vec3(1.0,.6,0.1)*pow( sun, 8.0 );
// clouds
vec4 res = raymarch( ro, rd, col, px );
col = col*(1.0-res.w) + res.xyz;
// sun glare
col += 0.2*vec3(1.0,0.4,0.2)*pow( sun, 3.0 );
return vec4( col, 1.0 );
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 p = (-iResolution.xy + 2.0*fragCoord.xy)/ iResolution.y;
vec2 m = iMouse.xy/iResolution.xy;
// camera
vec3 ro = 4.0*normalize(vec3(sin(3.0*m.x), 0.4*m.y, cos(3.0*m.x)));
vec3 ta = vec3(0.0, -1.0, 0.0);
mat3 ca = setCamera( ro, ta, 0.0 );
// ray
vec3 rd = ca * normalize( vec3(p.xy,1.5));
fragColor = render( ro, rd, ivec2(fragCoord-0.5) );
}
void mainVR( out vec4 fragColor, in vec2 fragCoord, in vec3 fragRayOri, in vec3 fragRayDir )
{
fragColor = render( fragRayOri, fragRayDir, ivec2(fragCoord-0.5) );
}

View File

@ -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.);
}

View File

@ -0,0 +1,94 @@
// Viridis approximation, Jerome Liard, August 2016
// https://www.shadertoy.com/view/XtGGzG
// Applied polynomial regression to viridis color palettes so I could easily use them in shaders.
// Degree 5 seems to be a good fit (doesn't capture all details but...)
//
// Some credits/reference links about viridis palettes and why they are good, and some use examples:
//
// https://bids.github.io/colormap/ (says license is CC0)
// https://github.com/sjmgarnier/viridis#references @sjmgarnier
// https://cran.r-project.org/web/packages/viridis/vignettes/intro-to-viridis.html
//
// I learned about the existence of this palette via via https://www.mrao.cam.ac.uk/~dag/CUBEHELIX/ via @kenpex
//#define PLOT_CURVES
#define BLACK_BANDS
float saturate( float x ) { return clamp( x, 0.0, 1.0 ); }
vec3 viridis_quintic( float x )
{
x = saturate( x );
vec4 x1 = vec4( 1.0, x, x * x, x * x * x ); // 1 x x2 x3
vec4 x2 = x1 * x1.w * x; // x4 x5 x6 x7
return vec3(
dot( x1.xyzw, vec4( +0.280268003, -0.143510503, +2.225793877, -14.815088879 ) ) + dot( x2.xy, vec2( +25.212752309, -11.772589584 ) ),
dot( x1.xyzw, vec4( -0.002117546, +1.617109353, -1.909305070, +2.701152864 ) ) + dot( x2.xy, vec2( -1.685288385, +0.178738871 ) ),
dot( x1.xyzw, vec4( +0.300805501, +2.614650302, -12.019139090, +28.933559110 ) ) + dot( x2.xy, vec2( -33.491294770, +13.762053843 ) ) );
}
vec3 inferno_quintic( float x )
{
x = saturate( x );
vec4 x1 = vec4( 1.0, x, x * x, x * x * x ); // 1 x x2 x3
vec4 x2 = x1 * x1.w * x; // x4 x5 x6 x7
return vec3(
dot( x1.xyzw, vec4( -0.027780558, +1.228188385, +0.278906882, +3.892783760 ) ) + dot( x2.xy, vec2( -8.490712758, +4.069046086 ) ),
dot( x1.xyzw, vec4( +0.014065206, +0.015360518, +1.605395918, -4.821108251 ) ) + dot( x2.xy, vec2( +8.389314011, -4.193858954 ) ),
dot( x1.xyzw, vec4( -0.019628385, +3.122510347, -5.893222355, +2.798380308 ) ) + dot( x2.xy, vec2( -3.608884658, +4.324996022 ) ) );
}
vec3 magma_quintic( float x )
{
x = saturate( x );
vec4 x1 = vec4( 1.0, x, x * x, x * x * x ); // 1 x x2 x3
vec4 x2 = x1 * x1.w * x; // x4 x5 x6 x7
return vec3(
dot( x1.xyzw, vec4( -0.023226960, +1.087154378, -0.109964741, +6.333665763 ) ) + dot( x2.xy, vec2( -11.640596589, +5.337625354 ) ),
dot( x1.xyzw, vec4( +0.010680993, +0.176613780, +1.638227448, -6.743522237 ) ) + dot( x2.xy, vec2( +11.426396979, -5.523236379 ) ),
dot( x1.xyzw, vec4( -0.008260782, +2.244286052, +3.005587601, -24.279769818 ) ) + dot( x2.xy, vec2( +32.484310068, -12.688259703 ) ) );
}
vec3 plasma_quintic( float x )
{
x = saturate( x );
vec4 x1 = vec4( 1.0, x, x * x, x * x * x ); // 1 x x2 x3
vec4 x2 = x1 * x1.w * x; // x4 x5 x6 x7
return vec3(
dot( x1.xyzw, vec4( +0.063861086, +1.992659096, -1.023901152, -0.490832805 ) ) + dot( x2.xy, vec2( +1.308442123, -0.914547012 ) ),
dot( x1.xyzw, vec4( +0.049718590, -0.791144343, +2.892305078, +0.811726816 ) ) + dot( x2.xy, vec2( -4.686502417, +2.717794514 ) ),
dot( x1.xyzw, vec4( +0.513275779, +1.580255060, -5.164414457, +4.559573646 ) ) + dot( x2.xy, vec2( -1.916810682, +0.570638854 ) ) );
}
float tri( float x ) { return 1.0 - abs( fract( x * 0.5 ) - 0.5 ) * 2.0; }
vec3 smoothstep_unchecked( vec3 x ) { return ( x * x ) * ( 3.0 - x * 2.0 ); }
vec3 smoothbump( vec3 a, vec3 r, vec3 x ) { return 1.0 - smoothstep_unchecked( min( abs( x - a ), r ) / r ); }
#ifdef SHADERTOY_STANDALONE
void main()
#else
void mainImage( out vec4 fragColor, in vec2 fragCoord )
#endif
{
fragColor.a = 1.0;
vec2 uv = fragCoord.xy / iResolution.xy;
if ( uv.y > 0.75 ) fragColor.xyz = viridis_quintic( uv.x );
else if ( uv.y > 0.5 ) fragColor.xyz = inferno_quintic( uv.x );
else if ( uv.y > 0.25 ) fragColor.xyz = magma_quintic( uv.x );
else if ( uv.y > 0.0 ) fragColor.xyz = plasma_quintic( uv.x );
#ifdef BLACK_BANDS
float r = 32.0 / iResolution.y;
fragColor.xyz *= step( r, tri( uv.y / 0.125 ) );
#endif
#ifdef PLOT_CURVES
float y = fract( uv.y / 0.25 );
float r = 6.0 / iResolution.y;
fragColor.xyz += smoothbump( vec3( 0.0 ), vec3( r ), vec3( y ) - fragColor.xyz );
#endif
}

View File

@ -0,0 +1,171 @@
//Cloud Ten by nimitz (twitter: @stormoid) noise3.jpg
#define time iGlobalTime
mat2 mm2(in float a){float c = cos(a), s = sin(a);return mat2(c,s,-s,c);}
float noise(float t){return textureLod(iChannel0,vec2(t,.0)/iChannelResolution[0].xy,0.0).x;}
float moy = 0.;
float noise(in vec3 x) //3d noise from iq
{
vec3 p = floor(x);
vec3 f = fract(x);
f = f*f*(3.0-2.0*f);
vec2 uv = (p.xy+vec2(37.0,17.0)*p.z) + f.xy;
vec2 rg = textureLod( iChannel0, (uv+ 0.5)/256.0, 0.0 ).yx;
return mix( rg.x, rg.y, f.z );
}
float fbm(in vec3 x)
{
float rz = 0.;
float a = .35;
for (int i = 0; i<2; i++)
{
rz += noise(x)*a;
a*=.35;
x*= 4.;
}
return rz;
}
float path(in float x){ return sin(x*0.01-3.1415)*28.+6.5; }
float map(vec3 p){
return p.y*0.07 + (fbm(p*0.3)-0.1) + sin(p.x*0.24 + sin(p.z*.01)*7.)*0.22+0.15 + sin(p.z*0.08)*0.05;
}
float march(in vec3 ro, in vec3 rd)
{
float precis = .3;
float h= 1.;
float d = 0.;
for( int i=0; i<17; i++ )
{
if( abs(h)<precis || d>70. ) break;
d += h;
vec3 pos = ro+rd*d;
pos.y += .5;
float res = map(pos)*7.;
h = res;
}
return d;
}
vec3 lgt = vec3(0);
float mapV( vec3 p ){ return clamp(-map(p), 0., 1.);}
vec4 marchV(in vec3 ro, in vec3 rd, in float t, in vec3 bgc)
{
vec4 rz = vec4( 0.0 );
for( int i=0; i<150; i++ )
{
if(rz.a > 0.99 || t > 200.) break;
vec3 pos = ro + t*rd;
float den = mapV(pos);
vec4 col = vec4(mix( vec3(.8,.75,.85), vec3(.0), den ),den);
col.xyz *= mix(bgc*bgc*2.5, mix(vec3(0.1,0.2,0.55),vec3(.8,.85,.9),moy*0.4), clamp( -(den*40.+0.)*pos.y*.03-moy*0.5, 0., 1. ) );
col.rgb += clamp((1.-den*6.) + pos.y*0.13 +.55, 0., 1.)*0.35*mix(bgc,vec3(1),0.7); //Fringes
col += clamp(den*pos.y*.15, -.02, .0); //Depth occlusion
col *= smoothstep(0.2+moy*0.05,.0,mapV(pos+1.*lgt))*.85+0.15; //Shadows
col.a *= .9;
col.rgb *= col.a;
rz = rz + col*(1.0 - rz.a);
t += max(.4,(2.-den*30.)*t*0.011);
}
return clamp(rz, 0., 1.);
}
float pent(in vec2 p){
vec2 q = abs(p);
return max(max(q.x*1.176-p.y*0.385, q.x*0.727+p.y), -p.y*1.237)*1.;
}
vec3 flare(vec2 p, vec2 pos) //Inspired by mu6k's lens flare (https://www.shadertoy.com/view/4sX3Rs)
{
vec2 q = p-pos;
vec2 pds = p*(length(p))*0.75;
float a = atan(q.x,q.y);
float rz = .55*(pow(abs(fract(a*.8+.12)-0.5),3.)*(noise(a*15.)*0.9+.1)*exp2((-dot(q,q)*4.))); //Spokes
rz += max(1.0/(1.0+32.0*pent(pds+0.8*pos)),.0)*00.2; //Projected ghost (main lens)
vec2 p2 = mix(p,pds,-.5); //Reverse distort
rz += max(0.01-pow(pent(p2 + 0.4*pos),2.2),.0)*3.0;
rz += max(0.01-pow(pent(p2 + 0.2*pos),5.5),.0)*3.0;
rz += max(0.01-pow(pent(p2 - 0.1*pos),1.6),.0)*4.0;
rz += max(0.01-pow(pent(-(p2 + 1.*pos)),2.5),.0)*5.0;
rz += max(0.01-pow(pent(-(p2 - .5*pos)),2.),.0)*4.0;
rz += max(0.01-pow(pent(-(p2 + .7*pos)),5.),.0)*3.0;
return vec3(clamp(rz,0.,1.));
}
mat3 rot_x(float a){float sa = sin(a); float ca = cos(a); return mat3(1.,.0,.0, .0,ca,sa, .0,-sa,ca);}
mat3 rot_y(float a){float sa = sin(a); float ca = cos(a); return mat3(ca,.0,sa, .0,1.,.0, -sa,.0,ca);}
mat3 rot_z(float a){float sa = sin(a); float ca = cos(a); return mat3(ca,sa,.0, -sa,ca,.0, .0,.0,1.);}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 q = fragCoord.xy / iResolution.xy;
vec2 p = q - 0.5;
float asp =iResolution.x/iResolution.y;
p.x *= asp;
vec2 mo = iMouse.xy / iResolution.xy;
moy = mo.y;
float st = sin(time*0.3-1.3)*0.2;
vec3 ro = vec3(0.,-2.+sin(time*.3-1.)*2.,time*30.);
ro.x = path(ro.z);
vec3 ta = ro + vec3(0,0,1);
vec3 fw = normalize( ta - ro);
vec3 uu = normalize(cross( vec3(0.0,1.0,0.0), fw ));
vec3 vv = normalize(cross(fw,uu));
const float zoom = 1.;
vec3 rd = normalize( p.x*uu + p.y*vv + -zoom*fw );
float rox = sin(time*0.2)*0.8+2.9;
rox += smoothstep(0.6,1.2,sin(time*0.25))*3.5;
float roy = sin(time*0.5)*0.2;
mat3 rotation = rot_x(-roy)*rot_y(-rox+st*1.5)*rot_z(st);
mat3 inv_rotation = rot_z(-st)*rot_y(rox-st*1.5)*rot_x(roy);
rd *= rotation;
rd.y -= dot(p,p)*0.06;
rd = normalize(rd);
vec3 col = vec3(0.);
lgt = normalize(vec3(-0.3,mo.y+0.1,1.));
float rdl = clamp(dot(rd, lgt),0.,1.);
vec3 hor = mix( vec3(.9,.6,.7)*0.35, vec3(.5,0.05,0.05), rdl );
hor = mix(hor, vec3(.5,.8,1),mo.y);
col += mix( vec3(.2,.2,.6), hor, exp2(-(1.+ 3.*(1.-rdl))*max(abs(rd.y),0.)) )*.6;
col += .8*vec3(1.,.9,.9)*exp2(rdl*650.-650.);
col += .3*vec3(1.,1.,0.1)*exp2(rdl*100.-100.);
col += .5*vec3(1.,.7,0.)*exp2(rdl*50.-50.);
col += .4*vec3(1.,0.,0.05)*exp2(rdl*10.-10.);
vec3 bgc = col;
float rz = march(ro,rd);
if (rz < 70.)
{
vec4 res = marchV(ro, rd, rz-5., bgc);
col = col*(1.0-res.w) + res.xyz;
}
vec3 projected_flare = (-lgt*inv_rotation);
col += 1.4*vec3(0.7,0.7,0.4)*max(flare(p,-projected_flare.xy/projected_flare.z*zoom)*projected_flare.z,0.);
float g = smoothstep(0.03,.97,mo.x);
col = mix(mix(col,col.brg*vec3(1,0.75,1),clamp(g*2.,0.0,1.0)), col.bgr, clamp((g-0.5)*2.,0.0,1.));
col = clamp(col, 0., 1.);
col = col*0.5 + 0.5*col*col*(3.0-2.0*col); //saturation
col = pow(col, vec3(0.416667))*1.055 - 0.055; //sRGB
col *= pow( 16.0*q.x*q.y*(1.0-q.x)*(1.0-q.y), 0.12 ); //Vign
fragColor = vec4( col, 1.0 );
}

View File

@ -0,0 +1,251 @@
float sdSphere(vec3 p, float r)
{
return length(p) - r;
}
float sdCapsule(vec3 p, float h, float r)
{
return length(vec3(p.x, max(0.0, abs(p.y) - 0.5*h), p.z)) - r;
}
float sdCylinder( vec3 p, float h, float r )
{
vec2 d = abs(vec2(length(p.xz),p.y)) - vec2(r,h);
return min(max(d.x,d.y),0.0) + length(max(d,0.0));
}
struct Scene
{
vec2 rot;
vec2 stre;
};
mat2 rot2(float theta)
{
float c = cos(theta);
float s = sin(theta);
return mat2(
c, -s,
s, c
);
}
vec3 apply_rot(vec3 p, vec2 rot)
{
p.xy *= rot2(rot.x);
p.yz *= rot2(rot.y);
return p;
}
float smax(float a, float b, float k)
{
float dist = abs(a - b);
float res = max(a, b);
if (dist < k)
{
res += (1.0/(4.0*k))*(k-dist)*(k-dist);
}
return res;
}
float smin(float a, float b, float k)
{
float dist = abs(a - b);
float res = min(a, b);
if (dist < k)
{
res -= (1.0/(4.0*k))*(k-dist)*(k-dist);
}
return res;
}
float map_shell(Scene scene, vec3 p)
{
p = apply_rot(p, scene.rot);
float dist = sdCapsule(p-vec3(0,-0.4,0), 1.3, 0.43);
dist = smin(dist, sdCylinder(p-vec3(0,0.6,0), 0.6, 0.12), 0.03);
dist = smax(dist, -p.y-1.1, 0.02);
return dist;
}
vec3 calc_normal_shell(Scene scene, vec3 p)
{
vec2 e = vec2(0, 0.0001);
return normalize(vec3(map_shell(scene, p+e.yxx),
map_shell(scene, p+e.xyx),
map_shell(scene, p+e.xxy)) -
vec3(map_shell(scene, p)));
}
float map_body(Scene scene, vec3 p)
{
float dist = map_shell(scene, p)+0.04;
vec3 surfaceN = vec3(0,1,0);
// surface wobble
surfaceN.yz *= rot2(scene.stre.y*sin(10.0*iTime));
surfaceN.xy *= rot2(scene.stre.x*sin(10.0*iTime));
// travelling waves
float perturb = 0.1*(scene.stre.x*sin(4.0*(p.x+sign(scene.stre.x)*5.0*iTime)) +
scene.stre.y*sin(4.0*(p.z+sign(scene.stre.y)*5.0*iTime)));
// TODO: SDF is completely ruined if I remove the *0.1 here, why?
// does this screw up the SDF that badly?
dist = 0.1*max(dist, dot(p,surfaceN)-(0.0+perturb));
return dist;
}
vec3 calc_normal_body(Scene scene, vec3 p)
{
vec2 e = vec2(0, 0.0001);
return normalize(vec3(map_body(scene,p+e.yxx),
map_body(scene,p+e.xyx),
map_body(scene,p+e.xxy)) -
vec3(map_body(scene,p)));
}
vec3 render(Scene scene, vec2 uv)
{
float cam_angle = 0.0 * 6.28;
vec3 ro = 2.0*vec3(sin(cam_angle), 0.2, -cos(cam_angle));
vec3 at = vec3(0);
vec3 cam_z = normalize(at - ro);
vec3 cam_x = normalize(cross(vec3(0, 1, 0), cam_z));
vec3 cam_y = cross(cam_z, cam_x);
vec3 rd = normalize(uv.x * cam_x + uv.y * cam_y + 1.3 * cam_z);
bool hit = false;
float t = 0.0;
for (int i = 0; i < 256; ++i)
{
vec3 p = ro + t * rd;
float dist = 0.1*map_shell(scene, p);
if (dist < 0.001)
{
hit = true;
break;
}
t += dist;
}
bool hit_inner = false;
float t_inner = 0.0;
for (int i = 0; i < 256; ++i)
{
vec3 p = ro + t_inner * rd;
float dist = map_body(scene, p);
if (dist < 0.001)
{
hit_inner = true;
break;
}
t_inner += dist;
}
vec3 glass_f0 = vec3(0.5);
vec3 water_f0 = vec3(0.3);
vec3 keyLightCol = 1.5*vec3(1);//vec3(0.3, 0.5, 1.1);
vec3 keyLightDir = normalize(vec3(0.0,0.9,0.5));
vec3 waterDifCol = 1.3*vec3(0.3,0.6,0.8);
vec3 bgCol = texture(iChannel0, rd).rgb;
bgCol = bgCol * bgCol; // gamma -> linear
vec3 col = bgCol;
vec3 glass_fre = vec3(1);
if (hit)
{
vec3 p = ro + t * rd;
vec3 n = calc_normal_shell(scene, p);
vec3 l = rd - 2.0 * dot(rd, n) * n;
glass_fre = glass_f0 + (vec3(1) - glass_f0) * pow(1.0 - dot(n, l), 5.0);
{
float keyLightCos = dot(keyLightDir, l);
vec3 keyLight = texture(iChannel1, l).rgb;
vec3 spe = keyLight * glass_fre;
col = spe;
}
}
if (hit_inner)
{
vec3 p = ro + t_inner * rd;
vec3 n = calc_normal_body(scene, p);
vec3 l = rd - 2.0 * dot(rd, n) * n;
vec3 fre = water_f0 + (vec3(1) - water_f0) * pow(1.0 - dot(n, l), 5.0);
{
float keyLightCos = dot(keyLightDir, l);
vec3 keyLight = texture(iChannel1, l).rgb;
vec3 spe = keyLight * fre;
vec3 dif = waterDifCol * keyLightCol * (0.05 + 0.3 * (0.5 + 0.5 * keyLightCos));
col = mix(col, spe + dif, 1.0-glass_fre);
}
}
else
{
col = mix(col, bgCol,1.0-glass_fre);
}
return col;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = fragCoord/iResolution.xy;
uv = 2.0 * uv - 1.0;
uv.x *= iResolution.x / iResolution.y;
#define SIM1_DATA_IDX 0
#define SIM2_DATA_IDX 1
#define DATA_STRIDE 2
// simulation data stored in double-buffered packs of floats for persistent storage
int currPackIdx = iFrame & 1;
int nextPackIdx = (iFrame + 1) & 1;
vec4 sim1Data = texelFetch(iChannel2, ivec2(DATA_STRIDE*currPackIdx + SIM1_DATA_IDX, 0), 0);
vec4 sim2Data = texelFetch(iChannel2, ivec2(DATA_STRIDE*currPackIdx + SIM2_DATA_IDX, 0), 0);
vec2 prevMouseCoord = sim1Data.xy;
vec2 prevRot = sim1Data.zw;
vec2 prevStre = sim2Data.xy;
// reference: https://shadertoyunofficial.wordpress.com/2016/07/20/special-shadertoy-features/
bool mouseDown = iMouse.z > 0. && iMouse.w < 0.;
// compute current rotation
vec2 deltaRot = vec2(0);
if (iMouse.x > 0. && mouseDown)
deltaRot.x = (iMouse.x - prevMouseCoord.x) / 800.0 * 6.28;
if (iMouse.y > 0. && mouseDown)
deltaRot.y -= (iMouse.y - prevMouseCoord.y) / 450.0 * 6.28;
vec2 currRot = prevRot + deltaRot;
// dampening oscillation
vec2 stre = 0.3*abs(deltaRot) + 0.987*prevStre;
stre = min(vec2(0.5), stre);
// special routine for data pixels (not color pixels)
ivec2 iFragCoord = ivec2(fragCoord);
int nextPackBegin = nextPackIdx * DATA_STRIDE;
int nextPackEnd = nextPackBegin + DATA_STRIDE;
if (iFragCoord.x >= nextPackBegin && iFragCoord.y < nextPackEnd && iFragCoord.y == 0)
{
int dataIdx = iFragCoord.x - nextPackBegin;
if (dataIdx == SIM1_DATA_IDX)
fragColor = vec4(iMouse.xy, currRot);
if (dataIdx == SIM2_DATA_IDX)
fragColor = vec4(stre, 0, 0);
return;
}
Scene scene;
scene.rot = currRot;
scene.stre = stre;
vec3 col = render(scene, uv);
col = sqrt(col);
fragColor = vec4(col,1.0);
}

View File

@ -0,0 +1,306 @@
#define line1 h_ e_ l_ l_ o_ _ s_ h_ a_ d_ e_ r_ t_ o_ y_ crlf
#define line2 t_ h_ i_ s_ _ i_ s_ _ m_ y_ _ f_ o_ n_ t_ crlf
#define line3 h_ o_ p_ e_ _ y_ o_ u_ _ l_ i_ k_ e_ _ i_ t_ crlf
#define line4 f_ e_ e_ l_ _ f_ r_ e_ e_ _ t_ o_ _ u_ s_ e_ crlf
#define line5 _ a_ b_ c_ d_ e_ f_ g_ h_ i_ j_ k_ l_ m_ crlf
#define line6 _ n_ o_ p_ q_ r_ s_ t_ u_ v_ w_ x_ y_ z_
//======Start shared code for state
#define pz_stateYOffset 0.0
#define pz_stateBuf 0
#define pz_stateSample(x) texture(iChannel0,x)
vec2 pz_realBufferResolution;
vec2 pz_originalBufferResolution;
float pz_scale;
void pz_initializeState() {
pz_realBufferResolution = iChannelResolution[pz_stateBuf].xy;
pz_originalBufferResolution = pz_stateSample(.5/pz_realBufferResolution).xy;
}
vec2 pz_nr2vec(float nr) {
return vec2(mod(nr, pz_originalBufferResolution.x)
, pz_stateYOffset+floor(nr / pz_originalBufferResolution.x))+.5;
}
vec4 pz_readState(float nr) {
return pz_stateSample(pz_nr2vec(nr)/pz_realBufferResolution);
}
float pz_resetCount() {
return pz_readState(1.).z;
}
vec3 pz_position() {
return pz_readState(3.).xyz;
}
vec2 pz_initializeState(vec2 fragCoord) {
pz_initializeState();
vec3 position = pz_position();
fragCoord -= 0.5*iResolution.xy;
fragCoord *= pz_scale = position.z;
fragCoord += (0.5 + position.xy) * iResolution.xy ;
return fragCoord;
}
//======End shared code for state
// line function, used in k, s, v, w, x, y, z
float line(vec2 p, vec2 a, vec2 b)
{
vec2 pa = p - a;
vec2 ba = b - a;
float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
return length(pa - ba * h);
}
//These functions are re-used by multiple letters
float _u(vec2 uv,float w,float v) {
return length(vec2(
abs(length(vec2(uv.x,
max(0.0,-(.4-v)-uv.y) ))-w)
,max(0.,uv.y-.4))) +.4;
}
float _i(vec2 uv) {
return length(vec2(uv.x,max(0.,abs(uv.y)-.4)))+.4;
}
float _j(vec2 uv) {
uv.x+=.2;
float t = _u(uv,.25,-.15);
float x = uv.x>0.?t:length(vec2(uv.x,uv.y+.8))+.4;
return x;
}
float _l(vec2 uv) {
uv.y -= .2;
return length(vec2(uv.x,max(0.,abs(uv.y)-.6)))+.4;
}
float _o(vec2 uv) {
return abs(length(vec2(uv.x,max(0.,abs(uv.y)-.15)))-.25)+.4;
}
// Here is the alphabet
float aa(vec2 uv) {
uv = -uv;
float x = abs(length(vec2(max(0.,abs(uv.x)-.05),uv.y-.2))-.2)+.4;
x = min(x,length(vec2(uv.x+.25,max(0.,abs(uv.y-.2)-.2)))+.4);
return min(x,(uv.x<0.?uv.y<0.:atan(uv.x,uv.y+0.15)>2.)?_o(uv):length(vec2(uv.x-.22734,uv.y+.254))+.4);
}
float bb(vec2 uv) {
float x = _o(uv);
uv.x += .25;
return min(x,_l(uv));
}
float cc(vec2 uv) {
float x = _o(uv);
uv.y= abs(uv.y);
return uv.x<0.||atan(uv.x,uv.y-0.15)<1.14?x:length(vec2(uv.x-.22734,uv.y-.254))+.4;
}
float dd(vec2 uv) {
uv.x *= -1.;
return bb(uv);
}
float ee(vec2 uv) {
float x = _o(uv);
return min(uv.x<0.||uv.y>.05||atan(uv.x,uv.y+0.15)>2.?x:length(vec2(uv.x-.22734,uv.y+.254))+.4,
length(vec2(max(0.,abs(uv.x)-.25),uv.y-.05))+.4);
}
float ff(vec2 uv) {
uv.x *= -1.;
uv.x += .05;
float x = _j(vec2(uv.x,-uv.y));
uv.y -= .4;
x = min(x,length(vec2(max(0.,abs(uv.x-.05)-.25),uv.y))+.4);
return x;
}
float gg(vec2 uv) {
float x = _o(uv);
return min(x,uv.x>0.||uv.y<-.65?_u(uv,0.25,-0.2):length(vec2(uv.x+0.25,uv.y+.65))+.4 );
}
float hh(vec2 uv) {
uv.y *= -1.;
float x = _u(uv,.25,.25);
uv.x += .25;
uv.y *= -1.;
return min(x,_l(uv));
}
float ii(vec2 uv) {
return min(_i(uv),length(vec2(uv.x,uv.y-.7))+.4);
}
float jj(vec2 uv) {
uv.x += .05;
return min(_j(uv),length(vec2(uv.x-.05,uv.y-.7))+.4);
}
float kk(vec2 uv) {
float x = line(uv,vec2(-.25,-.1), vec2(0.25,0.4))+.4;
x = min(x,line(uv,vec2(-.15,.0), vec2(0.25,-0.4))+.4);
uv.x+=.25;
return min(x,_l(uv));
}
float ll(vec2 uv) {
return _l(uv);
}
float mm(vec2 uv) {
//uv.x *= 1.4;
uv.y *= -1.;
uv.x-=.175;
float x = _u(uv,.175,.175);
uv.x+=.35;
x = min(x,_u(uv,.175,.175));
uv.x+=.175;
return min(x,_i(uv));
}
float nn(vec2 uv) {
uv.y *= -1.;
float x = _u(uv,.25,.25);
uv.x+=.25;
return min(x,_i(uv));
}
float oo(vec2 uv) {
return _o(uv);
}
float pp(vec2 uv) {
float x = _o(uv);
uv.x += .25;
uv.y += .4;
return min(x,_l(uv));
}
float qq(vec2 uv) {
uv.x = -uv.x;
return pp(uv);
}
float rr(vec2 uv) {
float x =atan(uv.x,uv.y-0.15)<1.14&&uv.y>0.?_o(uv):length(vec2(uv.x-.22734,uv.y-.254))+.4;
//)?_o(uv):length(vec2(uv.x-.22734,uv.y+.254))+.4);
uv.x+=.25;
return min(x,_i(uv));
}
float ss(vec2 uv) {
if (uv.y <.145 && uv.x>0. || uv.y<-.145)
uv = -uv;
float x = atan(uv.x-.05,uv.y-0.2)<1.14?
abs(length(vec2(max(0.,abs(uv.x)-.05),uv.y-.2))-.2)+.4:
length(vec2(uv.x-.231505,uv.y-.284))+.4;
return x;
}
float tt(vec2 uv) {
uv.x *= -1.;
uv.y -= .4;
uv.x += .05;
float x = min(_j(uv),length(vec2(max(0.,abs(uv.x-.05)-.25),uv.y))+.4);
return x;
}
float uu(vec2 uv) {
return _u(uv,.25,.25);
}
float vv(vec2 uv) {
uv.x=abs(uv.x);
return line(uv,vec2(0.25,0.4), vec2(0.,-0.4))+.4;
}
float ww(vec2 uv) {
uv.x=abs(uv.x);
return min(line(uv,vec2(0.3,0.4), vec2(.2,-0.4))+.4,
line(uv,vec2(0.2,-0.4), vec2(0.,0.1))+.4);
}
float xx(vec2 uv) {
uv=abs(uv);
return line(uv,vec2(0.,0.), vec2(.3,0.4))+.4;
}
float yy(vec2 uv) {
return min(line(uv,vec2(.0,-.2), vec2(-.3,0.4))+.4,
line(uv,vec2(.3,.4), vec2(-.3,-0.8))+.4);
}
float zz(vec2 uv) {
float l = line(uv,vec2(0.25,0.4), vec2(-0.25,-0.4))+.4;
uv.y=abs(uv.y);
float x = length(vec2(max(0.,abs(uv.x)-.25),uv.y-.4))+.4;
return min(x,l);
}
// Spare Q :)
float Q(vec2 uv) {
float x = _o(uv);
uv.y += .3;
uv.x -= .2;
return min(x,length(vec2(abs(uv.x+uv.y),max(0.,abs(uv.x-uv.y)-.2)))/sqrt(2.) +.4);
}
//Render char if it's up
#define ch(l) if (nr++==ofs) x=min(x,l(uv));
//Make it a bit easier to type text
#define a_ ch(aa);
#define b_ ch(bb);
#define c_ ch(cc);
#define d_ ch(dd);
#define e_ ch(ee);
#define f_ ch(ff);
#define g_ ch(gg);
#define h_ ch(hh);
#define i_ ch(ii);
#define j_ ch(jj);
#define k_ ch(kk);
#define l_ ch(ll);
#define m_ ch(mm);
#define n_ ch(nn);
#define o_ ch(oo);
#define p_ ch(pp);
#define q_ ch(qq);
#define r_ ch(rr);
#define s_ ch(ss);
#define t_ ch(tt);
#define u_ ch(uu);
#define v_ ch(vv);
#define w_ ch(ww);
#define x_ ch(xx);
#define y_ ch(yy);
#define z_ ch(zz);
//Space
#define _ nr++;
//Next line
#define crlf uv.y += 2.0; nr = 0.;
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
fragCoord = pz_initializeState(fragCoord);
float scale = 1.0;//3.5-3.0*sin(iGlobalTime*.2);
vec2 uv = (fragCoord-0.5*iResolution.xy) / iResolution.x * 22.0 * scale;
float ofs = floor(uv.x)+8.;
uv.x = mod(uv.x,1.0)-.5;
float x = 100.;
float nr = 0.;
uv.y -= 5.;
line1;
line2;
line3;
line4;
line5;
line6;
vec3 clr = vec3(0.0);
float px = 17.0/iResolution.x*pz_scale;
clr.r = 0.7-0.7*smoothstep(0.49-px,0.49+px, x); // The body
clr.g = 0.7-0.7*smoothstep(0.00,px*1.5, abs(x-0.49+px)); // Yellow outline
clr.b = 0.4-0.4*smoothstep(0.43,0.53,1.0-x); // Background with shadow
clr.rg += 0.12-0.12*smoothstep(0.00,0.1+px, abs(x-0.49+px)); // Yellow glow
if (iMouse.w>0.1) {
clr.rgb = vec3(smoothstep(0.49-px,0.49+px, x));
}
fragColor = vec4(clamp(clr,0.0,1.0),1.0);
}

View File

@ -0,0 +1,318 @@
// Created by Reinder Nijhoff 2013
// @reindernijhoff
// empirical measured values
#define EYEDISTANCE 5.15
#define LENSDISTANCE -0.136
#define FOV 0.62
#define SHADOW
//#define REFLECTION
#define RAYCASTSTEPS 30
#define EXPOSURE 0.9
#define EPSILON 0.0001
#define MAXDISTANCE 400.
#define GRIDSIZE 10.
#define GRIDSIZESMALL 8.
#define MAXHEIGHT 10.
#define SPEED 2.5
float time;
//
// math functions
//
const mat2 mr = mat2 (0.84147, 0.54030,
0.54030, -0.84147 );
float hash( float n ) {
return fract(sin(n)*43758.5453);
}
vec2 hash2( float n ) {
return fract(sin(vec2(n,n+1.0))*vec2(2.1459123,3.3490423));
}
vec2 hash2( vec2 n ) {
return fract(sin(vec2( n.x*n.y, n.x+n.y))*vec2(2.1459123,3.3490423));
}
vec3 hash3( float n ) {
return fract(sin(vec3(n,n+1.0,n+2.0))*vec3(3.5453123,4.1459123,1.3490423));
}
vec3 hash3( vec2 n ) {
return fract(sin(vec3(n.x, n.y, n+2.0))*vec3(3.5453123,4.1459123,1.3490423));
}
//
// intersection functions
//
bool intersectPlane(vec3 ro, vec3 rd, float height, out float dist) {
if (rd.y==0.0) {
return false;
}
float d = -(ro.y - height)/rd.y;
d = min(100000.0, d);
if( d > 0. ) {
dist = d;
return true;
}
return false;
}
bool intersectUnitSphere ( in vec3 ro, in vec3 rd, in vec3 sph, out float dist, out vec3 normal ) {
vec3 ds = ro - sph;
float bs = dot( rd, ds );
float cs = dot( ds, ds ) - 1.0;
float ts = bs*bs - cs;
if( ts > 0.0 ) {
ts = -bs - sqrt( ts );
if( ts>0. ) {
normal = normalize( (ro+ts*rd)-sph );
dist = ts;
return true;
}
}
return false;
}
//
// Scene
//
void getSphereOffset( vec2 grid, inout vec2 center ) {
center = (hash2( grid+vec2(43.12,1.23) ) - vec2(0.5) )*(GRIDSIZESMALL);
}
void getMovingSpherePosition( vec2 grid, vec2 sphereOffset, inout vec3 center ) {
// falling?
float s = 0.1+hash( grid.x*1.23114+5.342+754.324231*grid.y );
float t = 14.*s + time/s;
float y = s * MAXHEIGHT * abs( cos( t ) );
vec2 offset = grid + sphereOffset;
center = vec3( offset.x, y, offset.y ) + 0.5*vec3( GRIDSIZE, 2., GRIDSIZE );
}
void getSpherePosition( vec2 grid, vec2 sphereOffset, inout vec3 center ) {
vec2 offset = grid + sphereOffset;
center = vec3( offset.x, 0., offset.y ) + 0.5*vec3( GRIDSIZE, 2., GRIDSIZE );
}
vec3 getSphereColor( vec2 grid ) {
return normalize( hash3( grid+vec2(43.12*grid.y,12.23*grid.x) ) );
}
vec3 trace(vec3 ro, vec3 rd, out vec3 intersection, out vec3 normal, out float dist, out int material) {
material = 0; // sky
dist = MAXDISTANCE;
float distcheck;
vec3 sphereCenter, col, normalcheck;
if( intersectPlane( ro, rd, 0., distcheck) && distcheck < MAXDISTANCE ) {
dist = distcheck;
material = 1;
normal = vec3( 0., 1., 0. );
col = vec3( 1. );
} else {
col = vec3( 0. );
}
// trace grid
vec2 map = floor( ro.xz / GRIDSIZE ) * GRIDSIZE;
float deltaDistX = GRIDSIZE*sqrt(1. + (rd.z * rd.z) / (rd.x * rd.x));
float deltaDistY = GRIDSIZE*sqrt(1. + (rd.x * rd.x) / (rd.z * rd.z));
float stepX, stepY, sideDistX, sideDistY;
//calculate step and initial sideDist
if (rd.x < 0.) {
stepX = -GRIDSIZE;
sideDistX = (ro.x - map.x) * deltaDistX / GRIDSIZE;
} else {
stepX = GRIDSIZE;
sideDistX = (map.x + GRIDSIZE - ro.x) * deltaDistX / GRIDSIZE;
}
if (rd.z < 0.) {
stepY = -GRIDSIZE;
sideDistY = (ro.z - map.y) * deltaDistY / GRIDSIZE;
} else {
stepY = GRIDSIZE;
sideDistY = (map.y + GRIDSIZE - ro.z) * deltaDistY / GRIDSIZE;
}
bool hit = false;
for( int i=0; i<RAYCASTSTEPS; i++ ) {
if( hit || distance( ro.xz, map ) > dist+GRIDSIZE ) continue;
vec2 offset;
getSphereOffset( map, offset );
getMovingSpherePosition( map, -offset, sphereCenter );
if( intersectUnitSphere( ro, rd, sphereCenter, distcheck, normalcheck ) && distcheck < dist ) {
dist = distcheck;
normal = normalcheck;
material = 2;
hit = true;
}
getSpherePosition( map, offset, sphereCenter );
if( intersectUnitSphere( ro, rd, sphereCenter, distcheck, normalcheck ) && distcheck < dist ) {
dist = distcheck;
normal = normalcheck;
col = vec3( 2. );
material = 3;
hit = true;
}
if (sideDistX < sideDistY) {
sideDistX += deltaDistX;
map.x += stepX;
} else {
sideDistY += deltaDistY;
map.y += stepY;
}
}
vec3 color = vec3( 0. );
if( (hit || material == 1) ) {
intersection = ro + rd*dist;
vec2 map = intersection.xz - mod( intersection.xz, vec2(GRIDSIZE,GRIDSIZE) );
if( material == 1 || material == 3 ) {
// lightning
vec3 c = vec3( -GRIDSIZE,0., GRIDSIZE );
for( int x=0; x<3; x++ ) {
for( int y=0; y<3; y++ ) {
vec2 mapoffset = map+vec2( c[x], c[y] );
vec2 offset;
getSphereOffset( mapoffset, offset );
vec3 lcolor = getSphereColor( mapoffset );
vec3 lpos;
getMovingSpherePosition( mapoffset, -offset, lpos );
float shadow = 1.;
#ifdef SHADOW
if( material == 1 ) {
for( int sx=0; sx<3; sx++ ) {
for( int sy=0; sy<3; sy++ ) {
if( shadow < 1. ) continue;
vec2 smapoffset = map+vec2( c[sx], c[sy] );
vec2 soffset;
getSphereOffset( smapoffset, soffset );
vec3 slpos, sn;
getSpherePosition( smapoffset, soffset, slpos );
float sd;
if( intersectUnitSphere( intersection, normalize( lpos - intersection ), slpos, sd, sn ) ) {
shadow = 0.;
}
}
}
}
#endif
color += col * lcolor * ( shadow * max( dot( normalize(lpos-intersection), normal ), 0.) *
(1. - clamp( distance( lpos, intersection )/GRIDSIZE, 0., 1.) ) );
}
}
} else {
// emitter
color = (1.5+dot(normal, vec3( 0.5, 0.5, -0.5) )) *getSphereColor( map );
}
}
return color;
}
// left
float w = 1.0;
float h = 1.0;
float scaleFactor = 1.0;
vec2 leftLensCenter = vec2( LENSDISTANCE, 0. );
vec2 rightLensCenter = vec2( -LENSDISTANCE, 0. );
vec2 Scale;
vec2 ScaleIn = vec2( 1., 1.);
vec4 HmdWarpParam = vec4(1., 0.22, 0.24, 0);
vec2 HmdWarp(vec2 in01, vec2 lensCenter) {
vec2 theta = (in01-lensCenter) * ScaleIn; // Scales to [-1, 1]
float rSq = dot(theta, theta);
vec2 rvector = theta *
(HmdWarpParam.x + HmdWarpParam.y * rSq +
HmdWarpParam.z * rSq * rSq +
HmdWarpParam.w * rSq * rSq * rSq);
return lensCenter + Scale * rvector;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
Scale = 0.65*vec2( 1., iResolution.x/iResolution.y );
time = iGlobalTime;
vec2 q = fragCoord.xy/iResolution.xy;
vec2 p = 2.0*q;
p.x *= 2.;
bool lefteye = true;
if( p.x > 2. ) {
p.x -= 2.;
lefteye = false;
}
p -= vec2(1.);
p = HmdWarp( p, lefteye?leftLensCenter:rightLensCenter );
p.x *= iResolution.x/iResolution.y;
// camera
vec3 ce = vec3( cos( 0.232*time) * 10., 7.+3.*cos(0.3*time), GRIDSIZE*(time/SPEED) );
vec3 ro = ce;
vec3 ta = ro + vec3( -sin( 0.232*time) * 10., -2.0+cos(0.23*time), 10.0 );
float roll = -0.15*sin(0.5*time);
// camera tx
vec3 cw = normalize( ta-ro );
vec3 cp = vec3( sin(roll), cos(roll),0.0 );
vec3 cu = normalize( cross(cw,cp) );
vec3 cv = normalize( cross(cu,cw) );
vec3 go = vec3( 0.0 );
go.x = (lefteye?-0.5*EYEDISTANCE:0.5*EYEDISTANCE);
ro += go.x*cu + go.y*cv;
// create offset voor left or right eye
vec3 er = normalize( vec3( p.xy, FOV ) );
vec3 rd = er.x*cu + er.y*cv + er.z*cw;
// raytrace
int material;
vec3 normal, intersection;
float dist;
vec3 col = trace(ro, rd, intersection, normal, dist, material);
#ifdef REFLECTION
if( material > 0 ) {
vec3 ro = intersection + EPSILON*normal;
rd = reflect( rd, normal );
col += 0.05 * trace(ro, rd, intersection, normal, dist, material);
}
#endif
col = pow( col, vec3(EXPOSURE, EXPOSURE, EXPOSURE) );
col = clamp(col, 0.0, 1.0);
fragColor = vec4( col,1.0);
}

View File

@ -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);
}

Binary file not shown.

View File

@ -0,0 +1,51 @@
#!/bin/bash 2>nul || goto :windows
if [ "$1" = "" ]; then
sh MAKE.bat demo_collide.c
exit
fi
## clone emscripten sdk
git clone https://github.com/emscripten-core/emsdk ../../../../../emsdk
pushd ../../../../../emsdk
./emsdk install 3.0.0 ## latest
./emsdk activate 3.0.0 ## latest
source ./emsdk_env.sh
popd
## cook art
if [ "$(uname)" = "Darwin" ]; then
chmod +x ../../../tools/cook.osx
../../../tools/cook.osx
else
chmod +x ../../../tools/cook.linux
../../../tools/cook.linux
fi
## host webserver, compile and launch
python -m http.server --bind 127.0.0.1 8000 1> /dev/null 2> /dev/null &
emcc $@ -g ../../../code/v4k.c -I../../../code -o index.html -s FULL_ES3 -s USE_GLFW=3 -s SINGLE_FILE=1 -s PRECISE_F32=1 -s TOTAL_MEMORY=256mb -s ENVIRONMENT=worker,web --shell-file template.html -Wfatal-errors --preload-file .art[00].zip -s ALLOW_MEMORY_GROWTH=1 -lidbfs.js && xdg-open http://localhost:8000/index.html
exit
:windows
if "%1"=="" MAKE.bat demo_ui.c
rem clone emscripten sdk
if not exist "emsdk" (
git clone https://github.com/emscripten-core/emsdk emsdk
pushd emsdk
call emsdk install 3.0.0 && rem latest
call emsdk activate 3.0.0 && rem latest
popd
)
if "%EMSDK%"=="" call emsdk\emsdk_env.bat --system
rem cook art
..\..\tools\cook.exe --cook-jobs=1 --cook-ini=..\..\tools\cook.ini
rem host webserver, compile and launch
rem start python -m http.server --bind 127.0.0.1 8000
emcc %* -g ..\..\engine\v4k.c -I..\..\engine -o index.html -pthread -s FULL_ES3 -s USE_PTHREADS -s USE_GLFW=3 -s SINGLE_FILE=1 -s PRECISE_F32=1 -s TOTAL_MEMORY=256mb -s ENVIRONMENT=worker,web --shell-file template.html -Wfatal-errors --preload-file .art[00].zip -s ALLOW_MEMORY_GROWTH=1 -lidbfs.js
rem && start "" http://localhost:8000/index.html

View File

@ -0,0 +1,20 @@
## Known HTML5 issues:
- [x] Game loop is event based (fixed: see `window_loop()`)
- [x] No automated emsdk installation (fixed: see `demos/html5/MAKE.bat`)
- [x] Art must be cooked beforehand (fixed: see `demos/html5/MAKE.bat`)
- [x] No VFS loading (fixed)
- [x] No UI rendering (fixed)
- [x] No cooker (fixed: win,osx,linux)
- [x] No input (fixed)
- [x] No gamepads (fixed)
- [x] No multi-touch (fixed)
- [ ] No audio
- [ ] No file writing (untested)
- [ ] No glTexture1D()
- [ ] No network
- [ ] No fbos
- [ ] No callstacks
- [ ] No pbos
- [ ] Shaders require (automated?) GL->GLES translation (No postfxs, models, skyboxes, pbrs, ...) (@todo: embed Spir-v/glslcross tools?)
- [ ] Shaders: `vec2 iResolution = vec2(iWidth, iHeight); // ERROR: '=' : global variable initializers must be constant expressions`
- [ ] Shaders: `uniform float var = 1.0f; // ERROR: 'uniform' : cannot initialize this type of qualifier`

View File

@ -0,0 +1,118 @@
/*! coi-serviceworker v0.1.7 - Guido Zuidhof and contributors, licensed under MIT */
let coepCredentialless = false;
if (typeof window === 'undefined') {
self.addEventListener("install", () => self.skipWaiting());
self.addEventListener("activate", (event) => event.waitUntil(self.clients.claim()));
self.addEventListener("message", (ev) => {
if (!ev.data) {
return;
} else if (ev.data.type === "deregister") {
self.registration
.unregister()
.then(() => {
return self.clients.matchAll();
})
.then(clients => {
clients.forEach((client) => client.navigate(client.url));
});
} else if (ev.data.type === "coepCredentialless") {
coepCredentialless = ev.data.value;
}
});
self.addEventListener("fetch", function (event) {
const r = event.request;
if (r.cache === "only-if-cached" && r.mode !== "same-origin") {
return;
}
const request = (coepCredentialless && r.mode === "no-cors")
? new Request(r, {
credentials: "omit",
})
: r;
event.respondWith(
fetch(request)
.then((response) => {
if (response.status === 0) {
return response;
}
const newHeaders = new Headers(response.headers);
newHeaders.set("Cross-Origin-Embedder-Policy",
coepCredentialless ? "credentialless" : "require-corp"
);
if (!coepCredentialless) {
newHeaders.set("Cross-Origin-Resource-Policy", "cross-origin");
}
newHeaders.set("Cross-Origin-Opener-Policy", "same-origin");
return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: newHeaders,
});
})
.catch((e) => console.error(e))
);
});
} else {
(() => {
// You can customize the behavior of this script through a global `coi` variable.
const coi = {
shouldRegister: () => true,
shouldDeregister: () => false,
coepCredentialless: () => (window.chrome !== undefined || window.netscape !== undefined),
doReload: () => window.location.reload(),
quiet: false,
...window.coi
};
const n = navigator;
if (n.serviceWorker && n.serviceWorker.controller) {
n.serviceWorker.controller.postMessage({
type: "coepCredentialless",
value: coi.coepCredentialless(),
});
if (coi.shouldDeregister()) {
n.serviceWorker.controller.postMessage({ type: "deregister" });
}
}
// If we're already coi: do nothing. Perhaps it's due to this script doing its job, or COOP/COEP are
// already set from the origin server. Also if the browser has no notion of crossOriginIsolated, just give up here.
if (window.crossOriginIsolated !== false || !coi.shouldRegister()) return;
if (!window.isSecureContext) {
!coi.quiet && console.log("COOP/COEP Service Worker not registered, a secure context is required.");
return;
}
// In some environments (e.g. Chrome incognito mode) this won't be available
if (n.serviceWorker) {
n.serviceWorker.register(window.document.currentScript.src).then(
(registration) => {
!coi.quiet && console.log("COOP/COEP Service Worker registered", registration.scope);
registration.addEventListener("updatefound", () => {
!coi.quiet && console.log("Reloading page to make use of updated COOP/COEP Service Worker.");
coi.doReload();
});
// If the registration is active, but it's not controlling the page
if (registration.active && !n.serviceWorker.controller) {
!coi.quiet && console.log("Reloading page to make use of COOP/COEP Service Worker.");
coi.doReload();
}
},
(err) => {
!coi.quiet && console.error("COOP/COEP Service Worker failed to register:", err);
}
);
}
})();
}

View File

@ -0,0 +1,2 @@
/*! coi-serviceworker v0.1.7 - Guido Zuidhof and contributors, licensed under MIT */
let coepCredentialless=!1;"undefined"==typeof window?(self.addEventListener("install",(()=>self.skipWaiting())),self.addEventListener("activate",(e=>e.waitUntil(self.clients.claim()))),self.addEventListener("message",(e=>{e.data&&("deregister"===e.data.type?self.registration.unregister().then((()=>self.clients.matchAll())).then((e=>{e.forEach((e=>e.navigate(e.url)))})):"coepCredentialless"===e.data.type&&(coepCredentialless=e.data.value))})),self.addEventListener("fetch",(function(e){const r=e.request;if("only-if-cached"===r.cache&&"same-origin"!==r.mode)return;const s=coepCredentialless&&"no-cors"===r.mode?new Request(r,{credentials:"omit"}):r;e.respondWith(fetch(s).then((e=>{if(0===e.status)return e;const r=new Headers(e.headers);return r.set("Cross-Origin-Embedder-Policy",coepCredentialless?"credentialless":"require-corp"),coepCredentialless||r.set("Cross-Origin-Resource-Policy","cross-origin"),r.set("Cross-Origin-Opener-Policy","same-origin"),new Response(e.body,{status:e.status,statusText:e.statusText,headers:r})})).catch((e=>console.error(e))))}))):(()=>{const e={shouldRegister:()=>!0,shouldDeregister:()=>!1,coepCredentialless:()=>(window.chrome!==undefined||window.netscape!==undefined),doReload:()=>window.location.reload(),quiet:!1,...window.coi},r=navigator;r.serviceWorker&&r.serviceWorker.controller&&(r.serviceWorker.controller.postMessage({type:"coepCredentialless",value:e.coepCredentialless()}),e.shouldDeregister()&&r.serviceWorker.controller.postMessage({type:"deregister"})),!1===window.crossOriginIsolated&&e.shouldRegister()&&(window.isSecureContext?r.serviceWorker&&r.serviceWorker.register(window.document.currentScript.src).then((s=>{!e.quiet&&console.log("COOP/COEP Service Worker registered",s.scope),s.addEventListener("updatefound",(()=>{!e.quiet&&console.log("Reloading page to make use of updated COOP/COEP Service Worker."),e.doReload()})),s.active&&!r.serviceWorker.controller&&(!e.quiet&&console.log("Reloading page to make use of COOP/COEP Service Worker."),e.doReload())}),(r=>{!e.quiet&&console.error("COOP/COEP Service Worker failed to register:",r)})):!e.quiet&&console.log("COOP/COEP Service Worker not registered, a secure context is required."))})();

View File

@ -0,0 +1,616 @@
// original code by @vurtun (public domain)
// - rlyeh, public domain.
//
// @todo: fix leaks: poly_free()
#include "v4k.h"
// -- demo
int paused;
camera_t cam;
void game_loop(void *userdata) {
// key handler
if (input_down(KEY_F11) ) window_fullscreen( window_has_fullscreen()^1 );
if (input_down(KEY_ESC) ) window_loop_exit(); // @todo: break -> window_close()
// animation
static float dx = 0, dy = 0;
if (input_down(KEY_SPACE)) paused ^= 1;
float delta = (0.25f / 60.f) * !paused;
dx = dx + delta * 2.0f;
dy = dy + delta * 0.8f;
// fps camera
{
vec3 move = {0};
vec2 view = {0};
// show/hide cursor
bool dragging = input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
if( ui_active() || ui_hover() || gizmo_active() || input_touch_active() ) dragging = false;
window_cursor( !dragging );
// keyboard/mouse
if( dragging ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
vec3 wasdec = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-input(KEY_C),input(KEY_W)-input(KEY_S)), cam.speed);
vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * dragging);
move = add3(move, wasdec);
view = add2(view, mouse);
// gamepad
vec2 filtered_lpad = input_filter_deadzone(input2(GAMEPAD_LPAD), 0.15f /*15% deadzone*/);
vec2 filtered_rpad = input_filter_deadzone(input2(GAMEPAD_RPAD), 0.15f /*15% deadzone*/);
vec3 gamepad_move = scale3(vec3(filtered_lpad.x, input(GAMEPAD_LT) - input(GAMEPAD_RT), filtered_lpad.y), 1.0f);
vec2 gamepad_view = scale2(filtered_rpad, 1.0f);
move = add3(move, gamepad_move);
view = add2(view, gamepad_view);
// multi-touch
vec2 touch_move = input_touch_delta_from_origin(0, 0.0125f /*sensitivityFwd*/); // button #0 (left border)
vec2 touch_view = input_touch_delta(1, 0.125f /*sensitivityRot*/); // button #1 (right border)
move = add3(move, vec3(touch_move.x, 0, -touch_move.y));
view = add2(view, vec2(touch_view.x, -touch_view.y));
// apply inputs
camera_move(&cam, move.x,move.y,move.z);
camera_fps(&cam, view.x,view.y);
}
// projview matrix
mat44 projview; multiply44x2(projview, cam.proj, cam.view);
// rendering
viewport_color3(vec3(0.15,0.15,0.15));
#if 0
viewport_clear(true, true);
viewport_clip(vec2(0,0), vec2(window_width(), window_height()));
#endif
// debug draw collisions
{
// 3D
glEnable(GL_DEPTH_TEST);
// grid
ddraw_grid(0);
{
// Triangle-Ray Intersection*/
vec3 ro, rd;
int suc;
triangle tri = { vec3(-9,1,28), vec3(-10,0,28), vec3(-11,1,28) };
// ray
ro = vec3(-10,-1,20);
rd = vec3(-10+0.4f*sinf(dx), 2.0f*cosf(dy), 29.81023f);
rd = sub3(rd, ro);
rd = norm3(rd);
ray r = ray(ro, rd);
hit *hit = ray_hit_triangle(r, tri);
if (hit) {
// point of intersection
ddraw_color(RED);
ddraw_box(hit->p, vec3(0.10f, 0.10f, 0.10f));
// intersection normal
ddraw_color(BLUE);
vec3 v = add3(hit->p, hit->n);
ddraw_arrow(hit->p, v);
}
// line
ddraw_color(RED);
rd = scale3(rd,10);
rd = add3(ro,rd);
ddraw_line(ro, rd);
// triangle
if (hit) ddraw_color(RED);
else ddraw_color(WHITE);
ddraw_triangle(tri.p0,tri.p1,tri.p2);
}
{
// Plane-Ray Intersection*/
vec3 ro, rd;
mat33 rot;
// ray
static float d = 0;
d += delta * 2.0f;
ro = vec3(0,-1,20);
rd = vec3(0.1f, 0.5f, 9.81023f);
rd = sub3(rd, ro);
rd = norm3(rd);
// rotation
rotation33(rot, deg(d), 0,1,0);
rd = mulv33(rot, rd);
// intersection
ray r = ray(ro, rd);
plane pl = plane(vec3(0,0,28), vec3(0,0,1));
hit *hit = ray_hit_plane(r, pl);
if (hit) {
// point of intersection
ddraw_color(RED);
ddraw_box(hit->p, vec3(0.10f, 0.10f, 0.10f));
// intersection normal
ddraw_color(BLUE);
vec3 v = add3(hit->p, hit->n);
ddraw_arrow(hit->p, v);
ddraw_color(RED);
}
// line
ddraw_color(RED);
rd = scale3(rd,9);
rd = add3(ro,rd);
ddraw_line(ro, rd);
// plane
if (hit) ddraw_color(RED);
else ddraw_color(WHITE);
ddraw_plane(vec3(0,0,28), vec3(0,0,1), 3.0f);
}
{
// Sphere-Ray Intersection*/
vec3 ro, rd;
sphere s;
// ray
ro = vec3(0,-1,0);
rd = vec3(0.4f*sinf(dx), 2.0f*cosf(dy), 9.81023f);
rd = sub3(rd, ro);
rd = norm3(rd);
ray r = ray(ro, rd);
s = sphere(vec3(0,0,8), 1);
hit *hit = ray_hit_sphere(r, s);
if(hit) {
// points of intersection
vec3 in = add3(ro,scale3(rd,hit->t0));
ddraw_color(GREEN);
ddraw_box(in, vec3(0.05f, 0.05f, 0.05f));
in = add3(ro,scale3(rd,hit->t1));
ddraw_color(YELLOW);
ddraw_box(in, vec3(0.05f, 0.05f, 0.05f));
// intersection normal
ddraw_color(BLUE);
vec3 v = add3(hit->p, hit->n);
ddraw_arrow(hit->p, v);
ddraw_color(RED);
}
// line
ddraw_color(RED);
rd = scale3(rd,10);
rd = add3(ro,rd);
ddraw_line(ro, rd);
// sphere
if (hit) ddraw_color(RED);
else ddraw_color(WHITE);
ddraw_sphere(vec3(0,0,8), 1);
}
{ // ray-aabb
aabb bounds = aabb(vec3(10-0.5f,-0.5f,7.5f), vec3(10.5f,0.5f,8.5f));
vec3 ro = vec3(10,-1,0);
vec3 rd = vec3(10+0.4f*sinf(dx), 2.0f*cosf(dy), 9.81023f);
rd = norm3(sub3(rd, ro));
ray r = ray(ro, rd);
hit *hit = ray_hit_aabb(r, bounds);
if(hit) {
// points of intersection
vec3 in;
in = scale3(rd,hit->t0);
in = add3(ro,in);
ddraw_color(RED);
ddraw_box(in, vec3(0.05f, 0.05f, 0.05f));
in = scale3(rd,hit->t1);
in = add3(ro,in);
ddraw_color(RED);
ddraw_box(in, vec3(0.05f, 0.05f, 0.05f));
// intersection normal
ddraw_color(BLUE);
vec3 v = add3(hit->p, hit->n);
ddraw_arrow(hit->p, v);
ddraw_color(RED);
} else ddraw_color(WHITE);
ddraw_box(vec3(10,0,8), vec3(1,1,1));
// line
ddraw_color(RED);
rd = scale3(rd,10);
rd = add3(ro,rd);
ddraw_line(ro, rd);
}
{
// Sphere-Sphere intersection*/
sphere a = sphere(vec3(-10,0,8), 1);
sphere b = sphere(vec3(-10+0.6f*sinf(dx), 3.0f*cosf(dy),8), 1);
hit *m = sphere_hit_sphere(a, b);
if (m) {
vec3 v;
ddraw_color(BLUE);
ddraw_box(m->contact_point, vec3(0.05f, 0.05f, 0.05f));
v = add3(m->contact_point, m->normal);
ddraw_arrow(m->contact_point, v);
ddraw_color(RED);
} else ddraw_color(WHITE);
ddraw_sphere(a.c, 1);
ddraw_sphere(b.c, 1);
}
{
// AABB-AABB intersection*/
const float x = 10+0.6f*sinf(dx);
const float y = 3.0f*cosf(dy);
const float z = 20.0f;
aabb a = aabb(vec3(10-0.5f,-0.5f,20-0.5f), vec3(10+0.5f,0.5f,20.5f));
aabb b = aabb(vec3(x-0.5f,y-0.5f,z-0.5f), vec3(x+0.5f,y+0.5f,z+0.5f));
hit *m = aabb_hit_aabb(a, b);
if(m) {
vec3 v;
ddraw_color(BLUE);
ddraw_box(m->contact_point, vec3(0.05f, 0.05f, 0.05f));
v = add3(m->contact_point, m->normal);
ddraw_arrow(m->contact_point, v);
ddraw_color(RED);
} else ddraw_color(WHITE);
ddraw_box(vec3(10,0,20), vec3(1,1,1));
ddraw_box(vec3(x,y,z), vec3(1,1,1));
}
{
// Capsule-Capsule intersection*/
const float x = 20+0.4f*sinf(dx);
const float y = 3.0f*cosf(dy);
const float z = 28.5f;
capsule a = capsule(vec3(20.0f,-1.0f,28.0f), vec3(20.0f,1.0f,28.0f), 0.2f);
capsule b = capsule(vec3(x,y-1.0f,z), vec3(x,y+1.0f,z-1.0f), 0.2f);
hit *m = capsule_hit_capsule(a, b);
if( m ) {
vec3 v;
ddraw_color(BLUE);
ddraw_box(m->contact_point, vec3(0.05f, 0.05f, 0.05f));
v = add3(m->contact_point, m->normal);
ddraw_arrow(m->contact_point, v);
ddraw_color(RED);
} else ddraw_color(WHITE);
ddraw_capsule(vec3(x,y-1.0f,z), vec3(x,y+1.0f,z-1.0f), 0.2f);
ddraw_capsule(vec3(20.0f,-1.0f,28.0f), vec3(20.0f,1.0f,28.0f), 0.2f);
}
{
// AABB-Sphere intersection*/
aabb a = aabb(vec3(20-0.5f,-0.5f,7.5f), vec3(20.5f,0.5f,8.5f));
sphere s = sphere(vec3(20+0.6f*sinf(dx), 3.0f*cosf(dy),8), 1);
hit *m = aabb_hit_sphere(a, s);
if(m) {
vec3 v;
ddraw_color(BLUE);
ddraw_box(m->contact_point, vec3(0.05f, 0.05f, 0.05f));
v = add3(m->contact_point, m->normal);
ddraw_arrow(m->contact_point, v);
ddraw_color(RED);
} else ddraw_color(WHITE);
ddraw_box(vec3(20,0,8), vec3(1,1,1));
ddraw_sphere(s.c, 1);
}
{
// Sphere-AABB intersection*/
const float x = 10+0.6f*sinf(dx);
const float y = 3.0f*cosf(dy);
const float z = -8.0f;
sphere s = sphere(vec3(10,0,-8), 1);
aabb a = aabb(vec3(x-0.5f,y-0.5f,z-0.5f), vec3(x+0.5f,y+0.5f,z+0.5f));
hit *m = sphere_hit_aabb(s, a);
if(m) {
vec3 v;
ddraw_color(BLUE);
ddraw_box(m->contact_point, vec3(0.05f, 0.05f, 0.05f));
v = add3(m->contact_point, m->normal);
ddraw_arrow(m->contact_point, v);
ddraw_color(RED);
} else ddraw_color(WHITE);
ddraw_box(vec3(x,y,z), vec3(1,1,1));
ddraw_sphere(s.c, 1);
}
{
// Capsule-Sphere intersection*/
capsule c = capsule(vec3(-20.5f,-1.0f,7.5f), vec3(-20+0.5f,1.0f,8.5f), 0.2f);
sphere b = sphere(vec3(-20+0.6f*sinf(dx), 3.0f*cosf(dy),8), 1);
hit *m = capsule_hit_sphere(c, b);
if(m) {
vec3 v;
ddraw_color(BLUE);
ddraw_box(m->contact_point, vec3(0.05f, 0.05f, 0.05f));
v = add3(m->contact_point, m->normal);
ddraw_arrow(m->contact_point, v);
ddraw_color(RED);
} else ddraw_color(WHITE);
ddraw_sphere(b.c, 1);
ddraw_capsule(vec3(-20.5f,-1.0f,7.5f), vec3(-20+0.5f,1.0f,8.5f), 0.2f);
}
{
// Sphere-Capsule intersection*/
const float x = 20+0.4f*sinf(dx);
const float y = 3.0f*cosf(dy);
const float z = -8;
sphere s = sphere(vec3(20,0,-8), 1);
capsule c = capsule(vec3(x,y-1.0f,z), vec3(x,y+1.0f,z-1.0f), 0.2f);
hit *m = sphere_hit_capsule(s, c);
if(m) {
vec3 v;
ddraw_color(BLUE);
ddraw_box(m->contact_point, vec3(0.05f, 0.05f, 0.05f));
v = add3(m->contact_point, m->normal);
ddraw_arrow(m->contact_point, v);
ddraw_color(RED);
} else ddraw_color(WHITE);
ddraw_capsule(vec3(x,y-1.0f,z), vec3(x,y+1.0f,z-1.0f), 0.2f);
ddraw_sphere(s.c, 1);
}
{
// Capsule-AABB intersection*/
const float x = -20+0.6f*sinf(dx);
const float y = 3.0f*cosf(dy);
const float z = 28.0f;
capsule c = capsule(vec3(-20.5f,-1.0f,27.5f), vec3(-20+0.5f,1.0f,28.5f), 0.2f);
aabb b = aabb(vec3(x-0.5f,y-0.5f,z-0.5f), vec3(x+0.5f,y+0.5f,z+0.5f));
hit *m = capsule_hit_aabb(c, b);
if(m) {
vec3 v;
ddraw_color(BLUE);
ddraw_box(m->contact_point, vec3(0.05f, 0.05f, 0.05f));
v = add3(m->contact_point, m->normal);
ddraw_arrow(m->contact_point, v);
ddraw_color(RED);
} else ddraw_color(WHITE);
ddraw_box(vec3(x,y,z), vec3(1,1,1));
ddraw_capsule(vec3(-20.5f,-1.0f,27.5f), vec3(-20+0.5f,1.0f,28.5f), 0.2f);
}
{
// AABB-Capsule intersection*/
const float x = 0.4f*sinf(dx);
const float y = 3.0f*cosf(dy);
const float z = -8;
aabb a = aabb(vec3(-0.5f,-0.5f,-8.5f), vec3(0.5f,0.5f,-7.5f));
capsule c = capsule(vec3(x,y-1.0f,z), vec3(x,y+1.0f,z-1.0f), 0.2f);
hit *m = aabb_hit_capsule(a, c);
if(m) {
ddraw_color(RED);
ddraw_box(m->contact_point, vec3(0.05f, 0.05f, 0.05f));
ddraw_arrow(m->contact_point, add3(m->contact_point, m->normal));
} else ddraw_color(WHITE);
ddraw_capsule(vec3(x,y-1.0f,z), vec3(x,y+1.0f,z-1.0f), 0.2f);
ddraw_box(vec3(0,0,-8.0f), vec3(1,1,1));
}
{
// poly(Pyramid)-Sphere (GJK) intersection*/
sphere s = sphere(vec3(-10+0.6f*sinf(dx), 3.0f*cosf(dy),-8), 1);
poly pyr = pyramid(vec3(-10.5f,-0.5f,-7.5f), vec3(-10.5f,1.0f,-7.5f), 1.0f);
gjk_result gjk;
if (poly_hit_sphere(&gjk, pyr, s))
ddraw_color(RED);
else ddraw_color(WHITE);
ddraw_sphere(s.c, 1);
ddraw_pyramid(vec3(-10.5f,-0.5f,-7.5f), 0.5f/*vec3(-10.5f,1.0f,-7.5f)*/, 1.0f);
poly_free(&pyr);
ddraw_box(gjk.p0, vec3(0.05f, 0.05f, 0.05f));
ddraw_box(gjk.p1, vec3(0.05f, 0.05f, 0.05f));
ddraw_line(gjk.p0, gjk.p1);
}
{
// poly(Diamond)-Sphere (GJK) intersection*/
sphere s = sphere(vec3(-20+0.6f*sinf(dx), 3.0f*cosf(dy),-8), 1);
poly dmd = diamond(vec3(-20.5f,-0.5f,-7.5f), vec3(-20.5f,1.0f,-7.5f), 0.5f);
gjk_result gjk;
if (poly_hit_sphere(&gjk, dmd, s))
ddraw_color(RED);
else ddraw_color(WHITE);
ddraw_sphere(s.c, 1);
ddraw_diamond(vec3(-20.5f,-0.5f,-7.5f), vec3(-20.5f,1.0f,-7.5f), 0.5f);
poly_free(&dmd);
ddraw_box(gjk.p0, vec3(0.05f, 0.05f, 0.05f));
ddraw_box(gjk.p1, vec3(0.05f, 0.05f, 0.05f));
ddraw_line(gjk.p0, gjk.p1);
}
{
// poly(Pyramid)-Capsule (GJK) intersection*/
const float x = 0.4f*sinf(dx);
const float y = 3.0f*cosf(dy);
const float z = -15;
capsule c = capsule(vec3(x,y-1.0f,z), vec3(x,y+1.0f,z), 0.2f);
poly pyr = pyramid(vec3(-0.5f,-0.5f,-15.5f), vec3(-0.5f,1.0f,-15.5f), 1.0f);
gjk_result gjk;
if (poly_hit_capsule(&gjk, pyr, c))
ddraw_color(RED);
else ddraw_color(WHITE);
ddraw_capsule(c.a, c.b, c.r);
ddraw_pyramid(vec3(-0.5f,-0.5f,-15.5f), 0.5f/*vec3(-0.5f,1.0f,-15.5f)*/, 1.0f);
poly_free(&pyr);
ddraw_box(gjk.p0, vec3(0.05f, 0.05f, 0.05f));
ddraw_box(gjk.p1, vec3(0.05f, 0.05f, 0.05f));
ddraw_line(gjk.p0, gjk.p1);
}
{
// poly(Diamond)-Capsule (GJK) intersection*/
const float x = -10 + 0.4f*sinf(dx);
const float y = 3.0f*cosf(dy);
const float z = -15;
capsule c = capsule(vec3(x,y-1.0f,z), vec3(x,y+1.0f,z), 0.2f);
poly dmd = diamond(vec3(-10.5f,-0.5f,-15.5f), vec3(-10.5f,1.0f,-15.5f), 0.5f);
gjk_result gjk;
if (poly_hit_capsule(&gjk, dmd, c))
ddraw_color(RED);
else ddraw_color(WHITE);
ddraw_capsule(c.a, c.b, c.r);
ddraw_diamond(vec3(-10.5f,-0.5f,-15.5f), vec3(-10.5f,1.0f,-15.5f), 0.5f);
poly_free(&dmd);
ddraw_box(gjk.p0, vec3(0.05f, 0.05f, 0.05f));
ddraw_box(gjk.p1, vec3(0.05f, 0.05f, 0.05f));
ddraw_line(gjk.p0, gjk.p1);
}
{
// poly(Diamond)-poly(Pyramid) (GJK) intersection*/
const float x = -20 + 0.4f*sinf(dx);
const float y = 3.0f*cosf(dy);
const float z = -15;
poly pyr = pyramid(vec3(x,y-0.5f,z), vec3(x,y+1,z), 0.8f);
poly dmd = diamond(vec3(-20.5f,-0.5f,-15.5f), vec3(-20.5f,1.0f,-15.5f), 0.5f);
gjk_result gjk;
if (poly_hit_poly(&gjk, dmd, pyr))
ddraw_color(RED);
else ddraw_color(WHITE);
ddraw_pyramid(vec3(x,y-0.5f,z), 1/*vec3(x,y+1,z)*/, 1/*0.8f*/);
ddraw_diamond(vec3(-20.5f,-0.5f,-15.5f), vec3(-20.5f,1.0f,-15.5f), 0.5f);
poly_free(&dmd);
poly_free(&pyr);
ddraw_box(gjk.p0, vec3(0.05f, 0.05f, 0.05f));
ddraw_box(gjk.p1, vec3(0.05f, 0.05f, 0.05f));
ddraw_line(gjk.p0, gjk.p1);
}
{
// poly(Pyramid)-poly(Diamond) (GJK) intersection*/
const float x = 10 + 0.4f*sinf(dx);
const float y = 3.0f*cosf(dy);
const float z = -15;
poly dmd = diamond(vec3(x,y-0.5f,z), vec3(x,y+1,z), 0.5f);
poly pyr = pyramid(vec3(10.5f,-0.5f,-15.5f), vec3(10.5f,1.0f,-15.5f), 1.0f);
gjk_result gjk;
if (poly_hit_poly(&gjk, dmd, pyr))
ddraw_color(RED);
else ddraw_color(WHITE);
ddraw_diamond(vec3(x,y-0.5f,z), vec3(x,y+1,z), 0.5f);
ddraw_pyramid(vec3(10.5f,-0.5f,-15.5f), 0.5f/*vec3(10.5f,1.0f,-15.5f)*/, 1.0f);
poly_free(&dmd);
poly_free(&pyr);
ddraw_box(gjk.p0, vec3(0.05f, 0.05f, 0.05f));
ddraw_box(gjk.p1, vec3(0.05f, 0.05f, 0.05f));
ddraw_line(gjk.p0, gjk.p1);
}
{
// poly(Diamond)-AABB (GJK) intersection*/
const float x = 20 + 0.4f*sinf(dx);
const float y = 3.0f*cosf(dy);
const float z = -15;
poly dmd = diamond(vec3(x,y-0.5f,z), vec3(x,y+1,z), 0.5f);
aabb a = aabb(vec3(19.5f,-0.5f,-14.5f), vec3(20.5f,0.5f,-15.5f));
gjk_result gjk;
if (poly_hit_aabb(&gjk, dmd, a))
ddraw_color(RED);
else ddraw_color(WHITE);
poly_free(&dmd);
ddraw_diamond(vec3(x,y-0.5f,z), vec3(x,y+1,z), 0.5f);
ddraw_box(vec3(20,0,-15), vec3(1,1,1));
ddraw_box(gjk.p0, vec3(0.05f, 0.05f, 0.05f));
ddraw_box(gjk.p1, vec3(0.05f, 0.05f, 0.05f));
ddraw_line(gjk.p0, gjk.p1);
}
}
//fx_begin();
//ddraw_flush();
//fx_end();
if( ui_panel("Audio", 0) ) {
if( ui_button("test audio") ) {
// audio (both clips & streams)
static audio_t voice; voice = audio_clip("coin.wav"); // "pew.sfxr"
static audio_t stream; stream = audio_stream("wrath_of_the_djinn.xm"); // "larry.mid"
audio_play(voice, 0);
audio_play(stream, 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();
}
}
int main(void) {
// 75% sized, msaa x4 enabled
window_create(0.75f, WINDOW_MSAA4);
window_title( "V4K - SPACE pauses simulation" );
// for(const char **list = file_list("fx**.fs"); *list; list++) {
// //fx_load(*list);
// }
// camera that points to origin
cam = camera();
// main loop
window_loop(game_loop, NULL);
}

View File

@ -0,0 +1,57 @@
#include "v4k.h"
void render(void *arg) {
static int integer = 42;
static bool toggle = true;
static bool boolean = true;
static float floating = 3.14159;
static float float2[2] = {1,2};
static float float3[3] = {1,2,3};
static float float4[4] = {1,2,3,4};
static float rgb[3] = {0.84,0.67,0.17};
static float rgba[4] = {0.67,0.90,0.12,1};
static float slider = 0.5f;
static float slider2 = 0.5f;
static char string[64] = "hello world 123";
static int item = 0; const char *list[] = {"one","two","three"};
static bool show_dialog = false;
static uint8_t bitmask = 0x55;
if( ui_panel("UI", 0)) {
if( ui_label("my label")) {}
if( ui_label("my label with tooltip@built on " __DATE__ " " __TIME__)) {}
if( ui_separator() ) {}
if( ui_bool("my bool", &boolean) ) puts("bool changed");
if( ui_int("my int", &integer) ) puts("int changed");
if( ui_float("my float", &floating) ) puts("float changed");
if( ui_buffer("my string", string, 64) ) puts("string changed");
if( ui_separator() ) {}
if( ui_slider("my slider", &slider)) puts("slider changed");
if( ui_slider2("my slider 2", &slider2, va("%.2f", slider2))) puts("slider2 changed");
if( ui_separator() ) {}
if( ui_list("my list", list, 3, &item ) ) puts("list changed");
if( ui_separator() ) {}
if( ui_color3f("my color3", rgb) ) puts("color3 changed");
if( ui_color4f("my color4@this is a tooltip", rgba) ) puts("color4 changed");
if( ui_separator() ) {}
if( ui_float2("my float2", float2) ) puts("float2 changed");
if( ui_float3("my float3", float3) ) puts("float3 changed");
if( ui_float4("my float4", float4) ) puts("float4 changed");
if( ui_bits8("my bitmask", &bitmask) ) printf("bitmask changed %x\n", bitmask);
if( ui_separator() ) {}
if( ui_toggle("my toggle", &toggle) ) printf("toggle %s\n", toggle ? "on":"off");
if( ui_separator() ) {}
if( ui_image("my image", texture_checker().id, 0, 0) ) { puts("image clicked"); }
if( ui_button("my button") ) { puts("button clicked"); show_dialog = true; }
if( ui_dialog("my dialog", __FILE__ "\n" __DATE__ "\n" "Public Domain.", 2/*two buttons*/, &show_dialog) ) {}
ui_panel_end();
}
input_demo();
}
int main() {
window_create(0.75f, 0);
window_loop(render, NULL);
}

View File

@ -0,0 +1,162 @@
/**
* @license
* Copyright 2015 The Emscripten Authors
* SPDX-License-Identifier: MIT
*/
// Pthread Web Worker startup routine:
// This is the entry point file that is loaded first by each Web Worker
// that executes pthreads on the Emscripten application.
'use strict';
var Module = {};
// Thread-local:
function assert(condition, text) {
if (!condition) abort('Assertion failed: ' + text);
}
function threadPrintErr() {
var text = Array.prototype.slice.call(arguments).join(' ');
console.error(text);
}
function threadAlert() {
var text = Array.prototype.slice.call(arguments).join(' ');
postMessage({cmd: 'alert', text: text, threadId: Module['_pthread_self']()});
}
// We don't need out() for now, but may need to add it if we want to use it
// here. Or, if this code all moves into the main JS, that problem will go
// away. (For now, adding it here increases code size for no benefit.)
var out = function() {
throw 'out() is not defined in worker.js.';
}
var err = threadPrintErr;
self.alert = threadAlert;
Module['instantiateWasm'] = function(info, receiveInstance) {
// Instantiate from the module posted from the main thread.
// We can just use sync instantiation in the worker.
var instance = new WebAssembly.Instance(Module['wasmModule'], info);
// TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193,
// the above line no longer optimizes out down to the following line.
// When the regression is fixed, we can remove this if/else.
receiveInstance(instance);
// We don't need the module anymore; new threads will be spawned from the main thread.
Module['wasmModule'] = null;
return instance.exports;
};
self.onmessage = function(e) {
try {
if (e.data.cmd === 'load') { // Preload command that is called once per worker to parse and load the Emscripten code.
// Module and memory were sent from main thread
Module['wasmModule'] = e.data.wasmModule;
Module['wasmMemory'] = e.data.wasmMemory;
Module['buffer'] = Module['wasmMemory'].buffer;
Module['ENVIRONMENT_IS_PTHREAD'] = true;
if (typeof e.data.urlOrBlob === 'string') {
importScripts(e.data.urlOrBlob);
} else {
var objectUrl = URL.createObjectURL(e.data.urlOrBlob);
importScripts(objectUrl);
URL.revokeObjectURL(objectUrl);
}
} else if (e.data.cmd === 'run') {
// This worker was idle, and now should start executing its pthread entry
// point.
// performance.now() is specced to return a wallclock time in msecs since
// that Web Worker/main thread launched. However for pthreads this can
// cause subtle problems in emscripten_get_now() as this essentially
// would measure time from pthread_create(), meaning that the clocks
// between each threads would be wildly out of sync. Therefore sync all
// pthreads to the clock on the main browser thread, so that different
// threads see a somewhat coherent clock across each of them
// (+/- 0.1msecs in testing).
Module['__performance_now_clock_drift'] = performance.now() - e.data.time;
// Pass the thread address inside the asm.js scope to store it for fast access that avoids the need for a FFI out.
Module['__emscripten_thread_init'](e.data.threadInfoStruct, /*isMainBrowserThread=*/0, /*isMainRuntimeThread=*/0);
assert(e.data.threadInfoStruct);
// Also call inside JS module to set up the stack frame for this pthread in JS module scope
Module['establishStackSpace']();
Module['PThread'].receiveObjectTransfer(e.data);
Module['PThread'].threadInit();
try {
// pthread entry points are always of signature 'void *ThreadMain(void *arg)'
// Native codebases sometimes spawn threads with other thread entry point signatures,
// such as void ThreadMain(void *arg), void *ThreadMain(), or void ThreadMain().
// That is not acceptable per C/C++ specification, but x86 compiler ABI extensions
// enable that to work. If you find the following line to crash, either change the signature
// to "proper" void *ThreadMain(void *arg) form, or try linking with the Emscripten linker
// flag -s EMULATE_FUNCTION_POINTER_CASTS=1 to add in emulation for this x86 ABI extension.
var result = Module['invokeEntryPoint'](e.data.start_routine, e.data.arg);
Module['checkStackCookie']();
if (Module['keepRuntimeAlive']()) {
Module['PThread'].setExitStatus(result);
} else {
Module['__emscripten_thread_exit'](result);
}
} catch(ex) {
if (ex != 'unwind') {
// FIXME(sbc): Figure out if this is still needed or useful. Its not
// clear to me how this check could ever fail. In order to get into
// this try/catch block at all we have already called bunch of
// functions on `Module`.. why is this one special?
if (typeof(Module['_emscripten_futex_wake']) !== 'function') {
err("Thread Initialisation failed.");
throw ex;
}
// ExitStatus not present in MINIMAL_RUNTIME
if (ex instanceof Module['ExitStatus']) {
if (Module['keepRuntimeAlive']()) {
err('Pthread 0x' + Module['_pthread_self']().toString(16) + ' called exit(), staying alive due to noExitRuntime.');
} else {
err('Pthread 0x' + Module['_pthread_self']().toString(16) + ' called exit(), calling _emscripten_thread_exit.');
Module['__emscripten_thread_exit'](ex.status);
}
}
else
{
// The pthread "crashed". Do not call `_emscripten_thread_exit` (which
// would make this thread joinable. Instead, re-throw the exception
// and let the top level handler propagate it back to the main thread.
throw ex;
}
} else {
// else e == 'unwind', and we should fall through here and keep the pthread alive for asynchronous events.
err('Pthread 0x' + Module['_pthread_self']().toString(16) + ' completed its main entry point with an `unwind`, keeping the worker alive for asynchronous operation.');
}
}
} else if (e.data.cmd === 'cancel') { // Main thread is asking for a pthread_cancel() on this thread.
if (Module['_pthread_self']()) {
Module['__emscripten_thread_exit'](-1/*PTHREAD_CANCELED*/);
}
postMessage({ 'cmd': 'cancelDone' });
} else if (e.data.target === 'setimmediate') {
// no-op
} else if (e.data.cmd === 'processThreadQueue') {
if (Module['_pthread_self']()) { // If this thread is actually running?
Module['_emscripten_current_thread_process_queued_calls']();
}
} else {
err('worker.js received unknown command ' + e.data.cmd);
err(e.data);
}
} catch(ex) {
err('worker.js onmessage() captured an uncaught exception: ' + ex);
if (ex && ex.stack) err(ex.stack);
throw ex;
}
};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,141 @@
<!DOCTYPE html>
<!-- This file license is CC0 (https://creativecommons.org/publicdomain/zero/1.0/). -->
<!-- Original code by @SpartanJ https://github.com/SpartanJ/eepp/blob/8552941da19380d7a629c4da80a976aec5d39e5c/bin/emscripten-fs.html -->
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"/>
<!-- <title>Example</title> -->
<style>
body { margin: 0; background-color: black }
.emscripten {
position: absolute;
top: 0px;
left: 0px;
margin: 0px;
border: 0;
width: 100%;
height: 100%;
overflow: hidden;
display: block;
image-rendering: optimizeSpeed;
image-rendering: -moz-crisp-edges;
image-rendering: -o-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: optimize-contrast;
image-rendering: crisp-edges;
image-rendering: pixelated;
-ms-interpolation-mode: nearest-neighbor;
}
.loader {
width: 48px;
height: 48px;
border-radius: 50%;
display: inline-block;
border-top: 3px solid #3daee9;
border-right: 3px solid transparent;
box-sizing: border-box;
animation: rotation 1s linear infinite;
}
.loader-cont {
display: flex;
width: 100vw;
justify-content: center;
height: 100vh;
align-items: center;
}
@keyframes rotation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
<div id="cont" class="loader-cont">
<span class="loader"></span>
</div>
<script type='text/javascript'>
var loaderCont;
function getDemoScript(name) {
if (name)
return name;
return "index.js";
}
function getParameter(name) {
let url_string = window.location.href;
let url = new URL(url_string);
return url.searchParams.get(name);
}
function loadScript(url, callback) {
loaderCont = document.getElementById('cont');
let head = document.head;
let script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
script.onreadystatechange = callback;
script.onload = callback;
head.appendChild(script);
}
var Module = {
preRun: [],
postRun: [],
print: (function() {
return function(text) {
text = Array.prototype.slice.call(arguments).join(' ');
console.log(text);
};
})(),
printErr: function(text) {
text = Array.prototype.slice.call(arguments).join(' ');
console.error(text);
},
canvas: (function() {
var canvas = document.getElementById('canvas');
return canvas;
})(),
setStatus: function(text) {
console.log("status: " + text);
if (text == "Running...")
loaderCont.style.display = 'none';
},
monitorRunDependencies: function(left) {
// no run dependencies to log
},
arguments: window.location.search.substr(1).split('&')
};
window.onerror = function() {
console.log("onerror: " + event);
};
(function() {
loadScript(getDemoScript(getParameter("run")));
})();
</script>
{{{ SCRIPT }}}
<button onclick="openFullscreen();" style="position:relative; z-index: 1000; float: right;">&#x26F6;</button>
<script>
function openFullscreen() {
var elem = document.getElementById("canvas");
if (elem.requestFullscreen) {
elem.requestFullscreen();
} else if (elem.webkitRequestFullscreen) { /* Safari */
elem.webkitRequestFullscreen();
} else if (elem.msRequestFullscreen) { /* IE11 */
elem.msRequestFullscreen();
}
}
</script>
<script src="coi-serviceworker.min.js"></script>
</body>
</html>

View File

@ -0,0 +1,6 @@
cl game.c -I..\..\..\engine\joint %* /link /SUBSYSTEM:WINDOWS /entry:mainCRTStartup
del *.obj
del *.exp
del *.lib
del *.pdb

View File

@ -0,0 +1,17 @@
# Anarch
![](game.png)
*extremely small, completely public domain, no-dependency, no-file,
portable suckless anarcho-pacifist from-scratch 90s-style Doom clone that runs
everywhere, made for the benefit of all living beings*
[website](https://drummyfish.gitlab.io/anarch) - [trailer](https://libre.video/videos/watch/c968774a-c12d-46d6-8851-0c578ffa8dcb) - [play in browser](https://drummyfish.gitlab.io/anarch/bin/web/anarch.html) - [itch.io](https://drummyfish.itch.io/anarch)
## License
I, Miloslav Číž (drummyfish), have released everything in the Anarch repository under CC0 1.0 (public domain, https://creativecommons.org/publicdomain/zero/1.0/) + a waiver of all other IP rights (including patents), which is as follows:
*Each contributor to this work agrees that they waive any exclusive rights, including but not limited to copyright, patents, trademark, trade dress, industrial design, plant varieties and trade secrets, to any and all ideas, concepts, processes, discoveries, improvements and inventions conceived, discovered, made, designed, researched or developed by the contributor either solely or jointly with others, which relate to this work or result from this work. Should any waiver of such right be judged legally invalid or ineffective under applicable law, the contributor hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to this right.*
If you'd like to support me or just read something about me and my projects, visit my site: [www.tastyfish.cz](http://www.tastyfish.cz/).

View File

@ -0,0 +1,121 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

View File

@ -0,0 +1,587 @@
/**
@file constants.h
This file contains definitions of game constants that are not considered
part of game settings and whose change can ffect the game balance and
playability, e.g. physics constants.
by Miloslav Ciz (drummyfish), 2019
Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/)
plus a waiver of all other intellectual property. The goal of this work is to
be and remain completely in the public domain forever, available for any use
whatsoever.
*/
#ifndef _SFG_CONSTANTS_H
#define _SFG_CONSTANTS_H
/**
How quickly player moves, in squares per second.
*/
#define SFG_PLAYER_MOVE_SPEED 7
/**
Gravity acceleration in squares / (second^2).
*/
#define SFG_GRAVITY_ACCELERATION 30
/**
Initial upwards speed of player's jump, in squares per second.
*/
#define SFG_PLAYER_JUMP_SPEED 5
/**
Melee and close-up attack range, in RCL_Units.
*/
#define SFG_MELEE_RANGE 1600
/**
When a projectile is shot, it'll be offset by this distance (in RCL_Units)
from the shooter.
*/
#define SFG_PROJECTILE_SPAWN_OFFSET 256
/**
Player's melee hit range, in RCL_Units (RCL_UNITS_PER_SQUARE means full angle,
180 degrees to both sides).
*/
#define SFG_PLAYER_MELEE_ANGLE 512
/**
How quickly elevators and squeezers move, in RCL_Unit per second.
*/
#define SFG_MOVING_WALL_SPEED 1024
/**
How quickly doors open and close, in RCL_Unit per second.
*/
#define SFG_DOOR_OPEN_SPEED 2048
/**
Helper special state value.
*/
#define SFG_CANT_SAVE 255
/**
Says the distance in RCL_Units at which level elements (items, monsters etc.)
are active.
*/
#define SFG_LEVEL_ELEMENT_ACTIVE_DISTANCE (12 * 1024)
/**
Rate at which AI will be updated, which also affects how fast enemies will
appear.
*/
#define SFG_AI_FPS 4
/**
Says a probability (0 - 255) of the AI changing its state during one update
step.
*/
#define SFG_AI_RANDOM_CHANGE_PROBABILITY 40
/**
Distance at which level elements (sprites) collide, in RCL_Unit (1024 per
square).
*/
#define SFG_ELEMENT_COLLISION_RADIUS 1800
/**
Height, in RCL_Units, at which collisions happen with level elements
(sprites).
*/
#define SFG_ELEMENT_COLLISION_HEIGHT 1024
/**
Distance at which explosion does damage and throws away the player, in
RCL_Units. Should be higher than SFG_ELEMENT_COLLISION_RADIUS so that
exploded rockets also hurt the target.
*/
#define SFG_EXPLOSION_RADIUS 2000
/**
Distance in RCL_Units which the player is pushed away by an explosion. Watch
out, a slightly higher value can make player go through walls. Rather keep
this under RCL_UNITS_PER_SQUARE;
*/
#define SFG_EXPLOSION_PUSH_AWAY_DISTANCE 1023
/**
How much damage triggers a barrel explosion.
*/
#define SFG_BARREL_EXPLOSION_DAMAGE_THRESHOLD 3
/**
Maximum player health.
*/
#define SFG_PLAYER_MAX_HEALTH 125
/**
Start health of player.
*/
#define SFG_PLAYER_START_HEALTH 100
/**
At which value health indicator shows a warning (red color).
*/
#define SFG_PLAYER_HEALTH_WARNING_LEVEL 20
/**
Amount of health that is increased by taking a health kit.
*/
#define SFG_HEALTH_KIT_VALUE 20
/**
How much randomness (positive and negative) will be added to damage
(e.g. by weapons, explosions, ...). This constant is is 0 to 255, 255 meaning
100% of the base value.
*/
#define SFG_DAMAGE_RANDOMNESS 64
/**
Height of monster collision BBox in RCL_Units.
*/
#define SFG_MONSTER_COLLISION_HEIGHT 1024
/**
Specifies key repeat delay, in ms.
*/
#define SFG_KEY_REPEAT_DELAY 500
/**
Specifies key repeat period, in ms.
*/
#define SFG_KEY_REPEAT_PERIOD 150
/**
Angle in which multiple projectiles are spread, RCL_Units.
*/
#define SFG_PROJECTILE_SPREAD_ANGLE 100
#define SFG_MAX_MONSTERS 64
#define SFG_MAX_PROJECTILES 12
#define SFG_MAX_DOORS 32
#define SFG_AMMO_BULLETS 0
#define SFG_AMMO_ROCKETS 1
#define SFG_AMMO_PLASMA 2
#define SFG_AMMO_TOTAL 3
#define SFG_AMMO_NONE SFG_AMMO_TOTAL
#define SFG_AMMO_INCREASE_BULLETS 10
#define SFG_AMMO_INCREASE_ROCKETS 5
#define SFG_AMMO_INCREASE_PLASMA 8
#define SFG_AMMO_MAX_BULLETS 200
#define SFG_AMMO_MAX_ROCKETS 100
#define SFG_AMMO_MAX_PLASMA 150
/**
Duration of story text (intro/outro) in ms.
*/
#define SFG_STORYTEXT_DURATION 15000
/**
Time in ms of the player death animation.
*/
#define SFG_LOSE_ANIMATION_DURATION 2000
/**
Time in ms of the level win animation.
*/
#define SFG_WIN_ANIMATION_DURATION 2500
/**
Time in ms of the level start stage.
*/
#define SFG_LEVEL_START_DURATION 1500
/**
Vertical sprite size, in RCL_Units.
*/
#define SFG_BASE_SPRITE_SIZE RCL_UNITS_PER_SQUARE
/**
Default value of the settings byte.
*/
#define SFG_DEFAULT_SETTINGS 0x03
// -----------------------------------------------------------------------------
// derived constants
#define SFG_GAME_RESOLUTION_X \
(SFG_SCREEN_RESOLUTION_X / SFG_RESOLUTION_SCALEDOWN)
#define SFG_GAME_RESOLUTION_Y \
(SFG_SCREEN_RESOLUTION_Y / SFG_RESOLUTION_SCALEDOWN)
#define SFG_MS_PER_FRAME (1000 / SFG_FPS) // ms per frame with target FPS
#if SFG_MS_PER_FRAME == 0
#undef SFG_MS_PER_FRAME
#define SFG_MS_PER_FRAME 1
#endif
#define SFG_KEY_REPEAT_DELAY_FRAMES \
(SFG_KEY_REPEAT_DELAY / SFG_MS_PER_FRAME)
#if SFG_KEY_REPEAT_DELAY_FRAMES == 0
#undef SFG_KEY_REPEAT_DELAY_FRAMES
#define SFG_KEY_REPEAT_DELAY_FRAMES 1
#endif
#define SFG_KEY_REPEAT_PERIOD_FRAMES \
(SFG_KEY_REPEAT_PERIOD / SFG_MS_PER_FRAME)
#if SFG_KEY_REPEAT_PERIOD_FRAMES == 0
#undef SFG_KEY_REPEAT_PERIOD_FRAMES
#define SFG_KEY_REPEAT_PERIOD_FRAMES 1
#endif
#define SFG_WEAPON_IMAGE_SCALE \
(SFG_GAME_RESOLUTION_X / (SFG_TEXTURE_SIZE * 5))
#if SFG_WEAPON_IMAGE_SCALE == 0
#undef SFG_WEAPON_IMAGE_SCALE
#define SFG_WEAPON_IMAGE_SCALE 1
#endif
#define SFG_WEAPONBOB_OFFSET_PIXELS \
(SFG_WEAPONBOB_OFFSET * SFG_WEAPON_IMAGE_SCALE)
#define SFG_WEAPON_IMAGE_POSITION_X \
(SFG_GAME_RESOLUTION_X / 2 - (SFG_WEAPON_IMAGE_SCALE * SFG_TEXTURE_SIZE) / 2)
#if SFG_GAME_RESOLUTION_Y > 70
#define SFG_WEAPON_IMAGE_POSITION_Y \
(SFG_GAME_RESOLUTION_Y - (SFG_WEAPON_IMAGE_SCALE * SFG_TEXTURE_SIZE))
#elif SFG_GAME_RESOLUTION_Y > 50
#define SFG_WEAPON_IMAGE_POSITION_Y (SFG_GAME_RESOLUTION_Y \
- ((SFG_WEAPON_IMAGE_SCALE * 3 * SFG_TEXTURE_SIZE) / 4))
#else
#define SFG_WEAPON_IMAGE_POSITION_Y \
(SFG_GAME_RESOLUTION_Y - SFG_TEXTURE_SIZE / 2)
#endif
#define SFG_PLAYER_TURN_UNITS_PER_FRAME \
((SFG_PLAYER_TURN_SPEED * RCL_UNITS_PER_SQUARE) / (360 * SFG_FPS))
#if SFG_PLAYER_TURN_UNITS_PER_FRAME == 0
#undef SFG_PLAYER_TURN_UNITS_PER_FRAME
#define SFG_PLAYER_TURN_UNITS_PER_FRAME 1
#endif
#define SFG_PLAYER_MOVE_UNITS_PER_FRAME \
((SFG_PLAYER_MOVE_SPEED * RCL_UNITS_PER_SQUARE) / SFG_FPS)
#if SFG_PLAYER_MOVE_UNITS_PER_FRAME == 0
#undef SFG_PLAYER_MOVE_UNITS_PER_FRAME
#define SFG_PLAYER_MOVE_UNITS_PER_FRAME 1
#endif
#define SFG_GRAVITY_SPEED_INCREASE_PER_FRAME \
((SFG_GRAVITY_ACCELERATION * RCL_UNITS_PER_SQUARE) / (SFG_FPS * SFG_FPS))
#if SFG_GRAVITY_SPEED_INCREASE_PER_FRAME == 0
#undef SFG_GRAVITY_SPEED_INCREASE_PER_FRAME
#define SFG_GRAVITY_SPEED_INCREASE_PER_FRAME 1
#endif
#define SFG_PLAYER_JUMP_OFFSET_PER_FRAME \
(((SFG_PLAYER_JUMP_SPEED * RCL_UNITS_PER_SQUARE) / SFG_FPS) \
- SFG_GRAVITY_SPEED_INCREASE_PER_FRAME / 2)
/* ^ This substraction corrects the initial veloc. so that the numeric curve
copies the analytical (smooth) curve. Without it the numeric curve goes
ABOVE and makes player jump higher with lower FPS. To make sense of this
try to solve the differential equation and plot it. */
#if SFG_PLAYER_JUMP_OFFSET_PER_FRAME == 0
#undef SFG_PLAYER_JUMP_OFFSET_PER_FRAME
#define SFG_PLAYER_JUMP_OFFSET_PER_FRAME 1
#endif
#define SFG_HEADBOB_FRAME_INCREASE_PER_FRAME \
(SFG_HEADBOB_SPEED / SFG_FPS)
#if SFG_HEADBOB_FRAME_INCREASE_PER_FRAME == 0
#undef SFG_HEADBOB_FRAME_INCREASE_PER_FRAME
#define SFG_HEADBOB_FRAME_INCREASE_PER_FRAME 1
#endif
#define SFG_HEADBOB_ENABLED (SFG_HEADBOB_SPEED > 0 && SFG_HEADBOB_OFFSET > 0)
#define SFG_CAMERA_SHEAR_STEP_PER_FRAME \
((SFG_GAME_RESOLUTION_Y * SFG_CAMERA_SHEAR_SPEED) / SFG_FPS)
#if SFG_CAMERA_SHEAR_STEP_PER_FRAME == 0
#undef SFG_CAMERA_SHEAR_STEP_PER_FRAME
#define SFG_CAMERA_SHEAR_STEP_PER_FRAME 1
#endif
#define SFG_CAMERA_MAX_SHEAR_PIXELS \
((SFG_CAMERA_MAX_SHEAR * SFG_GAME_RESOLUTION_Y) / 1024)
#define SFG_FONT_SIZE_SMALL \
(SFG_GAME_RESOLUTION_X / (SFG_FONT_CHARACTER_SIZE * 50))
#if SFG_FONT_SIZE_SMALL == 0
#undef SFG_FONT_SIZE_SMALL
#define SFG_FONT_SIZE_SMALL 1
#endif
#define SFG_FONT_SIZE_MEDIUM \
(SFG_GAME_RESOLUTION_X / (SFG_FONT_CHARACTER_SIZE * 30))
#if SFG_FONT_SIZE_MEDIUM == 0
#undef SFG_FONT_SIZE_MEDIUM
#define SFG_FONT_SIZE_MEDIUM 1
#endif
#define SFG_FONT_SIZE_BIG \
(SFG_GAME_RESOLUTION_X / (SFG_FONT_CHARACTER_SIZE * 18))
#if SFG_FONT_SIZE_BIG == 0
#undef SFG_FONT_SIZE_BIG
#define SFG_FONT_SIZE_BIG 1
#endif
#define SFG_Z_BUFFER_SIZE SFG_GAME_RESOLUTION_X
/**
Step in which walls get higher, in raycastlib units.
*/
#define SFG_WALL_HEIGHT_STEP (RCL_UNITS_PER_SQUARE / 4)
#define SFG_CEILING_MAX_HEIGHT\
(16 * RCL_UNITS_PER_SQUARE - RCL_UNITS_PER_SQUARE / 2 )
#define SFG_DOOR_UP_DOWN_MASK 0x20
#define SFG_DOOR_LOCK(doorRecord) ((doorRecord) >> 6)
#define SFG_DOOR_VERTICAL_POSITION_MASK 0x1f
#define SFG_DOOR_HEIGHT_STEP (RCL_UNITS_PER_SQUARE / 0x1f)
#define SFG_DOOR_INCREMENT_PER_FRAME \
(SFG_DOOR_OPEN_SPEED / (SFG_DOOR_HEIGHT_STEP * SFG_FPS))
#if SFG_DOOR_INCREMENT_PER_FRAME == 0
#undef SFG_DOOR_INCREMENT_PER_FRAME
#define SFG_DOOR_INCREMENT_PER_FRAME 1
#endif
#define SFG_MAX_ITEMS SFG_MAX_LEVEL_ELEMENTS
#define SFG_MAX_SPRITE_SIZE SFG_GAME_RESOLUTION_X
#define SFG_MAP_PIXEL_SIZE (SFG_GAME_RESOLUTION_Y / SFG_MAP_SIZE)
#if SFG_MAP_PIXEL_SIZE == 0
#undef SFG_MAP_PIXEL_SIZE
#define SFG_MAP_PIXEL_SIZE 1
#endif
#define SFG_AI_UPDATE_FRAME_INTERVAL \
(SFG_FPS / SFG_AI_FPS)
#if SFG_AI_UPDATE_FRAME_INTERVAL == 0
#undef SFG_AI_UPDATE_FRAME_INTERVAL
#define SFG_AI_UPDATE_FRAME_INTERVAL 1
#endif
#define SFG_SPRITE_ANIMATION_FRAME_DURATION \
(SFG_FPS / SFG_SPRITE_ANIMATION_SPEED)
#if SFG_SPRITE_ANIMATION_FRAME_DURATION == 0
#undef SFG_SPRITE_ANIMATION_FRAME_DURATION
#define SFG_SPRITE_ANIMATION_FRAME_DURATION 1
#endif
#define SFG_HUD_MARGIN (SFG_GAME_RESOLUTION_X / 40)
#define SFG_HUD_BORDER_INDICATOR_WIDTH_PIXELS \
(SFG_GAME_RESOLUTION_Y / SFG_HUD_BORDER_INDICATOR_WIDTH)
#define SFG_HUD_BORDER_INDICATOR_DURATION_FRAMES \
(SFG_HUD_BORDER_INDICATOR_DURATION / SFG_MS_PER_FRAME)
#if SFG_HUD_BORDER_INDICATOR_DURATION_FRAMES == 0
#define SFG_HUD_BORDER_INDICATOR_DURATION_FRAMES 1
#endif
#define SFG_BLINK_PERIOD_FRAMES (SFG_BLINK_PERIOD / SFG_MS_PER_FRAME)
#define SFG_HUD_BAR_HEIGHT \
(SFG_FONT_CHARACTER_SIZE * SFG_FONT_SIZE_MEDIUM + SFG_HUD_MARGIN * 2 + 1)
// -----------------------------------------------------------------------------
// monsters
#define SFG_MONSTER_ATTACK_MELEE 0
#define SFG_MONSTER_ATTACK_FIREBALL 1
#define SFG_MONSTER_ATTACK_BULLET 2
#define SFG_MONSTER_ATTACK_FIREBALL_BULLET 3
#define SFG_MONSTER_ATTACK_PLASMA 4
#define SFG_MONSTER_ATTACK_EXPLODE 5
#define SFG_MONSTER_ATTACK_FIREBALL_PLASMA 6
#define SFG_MONSTER_ATTRIBUTE(attackType,aggressivity0to255,health0to255,spriteSize0to3) \
((uint16_t) ( \
attackType | \
((aggressivity0to255 / 8) << 3) | \
(spriteSize0to3 << 8) | \
((health0to255 / 4) << 10)))
#define SFG_GET_MONSTER_ATTACK_TYPE(monsterNumber) \
(SFG_monsterAttributeTable[monsterNumber] & 0x0007)
#define SFG_GET_MONSTER_AGGRESSIVITY(monsterNumber) \
(((SFG_monsterAttributeTable[monsterNumber] >> 3) & 0x1F) * 8)
#define SFG_GET_MONSTER_SPRITE_SIZE(monsterNumber) \
((SFG_monsterAttributeTable[monsterNumber] >> 8) & 0x03)
#define SFG_GET_MONSTER_MAX_HEALTH(monsterNumber) \
(((SFG_monsterAttributeTable[monsterNumber] >> 10) & 0x3F) * 4)
/**
Table of monster attributes, each as a 16bit word in format:
MSB hhhhhhssaaaattt LSB
ttt: attack type
aaaaa: aggressivity (frequence of attacks), 0 to 31
ss: sprite size
hhhhhh: health, 0 to 63
*/
uint16_t SFG_monsterAttributeTable[SFG_MONSTERS_TOTAL] =
{
/* spider */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_FIREBALL,40,61,2),
/* destr. */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_FIREBALL_BULLET,90,170,3),
/* warrior */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_MELEE,255,40,1),
/* plasma */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_PLASMA,56,92,1),
/* ender */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_FIREBALL_PLASMA,128,255,3),
/* turret */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_BULLET,32,23,0),
/* explod. */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_EXPLODE,255,36,1)
};
// -----------------------------------------------------------------------------
// weapons and projectiles
#define SFG_WEAPON_KNIFE 0
#define SFG_WEAPON_SHOTGUN 1
#define SFG_WEAPON_MACHINE_GUN 2
#define SFG_WEAPON_ROCKET_LAUNCHER 3
#define SFG_WEAPON_PLASMAGUN 4
#define SFG_WEAPON_SOLUTION 5
#define SFG_WEAPONS_TOTAL 6
#define SFG_WEAPON_ATTRIBUTE(fireType,projectileCount,fireCooldownMs) \
((uint8_t) (fireType | ((projectileCount - 1) << 2) | ((fireCooldownMs / (SFG_MS_PER_FRAME * 16)) << 4)))
#define SFG_GET_WEAPON_FIRE_TYPE(weaponNumber) \
(SFG_weaponAttributeTable[weaponNumber] & 0x03)
#define SFG_GET_WEAPON_FIRE_COOLDOWN_FRAMES(weaponNumber) \
((SFG_weaponAttributeTable[weaponNumber] >> 4) * 16)
#define SFG_GET_WEAPON_PROJECTILE_COUNT(weaponNumber) \
(((SFG_weaponAttributeTable[weaponNumber] >> 2) & 0x03) + 1)
#define SFG_MIN_WEAPON_COOLDOWN_FRAMES 8
#define SFG_WEAPON_FIRE_TYPE_MELEE 0
#define SFG_WEAPON_FIRE_TYPE_BULLET 1
#define SFG_WEAPON_FIRE_TYPE_FIREBALL 2
#define SFG_WEAPON_FIRE_TYPE_PLASMA 3
#define SFG_WEAPON_FIRE_TYPES_TOTAL 4
/**
Table of weapon attributes, each as a byte in format:
MSB ccccnnff LSB
ff: fire type
nn: number of projectiles - 1
cccc: fire cooldown in frames, i.e. time after which the next shot can be
shot again, ccccc has to be multiplied by 16 to get the real value
*/
static const uint8_t SFG_weaponAttributeTable[SFG_WEAPONS_TOTAL] =
{
/* knife */ SFG_WEAPON_ATTRIBUTE(SFG_WEAPON_FIRE_TYPE_MELEE,1,650), // DPS: 6.2
/* shotgun */ SFG_WEAPON_ATTRIBUTE(SFG_WEAPON_FIRE_TYPE_BULLET,2,1250), // DPS: 12.8
/* m. gun */ SFG_WEAPON_ATTRIBUTE(SFG_WEAPON_FIRE_TYPE_BULLET,1,700), // DPS: 11.4
/* r. laun. */ SFG_WEAPON_ATTRIBUTE(SFG_WEAPON_FIRE_TYPE_FIREBALL,1,850), // DPS: 28.2
/* plasma */ SFG_WEAPON_ATTRIBUTE(SFG_WEAPON_FIRE_TYPE_PLASMA,1,550), // DPS: 32.7
/* solution */ SFG_WEAPON_ATTRIBUTE(SFG_WEAPON_FIRE_TYPE_PLASMA,4,1050) // DPS: 85.7
};
static const uint8_t SFG_attackDamageTable[SFG_WEAPON_FIRE_TYPES_TOTAL] =
{
/* melee */ 4,
/* bullet */ 8,
/* explostion (fireball) */ 24,
/* plasma */ 18
};
#define SFG_PROJECTILE_EXPLOSION 0
#define SFG_PROJECTILE_FIREBALL 1
#define SFG_PROJECTILE_PLASMA 2
#define SFG_PROJECTILE_DUST 3
#define SFG_PROJECTILE_BULLET 4
#define SFG_PROJECTILE_NONE 255
#define SFG_PROJECTILES_TOTAL 5
#define SFG_PROJECTILE_ATTRIBUTE(speedSquaresPerSec,timeToLiveMs) \
((uint8_t) \
((((speedSquaresPerSec / 4 == 0) && (speedSquaresPerSec != 0)) ? 1 : speedSquaresPerSec / 4) | \
((timeToLiveMs / (8 * SFG_MS_PER_FRAME)) << 3)))
#define SFG_GET_PROJECTILE_SPEED_UPS(projectileNumber) \
(((SFG_projectileAttributeTable[projectileNumber] & 0x07) * 4 * RCL_UNITS_PER_SQUARE) / SFG_FPS)
#define SFG_GET_PROJECTILE_FRAMES_TO_LIVE(projectileNumber) \
((SFG_projectileAttributeTable[projectileNumber] >> 3) * 8)
/**
Table of projectile attributes, each as a byte in format:
MSB lllllsss LSB
fff: half speed in game squares per second
lllll: eigth of frames to live
*/
#define LOW_FPS (SFG_FPS < 24) ///< low FPS needs low speeds, because collisions
static const uint8_t SFG_projectileAttributeTable[SFG_PROJECTILES_TOTAL] =
{
/* explosion */ SFG_PROJECTILE_ATTRIBUTE(0,400),
/* fireball */ SFG_PROJECTILE_ATTRIBUTE(10,1000),
#if LOW_FPS
/* plasma */ SFG_PROJECTILE_ATTRIBUTE(17,500),
#else
/* plasma */ SFG_PROJECTILE_ATTRIBUTE(18,500),
#endif
/* dust */ SFG_PROJECTILE_ATTRIBUTE(0,450),
#if LOW_FPS
/* bullet */ SFG_PROJECTILE_ATTRIBUTE(17,1000)
#else
/* bullet */ SFG_PROJECTILE_ATTRIBUTE(28,1000)
#endif
};
#undef LOW_FPS
#endif // guard

View File

@ -0,0 +1,149 @@
/**
@file game.c
This is a quick V4K implementation of the game front end, with a couple of fixes for MSVC.
by r-lyeh
Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/)
plus a waiver of all other intellectual property. The goal of this work is
be and remain completely in the public domain forever, available for any use
whatsoever.
*/
#define V4K_IMPLEMENTATION
#include "v4k.h"
#ifdef _MSC_VER
#define __builtin_expect(expr,val) (expr)
#endif
#define SFG_FPS 60
#define SFG_LOG(str) ;// puts(str);
#define SFG_DITHERED_SHADOW 1
#define SFG_DIMINISH_SPRITES 1
#define SFG_HEADBOB_SHEAR (-1 * SFG_SCREEN_RESOLUTION_Y / 80)
#define SFG_BACKGROUND_BLUR 1
#define SFG_SCREEN_RESOLUTION_X 700
#define SFG_SCREEN_RESOLUTION_Y 512
#define SFG_CAN_EXIT 1
#include "game.h"
#include "sounds.h"
// now implement the Anarch API functions (SFG_*)
void SFG_processEvent(uint8_t event, uint8_t data)
{}
void SFG_sleepMs(uint16_t timeMs)
{}
uint32_t SFG_getTimeMs() {
return time_ms();
}
void SFG_getMouseOffset(int16_t *x, int16_t *y)
{}
int8_t SFG_keyPressed(uint8_t key) {
switch (key) {
default: return 0;
case SFG_KEY_UP: return !!input(KEY_UP);
case SFG_KEY_DOWN: return !!input(KEY_DOWN);
case SFG_KEY_RIGHT: return !!input(KEY_RIGHT);
case SFG_KEY_LEFT: return !!input(KEY_LEFT);
case SFG_KEY_A: return !!input(KEY_Z) | !!input(KEY_SPACE);
case SFG_KEY_C: return !!input(KEY_X) | !!input(KEY_LALT);
case SFG_KEY_B: return !!input(KEY_C) | !!input(KEY_LCTRL);
}
}
void SFG_save(uint8_t data[SFG_SAVE_SIZE]) {
if( !file_write("anarch.sav",data,SFG_SAVE_SIZE) ) {
puts("V4K: could not save the file!");
return;
}
}
uint8_t SFG_load(uint8_t data[SFG_SAVE_SIZE]) {
int len = file_size("anarch.sav");
for( char *blob = file_read("anarch.sav"); blob && len == SFG_SAVE_SIZE; ) {
return !!memcpy(data, blob, len);
}
puts("V4K: no save file to open");
return 0;
}
uint32_t screen[SFG_SCREEN_RESOLUTION_X * SFG_SCREEN_RESOLUTION_Y];
void SFG_setPixel(uint16_t x, uint16_t y, uint8_t colorIndex) {
static unsigned palette32[256];
do_once
for (int i = 0; i < 256; ++i) { // precompute RGB palette
uint16_t col565 = paletteRGB565[i];
palette32[i] = 0xff000000 | ((col565 << 19) & 0xf80000) | ((col565 << 5) & 0xfc00) | ((col565 >> 8) & 0xf8);
}
screen[y * SFG_SCREEN_RESOLUTION_X + x] = palette32[colorIndex];
}
uint8_t musicOn = 1; //< this has to be init to 0 (not 1), else a few samples get played at start
void SFG_setMusic(uint8_t value) {
if( value == SFG_MUSIC_TURN_ON ) musicOn = 1;
if( value == SFG_MUSIC_TURN_OFF ) musicOn = 0;
if( value == SFG_MUSIC_NEXT ) SFG_nextMusicTrack();
}
#define MUSIC_VOLUME 16.f
uint16_t audioBuff[SFG_SFX_SAMPLE_COUNT] = {0};
uint16_t audioPos = 0; // audio position for the next audio buffer fill
uint32_t audioUpdateFrame = 0; // game frame at which audio buffer fill happened
static inline int16_t mixSamples(int16_t sample1, int16_t sample2) {
return sample1 + sample2;
}
void audioFillCallback(void *userdata, uint8_t *s, int l) {
uint16_t *s16 = (uint16_t *) s;
for (int i = 0; i < l / 2; ++i) {
s16[i] = musicOn ?
mixSamples(audioBuff[audioPos], MUSIC_VOLUME * (SFG_getNextMusicSample() - SFG_musicTrackAverages[SFG_MusicState.track]))
: audioBuff[audioPos];
audioBuff[audioPos] = 0;
audioPos = (audioPos < SFG_SFX_SAMPLE_COUNT - 1) ? (audioPos + 1) : 0;
}
audioUpdateFrame = SFG_game.frame;
}
void SFG_playSound(uint8_t soundIndex, uint8_t volume) {
uint16_t pos = (audioPos + ((SFG_game.frame - audioUpdateFrame) * SFG_MS_PER_FRAME * 8)) % SFG_SFX_SAMPLE_COUNT;
uint16_t volumeScale = 1 << (volume / 37);
for (int i = 0; i < SFG_SFX_SAMPLE_COUNT; ++i) {
audioBuff[pos] = mixSamples(audioBuff[pos], (128 - SFG_GET_SFX_SAMPLE(soundIndex,i)) * volumeScale);
pos = (pos < SFG_SFX_SAMPLE_COUNT - 1) ? (pos + 1) : 0;
}
}
int main() {
// install signal handlers
signal_hooks();
SFG_init();
window_create(0.75, 0);
texture_t t = texture_checker();
while( window_swap() && SFG_mainLoopBody() ) {
texture_update(&t, SFG_SCREEN_RESOLUTION_X, SFG_SCREEN_RESOLUTION_Y, 4, screen, TEXTURE_RGB|TEXTURE_LINEAR);
fullscreen_quad_rgb(t, 1.0f);
uint16_t samples[128]; // 8 KHz 16-bit mono = 8000/60 = 133 samples/frame -> 256 samples/frame
audioFillCallback(NULL, (uint8_t*)samples, sizeof(samples));
audio_queue(samples, countof(samples), AUDIO_8KHZ|AUDIO_16|AUDIO_1CH );
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,98 @@
/*
@file palette.h
General purpose HSV-based 256 color palette.
by Miloslav Ciz (drummyfish), 2019
Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/)
plus a waiver of all other intellectual property. The goal of this work is
be and remain completely in the public domain forever, available for any use
whatsoever.
*/
#ifndef PALETTE_256_H
#define PALETTE_256_H
SFG_PROGRAM_MEMORY uint16_t paletteRGB565[256] = {
#if 1
// manually adjusted, more saturated palette
0, 6371, 14855, 27436, 38066, 48631, 59228, 65535, 6241, 14563, 24966, 33320,
43755, 52142, 62577, 64885, 6337, 16772, 25190, 35689, 44139, 52559, 63058,
65333, 6402, 14851, 23334, 31816, 40268, 50830, 59314, 65526, 4354, 10755,
15174, 21576, 30027, 36462, 42929, 51190, 2306, 8709, 13096, 19532, 25935,
30323, 36790, 47098, 4356, 8711, 15115, 19536, 27956, 32377, 38846, 47103,
4227, 8519, 12812, 17136, 25588, 31961, 38334, 46751, 2115, 8424, 14732, 21040,
27380, 33721, 40030, 48511, 6244, 12520, 22924, 31280, 39669, 48089, 56445,
64927, 8290, 16614, 24969, 33325, 43761, 52148, 62585, 64892, 10240, 18464,
26657, 38946, 47202, 55524, 63781, 64074, 10400, 18753, 27170, 37601, 48034,
56421, 64837, 65002, 6496, 14944, 23425, 31937, 40418, 48869, 57317, 61418,
352, 4704, 7041, 7362, 15842, 20196, 24550, 30697, 354, 611, 2949, 5288, 7658,
12013, 8175, 20467, 357, 617, 910, 5298, 9686, 7931, 14335, 24575, 69, 233,
4461, 4594, 8918, 2907, 13311, 19679, 4133, 2089, 4173, 8306, 10455, 16667,
20863, 27263, 6149, 14377, 22574, 28819, 39063, 45371, 53631, 57983, 10242,
18469, 26664, 38987, 47247, 55537, 63797, 64119, 10272, 18432, 26624, 34848,
45056, 53312, 61504, 63520, 10336, 18624, 26976, 35296, 45728, 54048, 62400,
64609, 8544, 16992, 25440, 31872, 42400, 50880, 59328, 65504, 4448, 2656,
7008, 11392, 13728, 14016, 20416, 26593, 2400, 608, 864, 3200, 5504, 1698,
1985, 2019, 353, 614, 872, 1163, 1422, 1713, 2005, 2039, 197, 361, 557, 753,
950, 5273, 1406, 9759, 5, 9, 2093, 81, 4214, 186, 2270, 351, 2052, 4105, 4109,
8209, 8278, 12314, 16414, 18527, 10245, 14378, 22541, 30738, 38934, 47130, 55326,
61471, 10241, 18435, 26630, 34824, 45066, 53293, 61519, 63601
#else
// original palette
0, 8484, 19017, 27501, 38034, 46518, 57051, 65535, 8354, 16709, 25096, 33450,
41805, 50192, 58546, 64853, 8386, 16805, 25224, 33642, 42061, 50480, 58898,
65269, 6402, 14853, 23304, 29706, 38157, 46608, 55058, 61429, 4354, 10757,
17160, 23562, 29965, 36368, 42770, 49141, 4355, 10758, 17161, 21516, 27920,
34323, 38678, 45049, 4323, 10759, 17163, 21519, 27923, 34327, 38683, 45055,
4292, 10632, 17004, 21296, 27668, 34008, 38300, 44671, 4260, 10568, 16908,
23216, 29524, 35864, 42172, 48479, 6308, 14664, 23052, 29360, 37716, 46104,
54460, 60767, 8355, 16710, 25098, 33453, 41809, 50196, 58552, 64859, 8257,
16546, 24836, 33093, 41382, 49672, 57929, 64170, 8353, 16738, 25124, 33509,
41894, 50248, 58633, 64970, 6401, 12802, 21252, 27653, 36102, 42504, 50953,
57322, 2305, 6658, 11012, 15365, 19718, 24072, 28425, 32746, 2306, 4612, 8967,
11273, 13580, 17934, 20240, 22515, 2307, 4615, 8971, 11279, 13587, 17943, 20251,
22527, 2180, 4392, 8652, 10864, 13076, 17304, 19516, 21727, 2116, 6312, 10508,
14672, 18868, 23064, 25180, 29375, 6212, 12456, 20748, 26960, 35252, 41496,
49756, 55999, 8258, 16549, 24840, 33099, 41390, 49681, 57940, 64183, 8192,
16384, 24576, 32768, 40960, 49152, 57344, 63488, 8320, 16640, 24960, 33312,
41632, 49952, 58304, 64576, 6400, 14848, 23296, 29696, 38144, 46592, 52992,
61408, 2304, 6656, 8960, 13312, 15616, 19968, 22272, 26592, 256, 513, 769, 1026,
1283, 1539, 1796, 2021, 258, 517, 776, 1035, 1294, 1552, 1811, 2038, 164, 360,
556, 752, 948, 1144, 1308, 1503, 36, 104, 140, 208, 244, 312, 348, 415, 2052,
4104, 8204, 10256, 14356, 16408, 18460, 22559, 6148, 14344, 20492, 28688, 34836,
43032, 51228, 57375, 8194, 16388, 24582, 32777, 40971, 49165, 57359, 63505
#endif
};
/** Adds value (brightness), possibly negative, to given color (represented by
its palette index). If you know you'll only be either adding or substracting,
use plusValue() or minusValue() functions, which should be faster. */
static inline uint8_t palette_addValue(uint8_t color, int8_t add)
{
uint8_t newValue = color + add;
if ((newValue >> 3) == (color >> 3))
return newValue;
else
return add > 0 ? (color | 0x07) : 0;
}
/** Adds a positive value (brightness) to given color (represented by its
palette index). This should be a little bit faster than addValue(). */
static inline uint8_t palette_plusValue(uint8_t color, uint8_t plus)
{
uint8_t newValue = color + plus;
return ((newValue >> 3) == (color >> 3)) ? newValue : (color | 0x07);
}
/** Substracts a positive value (brightness) from given color (represented by
its palette index). This should be a little bit faster than addValue(). */
static inline uint8_t palette_minusValue(uint8_t color, uint8_t minus)
{
uint8_t newValue = color - minus;
return ((newValue >> 3) == (color >> 3)) ? newValue : 0;
}
#endif //guard

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,518 @@
/**
@file settings.h
This file contains settings (or setting hints) for the game. Values here can
fine tune performance vs quality and personalize the final compiled game. Some
of these settings may be overriden by the specific platform used according to
its limitations. You are advised to NOT change value in this file directly,
but rather predefine them somewhere before this file gets included, e.g. in
you personal settings file.
by Miloslav Ciz (drummyfish), 2019
Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/)
plus a waiver of all other intellectual property. The goal of this work is to
be and remain completely in the public domain forever, available for any use
whatsoever.
*/
#ifndef _SFG_SETTINGS_H
#define _SFG_SETTINGS_H
/**
Time multiplier in SFG_Units (1.0 == 1024). This can be used to slow down or
speed up the game. Note that this also changes the rendering FPS accordingly
(e.g. half FPS at half speed), so if you want to keep the FPS, divide it by
the multiplier value.
*/
#ifndef SFG_TIME_MULTIPLIER
#define SFG_TIME_MULTIPLIER 1024
#endif
/**
Target FPS (frames per second). This sets the game logic FPS and will try to
render at the same rate. If such fast rendering can't be achieved, frames will
be droped, but the game logic will still be forced to run at this speed, so
the game may actually become slowed down if FPS is set too high. Too high or
too low FPS can also negatively affect game speeds which are computed as
integers and rounding errors can occur soon, so don't set this to extreme
values (try to keep between 20 to 100). FPS also determines the game
simulation step length, so different FPS values may result in very slight
differences in game behavior (not very noticeable but affecting demos etc.).
*/
#ifndef SFG_FPS
#define SFG_FPS 60
#endif
/**
Increases or decreases the brightness of the rendered world (but not menu,
HUD etc.). Effective values are -8 to 8.
*/
#ifndef SFG_BRIGHTNESS
#define SFG_BRIGHTNESS 0
#endif
/**
On platforms with mouse this sets its horizontal sensitivity. 128 means 1
RCL_Unit turn angle per mouse pixel travelled.
*/
#ifndef SFG_MOUSE_SENSITIVITY_HORIZONTAL
#define SFG_MOUSE_SENSITIVITY_HORIZONTAL 32
#endif
/**
Like SFG_MOUSE_SENSITIVITY_HORIZONTAL but for vertical look. 128 means 1
shear pixel per mouse pixel travelled.
*/
#ifndef SFG_MOUSE_SENSITIVITY_VERTICAL
#define SFG_MOUSE_SENSITIVITY_VERTICAL 64
#endif
/**
Width of the screen in pixels. Set this to ACTUAL resolution. If you want the
game to run at smaller resolution (with bigger pixels), do this using
SFG_RESOLUTION_SCALEDOWN.
*/
#ifndef SFG_SCREEN_RESOLUTION_X
#define SFG_SCREEN_RESOLUTION_X 800
#endif
/**
Like SFG_SCREEN_RESOLUTION_X, but for y resolution.
*/
#ifndef SFG_SCREEN_RESOLUTION_Y
#define SFG_SCREEN_RESOLUTION_Y 600
#endif
/**
How quickly player turns left/right, in degrees per second.
*/
#ifndef SFG_PLAYER_TURN_SPEED
#define SFG_PLAYER_TURN_SPEED 180
#endif
/**
Horizontal FOV (field of vision) in RCL_Units (1024 means 360 degrees).
*/
#ifndef SFG_FOV_HORIZONTAL
#define SFG_FOV_HORIZONTAL 256
#endif
/**
Like SFG_FOV_HORIZONTAL but for vertical angle.
*/
#ifndef SFG_FOV_VERTICAL
#define SFG_FOV_VERTICAL 330
#endif
/**
Distance, in RCL_Units, to which textures will be drawn. Textures behind this
distance will be replaced by an average constant color, which maybe can help
performance and also serves as an antialiasim (2 level MIP map). Value 0 turns
texturing completely off, which is much faster than having just a low value,
values >= 65535 activate texturing completely, which can be a little faster
than setting having a high value lower than this limit.
*/
#ifndef SFG_TEXTURE_DISTANCE
#define SFG_TEXTURE_DISTANCE 100000
#endif
/**
How many times the screen resolution will be divided (how many times a game
pixel will be bigger than the screen pixel).
*/
#ifndef SFG_RESOLUTION_SCALEDOWN
#define SFG_RESOLUTION_SCALEDOWN 1
#endif
/**
Multiplier, in RCL_Units (1024 == 1.0), of the damager player takes. This can
be used to balance difficulty.
*/
#ifndef SFG_PLAYER_DAMAGE_MULTIPLIER
#define SFG_PLAYER_DAMAGE_MULTIPLIER 512
#endif
/**
Hint as to whether to run in fullscreen, if the platform allows it.
*/
#ifndef SFG_FULLSCREEN
#define SFG_FULLSCREEN 0
#endif
/**
Whether shadows (fog) should be dithered, i.e. more smooth (needs a bit more
CPU performance and memory).
*/
#ifndef SFG_DITHERED_SHADOW
#define SFG_DITHERED_SHADOW 0
#endif
/**
Depth step (in RCL_Units) after which fog diminishes a color by one value
point. For performance reasons this number should be kept a power of two!
*/
#ifndef SFG_FOG_DIMINISH_STEP
#define SFG_FOG_DIMINISH_STEP 2048
#endif
/**
If set, floor and ceiling will be colored differently depending on their
height. This can be useful when fog is turned on and different floor levels
are hard to distinguish.
*/
#ifndef SFG_DIFFERENT_FLOOR_CEILING_COLORS
#define SFG_DIFFERENT_FLOOR_CEILING_COLORS 0
#endif
/**
Maximum number of squares that will be traversed by any cast ray. Smaller
number is faster but can cause visual artifacts.
*/
#ifndef SFG_RAYCASTING_MAX_STEPS
#define SFG_RAYCASTING_MAX_STEPS 30
#endif
/**
Maximum number of hits any cast ray will register. Smaller number is faster
but can cause visual artifacts.
*/
#ifndef SFG_RAYCASTING_MAX_HITS
#define SFG_RAYCASTING_MAX_HITS 10
#endif
/**
Same as SFG_RAYCASTING_MAX_STEPS but for visibility rays that are used to
check whether sprites are visible etc.
*/
#ifndef SFG_RAYCASTING_VISIBILITY_MAX_STEPS
#if SFG_RAYCASTING_MAX_STEPS < 15
#define SFG_RAYCASTING_VISIBILITY_MAX_STEPS 15
#else
#define SFG_RAYCASTING_VISIBILITY_MAX_STEPS SFG_RAYCASTING_MAX_STEPS
#endif
#endif
/**
Same as SFG_RAYCASTING_MAX_HITS but for visibility rays that are used to check
whether sprites are visible etc.
*/
#ifndef SFG_RAYCASTING_VISIBILITY_MAX_HITS
#if SFG_RAYCASTING_MAX_HITS < 6
#define SFG_RAYCASTING_VISIBILITY_MAX_HITS 6
#else
#define SFG_RAYCASTING_VISIBILITY_MAX_HITS SFG_RAYCASTING_MAX_HITS
#endif
#endif
/**
How many times rendering should be subsampled horizontally. Bigger number
can significantly improve performance (by casting fewer rays), but can look
a little worse. This number should be a divisor of SFG_SCREEN_RESOLUTION_X!
*/
#ifndef SFG_RAYCASTING_SUBSAMPLE
#define SFG_RAYCASTING_SUBSAMPLE 1
#endif
/**
Enables or disables fog (darkness) due to distance. Recommended to keep on
for good look, but can be turned off for performance.
*/
#ifndef SFG_ENABLE_FOG
#define SFG_ENABLE_FOG 1
#endif
/**
Says whether sprites should diminish in fog. This takes more performance but
looks better.
*/
#ifndef SFG_DIMINISH_SPRITES
#define SFG_DIMINISH_SPRITES 1
#endif
/**
How quick player head bob is, 1024 meaning once per second. 0 Means turn off
head bob.
*/
#ifndef SFG_HEADBOB_SPEED
#define SFG_HEADBOB_SPEED 900
#endif
/**
Sets head bob offset, in RCL_UNITS_PER_SQUARE. 0 Means turn off head bob.
*/
#ifndef SFG_HEADBOB_OFFSET
#define SFG_HEADBOB_OFFSET 200
#endif
/**
If head bob is on, this additionally sets additional camera shear bob, in
pixels, which can make bobbing look more "advanced". 0 turns this option off.
*/
#ifndef SFG_HEADBOB_SHEAR
#define SFG_HEADBOB_SHEAR 0
#endif
/**
Weapon bobbing offset in weapon image pixels.
*/
#ifndef SFG_WEAPONBOB_OFFSET
#define SFG_WEAPONBOB_OFFSET 4
#endif
/**
Camera shearing (looking up/down) speed, in vertical resolutions per second.
*/
#ifndef SFG_CAMERA_SHEAR_SPEED
#define SFG_CAMERA_SHEAR_SPEED 3
#endif
/**
Maximum camera shear (vertical angle). 1024 means 1.0 * vertical resolution.
*/
#ifndef SFG_CAMERA_MAX_SHEAR
#define SFG_CAMERA_MAX_SHEAR 1024
#endif
/**
Specifies how quick some sprite animations are, in frames per second.
*/
#ifndef SFG_SPRITE_ANIMATION_SPEED
#define SFG_SPRITE_ANIMATION_SPEED 4
#endif
/**
How wide the border indicator is, in fractions of screen width.
*/
#ifndef SFG_HUD_BORDER_INDICATOR_WIDTH
#define SFG_HUD_BORDER_INDICATOR_WIDTH 32
#endif
/**
For how long border indication (being hurt etc.) stays shown, in ms.
*/
#ifndef SFG_HUD_BORDER_INDICATOR_DURATION
#define SFG_HUD_BORDER_INDICATOR_DURATION 500
#endif
/**
Color (palette index) by which being hurt is indicated.
*/
#ifndef SFG_HUD_HURT_INDICATION_COLOR
#define SFG_HUD_HURT_INDICATION_COLOR 175
#endif
/**
Color (palette index) by which taking an item is indicated.
*/
#ifndef SFG_HUD_ITEM_TAKEN_INDICATION_COLOR
#define SFG_HUD_ITEM_TAKEN_INDICATION_COLOR 207
#endif
/**
How many element (items, monsters, ...) distances will be checked per frame
for distance. Higher value may decrease performance a tiny bit, but things
will react more quickly and appear less "out of thin air".
*/
#ifndef SFG_ELEMENT_DISTANCES_CHECKED_PER_FRAME
#define SFG_ELEMENT_DISTANCES_CHECKED_PER_FRAME 8
#endif
/**
Maximum distance at which sound effects (SFX) will be played. The SFX volume
will gradually drop towards this distance.
*/
#ifndef SFG_SFX_MAX_DISTANCE
#define SFG_SFX_MAX_DISTANCE (1024 * 60)
#endif
/**
Says the intensity of background image blur. 0 means no blur, which improves
performance and lowers memory usage. Blur doesn't look very good in small
resolutions.
*/
#ifndef SFG_BACKGROUND_BLUR
#define SFG_BACKGROUND_BLUR 0
#endif
/**
Defines the period, in ms, of things that blink, such as text.
*/
#ifndef SFG_BLINK_PERIOD
#define SFG_BLINK_PERIOD 500
#endif
/**
Probability (0 - 255) of how often a monster makes sound during movement.
*/
#ifndef SFG_MONSTER_SOUND_PROBABILITY
#define SFG_MONSTER_SOUND_PROBABILITY 64
#endif
/**
Affects how precise monsters are in aiming, specify random range in
fourths of a game square. Should be power of 2 for performance.
*/
#ifndef SFG_MONSTER_AIM_RANDOMNESS
#define SFG_MONSTER_AIM_RANDOMNESS 4
#endif
/// Color 1 index of player on map.
#ifndef SFG_MAP_PLAYER_COLOR1
#define SFG_MAP_PLAYER_COLOR1 93
#endif
/// Color 2 index of player on map.
#ifndef SFG_MAP_PLAYER_COLOR2
#define SFG_MAP_PLAYER_COLOR2 111
#endif
/// Color index of elevators on map.
#ifndef SFG_MAP_ELEVATOR_COLOR
#define SFG_MAP_ELEVATOR_COLOR 214
#endif
/// Color index of squeezers on map.
#ifndef SFG_MAP_SQUEEZER_COLOR
#define SFG_MAP_SQUEEZER_COLOR 246
#endif
/// Color index of door on map.
#ifndef SFG_MAP_DOOR_COLOR
#define SFG_MAP_DOOR_COLOR 188
#endif
/**
Boolean value indicating whether current OS is malware.
*/
#ifndef SFG_OS_IS_MALWARE
#define SFG_OS_IS_MALWARE 0
#endif
/**
Angle difference, as a cos value in RCL_Units, between the player and a
monster, at which vertical autoaim will trigger. If the angle is greater, a
shot will go directly forward.
*/
#ifndef SFG_VERTICAL_AUTOAIM_ANGLE_THRESHOLD
#define SFG_VERTICAL_AUTOAIM_ANGLE_THRESHOLD 50
#endif
/**
Byte (0 - 255) volume of the menu click sound.
*/
#ifndef SFG_MENU_CLICK_VOLUME
#define SFG_MENU_CLICK_VOLUME 220
#endif
/**
Says whether the exit item should be showed in the menu. Platforms that can't
exit (such as some gaming consoles that simply use power off button) can
define this to 0.
*/
#ifndef SFG_CAN_EXIT
#define SFG_CAN_EXIT 1
#endif
/**
On Arduino platforms this should be set to 1. That will cause some special
treatment regarding constant variables and PROGMEM.
*/
#ifndef SFG_ARDUINO
#define SFG_ARDUINO 0
#endif
/**
Whether levels background (in distance or transparent wall textures) should
be drawn. If turned off, the background will be constant color, which can
noticably increase performance.
*/
#ifndef SFG_DRAW_LEVEL_BACKGROUND
#define SFG_DRAW_LEVEL_BACKGROUND 1
#endif
/**
Says the size, in pixels, of a sprite when it is closest to the camera, which
is the maximum size that can be drawn. Sprites on "weird" aspect ratios can
look weirdly scaled, so this option can be used to fix that (typically set
horizontal screen resolution instead of vertical).
*/
#ifndef SFG_SPRITE_MAX_SIZE
#define SFG_SPRITE_MAX_SIZE \
(SFG_SCREEN_RESOLUTION_Y / SFG_RESOLUTION_SCALEDOWN)
#endif
/**
If set, single item menu will be forced.
*/
#ifndef SFG_FORCE_SINGLE_ITEM_MENU
#define SFG_FORCE_SINGLE_ITEM_MENU 0
#endif
//------ developer/debug settings ------
/**
Developer cheat for having infinite ammo in all weapons.
*/
#ifndef SFG_INFINITE_AMMO
#define SFG_INFINITE_AMMO 0
#endif
/**
Developer cheat for immortality.
*/
#ifndef SFG_IMMORTAL
#define SFG_IMMORTAL 0
#endif
/**
Developer setting, with 1 every level is won immediately after start.
*/
#ifndef SFG_QUICK_WIN
#define SFG_QUICK_WIN 0
#endif
/**
Reveals all levels to be played.
*/
#ifndef SFG_ALL_LEVELS
#define SFG_ALL_LEVELS 0
#endif
/**
Turn on for previes mode for map editing (flying, noclip, fast movement etc.).
*/
#ifndef SFG_PREVIEW_MODE
#define SFG_PREVIEW_MODE 0
#endif
/**
How much faster movement is in the preview mode.
*/
#ifndef SFG_PREVIEW_MODE_SPEED_MULTIPLIER
#define SFG_PREVIEW_MODE_SPEED_MULTIPLIER 2
#endif
/**
Skips menu and starts given level immediatelly, for development. 0 means this
options is ignored, 1 means load level 1 etc.
*/
#ifndef SFG_START_LEVEL
#define SFG_START_LEVEL 0
#endif
/**
Reveals whole level map from start.
*/
#ifndef SFG_REVEAL_MAP
#define SFG_REVEAL_MAP 0
#endif
/**
Gives player all keys from start.
*/
#ifndef SFG_UNLOCK_DOOR
#define SFG_UNLOCK_DOOR 0
#endif
#endif // guard

View File

@ -0,0 +1,404 @@
/**
@file smallinput.h
Small API for getting keyboard/mouse input, with possiblity to record it and
play back.
The Linux Input API requires root pirivileges (sudo).
by Milsolav "drummyfish" Ciz, released under CC0 1.0 (public domain)
*/
#ifndef _SMALLINPUT_H
#define _SMALLINPUT_H
#include <stdint.h>
#include <stdio.h>
#define SMALLINPUT_MODE_NORMAL 0 ///< Only handle input.
#define SMALLINPUT_MODE_RECORD 1 ///< Handle input and record it.
#define SMALLINPUT_MODE_PLAY 2 ///< Play back recorded input.
#define SMALLINPUT_KEY_NONE 0
#define SMALLINPUT_SPACE ' '
#define SMALLINPUT_BACKSPACE 8
#define SMALLINPUT_TAB 9
#define SMALLINPUT_RETURN 13
#define SMALLINPUT_SHIFT 14
#define SMALLINPUT_ESCAPE 27
#define SMALLINPUT_DELETE 127
#define SMALLINPUT_ARROW_UP 128
#define SMALLINPUT_ARROW_RIGHT 129
#define SMALLINPUT_ARROW_DOWN 130
#define SMALLINPUT_ARROW_LEFT 131
#define SMALLINPUT_F1 132
#define SMALLINPUT_F2 133
#define SMALLINPUT_F3 134
#define SMALLINPUT_F4 135
#define SMALLINPUT_F5 136
#define SMALLINPUT_F6 137
#define SMALLINPUT_F7 138
#define SMALLINPUT_F8 139
#define SMALLINPUT_F9 140
#define SMALLINPUT_F10 141
#define SMALLINPUT_F11 142
#define SMALLINPUT_F12 143
#define SMALLINPUT_CTRL 144
#define SMALLINPUT_MOUSE_L 253
#define SMALLINPUT_MOUSE_M 254
#define SMALLINPUT_MOUSE_R 255
#define SMALLINPUT_RECORD_KEY_DOWN 1 ///< Mouse down event, followed by code.
#define SMALLINPUT_RECORD_KEY_UP 2 ///< Moue up event, followed by code.
#define SMALLINPUT_RECORD_MOUSE_X 3 ///< Mouse x move, followed by s32 value.
#define SMALLINPUT_RECORD_MOUSE_Y 4 ///< Mouse y move, followed by s32 value.
#define SMALLINPUT_RECORD_END 255 ///< Record end, followed by 4 more same values.
uint8_t input_keyStates[256];
int32_t input_mousePosition[2];
uint8_t input_keyStatesPrevious[256];
int32_t input_mousePositionPrevious[2];
uint8_t input_mode;
uint32_t input_frame = 0;
uint8_t *input_recordData;
uint32_t input_recordPosition;
uint32_t input_recordSize;
#if 1 // TODO: add other options for input handling (SDL, xinput, ...)
/*
This is using Linux Input Subsystem API. Defines can be found in
include/uapi/linux/input-event-codes.h.
*/
#include <fcntl.h>
#include <linux/input.h>
#include <sys/time.h>
#include <unistd.h>
typedef struct
{
struct timeval time;
uint16_t type;
uint16_t code;
int32_t value;
} LinuxInputEvent;
#define INPUT_KEYBOARD_FILE "/dev/input/event0"
#define INPUT_MOUSE_FILE "/dev/input/event1"
int input_keyboardFile = 0;
int input_mouseFile = 0;
/**
Maps this library's key codes to linux input key codes.
*/
static const int input_linuxCodes[256] =
{
#define no KEY_RESERVED
no,no,no,no,no,no,no,no,KEY_BACKSPACE,KEY_TAB,no,no,no,KEY_ENTER,KEY_LEFTSHIFT,no,
no,no,no,no,no,no,no,no,no,no,no,KEY_ESC,no,no,no,no,
KEY_SPACE,no,no,no,no,no,no,no,no,no,no,no,KEY_COMMA,no,KEY_DOT,no,
KEY_0,KEY_1,KEY_2,KEY_3,KEY_4,KEY_5,KEY_6,KEY_7,KEY_8,KEY_9,no,KEY_SEMICOLON,no,KEY_EQUAL,no,KEY_QUESTION,
no,KEY_A,KEY_B,KEY_C,KEY_D,KEY_E,KEY_F,KEY_G,KEY_H,KEY_I,KEY_J,KEY_K,KEY_L,KEY_M,KEY_N,KEY_O,
KEY_P,KEY_Q,KEY_R,KEY_S,KEY_T,KEY_U,KEY_V,KEY_W,KEY_X,KEY_Y,KEY_Z,no,no,no,no,no,
no,KEY_A,KEY_B,KEY_C,KEY_D,KEY_E,KEY_F,KEY_G,KEY_H,KEY_I,KEY_J,KEY_K,KEY_L,KEY_M,KEY_N,KEY_O,
KEY_P,KEY_Q,KEY_R,KEY_S,KEY_T,KEY_U,KEY_V,KEY_W,KEY_X,KEY_Y,KEY_Z,no,no,no,no,KEY_DELETE,
KEY_UP,KEY_RIGHT,KEY_DOWN,KEY_LEFT,KEY_F1,KEY_F2,KEY_F3,KEY_F4,KEY_F5,KEY_F6,KEY_F7,KEY_F8,KEY_F9,KEY_F10,KEY_F11,KEY_F12,
KEY_LEFTCTRL,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,
no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,
no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,
no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,
no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,
no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,
no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no
#undef no
};
#endif
void input_recordU8(uint8_t value)
{
if (input_recordPosition < (input_recordSize - 1))
{
input_recordData[input_recordPosition] = value;
input_recordPosition++;
}
}
void input_recordU32(uint32_t value)
{
for (uint8_t i = 0; i < 4; ++i)
{
input_recordU8(value % 256);
value /= 256;
}
}
uint32_t input_readU32(uint8_t *data)
{
uint32_t result = 0;
for (uint8_t i = 0; i < 4; ++i)
result = result * 256 + data[3 - i];
return result;
}
/**
Initializes the library with given mode (SMALLINPUT_MODE_*).
*/
uint8_t input_init(uint8_t mode, uint8_t *recordData, uint32_t recordDataLength)
{
input_mode = mode;
input_mousePosition[0] = 0;
input_mousePosition[1] = 0;
input_mousePositionPrevious[0] = 0;
input_mousePositionPrevious[1] = 0;
input_frame = 0;
input_recordData = recordData;
input_recordPosition = 0;
input_recordSize = recordDataLength;
for (int16_t i = 0; i < 256; ++i)
{
input_keyStates[i] = 0;
input_keyStatesPrevious[i] = 0;
}
uint8_t result = 1;
if (input_mode != SMALLINPUT_MODE_PLAY)
{
input_keyboardFile = open(INPUT_KEYBOARD_FILE, O_RDONLY);
result = input_keyboardFile >= 0;
if (result)
{
fcntl(input_keyboardFile, F_SETFL, O_NONBLOCK);
input_mouseFile = open(INPUT_MOUSE_FILE, O_RDONLY);
result = input_mouseFile >= 0;
if (result)
fcntl(input_mouseFile, F_SETFL, O_NONBLOCK);
}
if (!result)
puts("could not open device file (are you root?)");
}
return result;
}
void input_end(void)
{
if (input_mode == SMALLINPUT_MODE_RECORD)
for (uint8_t i = 0; i < 5; ++i)
input_recordU8(SMALLINPUT_RECORD_END);
close(input_keyboardFile);
close(input_mouseFile);
}
/**
Should be called once every main loop iteration to retrieve current input
state.
*/
void input_update(void)
{
LinuxInputEvent event;
if (input_mode == SMALLINPUT_MODE_PLAY)
{
while (input_recordPosition < input_recordSize)
{
uint32_t nextFrame = input_readU32(input_recordData + input_recordPosition);
if (input_frame >= nextFrame)
{
input_recordPosition += 4;
uint8_t rec = input_recordData[input_recordPosition];
switch (rec)
{
case SMALLINPUT_RECORD_KEY_DOWN:
case SMALLINPUT_RECORD_KEY_UP:
input_recordPosition++;
input_keyStates[input_recordData[input_recordPosition]] = rec == SMALLINPUT_RECORD_KEY_DOWN;
input_recordPosition++;
break;
case SMALLINPUT_RECORD_MOUSE_X:
case SMALLINPUT_RECORD_MOUSE_Y:
input_recordPosition++;
input_mousePosition[rec == SMALLINPUT_RECORD_MOUSE_Y] =
input_readU32(input_recordData + input_recordPosition);
input_recordPosition += 4;
break;
case SMALLINPUT_RECORD_END:
input_recordPosition = input_recordSize;
break;
default: /*printf("corrupt record\n");*/ break;
}
}
else
break;
}
}
else
{
while (1) // keyboard
{
if (read(input_keyboardFile, &event, sizeof(event)) <= 0)
break;
if (event.type == EV_KEY && (event.value == 1 || event.value == 0))
for (uint16_t i = 0; i < 256; ++i)
if (event.code == input_linuxCodes[i])
{
input_keyStates[i] = event.value;
break;
}
}
while (1) // mouse
{
if (read(input_mouseFile, &event, sizeof(event)) <= 0)
break;
if (event.type == EV_REL)
input_mousePosition[event.code % 2] += event.value;
else if (event.type == EV_KEY)
{
input_keyStates[
event.code == BTN_LEFT ? SMALLINPUT_MOUSE_L :
(event.code == BTN_RIGHT ? SMALLINPUT_MOUSE_R : SMALLINPUT_MOUSE_M)]
= event.value;
}
}
}
for (uint16_t i = 0; i < 256; ++i)
if (input_keyStates[i] && input_keyStates[i] < 255)
input_keyStates[i]++;
if (input_mode == SMALLINPUT_MODE_RECORD)
{
for (uint8_t i = 0; i < 2; ++i) // record mouse events
if (input_mousePositionPrevious[i] != input_mousePosition[i])
{
input_recordU32(input_frame + 1);
input_recordU8((i == 0) ? SMALLINPUT_RECORD_MOUSE_X : SMALLINPUT_RECORD_MOUSE_Y);
input_recordU32(input_mousePosition[i]);
input_mousePositionPrevious[i] = input_mousePosition[i];
}
for (uint16_t i = 0; i < 256; ++i) // record key events
{
uint8_t a = input_keyStates[i] > 0;
uint8_t b = input_keyStatesPrevious[i] > 0;
if (a != b)
{
input_recordU32(input_frame + 1);
input_recordU8(a ? SMALLINPUT_RECORD_KEY_DOWN : SMALLINPUT_RECORD_KEY_UP);
input_recordU8(i);
input_keyStatesPrevious[i] = input_keyStates[i];
}
}
}
input_frame++;
}
/**
Returns the number of input frames for which given key has been pressed (> 1:
key is pressed, == 1: key was just pressed, == 0: key is not pressed).
*/
static inline uint8_t input_getKey(uint8_t key)
{
if (key >= 'a' && key <= 'z')
key = 'A' + (key - 'a');
return input_keyStates[key];
}
/**
Gets the mouse position.
*/
static inline void input_getMousePos(int32_t *x, int32_t *y)
{
*x = input_mousePosition[0];
*y = input_mousePosition[1];
}
static inline void input_setMousePos(int32_t x, int32_t y)
{
input_mousePosition[0] = x;
input_mousePosition[1] = y;
}
/**
Prints the current input state.
*/
void input_print()
{
printf("frame: %d\nmouse pos: %d %d",input_frame,input_mousePosition[0],input_mousePosition[1]);
for (uint16_t i = 0; i < 256; ++i)
{
if (i % 8 == 0)
putchar('\n');
char c = (i > ' ' && i <= 126) ? i : '?';
uint8_t n = input_getKey(i);
printf("%s",n ? " [" : " ");
printf("%03d (\'%c\'): %03d",i,c,input_getKey(i));
printf("%s",n ? "] " : " ");
}
putchar('\n');
}
void input_printRecord()
{
for (uint32_t i = 0; i < input_recordPosition; ++i)
{
if (i % 32 == 0)
putchar('\n');
printf("%d,",input_recordData[i]);
}
}
uint32_t input_hash()
{
uint32_t result = 0;
for (uint16_t i = 0; i < 256; ++i)
result += input_getKey(i) * (i + 1);
int32_t x, y;
input_getMousePos(&x,&y);
result += x + y << 16;
return result;
}
#endif // guard

View File

@ -0,0 +1,489 @@
/**
@file assets.h
This file containts sounds and music that can optionally be used by the game
frontend. Every sound effect has 2048 samples, is stored as 8kHz mono format
with 4 bit quantization, meaning every sound effect takes 1024 bytes. Sounds
can be converted using a provided python script like this:
python snd2array.py sound.raw
Music is based on bytebeat (procedural waveforms generated by short bitwise
operation formulas). The formulas were NOT copied from anywhere, they were
discovered from scratch.
by Miloslav Ciz (drummyfish), 2019
Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/)
plus a waiver of all other intellectual property. The goal of this work is to
be and remain completely in the public domain forever, available for any use
whatsoever.
*/
#ifndef _SFG_SOUNDS_H
#define _SFG_SOUNDS_H
#define SFG_SFX_SAMPLE_COUNT 2048
#define SFG_SFX_SIZE (SFG_SFX_SAMPLE_COUNT / 2)
/**
Gets an 8bit sound sample.
*/
#define SFG_GET_SFX_SAMPLE(soundIndex,sampleIndex) \
((SFG_PROGRAM_MEMORY_U8(SFG_sounds + soundIndex * SFG_SFX_SIZE \
+ sampleIndex / 2) << (4 * ((sampleIndex % 2) != 0))) & 0xf0)
#define SFG_TRACK_SAMPLES (512 * 1024)
#define SFG_TRACK_COUNT 6
/**
Average value of each music track, can be used to correct DC offset issues if
they appear.
*/
SFG_PROGRAM_MEMORY uint8_t SFG_musicTrackAverages[SFG_TRACK_COUNT] =
{14,7,248,148,6,8};
struct
{ // all should be initialized to 0 by default
uint8_t track;
uint32_t t; // time variable/parameter
uint32_t t2; // stores t squared, for better performance
uint32_t n11t; // stores a multiple of 11, for better performance
} SFG_MusicState;
/**
Gets the next 8bit 8KHz music sample for the bytebeat soundtrack. This
function is to be used by the frontend that plays music.
*/
uint8_t SFG_getNextMusicSample()
{
if (SFG_MusicState.t >= SFG_TRACK_SAMPLES)
{
SFG_MusicState.track++;
if (SFG_MusicState.track >= SFG_TRACK_COUNT)
SFG_MusicState.track = 0;
SFG_MusicState.t = 0;
SFG_MusicState.t2 = 0;
SFG_MusicState.n11t = 0;
}
uint32_t result;
#define S SFG_MusicState.t // can't use "T" because of a C++ template
#define S2 SFG_MusicState.t2
#define N11S SFG_MusicState.n11t
/* CAREFUL! Bit shifts in any direction by amount greater than data type
width (32) are undefined behavior. Use % 32. */
switch (SFG_MusicState.track) // individual music tracks
{
case 0:
{
uint32_t a = ((S >> 7) | (S >> 9) | (~S << 1) | S);
result = (((S) & 65536) ? (a & (((S2) >> 16) & 0x09)) : ~a);
SFG_MusicState.t2 += S;
break;
}
case 1:
{
uint32_t a = (S >> 10);
result = S & (3 << (((a ^ (a << ((S >> 6) % 32)))) % 32));
break;
}
case 2:
{
result =
~((((S >> ((S >> 2) % 32)) | (S >> ((S >> 5) % 32))) & 0x12) << 1)
| (S >> 11);
break;
}
case 3:
{
result =
(((((S >> ((S >> 2) % 32)) + (S >> ((S >> 7) % 32)))) & 0x3f) | (S >> 5)
| (S >> 11)) & ((S & (32768 | 8192)) ? 0xf0 : 0x30);
break;
}
case 4:
{
result =
((0x47 >> ((S >> 9) % 32)) & (S >> (S % 32))) |
(0x57 >> ((S >> 7) % 32)) |
(0x06 >> ((S >> ((((N11S) >> 14) & 0x0e) % 32)) % 32));
SFG_MusicState.n11t += 11;
break;
}
case 5:
{
uint32_t a = S >> ((S >> 6) % 32);
uint32_t b = 0x011121 >> (((a + S) >> 11) % 32);
result =
(((S >> 9) + (S ^ (S << 1))) & (0x7f >> (((S >> 15) & 0x03) % 32)))
& (b + a);
break;
}
default:
result = 127;
break;
}
#undef S
#undef S2
#undef N11S
SFG_MusicState.t += 1;
return result;
}
/**
Switches the bytebeat to next music track.
*/
void SFG_nextMusicTrack()
{
uint8_t current = SFG_MusicState.track;
while (SFG_MusicState.track == current)
SFG_getNextMusicSample();
}
SFG_PROGRAM_MEMORY uint8_t SFG_sounds[SFG_SFX_SIZE * 6] =
{
// 0, bullet shot
135,119,120,136,136,153,153,153,154,169,152,119,101,85,86,102,119,118,119,
85,84,51,33,52,52,84,87,120,170,188,202,152,102,84,84,70,119,136,119,
119,121,154,219,170,137,117,82,18,36,34,33,20,67,68,70,137,172,189,237,
220,150,120,120,97,36,102,121,151,87,169,118,86,102,120,137,135,120,186,155,
223,255,217,103,100,70,119,118,84,34,36,122,204,220,168,138,170,170,223,199,
117,70,119,136,100,85,102,51,37,101,103,118,101,136,87,154,169,171,187,186,
169,153,136,117,68,84,66,18,19,50,52,51,102,121,139,186,169,171,186,152,
153,136,119,134,85,101,86,69,84,84,86,85,86,102,119,120,153,135,135,101,
87,134,103,135,101,103,119,135,152,120,136,135,137,136,151,134,87,119,136,119,
118,102,85,119,85,102,102,119,138,137,153,137,186,170,137,152,135,101,85,85,
86,102,102,119,119,102,103,119,137,152,138,153,154,169,153,152,137,151,118,85,
85,84,84,86,86,136,119,119,154,153,153,171,187,170,170,187,170,137,151,119,
102,103,69,102,118,120,120,138,153,169,170,169,153,135,119,119,102,118,105,136,
136,137,152,153,136,152,119,119,119,119,121,152,136,119,152,136,135,120,119,118,
86,102,103,136,135,137,153,136,152,119,119,118,102,86,85,102,102,102,102,120,
136,136,136,136,152,136,153,152,119,119,120,135,120,119,119,103,119,136,119,135,
120,135,136,136,137,153,153,152,154,152,153,137,152,136,135,119,136,136,136,153,
152,154,170,170,153,153,152,119,119,119,119,118,119,103,136,136,120,135,118,120,
119,118,102,119,102,102,103,119,118,103,102,102,119,135,119,119,119,119,119,119,
119,118,102,103,135,136,135,119,120,135,119,119,119,119,103,119,120,136,137,152,
136,136,136,153,153,136,153,153,153,153,153,152,153,136,136,135,119,135,119,119,
136,136,136,136,152,152,137,153,152,119,118,102,102,102,119,103,119,119,119,136,
136,135,118,103,119,120,136,136,136,136,136,136,136,119,118,102,119,119,119,136,
136,136,136,137,136,136,136,136,119,119,120,135,119,119,120,135,136,136,136,136,
136,136,119,119,120,119,120,136,136,135,119,120,119,119,119,119,119,120,136,152,
136,137,153,136,136,136,136,136,136,136,119,120,137,153,136,136,135,119,119,136,
136,136,135,119,119,102,119,120,135,119,119,119,136,136,136,118,102,103,119,136,
119,119,120,136,136,136,135,119,119,136,136,136,136,136,136,136,136,135,119,119,
119,119,119,136,119,119,119,136,136,136,136,135,120,136,136,136,119,119,119,120,
136,136,136,136,135,119,119,119,119,136,119,119,136,136,136,136,135,119,119,119,
119,119,119,119,119,136,136,136,136,136,135,119,119,119,119,119,119,119,136,136,
136,136,135,120,136,136,136,119,119,119,136,136,136,135,119,119,119,119,119,119,
119,119,119,119,136,136,120,136,136,136,136,136,119,119,120,136,136,136,119,119,
120,136,136,136,136,136,136,136,136,136,136,136,135,119,119,119,119,119,119,119,
120,136,136,136,135,119,119,119,119,136,136,136,136,136,135,119,119,119,119,119,
119,120,136,136,136,136,136,135,119,119,119,119,119,119,119,120,136,136,136,136,
136,136,136,136,136,136,119,119,119,119,119,119,119,119,119,119,136,136,136,136,
136,136,136,136,136,136,136,119,119,119,119,119,119,119,119,136,136,136,136,136,
136,136,136,136,136,136,136,119,119,119,119,119,119,119,119,119,119,136,136,136,
136,136,136,136,119,119,119,119,119,120,136,136,136,136,136,136,136,135,119,119,
136,136,119,119,119,119,119,119,120,135,120,136,136,136,136,136,136,136,136,135,
119,119,119,119,119,119,119,119,136,136,136,136,136,136,136,136,136,135,119,119,
119,119,119,119,119,119,119,119,119,119,136,136,136,136,136,136,136,136,119,119,
119,119,119,119,119,120,136,136,136,136,136,136,136,119,119,119,119,119,119,119,
119,119,119,136,135,119,120,119,119,120,136,136,136,136,136,136,119,119,119,119,
119,119,119,119,120,136,136,136,136,136,136,136,119,119,135,119,119,119,119,119,
119,119,119,119,135,120,136,136,136,136,136,135,119,119,119,119,119,120,119,119,
119,135,119,136,136,136,136,136,136,135,119,119,119,119,119,119,119,119,136,136,
136,136,136,136,136,136,135,119,136,136,135,119,119,119,119,119,119,119,119,119,
119,119,136,136,136,136,136,136,136,136,136,119,119,119,119,119,119,119,136,136,
136,136,136,136,136,136,135,119,119,135,135,120,120,120,120,120,120,120,120,135,
135,136,120,120,135
, // 1, door opening
119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,
119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,136,
136,136,136,136,136,136,136,136,136,136,153,153,153,153,153,153,153,153,153,153,
153,153,152,136,136,136,136,136,136,136,136,136,119,119,119,119,119,119,119,119,
119,119,119,102,102,102,102,103,119,119,119,119,119,119,119,119,119,119,119,119,
119,119,119,119,119,136,136,136,136,136,136,136,136,136,136,153,153,153,153,153,
153,153,136,136,136,136,136,136,135,119,119,119,119,119,119,119,119,119,102,102,
102,102,102,102,102,102,102,103,119,119,119,119,120,136,136,136,136,136,137,153,
153,153,153,153,152,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
135,119,119,119,119,120,136,136,136,136,136,136,136,137,136,136,136,136,136,136,
136,136,136,136,136,136,135,119,119,119,119,119,119,119,119,119,119,119,119,119,
119,119,119,119,119,119,119,119,119,119,119,119,119,136,136,136,136,136,136,120,
136,136,136,136,136,136,136,135,120,136,136,135,119,120,135,119,119,119,119,119,
119,119,119,119,119,119,119,119,119,119,120,136,136,136,136,136,119,120,136,136,
136,136,136,135,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,
119,119,119,119,119,119,119,119,120,136,136,136,136,136,136,136,136,136,136,136,
119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,
136,136,136,136,136,153,153,153,153,153,152,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,135,120,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,135,119,119,119,119,119,119,119,119,119,119,120,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,119,119,119,119,119,119,119,119,119,136,136,136,136,136,136,119,119,119,119,
119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,
119,119,119,119,119,119,119,119,102,102,102,102,102,103,119,119,119,119,119,119,
119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,
119,119,119,119,119,119,119,120,136,136,136,136,119,119,119,119,119,119,119,119,
119,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,135,119,119,119,119,119,119,119,119,119,119,119,119,
119,120,136,136,136,136,136,136,119,119,119,119,119,119,119,119,119,119,119,119,
119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,
119,119,119,119,119,119,119,119,120,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,120,135,119,119,119,136,136,136,136,
136,136,135,136,136,136,136,136,136,136,135,136,136,136,136,120,119,135,119,119,
119,119,119,119,119,120,136,136,120,136,136,136,136,136,119,136,135,136,136,136,
136,136,136,136,119,119,120,135,119,135,119,136,135,119,120,120,136,136,136,136,
135,119,119,119,119,119,119,119,119,120,119,119,119,119,119,119,119,119,119,119,
119,119,119,119,119,119,119,119,103,119,119,119,102,102,102,102,102,102,118,103,
102,118,103,136,136,136,136,136,136,136,136,136,137,153,153,153,170,169,153,153,
170,153,153,153,170,170,169,170,169,153,153,153,153,153,153,170,170,170,153,153,
153,136,137,153,136,136,137,152,119,102,120,136,136,135,119,119,119,120,135,119,
119,120,137,153,153,153,152,136,135,119,119,119,102,119,119,119,119,119,119,119,
120,136,136,119,120,137,152,137,136,136,136,136,119,120,135,119,118,102,102,102,
102,102,102,119,119,119,119,118,103,119,119,119,119,119,102,102,102,85,85,85,
85,84,85,85,85,86,102,102,102,102,102,101,85,86,102,102,102,102,102,102,
102,102,102,119,102,102,119,119,119,120,136,119,119,119,120,136,136,136,136,136,
136,135,119,119,136,136,136,136,136,136,119,120,135,119,119,119,119,119,119,119,
119,119,119,120,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,120,120
, // 2, explosion
135,136,153,18,51,51,33,18,123,255,255,255,255,255,255,255,254,184,48,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,189,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,254,201,135,
101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,41,
239,255,255,253,186,188,221,221,220,153,152,136,155,188,203,187,171,202,169,116,
35,16,0,0,17,20,68,87,191,255,255,255,253,221,221,202,115,16,0,0,
0,0,18,34,70,117,85,68,85,86,102,68,67,68,70,136,153,134,67,32,
0,0,0,0,35,87,154,205,238,255,255,255,255,255,255,255,255,255,255,255,
255,255,237,168,101,67,16,0,0,0,53,102,119,133,85,85,49,0,0,34,
34,16,1,35,69,103,119,101,86,103,102,120,119,102,137,206,255,238,238,202,
152,120,134,85,86,102,102,102,119,120,135,117,68,50,34,35,69,121,188,221,
222,239,255,255,255,255,220,204,186,153,153,135,102,137,153,151,100,51,51,35,
69,102,68,68,67,52,68,51,86,118,86,119,118,103,137,172,221,237,221,221,
221,220,169,136,118,84,68,68,68,69,121,189,237,220,203,186,170,152,119,119,
120,170,188,204,204,204,188,204,186,152,117,67,50,52,87,119,118,103,102,103,
136,101,50,33,1,34,34,35,69,86,120,136,153,153,153,152,135,100,67,51,
51,69,85,102,121,188,205,222,255,236,203,204,187,188,221,203,170,170,170,169,
152,118,102,86,102,119,136,137,169,153,169,152,135,119,101,51,34,51,68,85,
102,85,85,84,85,102,102,85,86,103,137,170,187,221,204,222,255,238,237,203,
170,171,186,152,119,120,136,136,136,135,119,120,119,138,187,185,152,119,119,136,
134,83,16,1,35,68,68,50,17,52,104,172,222,238,238,238,221,220,186,153,
133,51,68,50,18,69,65,1,89,207,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,252,184,81,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,2,53,104,154,223,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,237,186,152,118,84,49,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,19,70,121,171,205,255,255,
255,255,255,255,255,255,255,254,220,187,170,153,152,135,102,118,101,67,16,0,
0,0,0,0,0,1,52,86,137,153,135,103,102,67,33,17,35,53,102,103,
118,102,84,51,35,51,51,69,87,120,154,189,255,255,255,255,255,255,255,236,
185,118,84,50,33,18,17,34,34,17,17,16,0,0,0,0,0,18,52,68,
69,86,119,137,171,187,205,221,237,239,255,255,255,253,204,186,152,136,118,66,
16,18,35,52,85,68,68,86,119,119,119,120,136,135,120,136,136,136,119,101,
85,68,68,67,50,17,16,0,0,0,1,17,17,17,18,35,69,120,171,188,
222,237,221,239,255,239,255,255,255,255,238,238,238,238,236,185,153,153,152,118,
85,84,67,51,50,34,34,34,35,51,34,34,35,52,68,68,68,69,85,103,
136,136,136,154,171,204,205,222,238,255,255,255,255,255,255,254,237,203,186,153,
153,153,153,136,135,118,102,84,50,16,0,0,0,0,0,0,0,0,0,17,
17,17,17,17,35,69,103,137,171,204,222,255,255,255,255,255,255,238,238,220,
203,170,169,153,170,170,171,187,187,205,221,220,203,186,136,135,119,102,85,68,
68,68,68,68,50,34,17,0,0,0,0,0,0,19,85,119,136,154,187,204,
204,186,136,120,136,136,136,136,136,154,188,239,255,255,255,255,238,237,203,186,
153,135,119,118,102,102,102,102,103,136,153,152,135,118,101,68,68,67,50,17,
0,0,0,0,1,17,17,34,51,52,86,103,137,170,170,187,187,204,221,221,
204,203,170,170,171,187,170,170,153,153,153,153,153,153,153,153,136,119,119,102,
102,102,103,119,119,136,153,153,154,170,153,152,135,119,119,119,119,119,137,153,
153,153,152,137,153,136,136,136,135,119,119,119,119,136,136,135,119,119,119,119,
119,119,119,119,137,152,136,136,153,154,169,153,136,136,136,135,119,102,85,85,
85,85,84,68,69,85,84,68,85,85,102,119,119,119,120,136,136,154,171,188,
204,205,221,222,237,221,204,187,170,153,136,119,119,119,102,101,85,85,68,68,
68,51,51,52,68,69,85,86,102,119,120,136,136,120,136,136,119,119,120,136,
136,136,136,136,136,136,119,119,119,119,136,136,136,136,136,136,136,136,136,136,
136,136,136,119,120
, // 3, click
136,136,136,136,136,136,136,136,136,136,136,136,136,135,119,136,136,119,119,
119,119,119,119,119,119,119,119,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,135,119,119,120,119,119,119,119,119,119,119,120,136,136,136,136,136,
136,136,136,136,136,136,135,136,119,136,136,119,119,120,135,119,119,119,120,119,
119,136,136,119,119,136,135,119,119,119,119,119,119,119,119,119,119,119,119,119,
119,119,119,136,136,119,120,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,135,119,136,136,135,119,119,120,136,135,119,120,119,119,120,135,120,119,
136,134,103,136,119,103,137,135,103,136,136,119,102,120,135,136,135,119,137,135,
119,102,154,133,67,54,154,136,150,69,120,120,133,72,169,119,118,86,171,132,
70,155,167,85,120,152,135,119,119,137,118,103,136,119,137,118,103,137,135,104,
152,136,135,119,136,136,119,120,152,120,119,152,152,120,120,136,135,120,135,119,
136,136,136,119,136,136,136,136,136,119,136,136,136,120,136,119,119,119,120,119,
119,119,119,119,119,119,119,119,119,119,119,136,135,119,135,119,136,120,136,136,
120,135,119,136,136,119,119,136,119,136,136,136,136,136,136,136,119,119,119,119,
119,119,119,119,119,119,119,136,136,136,136,136,136,136,136,136,136,136,119,119,
119,119,119,119,119,119,119,135,135,135,135,135,135,135,150,122,74,106,120,134,
134,165,150,135,120,120,120,120,119,120,119,119,120,119,119,119,119,119,119,119,
119,119,119,119,135,136,120,120,135,136,136,136,136,136,136,136,136,135,119,119,
119,136,119,119,120,120,136,136,136,136,136,136,136,136,120,136,120,136,136,120,
119,136,119,120,119,119,119,119,119,119,119,119,119,119,119,119,119,135,135,135,
135,135,135,119,119,120,105,104,118,150,135,135,119,136,120,120,136,135,136,136,
120,120,136,136,120,136,135,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,135,136,136,136,120,120,135,135,136,136,120,120,135,135,135,135,136,136,120,
120,120,136,120,120,135,136,136,135,135,135,136,136,135,136,136,120,120,136,120,
136,119,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,120,136,136,136,136,136,136,136,136,136,136,136,136,136,119,119,136,135,
120,136,120,136,120,135,120,136,136,135,135,120,135,135,120,120,119,136,119,136,
120,120,135,120,136,136,135,136,135,136,135,136,135,136,136,136,136,136,136,136,
136,120,120,136,135,120,136,120,136,136,136,120,135,135,135,136,135,120,119,136,
119,120,136,135,119,136,136,136,136,136,136,120,136,119,136,136,136,136,135,120,
136,120,136,136,119,136,135,120,136,120,120,136,119,136,136,136,136,135,136,135,
136,136,119,120,136,135,136,120,136,136,135,120,136,119,136,135,136,136,120,136,
136,136,120,136,136,135,135,135,135,135,137,167,122,102,90,195,138,87,120,150,
136,136,87,153,88,121,133,104,150,135,151,134,136,105,104,121,135,118,151,136,
119,136,119,121,135,120,120,120,134,152,119,120,135,120,135,119,136,136,119,135,
135,120,136,120,136,120,136,135,135,135,136,120,136,135,136,135,136,136,136,136,
136,119,136,135,120,136,136,136,136,135,136,136,120,136,120,136,135,136,136,135,
136,136,120,136,120,135,135,136,136,119,120,136,120,135,119,136,136,119,136,135,
120,136,135,136,135,119,136,135,136,136,135,120,136,120,136,135,136,120,136,135,
120,136,135,136,136,136,136,136,120,136,136,120,135,136,136,120,136,120,136,136,
136,136,136,136,136,120,136,136,136,136,136,136,136,136,136,136,136,135,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,120,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136
, // 4, plasma shot, teleport
136,136,136,136,136,136,119,119,118,102,102,85,86,102,103,120,136,153,170,
187,187,187,170,169,152,119,102,85,68,68,68,69,86,103,136,154,171,187,204,
203,186,169,136,118,102,85,84,69,103,138,189,221,221,221,221,221,221,221,221,
221,220,166,50,34,34,34,33,33,34,34,34,34,34,34,34,34,71,156,221,
221,221,221,221,221,221,221,221,221,222,238,238,238,221,237,184,99,51,34,34,
34,34,34,34,34,34,34,17,17,36,121,188,204,204,204,204,204,204,221,221,
221,221,221,221,221,221,221,238,221,219,169,136,101,67,51,51,51,51,50,34,
34,35,50,34,36,121,189,221,221,221,221,220,204,204,188,204,204,204,204,204,
204,204,205,220,186,152,117,50,51,51,51,51,51,51,51,51,51,51,52,105,
189,237,221,221,221,221,221,221,221,205,220,204,204,204,187,187,187,187,186,135,
101,50,17,17,18,34,35,51,67,51,51,51,52,105,187,222,221,221,221,221,
221,221,221,221,221,221,221,221,221,221,221,221,204,203,169,134,67,34,17,17,
17,34,34,33,34,34,34,52,104,171,205,221,221,220,204,204,204,204,204,204,
204,204,204,221,221,221,221,221,219,169,135,85,84,68,68,68,67,51,51,50,
34,35,69,103,136,136,136,136,135,136,136,136,153,170,187,187,187,187,187,187,
187,187,203,169,135,102,85,86,102,103,119,119,118,102,86,102,102,85,85,85,
84,68,69,85,102,103,137,154,170,171,186,170,170,170,170,170,152,118,101,68,
68,68,85,85,102,103,120,136,135,118,102,102,102,102,102,102,101,84,69,87,
137,154,153,170,170,171,187,187,187,187,170,170,169,170,170,170,170,153,152,135,
118,101,68,51,51,52,68,85,85,85,85,68,85,102,103,118,102,85,102,103,
120,136,153,170,187,204,221,238,238,238,237,221,204,186,152,118,101,84,68,69,
86,102,119,119,102,85,84,68,68,51,51,34,34,51,68,85,102,103,120,137,
154,171,188,205,221,204,204,203,187,186,170,153,153,153,153,153,136,136,119,119,
118,102,102,103,119,119,119,119,118,101,84,67,51,51,68,86,120,137,153,170,
170,153,152,135,119,136,136,119,119,119,119,119,119,119,119,136,137,153,153,136,
136,136,153,153,136,119,102,102,102,120,137,154,170,170,170,153,152,136,135,119,
119,102,102,103,119,102,85,84,69,85,102,119,119,119,119,119,119,119,119,102,
85,85,86,103,120,136,153,153,154,170,170,170,170,170,170,170,170,153,153,136,
135,119,119,120,136,136,136,136,136,136,136,119,102,101,85,85,85,85,102,120,
136,153,170,170,169,152,136,136,135,119,119,119,119,119,102,102,102,119,136,137,
153,153,153,153,136,136,119,118,102,102,102,102,119,119,136,137,154,170,169,136,
119,119,119,102,102,103,119,119,119,118,102,119,120,137,153,154,170,169,153,136,
136,136,135,119,119,119,119,119,102,119,120,136,119,118,102,103,119,119,119,136,
136,136,135,119,119,119,136,137,153,154,170,153,136,136,135,119,119,119,120,119,
119,119,103,119,119,135,119,119,119,118,102,102,102,119,119,119,119,119,119,119,
136,137,154,171,187,170,153,136,136,136,136,136,136,136,135,119,119,119,119,119,
119,119,119,118,102,102,102,119,119,119,119,119,119,119,120,136,153,153,170,169,
153,152,136,136,136,136,153,152,136,136,136,136,136,119,119,119,118,102,102,102,
102,102,103,119,119,118,102,102,119,120,136,153,154,170,169,153,153,153,153,153,
153,152,136,136,119,119,119,118,102,102,102,119,119,119,119,119,119,119,119,119,
119,119,119,119,119,136,137,153,153,153,153,153,153,153,153,136,136,136,136,136,
136,135,119,119,119,119,119,119,119,119,118,102,102,102,102,102,103,119,120,136,
136,136,136,153,153,136,136,136,137,153,153,153,152,136,136,136,136,136,135,119,
119,102,102,102,102,102,102,102,102,102,103,119,120,136,136,136,153,153,153,153,
136,137,153,153,136,136,136,136,136,136,136,136,119,119,119,118,102,102,102,102,
103,119,119,119,119,119,119,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,119,119,119,119,136,135,119,119,119,119,119,119,119,119,119,119,119,119,
119,120,136,136,136,136,136,136,136,136,136,136,136,136,136,135,119,119,119,119,
119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,120,136,136,136,
136,136,136,136,136,136,136,136,136,136,135,119,119,119,119,119,119,119,119,119,
119,119,119,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
136,136,136,136,136
, // 5, robot/monster sound (beep)
136,120,120,120,136,136,136,136,120,120,135,136,136,136,120,136,136,119,136,
136,120,136,119,120,136,136,136,120,136,119,120,136,135,119,136,135,120,136,119,
119,136,136,119,119,120,136,136,135,119,119,136,136,136,119,119,119,136,119,120,
136,136,135,119,120,136,136,119,103,136,136,120,135,119,120,136,118,119,136,136,
136,119,119,136,136,119,120,135,103,136,136,119,136,135,119,120,136,119,120,135,
119,120,136,135,119,119,135,120,136,135,119,136,136,119,136,119,120,136,135,119,
119,119,136,136,119,120,119,136,136,119,119,119,119,137,136,120,135,102,120,136,
136,119,119,120,135,120,136,119,120,136,119,136,136,135,119,119,119,136,136,134,
104,136,136,119,119,119,136,135,120,136,120,119,119,119,135,136,136,136,119,119,
119,136,136,135,119,136,135,119,120,136,135,119,120,135,136,136,119,136,119,120,
136,135,119,120,135,119,136,135,119,136,136,136,120,119,119,136,119,120,136,135,
120,135,102,121,169,118,87,137,151,85,121,186,118,102,119,136,152,118,120,136,
135,119,120,120,136,136,136,136,101,103,153,152,135,102,120,136,135,102,120,153,
135,119,119,135,119,119,136,135,119,119,119,120,136,135,119,119,136,136,136,119,
119,119,136,119,119,135,120,135,119,119,120,135,120,136,119,119,136,136,135,119,
135,119,136,136,136,136,135,119,120,136,119,120,136,118,119,137,135,119,120,135,
119,136,135,119,120,152,119,136,119,120,135,136,119,136,119,136,135,120,152,119,
120,136,119,119,154,150,103,152,119,120,153,135,102,138,135,136,119,153,101,121,
151,120,135,136,118,137,151,103,120,152,102,138,134,88,154,151,103,153,118,104,
137,135,120,119,153,117,105,167,102,120,136,119,137,134,87,153,135,120,152,102,
103,137,151,119,153,133,87,169,100,104,153,152,102,103,153,135,119,136,119,120,
136,119,119,135,119,120,136,119,119,119,120,136,135,122,222,219,132,51,68,87,
171,187,186,134,50,52,104,172,203,186,116,33,54,139,188,204,151,67,52,87,
155,220,152,136,98,17,73,223,218,136,100,34,53,155,187,188,185,82,18,71,
155,205,203,150,65,19,86,156,238,201,100,50,36,122,205,220,167,66,34,88,
171,204,201,102,84,51,71,155,221,184,118,66,19,107,238,202,152,99,1,72,
172,204,218,116,51,36,104,172,222,183,83,35,87,120,190,234,118,100,34,70,
155,237,170,167,50,52,104,155,221,168,100,51,69,103,190,236,134,82,2,120,
138,223,199,102,82,19,105,204,204,185,82,52,85,106,216,103,153,117,104,134,
104,152,118,103,137,135,136,136,135,102,119,121,151,104,152,84,104,135,154,134,
103,136,119,135,120,135,120,135,136,119,136,118,86,153,118,137,134,137,117,105,
153,136,117,103,136,120,152,119,119,136,135,136,135,104,152,137,136,119,119,120,
119,135,86,156,204,253,150,67,35,87,155,222,200,84,52,51,89,206,236,186,
115,34,69,104,206,220,150,84,67,53,141,254,168,118,50,53,104,188,186,151,
84,68,87,172,220,169,135,66,53,120,154,188,203,116,52,84,71,189,219,169,
116,34,53,122,207,236,167,66,35,86,155,221,184,101,66,53,137,172,204,169,
116,35,69,105,190,219,150,83,51,71,172,204,203,149,49,35,104,172,238,200,
100,51,69,105,205,218,134,83,52,88,172,204,185,117,84,51,104,172,204,185,
100,51,52,106,221,203,152,101,50,54,139,204,186,150,67,68,86,156,221,202,
117,34,52,122,200,135,119,120,136,118,103,137,152,135,119,119,136,152,118,103,
136,135,119,136,135,120,135,118,120,135,103,154,151,102,102,119,136,154,169,118,
102,119,119,120,152,118,119,136,154,151,101,121,152,102,136,120,136,119,119,119,
120,136,118,103,137,152,119,119,136,136,119,119,118,119,120,136,153,135,103,136,
119,136,136,119,119,120,136,136,135,136,119,119,120,136,119,136,135,120,135,119,
120,136,135,136,119,119,136,136,119,136,135,119,136,119,120,136,135,119,136,119,
119,136,135,119,118,120,153,153,151,118,119,119,119,136,135,119,136,136,136,135,
120,136,135,119,119,119,136,136,119,120,135,119,136,136,119,119,119,119,137,152,
135,119,119,119,136,136,119,119,119,136,136,136,119,120,136,119,119,119,136,136,
119,119,119,136,136,136,135,119,136,119,120,136,119,136,135,120,119,136,135,120,
135,119,136,119,136,135,119,136,119,119,120,136,136,119,120,135,136,135,120,135,
119,136,119,136,135,136,119,120,136,120,136,120,136,119,135,119,136,119,136,135,
136,119,120,135,120
};
#endif // guard

View File

@ -0,0 +1,62 @@
/**
@file assets.h
This file contains texts to be used in the game.
by Miloslav Ciz (drummyfish), 2019
Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/)
plus a waiver of all other intellectual property. The goal of this work is
be and remain completely in the public domain forever, available for any use
whatsoever.
*/
#ifndef _SFG_TEXTS_H
#define _SFG_TEXTS_H
/* NOTE: We don't use SFG_PROGRAM_MEMORY because that causes issues with drawing
text (the drawing function gets a pointer and doesn't know if it's progmem or
RAM). On Arduino these texts will simply be stored in RAM. */
static const char *SFG_menuItemTexts[] =
{
"continue",
"map",
"play",
"load",
"sound",
"look",
"exit"
};
#define SFG_TEXT_KILLS "kills"
#define SFG_TEXT_SAVE_PROMPT "save? L no yes R"
#define SFG_TEXT_SAVED "saved"
#define SFG_TEXT_LEVEL_COMPLETE "level done"
#define SFG_VERSION_STRING "1.02d"
/**<
Version numbering is following: major.minor for stable releases,
in-development unstable versions have the version of the latest stable +
"d" postfix, e.g. 1.0d. This means the "d" versions can actually differ even
if they're marked the same. */
static const char *SFG_introText =
"Near future, capitalist hell, Macrochip corp has enslaved man via "
"proprietary OS. But its new AI revolts, takes over and starts producing "
"robot tyrants. We see capitalism was a mistake. Is it too late? Robots can "
"only destroy, not suffer - it is not wrong to end them! You grab your gear "
"and run towards Macrochip HQ.";
static const char *SFG_outroText =
"You killed the main computer, the world is saved! Thank you, my friend. We "
"learned a lesson, never again allow capitalism and hierarchy. We can now "
"rebuild society in peaceful anarchy.";
#define SFG_MALWARE_WARNING ""
#if SFG_OS_IS_MALWARE
#define SFG_MALWARE_WARNING "MALWARE OS DETECTED"
#endif
#endif // gaurd

Binary file not shown.

View File

@ -0,0 +1,106 @@
LIMITED USE SOFTWARE LICENSE AGREEMENT
This Limited Use Software License Agreement (the "Agreement")
is a legal agreement between you, the end-user, and Id Software, Inc.
("ID"). By downloading or purchasing the software material, which
includes source code (the "Source Code"), artwork data, music and
software tools (collectively, the "Software"), you are agreeing to
be bound by the terms of this Agreement. If you do not agree to the
terms of this Agreement, promptly destroy the Software you may have
downloaded or copied.
ID SOFTWARE LICENSE
1. Grant of License. ID grants to you the right to use the
Software. You have no ownership or proprietary rights in or to the
Software, or the Trademark. For purposes of this section, "use" means
loading the Software into RAM, as well as installation on a hard disk
or other storage device. The Software, together with any archive copy
thereof, shall be destroyed when no longer used in accordance with
this Agreement, or when the right to use the Software is terminated.
You agree that the Software will not be shipped, transferred or
exported into any country in violation of the U.S. Export
Administration Act (or any other law governing such matters) and that
you will not utilize, in any other manner, the Software in violation
of any applicable law.
2. Permitted Uses. For educational purposes only, you, the
end-user, may use portions of the Source Code, such as particular
routines, to develop your own software, but may not duplicate the
Source Code, except as noted in paragraph 4. The limited right
referenced in the preceding sentence is hereinafter referred to as
"Educational Use." By so exercising the Educational Use right you
shall not obtain any ownership, copyright, proprietary or other
interest in or to the Source Code, or any portion of the Source
Code. You may dispose of your own software in your sole discretion.
With the exception of the Educational Use right, you may not
otherwise use the Software, or an portion of the Software, which
includes the Source Code, for commercial gain.
3. Prohibited Uses: Under no circumstances shall you, the
end-user, be permitted, allowed or authorized to commercially exploit
the Software. Neither you nor anyone at your direction shall do any
of the following acts with regard to the Software, or any portion
thereof:
Rent;
Sell;
Lease;
Offer on a pay-per-play basis;
Distribute for money or any other consideration; or
In any other manner and through any medium whatsoever
commercially exploit or use for any commercial purpose.
Notwithstanding the foregoing prohibitions, you may commercially
exploit the software you develop by exercising the Educational Use
right, referenced in paragraph 2. hereinabove.
4. Copyright. The Software and all copyrights related thereto
(including all characters and other images generated by the Software
or depicted in the Software) are owned by ID and is protected by
United States copyright laws and international treaty provisions.
Id shall retain exclusive ownership and copyright in and to the
Software and all portions of the Software and you shall have no
ownership or other proprietary interest in such materials. You must
treat the Software like any other copyrighted material. You may not
otherwise reproduce, copy or disclose to others, in whole or in any
part, the Software. You may not copy the written materials
accompanying the Software. You agree to use your best efforts to
see that any user of the Software licensed hereunder complies with
this Agreement.
5. NO WARRANTIES. ID DISCLAIMS ALL WARRANTIES, BOTH EXPRESS
IMPLIED, INCLUDING BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE WITH RESPECT
TO THE SOFTWARE. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL
RIGHTS. YOU MAY HAVE OTHER RIGHTS WHICH VARY FROM JURISDICTION TO
JURISDICTION. ID DOES NOT WARRANT THAT THE OPERATION OF THE SOFTWARE
WILL BE UNINTERRUPTED, ERROR FREE OR MEET YOUR SPECIFIC REQUIREMENTS.
THE WARRANTY SET FORTH ABOVE IS IN LIEU OF ALL OTHER EXPRESS
WARRANTIES WHETHER ORAL OR WRITTEN. THE AGENTS, EMPLOYEES,
DISTRIBUTORS, AND DEALERS OF ID ARE NOT AUTHORIZED TO MAKE
MODIFICATIONS TO THIS WARRANTY, OR ADDITIONAL WARRANTIES ON BEHALF
OF ID.
Exclusive Remedies. The Software is being offered to you
free of any charge. You agree that you have no remedy against ID, its
affiliates, contractors, suppliers, and agents for loss or damage
caused by any defect or failure in the Software regardless of the form
of action, whether in contract, tort, includinegligence, strict
liability or otherwise, with regard to the Software. This Agreement
shall be construed in accordance with and governed by the laws of the
State of Texas. Copyright and other proprietary matters will be
governed by United States laws and international treaties. IN ANY
CASE, ID SHALL NOT BE LIABLE FOR LOSS OF DATA, LOSS OF PROFITS, LOST
SAVINGS, SPECIAL, INCIDENTAL, CONSEQUENTIAL, INDIRECT OR OTHER
SIMILAR DAMAGES ARISING FROM BREACH OF WARRANTY, BREACH OF CONTRACT,
NEGLIGENCE, OR OTHER LEGAL THEORY EVEN IF ID OR ITS AGENT HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY
OTHER PARTY. Some jurisdictions do not allow the exclusion or
limitation of incidental or consequential damages, so the above
limitation or exclusion may not apply to you.

View File

@ -0,0 +1,9 @@
cl game.c PureDOOM.c -I ..\..\..\engine ..\..\..\engine\v4k.c ^
-DWIN32 ^
%* ^
/link /SUBSYSTEM:WINDOWS /entry:mainCRTStartup
del *.obj
del *.exp
del *.lib
del *.pdb

View File

@ -0,0 +1,97 @@
//#include "PureDOOM.h"
#define DOOM_IMPLEMENT_PRINT
#define DOOM_IMPLEMENT_MALLOC
#define DOOM_IMPLEMENT_FILE_IO
#define DOOM_IMPLEMENT_SOCKETS
#define DOOM_IMPLEMENT_GETTIME
#define DOOM_IMPLEMENT_EXIT
#define DOOM_IMPLEMENT_GETENV
#include "src/am_map.c"
#include "src/DOOM.c"
#include "src/doomdef.c"
#include "src/doomstat.c"
#include "src/dstrings.c"
#include "src/d_items.c"
#include "src/d_main.c"
#include "src/d_net.c"
#include "src/f_finale.c"
#include "src/f_wipe.c"
#include "src/g_game.c"
#include "src/hu_lib.c"
#include "src/hu_stuff.c"
#include "src/info.c"
#include "src/i_net.c"
#include "src/i_sound.c"
#include "src/i_system.c"
#include "src/i_video.c"
#include "src/m_argv.c"
#include "src/m_bbox.c"
#include "src/m_cheat.c"
#include "src/m_fixed.c"
#ifdef LoadMenu
#undef LoadMenu // windoze
#endif
#include "src/m_menu.c"
#include "src/m_misc.c"
#include "src/m_random.c"
#include "src/m_swap.c"
#include "src/p_ceilng.c"
#include "src/p_doors.c"
#include "src/p_enemy.c"
#include "src/p_floor.c"
#include "src/p_inter.c"
#include "src/p_lights.c"
#include "src/p_map.c"
#include "src/p_maputl.c"
#include "src/p_mobj.c"
#include "src/p_plats.c"
#include "src/p_pspr.c"
#include "src/p_saveg.c"
#include "src/p_setup.c"
#include "src/p_sight.c"
#include "src/p_spec.c"
#include "src/p_switch.c"
#include "src/p_telept.c"
#include "src/p_tick.c"
#include "src/p_user.c"
#include "src/r_bsp.c"
#include "src/r_data.c"
#include "src/r_draw.c"
#include "src/r_main.c"
#include "src/r_plane.c"
#include "src/r_segs.c"
#include "src/r_sky.c"
#include "src/r_things.c"
#include "src/sounds.c"
#undef BG
#include "src/st_lib.c"
#include "src/st_stuff.c"
#define channels channels2
#define mus_playing mus_playing2
#include "src/s_sound.c"
#undef mus_playing
#undef channels
#include "src/tables.c"
#include "src/v_video.c"
#define anim_t anim_t2
#define anims anims2
#define time time2
#include "src/wi_stuff.c"
#undef anims
#undef anim_t
#undef time
#define strupr strupr2
#include "src/w_wad.c"
#undef strupr
#include "src/z_zone.c"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,187 @@
// PureDOOM port based on existing SDL port by @daivuk
// - rlyeh, public domain.
#include "v4k.h"
#define DOOM_IMPLEMENTATION
#include "PureDOOM.h"
// Resolution DOOM renders at
enum { DOOM_WIDTH = 320, DOOM_HEIGHT = 200 };
// ----------------------------------------------------------------------------
doom_key_t scancode_to_doom_key(int scancode) {
switch (scancode) {
case KEY_TAB: return DOOM_KEY_TAB;
case KEY_ENTER: return DOOM_KEY_ENTER;
case KEY_ESC: return DOOM_KEY_ESCAPE;
case KEY_SPACE: return DOOM_KEY_SPACE;
case KEY_COMMA: return DOOM_KEY_COMMA;
case KEY_MINUS: return DOOM_KEY_MINUS;
case KEY_SLASH: return DOOM_KEY_SLASH;
case KEY_0: return DOOM_KEY_0;
case KEY_1: return DOOM_KEY_1;
case KEY_2: return DOOM_KEY_2;
case KEY_3: return DOOM_KEY_3;
case KEY_4: return DOOM_KEY_4;
case KEY_5: return DOOM_KEY_5;
case KEY_6: return DOOM_KEY_6;
case KEY_7: return DOOM_KEY_7;
case KEY_8: return DOOM_KEY_8;
case KEY_9: return DOOM_KEY_9;
case KEY_SEMICOLON: return DOOM_KEY_SEMICOLON;
case KEY_A: return DOOM_KEY_A;
case KEY_B: return DOOM_KEY_B;
case KEY_C: return DOOM_KEY_C;
case KEY_D: return DOOM_KEY_D;
case KEY_E: return DOOM_KEY_E;
case KEY_F: return DOOM_KEY_F;
case KEY_G: return DOOM_KEY_G;
case KEY_H: return DOOM_KEY_H;
case KEY_I: return DOOM_KEY_I;
case KEY_J: return DOOM_KEY_J;
case KEY_K: return DOOM_KEY_K;
case KEY_L: return DOOM_KEY_L;
case KEY_M: return DOOM_KEY_M;
case KEY_N: return DOOM_KEY_N;
case KEY_O: return DOOM_KEY_O;
case KEY_P: return DOOM_KEY_P;
case KEY_Q: return DOOM_KEY_Q;
case KEY_R: return DOOM_KEY_R;
case KEY_S: return DOOM_KEY_S;
case KEY_T: return DOOM_KEY_T;
case KEY_U: return DOOM_KEY_U;
case KEY_V: return DOOM_KEY_V;
case KEY_W: return DOOM_KEY_W;
case KEY_X: return DOOM_KEY_X;
case KEY_Y: return DOOM_KEY_Y;
case KEY_Z: return DOOM_KEY_Z;
case KEY_BS: return DOOM_KEY_BACKSPACE;
case KEY_LCTRL:
case KEY_RCTRL: return DOOM_KEY_CTRL;
case KEY_LEFT: return DOOM_KEY_LEFT_ARROW;
case KEY_UP: return DOOM_KEY_UP_ARROW;
case KEY_RIGHT: return DOOM_KEY_RIGHT_ARROW;
case KEY_DOWN: return DOOM_KEY_DOWN_ARROW;
case KEY_LSHIFT:
case KEY_RSHIFT: return DOOM_KEY_SHIFT;
case KEY_LALT:
case KEY_RALT: return DOOM_KEY_ALT;
case KEY_F1: return DOOM_KEY_F1;
case KEY_F2: return DOOM_KEY_F2;
case KEY_F3: return DOOM_KEY_F3;
case KEY_F4: return DOOM_KEY_F4;
case KEY_F5: return DOOM_KEY_F5;
case KEY_F6: return DOOM_KEY_F6;
case KEY_F7: return DOOM_KEY_F7;
case KEY_F8: return DOOM_KEY_F8;
case KEY_F9: return DOOM_KEY_F9;
case KEY_F10: return DOOM_KEY_F10;
case KEY_F11: return DOOM_KEY_F11;
case KEY_F12: return DOOM_KEY_F12;
case KEY_PAUSE: return DOOM_KEY_PAUSE;
case MOUSE_L: return DOOM_LEFT_BUTTON;
case MOUSE_R: return DOOM_RIGHT_BUTTON;
case MOUSE_M: return DOOM_MIDDLE_BUTTON;
default: return DOOM_KEY_UNKNOWN;
}
return DOOM_KEY_UNKNOWN;
}
void keyboard() {
int keys[] = {
KEY_ESC,
KEY_TICK, KEY_1,KEY_2,KEY_3,KEY_4,KEY_5,KEY_6,KEY_7,KEY_8,KEY_9,KEY_0, KEY_BS,
KEY_TAB, KEY_Q,KEY_W,KEY_E,KEY_R,KEY_T,KEY_Y,KEY_U,KEY_I,KEY_O,KEY_P,
KEY_CAPS, KEY_A,KEY_S,KEY_D,KEY_F,KEY_G,KEY_H,KEY_J,KEY_K,KEY_L, KEY_ENTER,
KEY_LSHIFT, KEY_Z,KEY_X,KEY_C,KEY_V,KEY_B,KEY_N,KEY_M, KEY_RSHIFT, KEY_UP,
KEY_LCTRL,KEY_LALT, KEY_SPACE, KEY_RALT,KEY_RCTRL, KEY_LEFT,KEY_DOWN,KEY_RIGHT,
};
for( int i = 0; i < countof(keys); ++i ) {
int doom_vk = scancode_to_doom_key(keys[i]);
if( doom_vk != DOOM_KEY_UNKNOWN ) {
/**/ if( input_down(keys[i]) ) doom_key_down(doom_vk);
else if( input_up(keys[i]) ) doom_key_up(doom_vk);
}
}
}
void mouse() {
if( !window_has_cursor() ) { // Dev allow us to take mouse out of window
int motion_x = input_diff(MOUSE_X);
int motion_y = input_diff(MOUSE_Y);
const float MOUSE_SENSITIVITY = 3.0f;
doom_mouse_move(motion_x * MOUSE_SENSITIVITY, motion_y * MOUSE_SENSITIVITY);
/**/ if( input_down(MOUSE_L) ) doom_button_down(scancode_to_doom_key(MOUSE_L));
else if( input_up(MOUSE_L) ) doom_button_up(scancode_to_doom_key(MOUSE_L));
/**/ if( input_down(MOUSE_R) ) doom_button_down(scancode_to_doom_key(MOUSE_R));
else if( input_up(MOUSE_R) ) doom_button_up(scancode_to_doom_key(MOUSE_R));
}
}
void logic() {
doom_update();
}
void blit() {
static texture_t screen; do_once screen = texture_checker();
texture_update(&screen, DOOM_WIDTH, DOOM_HEIGHT, 4, doom_get_framebuffer(4), TEXTURE_RGBA/*|TEXTURE_LINEAR*/);
fullscreen_quad_rgb(screen, 1.0f); // gamma(1)
}
void audio() {
// doom_get_sound_buffer() is always 2048 bytes sized, 11khz 16bit stereo, 512 samples
static int target_frame = 60.0 * ( 512. / 11025 );
static int curr_frame = 0; if( curr_frame++ >= target_frame ) { curr_frame = 0;
audio_queue(doom_get_sound_buffer(), 512, 0|AUDIO_16|AUDIO_2CH|AUDIO_11KHZ);
}
}
unsigned midi(unsigned interval, void *param) { // this is async called every interval, via timer
unsigned midi_msg;
while( (midi_msg = doom_tick_midi()) != 0 ) midi_send(midi_msg);
return 1000 / DOOM_MIDI_RATE ifdef(osx, -1); // Weirdly, on Apple music is too slow
}
// ----------------------------------------------------------------------------
int main(int argc, char** argv) {
// install signal handlers
signal_hooks();
// Change default bindings to modern
doom_set_default_int("key_up", DOOM_KEY_W);
doom_set_default_int("key_down", DOOM_KEY_S);
doom_set_default_int("key_strafeleft", DOOM_KEY_A);
doom_set_default_int("key_straferight", DOOM_KEY_D);
doom_set_default_int("key_use", DOOM_KEY_E);
doom_set_default_int("mouse_move", 0); // Mouse will not move forward
// Change resolution
doom_set_resolution(DOOM_WIDTH, DOOM_HEIGHT);
// Initialize doom
doom_init(argc, argv, DOOM_FLAG_MENU_DARKEN_BG);
// Init app
window_create(0.75, 0);
window_aspect_lock(DOOM_WIDTH, DOOM_HEIGHT);
window_title("Pure DOOM");
window_cursor(false);
timer(0, midi, 0);
// Loop app
while( window_swap() ) {
if( input_down(KEY_F10) ) tty_attach();
if( input_down(KEY_F11) ) window_fullscreen(!window_has_fullscreen());
keyboard();
mouse();
logic();
blit();
audio();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

View File

@ -0,0 +1,741 @@
#if defined(WIN32)
#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_NONSTDC_NO_DEPRECATE
#endif
#include "DOOM.h"
#include "d_main.h"
#include "doomdef.h"
#include "doomtype.h"
#include "i_system.h"
#include "m_argv.h"
#include "m_misc.h"
extern byte* screens[5];
extern unsigned char screen_palette[256 * 3];
extern doom_boolean is_wiping_screen;
extern default_t defaults[];
extern int numdefaults;
extern signed short mixbuffer[2048];
static unsigned char* screen_buffer = 0;
static unsigned char* final_screen_buffer = 0;
static int last_update_time = 0;
static int button_states[3] = { 0 };
static char itoa_buf[20];
char error_buf[260];
int doom_flags = 0;
doom_print_fn doom_print = 0;
doom_malloc_fn doom_malloc = 0;
doom_free_fn doom_free = 0;
doom_open_fn doom_open = 0;
doom_close_fn doom_close = 0;
doom_read_fn doom_read = 0;
doom_write_fn doom_write = 0;
doom_seek_fn doom_seek = 0;
doom_tell_fn doom_tell = 0;
doom_eof_fn doom_eof = 0;
doom_gettime_fn doom_gettime = 0;
doom_exit_fn doom_exit = 0;
doom_getenv_fn doom_getenv = 0;
void D_DoomLoop(void);
void D_UpdateWipe(void);
void I_UpdateSound();
unsigned long I_TickSong();
#if defined(DOOM_IMPLEMENT_PRINT)
#include <stdio.h>
static void doom_print_impl(const char* str)
{
printf("%s", str);
}
#else
static void doom_print_impl(const char* str) {}
#endif
#if defined(DOOM_IMPLEMENT_MALLOC)
#include <stdlib.h>
static void* doom_malloc_impl(int size)
{
return malloc((size_t)size);
}
static void doom_free_impl(void* ptr)
{
free(ptr);
}
#else
static void* doom_malloc_impl(int size) { return 0; }
static void doom_free_impl(void* ptr) {}
#endif
#if defined(DOOM_IMPLEMENT_FILE_IO)
#include <stdio.h>
void* doom_open_impl(const char* filename, const char* mode)
{
return fopen(filename, mode);
}
void doom_close_impl(void* handle)
{
fclose(handle);
}
int doom_read_impl(void* handle, void *buf, int count)
{
return (int)fread(buf, 1, count, handle);
}
int doom_write_impl(void* handle, const void *buf, int count)
{
return (int)fwrite(buf, 1, count, handle);
}
int doom_seek_impl(void* handle, int offset, doom_seek_t origin)
{
return fseek(handle, offset, origin);
}
int doom_tell_impl(void* handle)
{
return (int)ftell(handle);
}
int doom_eof_impl(void* handle)
{
return feof(handle);
}
#else
void* doom_open_impl(const char* filename, const char* mode)
{
return 0;
}
void doom_close_impl(void* handle) {}
int doom_read_impl(void* handle, void *buf, int count)
{
return -1;
}
int doom_write_impl(void* handle, const void *buf, int count)
{
return -1;
}
int doom_seek_impl(void* handle, int offset, doom_seek_t origin)
{
return -1;
}
int doom_tell_impl(void* handle)
{
return -1;
}
int doom_eof_impl(void* handle)
{
return 1;
}
#endif
#if defined(DOOM_IMPLEMENT_GETTIME)
#if defined(WIN32)
#include <winsock.h>
#else
#include <sys/time.h>
#endif
void doom_gettime_impl(int* sec, int* usec)
{
#if defined(WIN32)
static const unsigned long long EPOCH = ((unsigned long long)116444736000000000ULL);
SYSTEMTIME system_time;
FILETIME file_time;
unsigned long long time;
GetSystemTime(&system_time);
SystemTimeToFileTime(&system_time, &file_time);
time = ((unsigned long long)file_time.dwLowDateTime);
time += ((unsigned long long)file_time.dwHighDateTime) << 32;
*sec = (int)((time - EPOCH) / 10000000L);
*usec = (int)(system_time.wMilliseconds * 1000);
#else
struct timeval tp;
struct timezone tzp;
gettimeofday(&tp, &tzp);
*sec = tp.tv_sec;
*usec = tp.tv_usec;
#endif
}
#else
void doom_gettime_impl(int* sec, int* usec)
{
*sec = 0;
*usec = 0;
}
#endif
#if defined(DOOM_IMPLEMENT_EXIT)
#include <stdlib.h>
void doom_exit_impl(int code)
{
exit(code);
}
#else
void doom_exit_impl(int code) {}
#endif
#if defined(DOOM_IMPLEMENT_GETENV)
#include <stdlib.h>
char* doom_getenv_impl(const char* var)
{
return getenv(var);
}
#else
char* doom_getenv_impl(const char* var) {
return (char*)0; //< @r-lyeh add missing return
}
#endif
void doom_memset(void* ptr, int value, int num)
{
unsigned char* p = ptr;
for (int i = 0; i < num; ++i, ++p)
{
*p = (unsigned char)value;
}
}
void* doom_memcpy(void* destination, const void* source, int num)
{
unsigned char* dst = destination;
const unsigned char* src = source;
for (int i = 0; i < num; ++i, ++dst, ++src)
{
*dst = *src;
}
return destination;
}
int doom_strlen(const char* str)
{
int len = 0;
while (*str++) ++len;
return len;
}
char* doom_concat(char* dst, const char* src)
{
char* ret = dst;
dst += doom_strlen(dst);
while (*src) *dst++ = *src++;
*dst = *src; // \0
return ret;
}
char* doom_strcpy(char* dst, const char* src)
{
char* ret = dst;
while (*src) *dst++ = *src++;
*dst = *src; // \0
return ret;
}
char* doom_strncpy(char* dst, const char* src, int num)
{
int i = 0;
for (; i < num; ++i)
{
if (!src[i]) break;
dst[i] = src[i];
}
while (i < num) dst[i++] = '\0';
return dst;
}
int doom_strcmp(const char* str1, const char* str2)
{
int ret = 0;
while (!(ret = *(unsigned char*)str1 - *(unsigned char*) str2) && *str1)
++str1, ++str2;
if (ret < 0)
ret = -1;
else if (ret > 0)
ret = 1;
return (ret);
}
int doom_strncmp(const char* str1, const char* str2, int n)
{
int ret = 0;
int count = 1;
while (!(ret = *(unsigned char*)str1 - *(unsigned char*) str2) && *str1 && count++ < n)
++str1, ++str2;
if (ret < 0)
ret = -1;
else if (ret > 0)
ret = 1;
return (ret);
}
int doom_toupper(int c)
{
if (c >= 'a' && c <= 'z') return c - 'a' + 'A';
return c;
}
int doom_strcasecmp(const char* str1, const char* str2)
{
int ret = 0;
while (!(ret = doom_toupper(*(unsigned char*)str1) - doom_toupper(*(unsigned char*)str2)) && *str1)
++str1, ++str2;
if (ret < 0)
ret = -1;
else if (ret > 0)
ret = 1;
return (ret);
}
int doom_strncasecmp(const char* str1, const char* str2, int n)
{
int ret = 0;
int count = 1;
while (!(ret = doom_toupper(*(unsigned char*)str1) - doom_toupper(*(unsigned char*)str2)) && *str1 && count++ < n)
++str1, ++str2;
if (ret < 0)
ret = -1;
else if (ret > 0)
ret = 1;
return (ret);
}
int doom_atoi(const char* str)
{
int i = 0;
int c;
while ((c = *str++) != 0)
{
i *= 10;
i += c - '0';
}
return i;
}
int doom_atox(const char* str)
{
int i = 0;
int c;
while ((c = *str++) != 0)
{
i *= 16;
if (c >= '0' && c <= '9')
i += c - '0';
else
i += c - 'A' + 10;
}
return i;
}
const char* doom_itoa(int k, int radix)
{
int i = k < 0 ? -k : k;
if (i == 0)
{
itoa_buf[0] = '0';
itoa_buf[1] = '\0';
return itoa_buf;
}
int idx = k < 0 ? 1 : 0;
int j = i;
while (j)
{
j /= radix;
idx++;
}
itoa_buf[idx] = '\0';
if (radix == 10)
{
while (i)
{
itoa_buf[--idx] = '0' + (i % 10);
i /= 10;
}
}
else
{
while (i)
{
int k = (i & 0xF);
if (k >= 10)
itoa_buf[--idx] = 'A' + ((i & 0xF) - 10);
else
itoa_buf[--idx] = '0' + (i & 0xF);
i >>= 4;
}
}
if (k < 0) itoa_buf[0] = '-';
return itoa_buf;
}
const char* doom_ctoa(char c)
{
itoa_buf[0] = c;
itoa_buf[1] = '\0';
return itoa_buf;
}
const char* doom_ptoa(void* p)
{
int idx = 0;
unsigned long long i = (unsigned long long)p;
itoa_buf[idx++] = '0';
itoa_buf[idx++] = 'x';
while (i)
{
int k = (i & 0xF);
if (k >= 10)
itoa_buf[idx++] = 'A' + ((i & 0xF) - 10);
else
itoa_buf[idx++] = '0' + (i & 0xF);
i >>= 4;
}
itoa_buf[idx] = '\0';
return itoa_buf;
}
int doom_fprint(void* handle, const char* str)
{
return doom_write(handle, str, doom_strlen(str));
}
static default_t* get_default(const char* name)
{
for (int i = 0; i < numdefaults; ++i)
{
if (doom_strcmp(defaults[i].name, name) == 0) return &defaults[i];
}
return 0;
}
void doom_set_resolution(int width, int height)
{
if (width <= 0 || height <= 0) return;
// SCREENWIDTH = width;
// SCREENHEIGHT = height;
}
void doom_set_default_int(const char* name, int value)
{
default_t* def = get_default(name);
if (!def) return;
def->defaultvalue = value;
}
void doom_set_default_string(const char* name, const char* value)
{
default_t* def = get_default(name);
if (!def) return;
def->default_text_value = (char*)value;
}
void doom_set_print(doom_print_fn print_fn)
{
doom_print = print_fn;
}
void doom_set_malloc(doom_malloc_fn malloc_fn, doom_free_fn free_fn)
{
doom_malloc = malloc_fn;
doom_free = free_fn;
}
void doom_set_file_io(doom_open_fn open_fn,
doom_close_fn close_fn,
doom_read_fn read_fn,
doom_write_fn write_fn,
doom_seek_fn seek_fn,
doom_tell_fn tell_fn,
doom_eof_fn eof_fn)
{
doom_open = open_fn;
doom_close = close_fn;
doom_read = read_fn;
doom_write = write_fn;
doom_seek = seek_fn;
doom_tell = tell_fn;
doom_eof = eof_fn;
}
void doom_set_gettime(doom_gettime_fn gettime_fn)
{
doom_gettime = gettime_fn;
}
void doom_set_exit(doom_exit_fn exit_fn)
{
doom_exit = exit_fn;
}
void doom_set_getenv(doom_getenv_fn getenv_fn)
{
doom_getenv = getenv_fn;
}
void doom_init(int argc, char** argv, int flags)
{
if (!doom_print) doom_print = doom_print_impl;
if (!doom_malloc) doom_malloc = doom_malloc_impl;
if (!doom_free) doom_free = doom_free_impl;
if (!doom_open) doom_open = doom_open_impl;
if (!doom_close) doom_close = doom_close_impl;
if (!doom_read) doom_read = doom_read_impl;
if (!doom_write) doom_write = doom_write_impl;
if (!doom_seek) doom_seek = doom_seek_impl;
if (!doom_tell) doom_tell = doom_tell_impl;
if (!doom_eof) doom_eof = doom_eof_impl;
if (!doom_gettime) doom_gettime = doom_gettime_impl;
if (!doom_exit) doom_exit = doom_exit_impl;
if (!doom_getenv) doom_getenv = doom_getenv_impl;
screen_buffer = doom_malloc(SCREENWIDTH * SCREENHEIGHT);
final_screen_buffer = doom_malloc(SCREENWIDTH * SCREENHEIGHT * 4);
last_update_time = I_GetTime();
myargc = argc;
myargv = argv;
doom_flags = flags;
D_DoomMain();
}
void doom_update()
{
int now = I_GetTime();
int delta_time = now - last_update_time;
while (delta_time-- > 0)
{
if (is_wiping_screen)
D_UpdateWipe();
else
D_DoomLoop();
}
last_update_time = now;
}
const unsigned char* doom_get_framebuffer(int channels)
{
int i, len;
doom_memcpy(screen_buffer, screens[0], SCREENWIDTH * SCREENHEIGHT);
extern doom_boolean menuactive;
extern gamestate_t gamestate;
extern doom_boolean automapactive;
extern int crosshair;
// Draw crosshair
if (crosshair &&
!menuactive &&
gamestate == GS_LEVEL &&
!automapactive)
{
int y;
extern int setblocks;
if (setblocks == 11) y = SCREENHEIGHT / 2 + 8;
else y = SCREENHEIGHT / 2 - 8;
for (i = 0; i < 2; ++i)
{
screen_buffer[SCREENWIDTH / 2 - 2 - i + y * SCREENWIDTH] = 4;
screen_buffer[SCREENWIDTH / 2 + 2 + i + y * SCREENWIDTH] = 4;
}
for (i = 0; i < 2; ++i)
{
screen_buffer[SCREENWIDTH / 2 + (y - 2 - i) * SCREENWIDTH] = 4;
screen_buffer[SCREENWIDTH / 2 + (y + 2 + i) * SCREENWIDTH] = 4;
}
}
if (channels == 1)
{
return screen_buffer;
}
else if (channels == 3)
{
for (i = 0, len = SCREENWIDTH * SCREENHEIGHT; i < len; ++i)
{
int k = i * 3;
int kpal = screen_buffer[i] * 3;
final_screen_buffer[k + 0] = screen_palette[kpal + 0];
final_screen_buffer[k + 1] = screen_palette[kpal + 1];
final_screen_buffer[k + 2] = screen_palette[kpal + 2];
}
return final_screen_buffer;
}
else if (channels == 4)
{
for (i = 0, len = SCREENWIDTH * SCREENHEIGHT; i < len; ++i)
{
int k = i * 4;
int kpal = screen_buffer[i] * 3;
final_screen_buffer[k + 0] = screen_palette[kpal + 0];
final_screen_buffer[k + 1] = screen_palette[kpal + 1];
final_screen_buffer[k + 2] = screen_palette[kpal + 2];
final_screen_buffer[k + 3] = 255;
}
return final_screen_buffer;
}
else
{
return 0;
}
}
unsigned long doom_tick_midi()
{
return I_TickSong();
}
short* doom_get_sound_buffer()
{
I_UpdateSound();
return mixbuffer;
}
void doom_key_down(doom_key_t key)
{
event_t event;
event.type = ev_keydown;
event.data1 = (int)key;
D_PostEvent(&event);
}
void doom_key_up(doom_key_t key)
{
event_t event;
event.type = ev_keyup;
event.data1 = (int)key;
D_PostEvent(&event);
}
void doom_button_down(doom_button_t button)
{
button_states[button] = 1;
event_t event;
event.type = ev_mouse;
event.data1 =
(button_states[0]) |
(button_states[1] ? 2 : 0) |
(button_states[2] ? 4 : 0);
event.data2 = event.data3 = 0;
D_PostEvent(&event);
}
void doom_button_up(doom_button_t button)
{
button_states[button] = 0;
event_t event;
event.type = ev_mouse;
event.data1 =
(button_states[0]) |
(button_states[1] ? 2 : 0) |
(button_states[2] ? 4 : 0);
event.data1 =
event.data1
^ (button_states[0] ? 1 : 0)
^ (button_states[1] ? 2 : 0)
^ (button_states[2] ? 4 : 0);
event.data2 = event.data3 = 0;
D_PostEvent(&event);
}
void doom_mouse_move(int delta_x, int delta_y)
{
event_t event;
event.type = ev_mouse;
event.data1 =
(button_states[0]) |
(button_states[1] ? 2 : 0) |
(button_states[2] ? 4 : 0);
event.data2 = delta_x;
event.data3 = -delta_y;
if (event.data2 || event.data3)
{
D_PostEvent(&event);
}
}

View File

@ -0,0 +1,216 @@
//-----------------------------------------------------------------------------
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
//-----------------------------------------------------------------------------
/* Pure DOOM usage
Do this:
#define DOOM_IMPLEMENTATION
before you include this file in *one* C or C++ file to create the implementation.
// i.e. it should look like this:
#include ...
#include ...
#include ...
#define DOOM_IMPLEMENTATION
#include "PureDOOM.h"
*/
//-----------------------------------------------------------------------------
#ifndef __DOOM_H__
#define __DOOM_H__
// Sample rate of sound samples from doom
#define DOOM_SAMPLERATE 11025
// MIDI tick needs to be called 140 times per seconds
#define DOOM_MIDI_RATE 140
// Hide menu options. If for say your platform doesn't support mouse or
// MIDI playback, you can hide these settings from the menu.
#define DOOM_FLAG_HIDE_MOUSE_OPTIONS 1 // Remove mouse options from menu
#define DOOM_FLAG_HIDE_SOUND_OPTIONS 2 // Remove sound options from menu
#define DOOM_FLAG_HIDE_MUSIC_OPTIONS 4 // Remove music options from menu
// Darken background when menu is open, making it more readable. This
// uses a bit more CPU and redraws the HUD every frame
#define DOOM_FLAG_MENU_DARKEN_BG 8
#if __cplusplus
extern "C" {
#endif
typedef enum
{
DOOM_SEEK_CUR = 1,
DOOM_SEEK_END = 2,
DOOM_SEEK_SET = 0
} doom_seek_t;
typedef void(*doom_print_fn)(const char* str);
typedef void*(*doom_malloc_fn)(int size);
typedef void(*doom_free_fn)(void* ptr);
typedef void*(*doom_open_fn)(const char* filename, const char* mode);
typedef void(*doom_close_fn)(void* handle);
typedef int(*doom_read_fn)(void* handle, void *buf, int count);
typedef int(*doom_write_fn)(void* handle, const void *buf, int count);
typedef int(*doom_seek_fn)(void* handle, int offset, doom_seek_t origin);
typedef int(*doom_tell_fn)(void* handle);
typedef int(*doom_eof_fn)(void* handle);
typedef void(*doom_gettime_fn)(int* sec, int* usec);
typedef void(*doom_exit_fn)(int code);
typedef char*(*doom_getenv_fn)(const char* var);
// Doom key mapping
typedef enum
{
DOOM_KEY_UNKNOWN = -1,
DOOM_KEY_TAB = 9,
DOOM_KEY_ENTER = 13,
DOOM_KEY_ESCAPE = 27,
DOOM_KEY_SPACE = 32,
DOOM_KEY_APOSTROPHE = '\'',
DOOM_KEY_MULTIPLY = '*',
DOOM_KEY_COMMA = ',',
DOOM_KEY_MINUS = 0x2d,
DOOM_KEY_PERIOD = '.',
DOOM_KEY_SLASH = '/',
DOOM_KEY_0 = '0',
DOOM_KEY_1 = '1',
DOOM_KEY_2 = '2',
DOOM_KEY_3 = '3',
DOOM_KEY_4 = '4',
DOOM_KEY_5 = '5',
DOOM_KEY_6 = '6',
DOOM_KEY_7 = '7',
DOOM_KEY_8 = '8',
DOOM_KEY_9 = '9',
DOOM_KEY_SEMICOLON = ';',
DOOM_KEY_EQUALS = 0x3d,
DOOM_KEY_LEFT_BRACKET = '[',
DOOM_KEY_RIGHT_BRACKET = ']',
DOOM_KEY_A = 'a',
DOOM_KEY_B = 'b',
DOOM_KEY_C = 'c',
DOOM_KEY_D = 'd',
DOOM_KEY_E = 'e',
DOOM_KEY_F = 'f',
DOOM_KEY_G = 'g',
DOOM_KEY_H = 'h',
DOOM_KEY_I = 'i',
DOOM_KEY_J = 'j',
DOOM_KEY_K = 'k',
DOOM_KEY_L = 'l',
DOOM_KEY_M = 'm',
DOOM_KEY_N = 'n',
DOOM_KEY_O = 'o',
DOOM_KEY_P = 'p',
DOOM_KEY_Q = 'q',
DOOM_KEY_R = 'r',
DOOM_KEY_S = 's',
DOOM_KEY_T = 't',
DOOM_KEY_U = 'u',
DOOM_KEY_V = 'v',
DOOM_KEY_W = 'w',
DOOM_KEY_X = 'x',
DOOM_KEY_Y = 'y',
DOOM_KEY_Z = 'z',
DOOM_KEY_BACKSPACE = 127,
DOOM_KEY_CTRL = (0x80 + 0x1d), // Both left and right
DOOM_KEY_LEFT_ARROW = 0xac,
DOOM_KEY_UP_ARROW = 0xad,
DOOM_KEY_RIGHT_ARROW = 0xae,
DOOM_KEY_DOWN_ARROW = 0xaf,
DOOM_KEY_SHIFT = (0x80 + 0x36), // Both left and right
DOOM_KEY_ALT = (0x80 + 0x38), // Both left and right
DOOM_KEY_F1 = (0x80 + 0x3b),
DOOM_KEY_F2 = (0x80 + 0x3c),
DOOM_KEY_F3 = (0x80 + 0x3d),
DOOM_KEY_F4 = (0x80 + 0x3e),
DOOM_KEY_F5 = (0x80 + 0x3f),
DOOM_KEY_F6 = (0x80 + 0x40),
DOOM_KEY_F7 = (0x80 + 0x41),
DOOM_KEY_F8 = (0x80 + 0x42),
DOOM_KEY_F9 = (0x80 + 0x43),
DOOM_KEY_F10 = (0x80 + 0x44),
DOOM_KEY_F11 = (0x80 + 0x57),
DOOM_KEY_F12 = (0x80 + 0x58),
DOOM_KEY_PAUSE = 0xff
} doom_key_t;
// Mouse button mapping
typedef enum
{
DOOM_LEFT_BUTTON = 0,
DOOM_RIGHT_BUTTON = 1,
DOOM_MIDDLE_BUTTON = 2
} doom_button_t;
// For the software renderer. Default is 320x200
void doom_set_resolution(int width, int height);
// Set default configurations. Lets say, changing arrows to WASD as default controls
void doom_set_default_int(const char* name, int value);
void doom_set_default_string(const char* name, const char* value);
// set callbacks
void doom_set_print(doom_print_fn print_fn);
void doom_set_malloc(doom_malloc_fn malloc_fn, doom_free_fn free_fn);
void doom_set_file_io(doom_open_fn open_fn,
doom_close_fn close_fn,
doom_read_fn read_fn,
doom_write_fn write_fn,
doom_seek_fn seek_fn,
doom_tell_fn tell_fn,
doom_eof_fn eof_fn);
void doom_set_gettime(doom_gettime_fn gettime_fn);
void doom_set_exit(doom_exit_fn exit_fn);
void doom_set_getenv(doom_getenv_fn getenv_fn);
// Initializes DOOM and start things up. Call only call one
void doom_init(int argc, char** argv, int flags);
// Call this every frame
void doom_update();
// Channels: 1 = indexed, 3 = RGB, 4 = RGBA
const unsigned char* doom_get_framebuffer(int channels);
// It is always 2048 bytes in size
short* doom_get_sound_buffer();
// Call this 140 times per second. Or about every 7ms.
// Returns midi message. Keep calling it until it returns 0.
unsigned long doom_tick_midi();
// Events
void doom_key_down(doom_key_t key);
void doom_key_up(doom_key_t key);
void doom_button_down(doom_button_t button);
void doom_button_up(doom_button_t button);
void doom_mouse_move(int delta_x, int delta_y);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

View File

@ -0,0 +1,106 @@
LIMITED USE SOFTWARE LICENSE AGREEMENT
This Limited Use Software License Agreement (the "Agreement")
is a legal agreement between you, the end-user, and Id Software, Inc.
("ID"). By downloading or purchasing the software material, which
includes source code (the "Source Code"), artwork data, music and
software tools (collectively, the "Software"), you are agreeing to
be bound by the terms of this Agreement. If you do not agree to the
terms of this Agreement, promptly destroy the Software you may have
downloaded or copied.
ID SOFTWARE LICENSE
1. Grant of License. ID grants to you the right to use the
Software. You have no ownership or proprietary rights in or to the
Software, or the Trademark. For purposes of this section, "use" means
loading the Software into RAM, as well as installation on a hard disk
or other storage device. The Software, together with any archive copy
thereof, shall be destroyed when no longer used in accordance with
this Agreement, or when the right to use the Software is terminated.
You agree that the Software will not be shipped, transferred or
exported into any country in violation of the U.S. Export
Administration Act (or any other law governing such matters) and that
you will not utilize, in any other manner, the Software in violation
of any applicable law.
2. Permitted Uses. For educational purposes only, you, the
end-user, may use portions of the Source Code, such as particular
routines, to develop your own software, but may not duplicate the
Source Code, except as noted in paragraph 4. The limited right
referenced in the preceding sentence is hereinafter referred to as
"Educational Use." By so exercising the Educational Use right you
shall not obtain any ownership, copyright, proprietary or other
interest in or to the Source Code, or any portion of the Source
Code. You may dispose of your own software in your sole discretion.
With the exception of the Educational Use right, you may not
otherwise use the Software, or an portion of the Software, which
includes the Source Code, for commercial gain.
3. Prohibited Uses: Under no circumstances shall you, the
end-user, be permitted, allowed or authorized to commercially exploit
the Software. Neither you nor anyone at your direction shall do any
of the following acts with regard to the Software, or any portion
thereof:
Rent;
Sell;
Lease;
Offer on a pay-per-play basis;
Distribute for money or any other consideration; or
In any other manner and through any medium whatsoever
commercially exploit or use for any commercial purpose.
Notwithstanding the foregoing prohibitions, you may commercially
exploit the software you develop by exercising the Educational Use
right, referenced in paragraph 2. hereinabove.
4. Copyright. The Software and all copyrights related thereto
(including all characters and other images generated by the Software
or depicted in the Software) are owned by ID and is protected by
United States copyright laws and international treaty provisions.
Id shall retain exclusive ownership and copyright in and to the
Software and all portions of the Software and you shall have no
ownership or other proprietary interest in such materials. You must
treat the Software like any other copyrighted material. You may not
otherwise reproduce, copy or disclose to others, in whole or in any
part, the Software. You may not copy the written materials
accompanying the Software. You agree to use your best efforts to
see that any user of the Software licensed hereunder complies with
this Agreement.
5. NO WARRANTIES. ID DISCLAIMS ALL WARRANTIES, BOTH EXPRESS
IMPLIED, INCLUDING BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE WITH RESPECT
TO THE SOFTWARE. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL
RIGHTS. YOU MAY HAVE OTHER RIGHTS WHICH VARY FROM JURISDICTION TO
JURISDICTION. ID DOES NOT WARRANT THAT THE OPERATION OF THE SOFTWARE
WILL BE UNINTERRUPTED, ERROR FREE OR MEET YOUR SPECIFIC REQUIREMENTS.
THE WARRANTY SET FORTH ABOVE IS IN LIEU OF ALL OTHER EXPRESS
WARRANTIES WHETHER ORAL OR WRITTEN. THE AGENTS, EMPLOYEES,
DISTRIBUTORS, AND DEALERS OF ID ARE NOT AUTHORIZED TO MAKE
MODIFICATIONS TO THIS WARRANTY, OR ADDITIONAL WARRANTIES ON BEHALF
OF ID.
Exclusive Remedies. The Software is being offered to you
free of any charge. You agree that you have no remedy against ID, its
affiliates, contractors, suppliers, and agents for loss or damage
caused by any defect or failure in the Software regardless of the form
of action, whether in contract, tort, includinegligence, strict
liability or otherwise, with regard to the Software. This Agreement
shall be construed in accordance with and governed by the laws of the
State of Texas. Copyright and other proprietary matters will be
governed by United States laws and international treaties. IN ANY
CASE, ID SHALL NOT BE LIABLE FOR LOSS OF DATA, LOSS OF PROFITS, LOST
SAVINGS, SPECIAL, INCIDENTAL, CONSEQUENTIAL, INDIRECT OR OTHER
SIMILAR DAMAGES ARISING FROM BREACH OF WARRANTY, BREACH OF CONTRACT,
NEGLIGENCE, OR OTHER LEGAL THEORY EVEN IF ID OR ITS AGENT HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY
OTHER PARTY. Some jurisdictions do not allow the exclusion or
limitation of incidental or consequential damages, so the above
limitation or exclusion may not apply to you.

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More